JWT Authorization with IdentityServer4 - authorization

I am getting Authorization error in postman which using JWT token. Please find below details
Code in identity server
services.AddIdentityServer() .AddAspNetIdentity() .AddConfigurationStore(options => { options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, opt => opt.MigrationsAssembly(migrationAssembly)); }) .AddOperationalStore(options => { options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, opt => opt.MigrationsAssembly(migrationAssembly)); }) .AddSigningCredential(certificate);
Code in API
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = "localhost:44339"; });
Token generated is :
eyJhbGciOiJSUzI1NiIsImtpZCI6IjgyRTlFNTUwRkY4MTM2ODRDRDRFRjNEQ0MyMzVBMjQyMTZFNkU1Q0NSUzI1NiIsInR5cCI6ImF0K2p3dCIsIng1dCI6Imd1bmxVUC1CTm9UTlR2UGN3aldpUWhibTVjdyJ9.eyJuYmYiOjE2NDEwNjMzMTYsImV4cCI6MTY0MTA2NjkxNiwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NDQzMzkiLCJhdWQiOiJwb2xpY3lzZXJ2aWNlIiwiY2xpZW50X2lkIjoieWNvbXBhbnlhbmd1bGFyY2xpZW50Iiwic3ViIjoiYzk2OTNjMTUtYzU4OS00OGE4LThjMDctYjE1ODQzODMwNjMzIiwiYXV0aF90aW1lIjoxNjQxMDYzMjkwLCJpZHAiOiJsb2NhbCIsIlVzZXJJRCI6ImM5NjkzYzE1LWM1ODktNDhhOC04YzA3LWIxNTg0MzgzMDYzMyIsIlJvbGUiOiJBZG1pbiIsImp0aSI6IjYxRTU1RTg2OTZGMURDRUE2QjJFNUNDREUyMjgwQzkwIiwiaWF0IjoxNjQxMDYzMzE2LCJzY29wZSI6WyJwb2xpY3lzZXJ2aWNlc2NvcGUiXSwiYW1yIjpbInB3ZCJdfQ.e8Uj7P6RCv0ZY0Fg-xeZT558uCJhyyvY0SbOsiFNSJYeDxJ42jK4b_pOG90kMRKHI_ENIbMllHizbAOWetJhWxFLzApP_qCmvKIs1CJNiE8g5B9XH5l3lWsmIDnfgVLu98KLjKOg7F0gVMVyq4NooNVD1DKcmflddBHzGtN4QD3kzOhHPcL4EeJHq7dxL_y6t-AUYD4oDeAf_kGtv-XLaVIyyahqUdJykEguG8GG7A0RKzHSlVSFsBQzMoBSsp-KvhAutKcfK53bACgZLQ2jlMBFLSofCuCBdwrStKFss6yPtq2qQqhh-bOa22bgGlcF_wjzlvHUO96CDHkLKOz-9A
It contains Role as well.
Code for API Controller
[HttpGet(Name = "GetWeatherForecast")]
[Authorize(Roles ="Admin")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}

Actually I got the answer.
I changed new Claim("Role","Admin") to new Claim(ClaimTypes.Role, "Admin")

Related

HttpContext.User.Identity.IsAuthenticated is false after calling HttpContext.SignInAsync("schema-name", claimsPrincipal);

