Swagger UI using swasbuckle is getting me CORS Origin issue on login redirect from Azure - asp.net-core

I'm facing a new issue with swashbuckle and login redirection after make a request and my token has been expired.
I really don't know if is a common issue or if this thins can't be done, that's why I make the question.
My request to my api enponit redirects fine but, when I click the Execute button on swagger UI, the request to https://localhost:port/api/v1/Contacts, the response is 302 and then try to redirect me to my login provider with this issue and I cannot redirect to login again.
What I'm missing here????
this is my authentication config:
//Add Auth options
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddOpenIdConnect(options =>
{
options.ClientId = ClientId;
options.Authority = $"{Instance}/{TenantId}";
options.SignedOutRedirectUri = SignedOutRedirectUri;
// Add needed scopes
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("roles");
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
options.SaveTokens = true;
options.Events = new OpenIdConnectEvents
{
OnRemoteFailure = context =>
{
context.HandleResponse();
return Task.CompletedTask;
}
};
})
.AddCookie()
.AddAzureAdBearer(options => configuration.Bind("bearer", options));

Related

How to use cookie authentication for Ocelot apigatway

I am using IdentitySever which issue id_token. Their is another website which uses cookie authentication with openidconnect. Code is as below
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Allow sign in via an OpenId Connect provider like OneLogin
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromHours(12);
options.SlidingExpiration = false;
options.Cookie.Name = "TestApp";
})
.AddOpenIdConnect(options =>
{
options.RequireHttpsMetadata = false;
options.SignInScheme = "Cookies";
options.ClientId = "Test";
options.ClientSecret = "client_sceret";
options.Authority = "http://localhost:57744/identity";
options.ResponseType = "id_token";
options.GetClaimsFromUserInfoEndpoint = true;
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = redirectToIdentityProvider
};
}
);
services.Configure<OidcOptions>(Configuration.GetSection("oidc"));
}
I am creating another Apigateway. If user is logged in website than should be able to make api request through gateway. Both website and gateway will be hosted under same sub-domain While making request to apigateway I will pass cookie created by website in header and want to utilize it at gateway to get claims from identityserver.
Is their way to integrate cookie authentication and identity sever with ocelot gateway?

Identityserve 4 in production env : "IDX10501: Signature validation failed. Unable to match key"

I have a 3 tier .NET core application with:
identityserver 4
an API
a blazer app
On my local/dev computer, everything works fine. But, I have installed everything
into a real server and then I have an issue that appears.
I log into the application, play with, then I wait some time (don't know how much) and then when I try to use the app, the Blazor app crash because of this code :
bool isAuthenticated = await _authenticationVerifier.IsAuthenticatedAsync();
if (isAuthenticated)
User = await _userAppService.GetCurrentUserAsync();
The 'isAuthenticated' is true, in fact my cookies look good, but the Blazor app is no more authorized to connect to the API server.
I got the following error message on the API server:
Bearer was not authenticated. Failure message: IDX10501: Signature validation failed. Unable to match key:
kid: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
Exceptions caught: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
token: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
What is strange is that it work for some time, then after some time (1/2 days), I got this crash.
I don't know what to check and/or how to debug this issue. I'm looking for a solution since weeks :-(
I join some code:
On the API Server:
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = true;
options.ApiName = "MyAppName";
});
}
On the Blazor (Server side Blazor):
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", options =>
{
options.ExpireTimeSpan = TimeSpan.FromDays(ApplicationConstants.LoginCookieExpirationDelay);
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = true;
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.ClientId = configuration["AuthServer:ClientId"];
options.ClientSecret = configuration["AuthServer:ClientSecret"];
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("role");
options.Scope.Add("email");
options.Scope.Add("phone");
options.Scope.Add("SoCloze");
options.ClaimActions.MapAbpClaimTypes();
});
context.Services.AddSingleton<BlazorServerAuthStateCache>();
context.Services.AddScoped<AuthenticationStateProvider, BlazorServerAuthState>();
context.Services.AddScoped<AuthenticationVerifier>();
}
On the IdentityServer 4 side:
// Identity cookie expiration
context.Services.ConfigureApplicationCookie(options =>
{
options.Cookie.Name = ".AspNetCore.Identity.Application";
options.ExpireTimeSpan = TimeSpan.FromDays(ApplicationConstants.LoginCookieExpirationDelay);
});
var clientConfig = context.Services.GetConfiguration().GetSection("IdentityServer:Clients");
context.Services
.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
options.RequireAuthenticatedSignIn = true;
})
.AddFacebook("Facebook", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.AppId = clientConfig["Facebook:ClientId"];
options.AppSecret = clientConfig["Facebook:ClientSecret"];
options.Fields.Add("picture");
})
.AddIdentityCookies();
}

