Signature is invalid while calling Saml2PostBinding.Unbind() - itfoxtec-identity-saml2

We are getting "Signature is invalid" errors while calling Unbind() and stumbled upon this in code.
https://github.com/ITfoxtec/ITfoxtec.Identity.Saml2/blob/42a2d6de46f38d14f0c6f607594d19f2366ad5f2/src/ITfoxtec.Identity.Saml2/Bindings/Saml2PostBinding.cs#L106
Why validateXmlSignature argmument is always true within UnbindInternal()?
protected override Saml2Request UnbindInternal(HttpRequest request, Saml2Request saml2RequestResponse, string messageName)
{
UnbindInternal(request, saml2RequestResponse);
return Read(request, saml2RequestResponse, messageName, true, true);
}
Our calling code:
var binding = new Saml2PostBinding();
var saml2AuthnResponse = new Saml2AuthnResponse(saml2Config);
binding.ReadSamlResponse(Request.ToGenericHttpRequest(), saml2AuthnResponse);
if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
{
throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
}
binding.Unbind(Request.ToGenericHttpRequest(), saml2AuthnResponse);

The validateXmlSignature argument is always true because the signature is placed in XML in a POST binding and the SAML 2.0 Authn response signature has to be validated. The signature validation is the trust of the SAML 2.0 token.

Related

JSESSIONID changing every time API Fires. if same then CORS POLICY issue

So here is the Problem.
Front end: React Js
Backend: Spring Boot (No .xml file only annotation and properties files)
What I did is first user have to login then only he can access other APIs
when user login:
#PostMapping("/signin")
public boolean signIn(HttpServletRequest request, #Valid #RequestBody UserCredentials loginData) {
return userCredentials.signInToAccount(request, loginData);
}
It will goes to this file and then it calls service class
#Override
public boolean signInToAccount(HttpServletRequest request, UserCredentials loginData) {
UserCredentials user;
HttpSession session;
try {
user = userDAO.findById(loginData.getAssociateId()).get();
} catch (NoSuchElementException e) {
logger.error(e.getMessage());
throw new NoSuchElementException(env.getProperty("signin.invalidId.error"));
}
if (user.getPassword().equals(loginData.getPassword())
&& user.getIsAssociateActive().equals(env.getProperty("active.yes"))) {
session = request.getSession(true);
session.setAttribute(env.getProperty("session.attribute"), loginData.getAssociateId());
return true;
} else {
return false;
}
}
Here I am setting the session with logged user id:
Now When I try to use any APIs like
#GetMapping("/my-tasks")
public List<Task> getAllTaskInfo(HttpServletRequest request) throws UserNotLoggedInException {
String id = session.getSessionAttributeValue(request);
return taskServices.getAllTasksDetail(id);
}
It called the session to get the id if session is not created then User Define Exception is thrown.
Here is my session file:
public String getSessionAttributeValue(HttpServletRequest request) throws UserNotLoggedInException {
String loginFirst = "";
try {
HttpSession session = request.getSession();
loginFirst = properties.getPropertyObject("session.notlogin");
return session.getAttribute(properties.getPropertyObject("session.attribute")).toString();
} catch (Exception e) {
throw new UserNotLoggedInException(loginFirst);
}
}
With Postman it is working fine.
But for Browser(edge,chrome) its nt working.
What I tried:
I tried to debug I found that with postman cookies stored with same id after login but with browser JSESSIONID is changed every time its called for APIs.
Please help me.
Thanking you in advance.
EDIT 1:
I used withCredentials:true in my api call like this
axios.post(BASE_URL_USER + "/signin", credentials,{withCredentials:true});
But now Facing CORS error
Access to XMLHttpRequest at 'http://localhost:9090/signin' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
I tried to remove the #CrossOrigin("*") to #CrossOrigin(origin="http://localhost:3000") or #CrossOrigin(origin="http://localhost:9090")
but not working
I have not applied any security filter or configuration in my backend and neither any header or cors nothing in frontend .
Just a normal call from frontend to backend.
Note: it is working perfectly with POSTMAN.