I am using multiple authentication schemes. Here is my Startup.cs code -
public void ConfigureServices(IServiceCollection services)
{
//code
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Default";
options.DefaultSignInScheme = "Default";
options.DefaultChallengeScheme = "O365OpenId";
})
.AddCookie("Default",options =>
{
options.LoginPath = "/";
options.LogoutPath = "/Logout";
options.Cookie.Name = "ip" + guid.ToString();
options.AccessDeniedPath = "/Auth/Denied";
})
.AddCookie("External", options =>
{
options.LoginPath = "/Auth/External";
options.LogoutPath = "/Logout";
options.Cookie.Name = "ip" + guid.ToString();
options.AccessDeniedPath = "/Auth/Denied";
})
.AddOAuth("O365OpenId", options =>
{
//options.Authority = "given";
options.ClientId = "given";
options.ClientSecret = "given";
options.CallbackPath = "/auth/callback";
options.AuthorizationEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
options.AuthorizationEndpoint += "?prompt=select_account";
options.TokenEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
options.UserInformationEndpoint = "https://graph.microsoft.com/oidc/userinfo";
options.AccessDeniedPath = "/Auth/Denied";
options.Scope.Add("openid");
options.Scope.Add("email");
//options.Scope.Add("profile");
//options.Scope.Add("offline_access");
//options.Scope.Add("user.read");
//options.Scope.Add("calendars.read");
options.SaveTokens = false;
//options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
//options.ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name");
//options.ClaimActions.MapJsonKey(ClaimTypes.Surname, "family_name");
//options.ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
options.ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
//options.ClaimActions.MapJsonKey(ClaimTypes., "picture");
options.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
if (context.AccessToken is { })
{
context.Identity?.AddClaim(new Claim("access_token", context.AccessToken));
}
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
response.EnsureSuccessStatusCode();
var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
context.RunClaimActions(json.RootElement);
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("Admin", policy =>
{
policy.AuthenticationSchemes.Add(CookieAuthenticationDefaults.AuthenticationScheme);
policy.RequireAuthenticatedUser();
policy.RequireRole("Admin");
});
options.AddPolicy("Regular&Admin", policy =>
{
policy.AuthenticationSchemes.Add(CookieAuthenticationDefaults.AuthenticationScheme);
policy.RequireAuthenticatedUser();
policy.RequireRole("Regular");
});
options.AddPolicy("External", policy =>
{
policy.AuthenticationSchemes.Add("External");
policy.RequireAuthenticatedUser();
policy.RequireRole("External");
});
});
}
When I sign in user using the "Default" scheme, I find that the HttpContext.User.Identity.IsAuthenticated is true after HttpContext.SignInAsync("schema-name", claimsPrincipal); method call. Here is the code for signing in -
public async Task<IActionResult> Success(string returnUrl)
{
// code
var claimIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var claimsPrincipal = new ClaimsPrincipal(claimIdentity);
await HttpContext.SignInAsync("Default",claimsPrincipal);
// more code
}
isAuthenticated is true
But When I sign in user using "External" scheme, HttpContext.User.Identity.IsAuthenticated is false after HttpContext.SignInAsync("schema-name", claimsPrincipal); call. Here is the code for signing in -
public async Task<IActionResult> External([FromQuery] string ReturnUrl, LoginOTP loginOTP, string email)
{
//code
var claimIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var claimsPrincipal = new ClaimsPrincipal(claimIdentity);
await HttpContext.SignInAsync("External", claimsPrincipal);
//code
}
IsAuthenticated is false.
I cannot understand what I am doing wrong. Why is the IsAuthenticated returning false?
Please help. Thank you.
you have 3 authentication schemes
the first one is cookie-based and you named it: "Default",
the second one is also cookie-based and you named it: "External",
the third one is OAhut-based and you named it: "O365OpenId",
when referring to one of these schemes you should use the names that you have created.
now the issue is, that you're creating a ClaimeIdentity with one scheme but you signing the user with a different scheme.
for the external method it should be like this:
var claimIdentity = new ClaimsIdentity(claims, "External");
var claimsPrincipal = new ClaimsPrincipal(claimIdentity);
// code ...
await HttpContext.SignInAsync("External", claimsPrincipal);
now the claims principal will be associated with the "External" scheme and the user will be authenticated.

How to add custom middleware in asp.net core with identity server 4 between authentication and authorization?

