public Task OnRedirectToIdentityProvider(RedirectContext context, TokenProviderConfiguration configuration) { _logger?.Message("Redirecting"); var defaultPolicy = _azureOptions.DefaultPolicy; if (context.Properties.Items.TryGetValue(AzureAdB2COptions.PolicyAuthenticationProperty, out var policy) && !policy.Equals(defaultPolicy)) { 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.PolicyAuthenticationProperty); } if (_upgradeHttp) { if (context.ProtocolMessage.RedirectUri.StartsWith("http://")) { context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri.Replace("http://", "https://"); } } if (IsMfaRequired(context, configuration)) { context.ProtocolMessage.SetParameter("mfa_required", "true"); } return(Task.CompletedTask); }
public static IAppBuilder UseVeracityAuthentication(this IAppBuilder app, TokenProviderConfiguration configuration, Func <IOwinContext, bool> isMfaRequiredOptions = null) { _conditionalMfaFunc = isMfaRequiredOptions; _redirectUrl = configuration.RedirectUrl; app.UseOpenIdConnectAuthentication( new OpenIdConnectAuthenticationOptions { // Generate the metadata address using the tenant and policy information MetadataAddress = Authority(configuration), // These are standard OpenID Connect parameters, with values pulled from web.config ClientId = ClientId(configuration), RedirectUri = configuration.RedirectUrl, PostLogoutRedirectUri = configuration.RedirectUrl, ClientSecret = configuration.ClientSecret, ResponseType = "code id_token", // Specify the callbacks for each type of notifications Notifications = new OpenIdConnectAuthenticationNotifications { RedirectToIdentityProvider = notification => OnRedirectToIdentityProvider(notification, configuration), AuthorizationCodeReceived = notification => OnAuthorizationCodeReceived(notification, configuration), AuthenticationFailed = notification => OnAuthenticationFailed(notification, configuration), }, TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name" }, // Specify the scope by appending all of the scopes requested into one string (seperated by a blank space) Scope = $"{OpenIdConnectScopes.OpenId} offline_access {configuration.Scope}" } ); return(app); }
private static async Task <ValidationResult> ValidatePolicies(TokenProviderConfiguration configuration, IPolicyValidation policyValidator, string protocolMessageRedirectUri) { var policy = configuration.ServiceId != null ? await policyValidator.ValidatePolicyWithServiceSpesificTerms(configuration.ServiceId, protocolMessageRedirectUri) : await policyValidator.ValidatePolicy(protocolMessageRedirectUri); return(policy); }
public static IServiceCollection AddVeracity(this IServiceCollection services, IConfiguration configuration, string key, out TokenProviderConfiguration tokenProviderConfiguration) { ConfigurationManagerHelper.SetManager(new NullConfig()); var t = new TokenProviderConfiguration(); configuration.Bind(key, t); tokenProviderConfiguration = t; return(services); }
public static IConfidentialClientApplication ConfidentialClientApplication(this TokenProviderConfiguration configuration, TokenCacheBase cache, Action <string> _debugLogger) { var context = ConfidentialClientApplicationBuilder.Create(ClientId(configuration)) .WithClientSecret(configuration.ClientSecret).WithB2CAuthority(Authority(configuration))//.WithAuthority(Authority(configuration),false)//.WithB2CAuthority(Authority(configuration)) .WithRedirectUri(configuration.RedirectUrl) .WithLogging((level, message, pii) => { _debugLogger?.Invoke(message); }) .Build(); cache.SetCacheInstance(context.UserTokenCache); return(context); }
internal void Configure(string name, OpenIdConnectOptions options, TokenProviderConfiguration configuration) { options.ClientId = _azureOptions.ClientId; options.Authority = $"{_azureOptions.Instance}/{_azureOptions.Domain}/{_azureOptions.SignUpSignInPolicyId}/v2.0"; options.UseTokenLifetime = true; options.CallbackPath = _azureOptions.CallbackPath; options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name" }; var handler = options.Events.OnAuthorizationCodeReceived; options.Events = new OpenIdConnectEvents { OnRedirectToIdentityProvider = context => OnRedirectToIdentityProvider(context, configuration), OnRemoteFailure = OnRemoteFailure, OnAuthorizationCodeReceived = context => OnAuthorizationCodeReceived(context, configuration, handler) }; }
private static Task OnRedirectToIdentityProvider( RedirectToIdentityProviderNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification, TokenProviderConfiguration configuration) { var policy = notification.OwinContext.Get <string>("Policy"); if (!string.IsNullOrEmpty(policy) && !policy.Equals(DefaultPolicy(configuration))) { notification.ProtocolMessage.Scope = OpenIdConnectScopes.OpenId; notification.ProtocolMessage.ResponseType = OpenIdConnectResponseTypes.IdToken; notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.ToLower().Replace(DefaultPolicy(configuration).ToLower(), policy.ToLower()); } if (IsMfaRequired(notification, configuration)) { notification.ProtocolMessage.SetParameter("mfa_required", "true"); } return(Task.FromResult(0)); }
public static object AppUrl(TokenProviderConfiguration configuration) => configuration.RedirectUrl.EndsWith("/") ? configuration.RedirectUrl.Remove(configuration.RedirectUrl.Length - 1, 1) : configuration.RedirectUrl;
public static object TenantId(TokenProviderConfiguration configuration) => configuration.TenantId;
public static string DefaultPolicy(TokenProviderConfiguration configuration) => configuration.Policy;
private static bool IsMfaRequired(AuthorizationCodeReceivedNotification context, TokenProviderConfiguration configuration) { return(configuration.RequireMfa || (_conditionalMfaFunc?.Invoke(context.OwinContext) ?? false)); }
public static string Authority(TokenProviderConfiguration configuration) => $"{configuration.Instance}{(configuration.Instance.EndsWith("/")?"":"/")}tfp/{TenantId(configuration)}/{configuration.Policy}/v2.0/.well-known/openid-configuration";
private static async Task ExchangeAuthCodeWithToken(AuthorizationCodeReceivedNotification notification, TokenProviderConfiguration configuration) { HttpContext.Current.User = new ClaimsPrincipal(notification.AuthenticationTicket.Identity); var c = HttpContext.Current; var cache = CacheFactoryFunc().Invoke(); var context = configuration.ConfidentialClientApplication(cache, _debugLogger); var user = await context.AcquireTokenByAuthorizationCode(new[] { configuration.Scope }, notification.Code) .ExecuteAsync(); HttpContext.Current = c; }
private TokenProvider(TokenProviderConfiguration configuration) { _configuration = configuration; }
private TokenProvider(IServiceProvider appApplicationServices, TokenProviderConfiguration configuration) { _configuration = configuration; }
public static string Authority(TokenProviderConfiguration configuration) => $"https://login.microsoftonline.com/tfp/{configuration.TenantId}/{configuration.Policy}/v2.0/.well-known/openid-configuration";
private static bool IsMfaRequired(AuthorizationCodeReceivedContext context, TokenProviderConfiguration configuration) { return(configuration.RequireMfa || (_conditionalMfaFunc?.Invoke(context.HttpContext, context.Properties) ?? false)); }
public TokenProvider(TokenProviderConfiguration tokenProviderConfiguration) { this.tokenProviderConfiguration = tokenProviderConfiguration; }
/* * Catch any failures received by the authentication middleware and handle appropriately */ private static Task OnAuthenticationFailed( AuthenticationFailedNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification, TokenProviderConfiguration configuration) { _errorLogger?.Invoke(notification.Exception, "external error"); notification.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 (notification.ProtocolMessage.ErrorDescription != null && notification.ProtocolMessage.ErrorDescription.Contains("AADB2C90118")) { // If the user clicked the reset password link, redirect to the reset password route notification.Response.Redirect("/Account/ResetPassword"); } else if (notification.Exception.Message == "access_denied") { notification.Response.Redirect("/"); } else { notification.Response.Redirect(string.Format(configuration.ErrorPage ?? "/error?message={0}", notification.Exception?.Message)); } return(Task.FromResult(0)); }
internal void Configure(OpenIdConnectOptions options, TokenProviderConfiguration configuration) { _logger?.Message("Configuring"); Configure(Options.DefaultName, options, configuration); }
/* * Callback function when an authorization code is received */ private static async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification, TokenProviderConfiguration configuration) { var ct = HttpContext.Current; try { if (IsMfaRequired(notification, configuration) && !notification.AuthenticationTicket.Identity.Claims.Any(c => c.Type == "mfa_required" && c.Value == "true")) { throw new UnauthorizedAccessException("MFA required"); } await ExchangeAuthCodeWithToken(notification, configuration); try { await ValidatePolicies(notification); notification.OwinContext.Authentication.SignIn(notification.AuthenticationTicket.Identity); notification.Response.Redirect(notification.RedirectUri); notification.HandleResponse(); HttpContext.Current = ct; } catch (AggregateException aex) { _exceptionLogger?.Invoke(aex); if (aex.InnerException != null) { _exceptionLogger?.Invoke(aex.InnerException); } HttpContext.Current = ct; if (aex.InnerException is ServerException serverException) { HandlePolicyViolation(notification, serverException); } } catch (ServerException ex) { _exceptionLogger?.Invoke(ex); HttpContext.Current = ct; HandlePolicyViolation(notification, ex); } } catch (Exception ex) { HttpContext.Current = ct; _exceptionLogger?.Invoke(ex); throw; } }
public static string Authority(TokenProviderConfiguration configuration) => $"{ConfigurationManagerHelper.GetValueOnKey("Instance", "https://login.veracity.com/")}{TenantId(configuration)}/{configuration.Policy}/v2.0/.well-known/openid-configuration";
private static bool IsMfaRequired(RedirectToIdentityProviderNotification <OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context, TokenProviderConfiguration configuration) { return(configuration.RequireMfa || (_conditionalMfaFunc?.Invoke(context.OwinContext) ?? false)); }
public static string ClientId(TokenProviderConfiguration configuration) => configuration.ClientId;
private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext arg, TokenProviderConfiguration configuration, Func <AuthorizationCodeReceivedContext, Task> handler) { _logger?.Message("Auth code received..."); var timer = Stopwatch.StartNew(); try { arg.HttpContext.User = arg.Principal; if (IsMfaRequired(arg, configuration) && !arg.Principal.Claims.Any(c => c.Type == "mfa_required" && c.Value == "true")) { throw new UnauthorizedAccessException("MFA required"); } var cache = arg.HttpContext.RequestServices.GetService <TokenCacheBase>(); var context = configuration.ConfidentialClientApplication(cache, s => { _logger?.Message(s); }); var user = await context.AcquireTokenByAuthorizationCode(new[] { configuration.Scope }, arg.ProtocolMessage.Code).ExecuteAsync(); _logger?.Message($"exchanging code with access token took: {timer.ElapsedMilliseconds}ms"); var policyValidator = arg.HttpContext.RequestServices.GetService <IPolicyValidation>(); try { if (policyValidator != null) { var timer2 = Stopwatch.StartNew(); var policy = await ValidatePolicies(configuration, policyValidator, arg.ProtocolMessage.RedirectUri ?? configuration.PolicyRedirectUrl ?? configuration.RedirectUrl); timer2.Stop(); _logger?.Message($"Policy check took {timer2.ElapsedMilliseconds}ms. "); if (policy.AllPoliciesValid) { _logger?.Message("Policies validated!"); AdditionalAuthCodeHandling?.Invoke(arg); } else { _logger?.Message("Not all policies is valid, redirecting to Veracity"); arg.Response.Redirect(policy.RedirectUrl); //Getting the redirect url from the error message. arg.HandleResponse(); } } else { AdditionalAuthCodeHandling?.Invoke(arg); } } catch (AggregateException aex) { var e = aex.InnerException as ServerException; if (e != null) { HandleServerException(arg, e); } } catch (ServerException ex) { HandleServerException(arg, ex); } } catch (Exception ex) { ex.Log(); } timer.Stop(); _logger?.Message($"Total on code received took {timer.ElapsedMilliseconds}ms. "); await handler(arg); }
public static AuthenticationBuilder AddAzureAdB2C(this AuthenticationBuilder builder, Action <AzureAdB2COptions> configureOptions, TokenProviderConfiguration configuration) { _builder = builder; builder.Services.Configure(configureOptions); builder.Services.AddSingleton <IConfigureOptions <OpenIdConnectOptions>, ConfigureAzureOptions>() .AddScoped <ITokenHandler, TokenProvider>() .AddSingleton <TokenProviderConfiguration, TokenProviderConfiguration>() .AddHttpContextAccessor() .AddSingleton <ILogger, LogWrapper>() .AddSingleton <ILogging, LogWrapper>() .AddScoped(s => s.GetService <IHttpContextAccessor>().HttpContext.User) .AddScoped <TokenCacheBase>(s => new DistributedTokenCache(s.GetService <IHttpContextAccessor>().HttpContext.User, s.GetService <IDistributedCache>(), s.GetService <ILogger>(), s.GetService <IDataProtector>())); builder.AddOpenIdConnect(opts => { _upgradeHttp = configuration.UpgradeHttp; opts.Scope.Add(configuration.Scope); opts.Scope.Add("openid"); opts.Scope.Add("offline_access"); opts.ClientSecret = configuration.ClientSecret; opts.AuthenticationMethod = OpenIdConnectRedirectBehavior.FormPost; opts.ResponseType = "code id_token"; }); return(builder); }