How do I get more recent userinfo with AddJwtBearer

We use IdentityServer to handle SSO authentication across our apps.
My application is an Aspnet core 3.0 website that passes the users Token to javascript. The javascript then calls a separate aspnet 2.2 API.
Problem: Logging a user out and back in does not update the ClaimsPrincipal on the API with new claims.
I have confirmed that the Web application has the new claims.
If I login Incognito or clear my cookies the new claim shows up in the API.
I am not sure where the responsibility for getting the claims should be and how to fix it. I assume the claims are part of the encrypted access_token, therefore I assume the Web app is sending a stale access_token to the API. So is the Web App what I need to fix? And what would be the proper fix?
Api Startup Code
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Bearer";
options.DefaultChallengeScheme = "Bearer";
})
.AddJwtBearer(options =>
{
options.Authority = oidcSettings.Authority;
options.Audience = oidcSettings.ApplicationName;
options.RequireHttpsMetadata = true;
});
Web App Startup Code
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
options.OnAppendCookie = cookieContext => { cookieContext.CookieOptions.SameSite = SameSiteMode.None; };
options.OnDeleteCookie = cookieContext =>
{
cookieContext.CookieOptions.SameSite = SameSiteMode.None; // this doesn't appear to get called.
};
});
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies", options =>
{
options.SlidingExpiration = false;
options.ExpireTimeSpan = TimeSpan.FromHours(8);
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = oidcSettings.Authority;
options.RequireHttpsMetadata = true;
options.ClientId = oidcSettings.ClientId;
options.ClientSecret = oidcSettings.ClientKey;
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("offline_access");
options.Scope.Add(oidcSettings.ApplicationName);
options.ClaimActions.MapJsonKey("role", "role"); // claims I am looking for are mapped here
options.Events.OnUserInformationReceived = async (context) =>
{
await Task.CompletedTask; // confirmed that after new sign in I can see updated info here.
};
});
TLDR: Javascript from Web app calls Api using access_token. When user logs out and logs back in, the API does not receive updated claims. I am not sure if the issue is the API needs to call out to identity server for user info or the Web App is not signing out properly and needs to send a fresh access_token?

Asp.net core 2.0+ - Multiple Authentication Schemes (Cookie / Bearer)