I need to add custom middleware between authentication and authorization that will add ClaimsIdentity to User that in context.
public class PermissionsMiddleware
{
private readonly RequestDelegate _next;
public PermissionsMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context, IAccountService accountService)
{
if (context.User.Identity == null || !context.User.Identity.IsAuthenticated)
{
await _next(context);
return;
}
var userSub = context.User.FindFirst(ClaimConstants.Subject)?.Value;
if (string.IsNullOrEmpty(userSub))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("User 'sub' claim is required");
return;
}
var permissionsIdentity = await accountService.GetUserPermissionsIdentity(userSub);
if (permissionsIdentity == null)
{
context.Response.StatusCode = 401;
return;
}
context.User.AddIdentity(permissionsIdentity);
await _next(context);
}
}
But context.User.Identity.IsAuthenticated is always false.
My ConfigureServicesmethod
string connectionString = Configuration["ConnectionStrings:DefaultConnection"];
string migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddCoreServices();
services.AddControllers();
services.AddDbContext<AppDbContext>(
options => options.UseMySql(
connectionString,
ServerVersion.AutoDetect(connectionString),
b => b.MigrationsAssembly(migrationsAssembly))
.UseSnakeCaseNamingConvention());
services.AddIdentity<ApplicationUser, ApplicationRole>().AddEntityFrameworkStores<AppDbContext>().AddDefaultTokenProviders();
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddScoped<IEmailSender, EmailSender>();
services.AddScoped<IUnitOfWork, HttpUnitOfWork>();
services.AddScoped<IAccountManager, AccountManager>();
services.AddTransient<IDatabaseInitializer, AppDbInitializer>();
services.AddScoped<IGrantValidationService, DelegationGrantValidationService>();
services.Configure<AppSettings>(Configuration);
services.Configure<IdentityOptions>(options =>
{
options.User.RequireUniqueEmail = false;
options.SignIn.RequireConfirmedEmail = false;
options.Password.RequireDigit = false;
options.Password.RequiredLength = 1;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
});
var applicationUrl = Configuration["ApplicationUrl"].TrimEnd('/');
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder => builder.UseMySql(
connectionString,
ServerVersion.AutoDetect(connectionString),
b => b.MigrationsAssembly(migrationsAssembly))
.UseSnakeCaseNamingConvention();
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder => builder.UseMySql(
connectionString,
ServerVersion.AutoDetect(connectionString),
b => b.MigrationsAssembly(migrationsAssembly))
.UseSnakeCaseNamingConvention();
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
})
.AddAspNetIdentity<ApplicationUser>()
.AddProfileService<ProfileService<ApplicationUser>>()
.AddDelegationGrant<ApplicationUser, string>();
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = applicationUrl;
options.SupportedTokens = SupportedTokens.Jwt;
options.RequireHttpsMetadata = false;
options.ApiName = IdentityServerConfig.ApiName;
});
//services.AddSingleton<IAuthorizationHandler, ViewUserAuthorizationHandler>();
//services.AddSingleton<IAuthorizationHandler, CreateUserAuthorizationHandler>();
//services.AddSingleton<IAuthorizationHandler, EditUserAuthorizationHandler>();
//services.AddSingleton<IAuthorizationHandler, DeleteUserAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, ViewRoleAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, AssignRolesAuthorizationHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy(Policies.ViewUsersPolicy, policy => policy.RequireClaim(ClaimConstants.Permission, ApplicationPermissions.ViewUsers));
options.AddPolicy(Policies.CreateUsersPolicy, policy => policy.RequireClaim(ClaimConstants.Permission, ApplicationPermissions.CreateUsers));
options.AddPolicy(Policies.EditUsersPolicy, policy => policy.RequireClaim(ClaimConstants.Permission, ApplicationPermissions.EditUsers));
options.AddPolicy(Policies.DeleteUsersPolicy, policy => policy.RequireClaim(ClaimConstants.Permission, ApplicationPermissions.DeleteUsers));
options.AddPolicy(Policies.ViewAllRolesPolicy, policy => policy.RequireClaim(ClaimConstants.Permission, ApplicationPermissions.ViewRoles));
options.AddPolicy(Policies.ViewRoleByRoleNamePolicy, policy => policy.Requirements.Add(new ViewRoleAuthorizationRequirement()));
options.AddPolicy(Policies.ManageAllRolesPolicy, policy => policy.RequireClaim(ClaimConstants.Permission, ApplicationPermissions.ManageRoles));
options.AddPolicy(Policies.AssignAllowedRolesPolicy, policy => policy.Requirements.Add(new AssignRolesAuthorizationRequirement()));
});
My Configure method
app.UseCors(x => x.SetIsOriginAllowed(origin => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
app.UseMiddleware<ErrorHandlerMiddleware>();
//app.UseSwagger();
//app.UseSwaggerUI();
app.UseRouting();
app.UseIdentityServer();
app.UseMiddleware<PermissionsMiddleware>();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
First off, make sure the Authority and ApiName are the same in the TOKEN as in your API. (I think this is case sensitive.) This is something you haven't provided so I cannot verify.
Also 1 line before this line:
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
add the following line:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
EDIT: Also remove this line in your startup:
app.UseIdentityServer();
This most likely overrides your own settings for identityserver.

Get access_token working calling API on same IS4 webapp

I'm trying to get the this access_token stuff working to do a call to a API which is declared with an Autohorize attrib from a BaseController. I think there is something wrong with my configuration.
Can anybody tell me what I'm doing wrong?
I have attached my Startup.cs for reference.
I'm trying to get a access token to send with the API called in the code below:
var httpClient = _httpClientFactory.CreateClient(BaseController.AUTHORIZATION_SERVICE_CLIENT_NAME);
httpClient.DefaultRequestHeaders.Clear();
httpClient.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
//AccessToken is always null
var accessToken = _httpContextAccessor.HttpContext.GetTokenAsync("access_token").Result;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var request = new HttpRequestMessage(HttpMethod.Get, "/api/auth/user/?id=" + id);
var response = httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result;
if (response.IsSuccessStatusCode)
return response.Content.ReadAsStringAsync().Result as string;
return "-";
My IS4 startup:
Confi
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddMvc().AddDataAnnotationsLocalization();
services.AddRazorPages()
.AddRazorPagesOptions(options =>
{
options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
});
//START IS4
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.UserInteraction.LoginUrl = "/Identity/Account/Login";
options.UserInteraction.LogoutUrl = "/Identity/Account/Logout";
options.Authentication = new AuthenticationOptions()
{
CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
CookieSlidingExpiration = true
};
})
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
options.EnableTokenCleanup = true;
})
.AddAspNetIdentity<User>();
if (env.IsDevelopment())
builder.AddDeveloperSigningCredential();
else
builder.AddSigningCredential(LoadCertificateFromStore());
//END IS4
//START IDENTITY
services.AddIdentity<User, Role>(options =>
{
options.SignIn.RequireConfirmedEmail = true;
})
.AddEntityFrameworkStores<IdentityContext>()
.AddUserStore<CustomUserStore>()
.AddRoleStore<CustomRoleStore>()
.AddDefaultTokenProviders()
.AddClaimsPrincipalFactory<CustomUserClaimsPrincipalFactory>();
services.ConfigureApplicationCookie(options => {
options.LoginPath = Startup.LoginPath;
options.LogoutPath = Startup.LogoutPath;
options.AccessDeniedPath = Startup.AccessDeniedPath;
});
services.AddAuthentication(o =>{})
.AddGoogle("Google", "Google", options =>
{
options.SignInScheme = IdentityConstants.ExternalScheme;
options.ClientId = configuration.GetValue<string>("Google:ClientId");
options.ClientSecret = configuration.GetValue<string>("Google:ClientSecret");
})
.AddOpenIdConnect("azuread", "Azure AD", options => configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>("azuread", options =>
{
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Events = new OpenIdConnectEvents()
{
OnRedirectToIdentityProviderForSignOut = context =>
{
context.HandleResponse();
context.Response.Redirect("/Identity/Account/Logout");
return Task.FromResult(0);
}
};
});
services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
//END IDENTITY
//Set named HttpClient settings for API to get roles of user
services.AddHttpContextAccessor();
services.AddTransient<BearerTokenHandler>();
services.AddHttpClient(BaseController.AUTHORIZATION_SERVICE_CLIENT_NAME, client =>
{
client.BaseAddress = new Uri("https://localhost:44318/");
}).AddHttpMessageHandler<BearerTokenHandler>();
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(ErrorPath);
}
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(name: "defaultArea",
pattern: "{area=Identity}/{controller=Account}/{action=Login}/{id?}");
endpoints.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
Bearer token handler, when I add 'AddHttpMessageHandler<BearerTokenHandler' to the client it gives null at the 'expiresAt' variable;
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var accessToken = await GetAccessTokenAsync();
if (!string.IsNullOrWhiteSpace(accessToken))
request.SetBearerToken(accessToken);
return await base.SendAsync(request, cancellationToken);
}
public async Task<string> GetAccessTokenAsync()
{
// get the expires_at value & parse it
var expiresAt = await _httpContextAccessor.HttpContext.GetTokenAsync("expires_at");
var expiresAtAsDateTimeOffset = DateTimeOffset.Parse(expiresAt, CultureInfo.InvariantCulture);
if ((expiresAtAsDateTimeOffset.AddSeconds(-60)).ToUniversalTime() > DateTime.UtcNow)
return await _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken); // no need to refresh, return the access token
var idpClient = _httpClientFactory.CreateClient("IDPClient");
// get the discovery document
var discoveryReponse = await idpClient.GetDiscoveryDocumentAsync();
// refresh the tokens
var refreshToken = await _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);
var refreshResponse = await idpClient.RequestRefreshTokenAsync(new RefreshTokenRequest {
Address = discoveryReponse.TokenEndpoint,
ClientId = "mvc",
ClientSecret = "secret",
RefreshToken = refreshToken
});
// store the tokens
var updatedTokens = new List<AuthenticationToken>();
updatedTokens.Add(new AuthenticationToken {
Name = OpenIdConnectParameterNames.IdToken,
Value = refreshResponse.IdentityToken
});
updatedTokens.Add(new AuthenticationToken {
Name = OpenIdConnectParameterNames.AccessToken,
Value = refreshResponse.AccessToken
});
updatedTokens.Add(new AuthenticationToken {
Name = OpenIdConnectParameterNames.RefreshToken,
Value = refreshResponse.RefreshToken
});
updatedTokens.Add(new AuthenticationToken {
Name = "expires_at",
Value = (DateTime.UtcNow + TimeSpan.FromSeconds(refreshResponse.ExpiresIn)).
ToString("o", CultureInfo.InvariantCulture)
});
// get authenticate result, containing the current principal & properties
var currentAuthenticateResult = await _httpContextAccessor.HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
// store the updated tokens
currentAuthenticateResult.Properties.StoreTokens(updatedTokens);
// sign in
await _httpContextAccessor.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, currentAuthenticateResult.Principal, currentAuthenticateResult.Properties);
return refreshResponse.AccessToken;
}
One idea could be to try to set the SaveTokens=true in your configuration.
See this article or ideas.