IDP Initiated Login

I'm trying to implement an IDP Initiated login in my company, we hire a platform that generates a SAML XML response for me and posts it to my backend (.NET Core 3.1).
This SAML Response is a Base64 hash and has already been converted to XML. The lib has some specific method to deal with SAML response in this scenario?
Thanks!
It is more or less the samme as the TestWebAppCore sample expect to recive in the AssertionConsumerService method. The code show a post binding, you can change it to redirect if the authn response is send as a query parameter.
var binding = new Saml2PostBinding();
var saml2AuthnResponse = new Saml2AuthnResponse(config);
binding.ReadSamlResponse(Request.ToGenericHttpRequest(), saml2AuthnResponse);
if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
{
throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
}
binding.Unbind(Request.ToGenericHttpRequest(), saml2AuthnResponse);
await saml2AuthnResponse.CreateSession(HttpContext, claimsTransform: (claimsPrincipal) => ClaimsTransform.Transform(claimsPrincipal));
var relayStateQuery = binding.GetRelayStateQuery();
//var some_value = relayStateQuery.ContainsKey("some_key");
return Redirect("...some_url...");

No shared secret configured for client for IdentityServer4's reference token

I'm using IdentityServer4 with IdentityServer4.AccessTokenValidation for handling Reference Token.
This is what I have done in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// Add identity server 4.
services.AddIdentityServer()
.AddProfileService<IdentityServerProfileService>()
.AddInMemoryClients(LoadInMemoryIdentityServerClients())
.AddInMemoryApiResources(LoadInMemoryApiResources())
.AddInMemoryIdentityResources(LoadInMemoryIdentityResource())
.AddProfileService<IdentityServerProfileService>()
.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
.AddDeveloperSigningCredential();
// Add jwt validation.
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddIdentityServerAuthentication(options =>
{
// base-address of your identityserver
options.Authority = "https://localhost:44386";
options.ClaimsIssuer = "https://localhost:44386";
// name of the API resource
options.ApiName = "api1";
options.ApiSecret = "web-api-secret";
options.RequireHttpsMetadata = false;
});
}
protected static IEnumerable<Client> LoadInMemoryIdentityServerClients()
{
var clients = new List<Client>();
var client = new Client();
client.ClientId = "web-api-client";
client.AllowedGrantTypes = GrantTypes.ResourceOwnerPassword;
client.ClientSecrets = new[] {new Secret("web-api-secret".Sha256())};
client.AccessTokenType = AccessTokenType.Reference;
client.AllowedScopes = new[]
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.Address,
"api1"
};
clients.Add(client);
return clients;
}
protected static IEnumerable<IdentityResource> LoadInMemoryIdentityResource()
{
//var profileIdentityResource = new IdentityResource("repository-read", "repository-read", new List<string> { "claim-01", "age" });
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
//profileIdentityResource
};
}
protected static IEnumerable<ApiResource> LoadInMemoryApiResources()
{
var apiResources = new List<ApiResource>();
var apiResource = new ApiResource("api1", "My API");
apiResource.UserClaims = new[]
{
"age"
};
apiResources.Add(apiResource);
return apiResources;
}
When I make a request with structure shown in the below image:
I received a token.
After using the received token to make a request to protected api resource api/user/search. It gave me 401 status code.
In visual studio output. This is what I saw:
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST http://localhost:56219/api/user/search application/json 5
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 10.9132ms 307
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST https://localhost:44386/api/user/search application/json 5
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST https://localhost:44386/connect/introspect application/x-www-form-urlencoded 143
IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Debug: AuthenticationScheme: Bearer was not authenticated.
IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Debug: AuthenticationScheme: Bearer was not authenticated.
IdentityServer4.Hosting.EndpointRouter:Debug: Request path /connect/introspect matched to endpoint type Introspection
IdentityServer4.Hosting.EndpointRouter:Debug: Endpoint enabled: Introspection, successfully created handler: IdentityServer4.Endpoints.IntrospectionEndpoint
IdentityServer4.Hosting.IdentityServerMiddleware:Information: Invoking IdentityServer endpoint: IdentityServer4.Endpoints.IntrospectionEndpoint for /connect/introspect
IdentityServer4.Endpoints.IntrospectionEndpoint:Debug: Starting introspection request.
IdentityServer4.Validation.BasicAuthenticationSecretParser:Debug: Start parsing Basic Authentication secret
IdentityServer4.Validation.PostBodySecretParser:Debug: Start parsing for secret in post body
IdentityServer4.Validation.SecretParser:Debug: Parser found secret: PostBodySecretParser
IdentityServer4.Validation.SecretParser:Debug: Secret id found: api1
IdentityServer4.Validation.HashedSharedSecretValidator:Debug: No shared secret configured for client.
IdentityServer4.Validation.SecretValidator:Debug: Secret validators could not validate secret
IdentityServer4.Validation.ApiSecretValidator:Error: API validation failed.
IdentityServer4.Endpoints.IntrospectionEndpoint:Error: API unauthorized to call introspection endpoint. aborting.
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 57.8551ms 401
IdentityModel.AspNetCore.OAuth2Introspection.OAuth2IntrospectionHandler:Error: Error returned from introspection endpoint: Unauthorized
IdentityModel.AspNetCore.OAuth2Introspection.OAuth2IntrospectionHandler:Information: BearerIdentityServerAuthenticationIntrospection was not authenticated. Failure message: Error returned from introspection endpoint: Unauthorized
IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Information: Bearer was not authenticated. Failure message: Error returned from introspection endpoint: Unauthorized
IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Information: Bearer was not authenticated. Failure message: Error returned from introspection endpoint: Unauthorized
IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Information: Bearer was not authenticated. Failure message: Error returned from introspection endpoint: Unauthorized
Microsoft.AspNetCore.Routing.EndpointMiddleware:Information: Executing endpoint 'QrApi.Controllers.UserController.SearchUsersAsync (QrApi)'
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "SearchUsersAsync", controller = "User"}. Executing action QrApi.Controllers.UserController.SearchUsersAsync (QrApi)
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
IdentityModel.AspNetCore.OAuth2Introspection.OAuth2IntrospectionHandler:Information: AuthenticationScheme: BearerIdentityServerAuthenticationIntrospection was challenged.
IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Information: AuthenticationScheme: Bearer was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action QrApi.Controllers.UserController.SearchUsersAsync (QrApi) in 10.8603ms
Microsoft.AspNetCore.Routing.EndpointMiddleware:Information: Executed endpoint 'QrApi.Controllers.UserController.SearchUsersAsync (QrApi)'
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 135.7991ms 401
I have found tutorials about reference token, but none of them help me to solve this case.
What am I missing ?
Thank you,
Seems to be my configuration is invalid for API Resource.
This is my original setting for API Resources:
protected static IEnumerable<ApiResource> LoadInMemoryApiResources()
{
var apiResources = new List<ApiResource>();
var apiResource = new ApiResource("api1", "My API");
apiResource.UserClaims = new[]
{
"age"
};
apiResources.Add(apiResource);
return apiResources;
}
After having added the shared secret key which has been defined in client.ClientSecrets = new[] {new Secret("web-api-secret".Sha256())}; to apiResource:
protected static IEnumerable<ApiResource> LoadInMemoryApiResources()
{
//...
var apiResource = new ApiResource("api1", "My API");
api1Resource.ApiSecrets.Add(new Secret("web-api-secret".Sha256()));
//...
}
I could make request to protected resources successfully.
Hope this helps someone who is struggling with IdentityServer4 as I did.
My solution was to add the secret when instantiating the API resource.
protected static IEnumerable<ApiResource> LoadInMemoryApiResources()
{
var apiResources = new List<ApiResource>();
var apiResource = new ApiResource("api1", "My API"){
ApiSecrets = new List<Secret>{
new Secret("web-api-secret".Sha256())
},
Scopes = {
new Scope("openid")
}
};
apiResources.Add(apiResource);
return apiResources;
}
It looks like the issue could be that you don't have an API secret configured. In your config file change the API resource to match the configuration below. I believe to communicate with the introspection endpoint the api secret is required.
return new List<ApiResource>
{
new ApiResource("api1", "My API")
{
ApiSecrets = new List<Secret>
{
new Secret("secret".Sha256())
}
}
};