I've been struggling to get multiple authentication schemes working correctly in Asp.net core 2.1.
I am using Identity Server with an implicit flow and OpenIdConnect as the protocol.
When authorizing an action or controller with one of the schemes only (e.g Cookie or Bearer) the functionality works correctly.
Example:
[Authorize(AuthenticationSchemes = "Cookies")]
[Route("Cookies")]
public class BearerAndCookiesController : Controller {
If I however I specify on the Authorize attribute both schemes, then it fails partially. Bearer works as normal, but when I try to view the page in the browser it attempts to redirect to a local Login page (http://localhost/Account/Login).
When I inspect the debug logs of Identity Server nothing is returned, which makes sense as it hasn't attempted to contact the Authority. However when I look at the debug log of the Test MVC Site both the Bearer and Cookie schemes are challenged:
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:5002/cookies
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "Get", controller = "BearerAndCookies"}. Executing action MvcClient.Controllers.BearerAndCookiesController.Get (MvcClient)
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 (Bearer, Cookies).
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AuthenticationScheme: Bearer was challenged.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Cookies was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action MvcClient.Controllers.BearerAndCookiesController.Get (MvcClient) in 68.1922ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 93.2016ms 302
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:5002/Account/Login?ReturnUrl=%2Fcookies
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 30.2532ms 404
Failed to load resource: the server responded with a status of 404 (Not Found) [http://localhost:5002/Account/Login?ReturnUrl=%2Fcookies]
Does anyone know why this isn't working? I'll the person a beer! It's been hunting me for the last week.
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-2.2&tabs=aspnetcore2x
Here is my Startup.cs configuration:
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options => {
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddJwtBearer(options => {
options.Authority = "http://localhost:5000";
options.Audience = "myApi";
options.RequireHttpsMetadata = false;
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options => {
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "myApi";
options.SaveTokens = true;
});
}
[Authorize(AuthenticationSchemes = AuthSchemes)]
[Route("Cookies")]
public class BearerAndCookiesController : Controller {
private const string AuthSchemes =
JwtBearerDefaults.AuthenticationScheme + "," +
CookieAuthenticationDefaults.AuthenticationScheme;
I wanted to give a better explanation of this answer:
I had to move services.AddAuthorization after the part were I
added both of the schemes. This ensures both schemes are registered
correctly.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options => {
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options => {
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "myApi";
options.SaveTokens = true;
}).AddIdentityServerAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme, options => {
options.Authority = "http://localhost:5000";
options.ApiName = "myApi";
options.RequireHttpsMetadata = false;
});
services.AddAuthorization(options => {
...
});
Then instead of specifying the Authorization Scheme as a part of the
Controller Action Authorize tag, I used a global policy when using
services.AddAuthorization
services.AddAuthorization(options =>
{
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
CookieAuthenticationDefaults.AuthenticationScheme,
JwtBearerDefaults.AuthenticationScheme);
defaultAuthorizationPolicyBuilder =
defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});
When I navigated to the any parts of the API it wouldn't redirect to the Login screen. I noticed that if you logged in first by navigating to Identity Server, then go back to that page it would actually authenticate you as normal. So I've put in what feel to be a little bit of hack. It is important that this directly goes in under the app.UseAuthentication.
app.UseAuthentication();
app.Use(async (context, next) => {
await next();
var bearerAuth = context.Request.Headers["Authorization"]
.FirstOrDefault()?.StartsWith("Bearer ") ?? false;
if (context.Response.StatusCode == 401
&& !context.User.Identity.IsAuthenticated
&& !bearerAuth) {
await context.ChallengeAsync("oidc");
}
});
Bob's your uncle... and thanks to this post for helping considerably!! oipapio.com/question-1510997

Sharing cookie between two applications

I have a question regarding sharing of cookies between multiple ASP.NET Core applications and Entity Framework.
I Have Two domains
www.servic2.com
www.servic1.com
I'am setting cookie in servic1 but need cookie on servic2.
I can't get the authentication to persist across both.
I have the startup.cs configured in the following way:
.AddAuthentication(options =>
{
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.SlidingExpiration = true;
options.LoginPath = "/Login";
options.LogoutPath = "/Logout";
//options.AccessDeniedPath = new PathString("/Home/Forbidden/");
//options.Cookie.Name = ".my.app1.cookie";
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
//Indicates whether the browser should allow the cookie to be attached to same-site requests only (SameSiteMode.Strict) or cross-site requests using safe HTTP methods and same-site requests (SameSiteMode.Lax).
options.Cookie.SameSite = SameSiteMode.Lax;
options.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = context =>
{
var cookieValidatorService = context.HttpContext.RequestServices.GetRequiredService<ICookieValidatorService>();
return cookieValidatorService.ValidateAsync(context);
}
};
});