/// <summary> /// Is called whenever B2C retrieves a new auth token. /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context) { // Use MSAL to swap the code for an access token // Extract the authorization code from the response notification var code = context.ProtocolMessage.Code; var signedInUserId = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value; var userTokenCache = new MsalSessionCache(signedInUserId, context.HttpContext).GetMsalCacheInstance(); var clientApplication = new ConfidentialClientApplication( AzureAdB2COptions.ClientId, AzureAdB2COptions.Authority, AzureAdB2COptions.RedirectUri, new ClientCredential(AzureAdB2COptions.ClientSecret), userTokenCache, null); // try to retrieve the baerer token try { var result = await clientApplication.AcquireTokenByAuthorizationCodeAsync(code, AzureAdB2COptions.ApiScopes.Split(' ')); context.HandleCodeRedemption(result.AccessToken, result.IdToken); } catch (Exception ex) { Trace.TraceError(ex.Message); throw; } }
public AzureAdB2CSecuredApiConnector(IOptions <AzureAdB2COptions> options, IHttpContextAccessor httpContextAccessor) { _azureAdB2COptions = options.Value; ValidateOptions(options); _requiredScopes = _azureAdB2COptions.ApiScopes.Split(' ').ToList(); var signedInUserId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value; var userTokenCache = new MsalSessionCache(signedInUserId, httpContextAccessor.HttpContext).GetMsalCacheInstance(); _confidentialClientApplication = new ConfidentialClientApplication(_azureAdB2COptions.ClientId, _azureAdB2COptions.Authority, _azureAdB2COptions.RedirectUri, new ClientCredential(_azureAdB2COptions.ClientSecret), userTokenCache, null); }
public async Task <IActionResult> Api() { var responseString = ""; try { // Retrieve the token with the specified scopes var scope = _azureAdB2COptions.ApiScopes.Split(' '); var signedInUserId = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value; var userTokenCache = new MsalSessionCache(signedInUserId, HttpContext).GetMsalCacheInstance(); var clientApplication = new ConfidentialClientApplication( _azureAdB2COptions.ClientId, _azureAdB2COptions.Authority, _azureAdB2COptions.RedirectUri, new ClientCredential(_azureAdB2COptions.ClientSecret), userTokenCache, null); var result = await clientApplication.AcquireTokenSilentAsync(scope, clientApplication.Users.FirstOrDefault(), _azureAdB2COptions.Authority, false); using (var client = new HttpClient()) { var request = new HttpRequestMessage(HttpMethod.Get, _azureAdB2COptions.ApiUrl); // Add token to the Authorization header and make the request request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken); var response = await client.SendAsync(request); // Handle the response switch (response.StatusCode) { case HttpStatusCode.OK: responseString = await response.Content.ReadAsStringAsync(); break; case HttpStatusCode.Unauthorized: responseString = $"Please sign in again. {response.ReasonPhrase}"; break; default: responseString = $"Error calling API. StatusCode=${response.StatusCode}"; break; } } } catch (MsalUiRequiredException ex) { responseString = $"Session has expired. Please sign in again. {ex.Message}"; } catch (Exception ex) { responseString = $"Error calling API: {ex.Message}"; } ViewData["Payload"] = $"{responseString}"; return(View()); }
private async Task <AuthenticationResult> AcquireTokenSilentAsync(AzureAdB2COptions azureAdB2COptions) { // Retrieve the token with the specified scopes var scope = azureAdB2COptions.ApiScopes.Split(' '); var signedInUserId = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value; var userTokenCache = new MsalSessionCache(signedInUserId, HttpContext).GetMsalCacheInstance(); var cca = new ConfidentialClientApplication( azureAdB2COptions.ApplicationId, azureAdB2COptions.Authority, azureAdB2COptions.RedirectUri, new ClientCredential(azureAdB2COptions.ClientSecret), userTokenCache, null); var result = await cca.AcquireTokenSilentAsync(scope, cca.Users.FirstOrDefault(), azureAdB2COptions.Authority, false); return(result); }
public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context, string clientId, string authority, string clientSecret, string redirectUri, string apiScopes) { // Use MSAL to swap the code for an access token // Extract the code from the response notification var code = context.ProtocolMessage.Code; var signedInUserId = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value; var userTokenCache = new MsalSessionCache(signedInUserId, context.HttpContext).GetMsalCacheInstance(); var cca = new ConfidentialClientApplication(clientId, authority, redirectUri, new ClientCredential(clientSecret), userTokenCache, null); try { var result = await cca.AcquireTokenByAuthorizationCodeAsync(code, apiScopes.Split(' ')); context.HandleCodeRedemption(result.AccessToken, result.IdToken); } catch (Exception ex) { //TODO: Handle throw; } }
public static AuthenticationBuilder AddAzureB2CCookieAuthentication(this IServiceCollection services, AzureAdB2COptions azureAdB2CSettings, string resetPasswordUrl, bool requestAccessToken, bool loadMemberGroupsAsRoles = false) { services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(20); // no javascript calls to cookie options.Cookie.HttpOnly = true; }); return(services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie() .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => { options.ClientId = azureAdB2CSettings.ClientId; // Set the authority to your Azure domain options.Authority = azureAdB2CSettings.Authority; options.UseTokenLifetime = true; options.TokenValidationParameters = new TokenValidationParameters() { NameClaimType = "name" }; options.Events = new OpenIdConnectEvents { OnRedirectToIdentityProvider = (context) => { // pass language (adds ui_locales to query string) var requestCulture = context.HttpContext.Features.Get <IRequestCultureFeature>(); var lang = requestCulture?.RequestCulture.Culture.TextInfo.ToTitleCase( requestCulture.RequestCulture.Culture.TwoLetterISOLanguageName); if (lang != null) { context.ProtocolMessage.UiLocales = lang; } // no explict policy or default policy passed - just continue var defaultPolicy = azureAdB2CSettings.DefaultPolicy; if (!context.Properties.Items.TryGetValue(AzureAdB2COptions.POLICY_AUTHENTICATION_PROPERTY, out var policy) || policy.Equals(defaultPolicy)) { if (requestAccessToken) { context.ProtocolMessage.Scope += $" offline_access {String.Join(" ", azureAdB2CSettings.Scopes)}"; context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.CodeIdToken; } } else { // explict policy set in context => see AuthenticationProperties.Items.Add("Policy", desired policy_name) // example --> custom policy has been set to reset password context.ProtocolMessage.Scope = OpenIdConnectScope.OpenIdProfile; context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.IdToken; context.ProtocolMessage.IssuerAddress = context.ProtocolMessage.IssuerAddress.ToLower().Replace($"/{defaultPolicy.ToLower()}/", $"/{policy.ToLower()}/"); context.Properties.Items.Remove(AzureAdB2COptions.POLICY_AUTHENTICATION_PROPERTY); } return Task.CompletedTask; }, OnRemoteFailure = (context) => { context.HandleResponse(); // Handle the error code that Azure AD B2C throws when trying to reset a password from the login page // because password reset is not supported by a "sign-up or sign-in policy" if (context.Failure is OpenIdConnectProtocolException && context.Failure.Message.Contains("AADB2C90118")) { // If the user clicked the reset password link, redirect to the reset password route context.Response.Redirect(resetPasswordUrl); } else if (context.Failure is OpenIdConnectProtocolException && context.Failure.Message.Contains("access_denied")) { context.Response.Redirect("/"); } else { throw context.Failure; } return Task.FromResult(0); }, OnAuthorizationCodeReceived = async(context) => { // Use MSAL to swap the code for an access token // Extract the code from the response notification var auhtorizationCode = context.ProtocolMessage.Code; string signedInUserId = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value; var userTokenCache = new MsalSessionCache(signedInUserId, context.HttpContext).GetMsalCacheInstance(); var clientApplication = new ConfidentialClientApplication(azureAdB2CSettings.ClientId, azureAdB2CSettings.Authority, azureAdB2CSettings.RedirectUri, new ClientCredential(azureAdB2CSettings.ClientSecret), userTokenCache, null); try { if (requestAccessToken) { var result = await clientApplication.AcquireTokenByAuthorizationCodeAsync(auhtorizationCode, azureAdB2CSettings.Scopes); context.HandleCodeRedemption(result.AccessToken, result.IdToken); } } catch (Exception e) { throw new Exception("AcquireTokenByAuthorizationCodeAsync failed", e); } }, // handle the logout redirection OnRedirectToIdentityProviderForSignOut = (context) => { var logoutUri = $"{azureAdB2CSettings.Domain}/v2/logout?client_id={azureAdB2CSettings.ClientId}"; var postLogoutUri = context.Properties.RedirectUri; if (!string.IsNullOrEmpty(postLogoutUri)) { if (postLogoutUri.StartsWith("/")) { // transform to absolute var request = context.Request; postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri; } logoutUri += $"&post_logout_redirect_uri={Uri.EscapeDataString(postLogoutUri)}"; } // set the audience parameter to get also an access token back after login to be able to call APIs of this application context.ProtocolMessage.SetParameter("audience", azureAdB2CSettings.ClientId); context.Response.Redirect(logoutUri); context.HandleResponse(); return Task.CompletedTask; } }; if (loadMemberGroupsAsRoles) { //Check via Azure Graph API if user is in correct group options.Events.OnTokenValidated = context => { var serviceProvider = services.BuildServiceProvider(); // resolve GraphApiConnector var graphApiConnector = serviceProvider.GetService <IGraphApiConnector>(); if (graphApiConnector == null) { throw new Exception("No implementation has been registered for IGraphApiConnector"); } // Get membergroups for user from AzureAd var signedInUserId = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value; var memberGroups = graphApiConnector.GetMemberGroupsForUser(signedInUserId).GetAwaiter() .GetResult(); // create roleclaim var roleClaims = memberGroups.Select(x => new Claim(ClaimTypes.Role, x)); // Add RoleClaim to useridentity ((ClaimsIdentity)context.Principal.Identity).AddClaims(roleClaims); return Task.FromResult(0); }; } }));