asp.net web api Authorize 302 code

When I send request from client side I received 302 code and redirect to login but
next I received:
Console log: XMLHttpRequest cannot load https://login.microsoftonline.com/........................ No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://localhost:' is therefore not allowed access.
Error: Response with status: 0 for URL: null
ApiController:
[Authorize]
public string Get()
{ }
I would like to return status code 401 or something like that.
It seems like you have not enabled CORS in your API or that you are using cookie authentication instead of Token based auth.
To return a 401 instead of a 302 you could write some Custom Owin Middleware that would check what your controller is returning and alter the response to make it fit your needs.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Middleware
{
using Microsoft.Owin;
public sealed class MyCustomMiddleware : OwinMiddleware
{
public MyCustomMiddleware(OwinMiddleware next)
: base(next)
{
}
public override async System.Threading.Tasks.Task Invoke(IOwinContext context)
{
// Code here executed before reaching the controller
await Next.Invoke(context);
// Code here executed after reaching the controller, includes the response
// check response here and modify it to suit your needs
if(context.Response.StatusCode == 302) {
var headers = context.Response.Headers;
headers.Keys.ForEach(k => headers.Remove(k));
context.Response.StatusCode = 401;
context.Response.ContentType = string.Empty;
context.Response.ContentLength = null;
await context.Response.WriteAsync(string.Empty);
}
}
}
}
then in startup.cs
app.Use<Middleware.MyCustomMiddleware>();