How to authorize user in multiple authentication scheme?

I have implemented multiple authentication scheme under my .net core application.
services.AddAuthentication(
sharedOptions =>
{
sharedOptions.DefaultScheme = Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddWsFederation("AuthenticationScheme1", options =>
{
options.Wtrealm = tenantList.Find(m => m.TenantID == 1).Wtrealm;
options.MetadataAddress = tenantList.Find(m => m.TenantID == 1).MetadataAddress;
})
.AddWsFederation("AuthenticationScheme2", options =>
{
options.Wtrealm = tenantList.Find(m => m.TenantID == 2).Wtrealm;
options.MetadataAddress = tenantList.Find(m => m.TenantID == 2).MetadataAddress;
});
I want to authorize specific users with specific scheme
You can choose the scheme want to authenticate based on user info from request body/header in a middleware :
app.Use(async (context, next) =>
{
//read userinfo from request body or header
if ("xxx".Equals("allen#xx.com"))
{
var result = await context.AuthenticateAsync("YourSchemeName");
if (!result.Succeeded)
{
context.Response.StatusCode = 401;
return;
}
}
....
await next();
});

OpenIdConnectEvents.OnTokenValidated not being reached

using asp.net core 2.2, I have the following in my startup below
i reach OnRedirectToIdentityProvider breakpoint , and then I reach relative path in appsettings "CallbackPath": " . But I don't i reach OnTokenValidated breakpoint . the Auth is triggered by [Authorize] decoration of a controller.
What am i missing ?
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options))
.AddCookie();
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/"; // Microsoft identity platform
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = async n =>
{
//save url to state
n.ProtocolMessage.State = n.HttpContext.Request.Path.Value.ToString();
},
OnTokenValidated = ctx =>
{
var url = ctx.ProtocolMessage.GetParameter("state");
var claims = new List<Claim>
{
new Claim("myurl", url)
};
var appIdentity = new ClaimsIdentity(claims);
//add url to claims
ctx.Principal.AddIdentity(appIdentity);
return Task.CompletedTask;
},
OnTicketReceived = ctx =>
{
var url = ctx.Principal.FindFirst("myurl").Value;
ctx.ReturnUri = url;
return Task.CompletedTask;
}
};
options.TokenValidationParameters.ValidateIssuer = false; // accept several tenants (here simplified)
});
You can change of ResponseMode to FormPost and add async to OnTokenValidated then it will be fixed.
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/"; // Microsoft identity platform
options.ResponseMode = OpenIdConnectResponseMode.FormPost;
options.CallbackPath = "/";
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = async n =>
{
...
},
OnTokenValidated = async ctx =>
{
...
},