Invalid CSRF Token in POST request

Overview
I am going to use API Gateway as the authentication which based on Spring security. I've just been following the steps in the https://spring.io/guides/tutorials/spring-security-and-angular-js/ link to create a project based on "pairs-double" module of its corresponding github project of https://github.com/spring-guides/tut-spring-security-and-angular-js.git.
Problem
The issue is the fact that when any POST request is submitted to the server the "Invalid CSRF Token" exception is thrown. An example of the thrown exception is as follows:
{
"timestamp": 1461714933215,
"status": 403,
"error": "Forbidden",
"message": "Invalid CSRF Token '1cdc44ad-43cb-44e6-b903-bec24fe903fd' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'.",
"path": "/ui/test"
}
I checked an rechecked the issue but to no avail. I tested this scenario with postman and set the 'X-XSRF-TOKEN' as the header of the POST request but nothing happened.
So, as I am beginner in using Spring security approaches, I would appreciate it if anyone could suggest me a solution.
Looking at the security configuration of that project, you will notice that a XSRF-TOKEN cookie is being added in each request using a filter. So what you have to do is take the value of that cookie and store it in X-XSRF-TOKEN header. I've made a test project with similar security configuration to test out this case, the complete code looks like this:
#RestController
#SpringBootApplication
public class TestApplication extends WebSecurityConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**") // Disable authentication for all requests.
.permitAll()
.and()
.csrf().csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), SessionManagementFilter.class); // Register csrf filter.
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null
&& !token.equals(cookie.getValue())) {
// Token is being added to the XSRF-TOKEN cookie.
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String testGet() {
return "hello";
}
#RequestMapping(value = "/test", method = RequestMethod.POST)
public String testPost() {
return "works!";
}
}
To test this out with postman do the following:
Enable interceptor to start capturing cookies.
Perform a GET /test request and open the cookies tab. There you should notice a cookie with a name XSRF-TOKEN.
Take the value of that cookie and put it in X-XSRF-TOKEN header and perform a POST /test request.

Resources