public async Task VerifyAccountControllerExternalLoginWithTokensFlow() { // Setup the external cookie like it would look from a real OAuth2 var externalId = "<externalId>"; var authScheme = "<authScheme>"; var externalIdentity = new ClaimsIdentity(); externalIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, externalId)); var externalPrincipal = new ClaimsPrincipal(externalIdentity); var externalLogin = new ExternalLoginInfo(externalPrincipal, authScheme, externalId, "displayname") { AuthenticationTokens = new[] { new AuthenticationToken { Name = "refresh_token", Value = "refresh" }, new AuthenticationToken { Name = "access_token", Value = "access" } } }; var context = new DefaultHttpContext(); var auth = MockAuth(context); auth.Setup(a => a.AuthenticateAsync(context, It.IsAny <string>())).Returns(Task.FromResult(AuthenticateResult.NoResult())); var contextAccessor = new Mock <IHttpContextAccessor>(); contextAccessor.Setup(a => a.HttpContext).Returns(context); var services = new ServiceCollection() .AddSingleton <IConfiguration>(new ConfigurationBuilder().Build()) .AddLogging() .AddSingleton(contextAccessor.Object); services.AddIdentity <TestUser, TestRole>(); services.AddSingleton <IUserStore <TestUser>, InMemoryStore <TestUser, TestRole> >(); services.AddSingleton <IRoleStore <TestRole>, InMemoryStore <TestUser, TestRole> >(); var app = new ApplicationBuilder(services.BuildServiceProvider()); // Act var user = new TestUser { UserName = "******" }; var userManager = app.ApplicationServices.GetRequiredService <IUserManager <TestUser> >(); var signInManager = app.ApplicationServices.GetRequiredService <SignInManager <TestUser> >(); IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); IdentityResultAssert.IsSuccess(await userManager.AddLoginAsync(user, new UserLoginInfo(authScheme, externalId, "whatever"))); IdentityResultAssert.IsSuccess(await signInManager.UpdateExternalAuthenticationTokensAsync(externalLogin)); Assert.Equal("refresh", await userManager.GetAuthenticationTokenAsync(user, authScheme, "refresh_token")); Assert.Equal("access", await userManager.GetAuthenticationTokenAsync(user, authScheme, "access_token")); }
/// <summary> /// Tries to validate a token on the current request /// </summary> /// <returns></returns> protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { _logger.LogTrace("HandleAuthenticateAsync called"); var jwtScheme = Scheme.Name + IdentityServerReferenceTokenAuthenticationDefaults.JwtAuthenticationScheme; var introspectionScheme = Scheme.Name + IdentityServerReferenceTokenAuthenticationDefaults.IntrospectionAuthenticationScheme; var token = Options.TokenRetriever(Context.Request); bool removeToken = false; try { if (token != null) { _logger.LogTrace("Token found: {token}", token); removeToken = true; Context.Items.Add(IdentityServerReferenceTokenAuthenticationDefaults.TokenItemsKey, token); // seems to be a JWT if (token.Contains('.') && Options.SupportsJwt) { _logger.LogTrace("Token is a JWT and is supported."); Context.Items.Add(IdentityServerReferenceTokenAuthenticationDefaults.EffectiveSchemeKey + Scheme.Name, jwtScheme); return(await Context.AuthenticateAsync(jwtScheme)); } else if (Options.SupportsIntrospection) { _logger.LogTrace("Token is a reference token and is supported."); Context.Items.Add(IdentityServerReferenceTokenAuthenticationDefaults.EffectiveSchemeKey + Scheme.Name, introspectionScheme); var authenticationResult = await Context.AuthenticateAsync(introspectionScheme); if (authenticationResult.Succeeded) { await _userHandler.Handle(authenticationResult.Principal); } return(authenticationResult); } else { _logger.LogTrace( "Neither JWT nor reference tokens seem to be correctly configured for incoming token."); } } // set the default challenge handler to JwtBearer if supported if (Options.SupportsJwt) { Context.Items.Add(IdentityServerReferenceTokenAuthenticationDefaults.EffectiveSchemeKey + Scheme.Name, jwtScheme); } return(AuthenticateResult.NoResult()); } catch (Exception ex) { _logger.LogError(ex, ex.Message); return(AuthenticateResult.Fail(ex)); } finally { if (removeToken) { Context.Items.Remove(IdentityServerReferenceTokenAuthenticationDefaults.TokenItemsKey); } } }
/// <summary> /// Searches the 'Authorization' header for a 'Bearer' token. If the 'Bearer' token is found, it is validated using <see cref="TokenValidationParameters"/> set in the options. /// </summary> /// <returns></returns> protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { string token = null; try { // Give application opportunity to find from a different location, adjust, or reject token var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options); // event can set the token await Events.MessageReceived(messageReceivedContext); if (messageReceivedContext.Result != null) { return(messageReceivedContext.Result); } // If application retrieved token from somewhere else, use that. token = messageReceivedContext.Token; if (string.IsNullOrEmpty(token)) { string authorization = Request.Headers[HeaderNames.Authorization]; // If no authorization header found, nothing to process further if (string.IsNullOrEmpty(authorization)) { return(AuthenticateResult.NoResult()); } if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { token = authorization.Substring("Bearer ".Length).Trim(); } // If no token found, no further work possible if (string.IsNullOrEmpty(token)) { return(AuthenticateResult.NoResult()); } } var currentConfiguration = await this.dynamicJwtBearerHanderConfigurationResolver.ResolveCurrentOpenIdConfiguration(Context); var validationParameters = Options.TokenValidationParameters.Clone(); if (currentConfiguration != null) { var issuers = new[] { currentConfiguration.Issuer }; validationParameters.ValidIssuers = validationParameters.ValidIssuers?.Concat(issuers) ?? issuers; validationParameters.IssuerSigningKeys = validationParameters.IssuerSigningKeys?.Concat(currentConfiguration.SigningKeys) ?? currentConfiguration.SigningKeys; } List <Exception> validationFailures = null; SecurityToken validatedToken; foreach (var validator in Options.SecurityTokenValidators) { if (validator.CanReadToken(token)) { ClaimsPrincipal principal; try { principal = validator.ValidateToken(token, validationParameters, out validatedToken); } catch (Exception ex) { Logger.TokenValidationFailed(ex); // Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the event. if (Options.RefreshOnIssuerKeyNotFound && Options.ConfigurationManager != null && ex is SecurityTokenSignatureKeyNotFoundException) { Options.ConfigurationManager.RequestRefresh(); } if (validationFailures == null) { validationFailures = new List <Exception>(1); } validationFailures.Add(ex); continue; } Logger.TokenValidationSucceeded(); var tokenValidatedContext = new TokenValidatedContext(Context, Scheme, Options) { Principal = principal, SecurityToken = validatedToken }; await Events.TokenValidated(tokenValidatedContext); if (tokenValidatedContext.Result != null) { return(tokenValidatedContext.Result); } if (Options.SaveToken) { tokenValidatedContext.Properties.StoreTokens(new[] { new AuthenticationToken { Name = "access_token", Value = token } }); } tokenValidatedContext.Success(); return(tokenValidatedContext.Result); } } if (validationFailures != null) { var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options) { Exception = (validationFailures.Count == 1) ? validationFailures[0] : new AggregateException(validationFailures) }; await Events.AuthenticationFailed(authenticationFailedContext); if (authenticationFailedContext.Result != null) { return(authenticationFailedContext.Result); } return(AuthenticateResult.Fail(authenticationFailedContext.Exception)); } return(AuthenticateResult.Fail("No SecurityTokenValidator available for token: " + token ?? "[null]")); } catch (Exception ex) { Logger.ErrorProcessingMessage(ex); var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options) { Exception = ex }; await Events.AuthenticationFailed(authenticationFailedContext); if (authenticationFailedContext.Result != null) { return(authenticationFailedContext.Result); } throw; } }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { if (!HasHMACAuthorizationHeader(Request)) { return(AuthenticateResult.NoResult()); }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { string authorizationHeader = Request.Headers["Authorization"]; if (string.IsNullOrEmpty(authorizationHeader)) { return(AuthenticateResult.NoResult()); } if (!authorizationHeader.StartsWith(_Scheme + ' ', StringComparison.OrdinalIgnoreCase)) { return(AuthenticateResult.NoResult()); } string encodedCredentials = authorizationHeader.Substring(_Scheme.Length).Trim(); if (string.IsNullOrEmpty(encodedCredentials)) { const string noCredentialsMessage = "No credentials"; Logger.LogInformation(noCredentialsMessage); return(AuthenticateResult.Fail(noCredentialsMessage)); } try { string decodedCredentials = string.Empty; try { decodedCredentials = Encoding.UTF8.GetString(Convert.FromBase64String(encodedCredentials)); } catch (Exception ex) { throw new Exception($"Failed to decode credentials : {encodedCredentials}", ex); } var delimiterIndex = decodedCredentials.IndexOf(':'); if (delimiterIndex == -1) { const string missingDelimiterMessage = "Invalid credentials, missing delimiter."; Logger.LogInformation(missingDelimiterMessage); return(AuthenticateResult.Fail(missingDelimiterMessage)); } var username = decodedCredentials.Substring(0, delimiterIndex); var password = decodedCredentials.Substring(delimiterIndex + 1); var validateCredentialsContext = new ValidateCredentialsContext(Context, Scheme, Options) { Username = username, Password = password }; await Options.Events.ValidateCredentials(validateCredentialsContext); if (validateCredentialsContext.Result != null) { var ticket = new AuthenticationTicket(validateCredentialsContext.Principal, Scheme.Name); return(AuthenticateResult.Success(ticket)); } return(AuthenticateResult.NoResult()); } catch (Exception ex) { var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options) { Exception = ex }; await Options.Events.AuthenticationFailed(authenticationFailedContext); if (authenticationFailedContext.Result.Succeeded) { return(AuthenticateResult.Success(authenticationFailedContext.Result.Ticket)); } if (authenticationFailedContext.Result.None) { return(AuthenticateResult.NoResult()); } throw; } }
public async Task <AuthenticationResult> GetAuthenticationResultAsync(AuthenticationHeaderValue authHeader) { ApiClientDetails apiClientDetails; try { // If there are credentials but the filter does not recognize the authentication scheme, do nothing. if (!authHeader.Scheme.EqualsIgnoreCase(AuthenticationScheme)) { _logger.Debug("Unknown auth header scheme"); return(new AuthenticationResult { AuthenticateResult = AuthenticateResult.NoResult() }); } // If the credentials are bad, set the error result. if (string.IsNullOrEmpty(authHeader.Parameter)) { _logger.Debug("Missing auth header parameter"); return(new AuthenticationResult { AuthenticateResult = AuthenticateResult.Fail("Missing auth header parameter") }); } // If there are credentials that the filter understands, try to validate them. apiClientDetails = await _oAuthTokenValidator.GetClientDetailsForTokenAsync(authHeader.Parameter); } catch (Exception e) { _logger.Error(e); return(new AuthenticationResult { AuthenticateResult = AuthenticateResult.Fail("Invalid Authorization Header") }); } if (_expectedUseSandboxValue.Value.HasValue && apiClientDetails.IsSandboxClient != _expectedUseSandboxValue.Value.Value) { string message = apiClientDetails.IsSandboxClient ? "Sandbox credentials used in call to Production API" : "Production credentials used in call to Sandbox API"; return(new AuthenticationResult { AuthenticateResult = AuthenticateResult.Fail(message) }); } var identity = _claimsIdentityProvider.GetClaimsIdentity( apiClientDetails.EducationOrganizationIds, apiClientDetails.ClaimSetName, apiClientDetails.NamespacePrefixes, apiClientDetails.Profiles.ToList()); var apiKeyContext = new ApiKeyContext( apiClientDetails.ApiKey, apiClientDetails.ClaimSetName, apiClientDetails.EducationOrganizationIds, apiClientDetails.NamespacePrefixes, apiClientDetails.Profiles, apiClientDetails.StudentIdentificationSystemDescriptor, apiClientDetails.CreatorOwnershipTokenId, apiClientDetails.OwnershipTokenIds); return(new AuthenticationResult { ClaimsIdentity = identity, ApiKeyContext = apiKeyContext }); }
/// <summary> /// Process Authentication Request /// </summary> /// <returns></returns> protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { // get siteminder headers _logger.LogDebug("Parsing the HTTP headers for SiteMinder authentication credential"); SiteMinderAuthOptions options = new SiteMinderAuthOptions(); bool isDeveloperLogin = false; bool isBCSCDeveloperLogin = false; try { ClaimsPrincipal principal; HttpContext context = Request.HttpContext; IDynamicsClient _dynamicsClient = (IDynamicsClient)context.RequestServices.GetService(typeof(IDynamicsClient)); IHostingEnvironment hostingEnv = (IHostingEnvironment)context.RequestServices.GetService(typeof(IHostingEnvironment)); UserSettings userSettings = new UserSettings(); string userId = null; string devCompanyId = null; string siteMinderGuid = ""; string siteMinderBusinessGuid = ""; string siteMinderUserType = ""; // ************************************************** // If this is an Error or Authentiation API - Ignore // ************************************************** string url = context.Request.GetDisplayUrl().ToLower(); if (url.Contains(".js")) { return(AuthenticateResult.NoResult()); } // ************************************************** // Check if we have a Dev Environment Cookie // ************************************************** //if (!hostingEnv.IsProduction()) //{ // check for a fake BCeID login in dev mode string temp = context.Request.Cookies[options.DevAuthenticationTokenKey]; if (string.IsNullOrEmpty(temp)) // could be an automated test user. { temp = context.Request.Headers["DEV-USER"]; } if (!string.IsNullOrEmpty(temp)) { if (temp.Contains("::")) { var temp2 = temp.Split("::"); userId = temp2[0]; if (temp2.Length >= 2) { devCompanyId = temp2[1]; } else { devCompanyId = temp2[0]; } } else { userId = temp; devCompanyId = temp; } isDeveloperLogin = true; _logger.LogDebug("Got user from dev cookie = " + userId + ", company = " + devCompanyId); } else { // same set of tests for a BC Services Card dev login temp = context.Request.Cookies[options.DevBCSCAuthenticationTokenKey]; if (string.IsNullOrEmpty(temp)) // could be an automated test user. { temp = context.Request.Headers["DEV-BCSC-USER"]; } if (!string.IsNullOrEmpty(temp)) { userId = temp; isBCSCDeveloperLogin = true; _logger.LogDebug("Got user from dev cookie = " + userId); } } //} // ************************************************** // Check if the user session is already created // ************************************************** try { _logger.LogInformation("Checking user session"); userSettings = UserSettings.ReadUserSettings(context); _logger.LogDebug("UserSettings found: " + userSettings.GetJson()); } catch { //do nothing _logger.LogDebug("No UserSettings found"); } // is user authenticated - if so we're done if ((userSettings.UserAuthenticated && string.IsNullOrEmpty(userId)) || (userSettings.UserAuthenticated && !string.IsNullOrEmpty(userId) && !string.IsNullOrEmpty(userSettings.UserId) && userSettings.UserId == userId)) { _logger.LogDebug("User already authenticated with active session: " + userSettings.UserId); principal = userSettings.AuthenticatedUser.ToClaimsPrincipal(options.Scheme, userSettings.UserType); return(AuthenticateResult.Success(new AuthenticationTicket(principal, null, Options.Scheme))); } string smgov_userdisplayname = context.Request.Headers["smgov_userdisplayname"]; if (!string.IsNullOrEmpty(smgov_userdisplayname)) { userSettings.UserDisplayName = smgov_userdisplayname; } string smgov_businesslegalname = context.Request.Headers["smgov_businesslegalname"]; if (!string.IsNullOrEmpty(smgov_businesslegalname)) { userSettings.BusinessLegalName = smgov_businesslegalname; } // ************************************************** // Authenticate based on SiteMinder Headers // ************************************************** _logger.LogDebug("Parsing the HTTP headers for SiteMinder authentication credential"); // At this point userID would only be set if we are logging in through as a DEV user if (string.IsNullOrEmpty(userId)) { _logger.LogDebug("Getting user data from headers"); userId = context.Request.Headers[options.SiteMinderUserNameKey]; if (string.IsNullOrEmpty(userId)) { userId = context.Request.Headers[options.SiteMinderUniversalIdKey]; } siteMinderGuid = context.Request.Headers[options.SiteMinderUserGuidKey]; siteMinderBusinessGuid = context.Request.Headers[options.SiteMinderBusinessGuidKey]; siteMinderUserType = context.Request.Headers[options.SiteMinderUserTypeKey]; // ************************************************** // Validate credentials // ************************************************** if (string.IsNullOrEmpty(userId)) { _logger.LogDebug(options.MissingSiteMinderUserIdError); return(AuthenticateResult.Fail(options.MissingSiteMinderGuidError)); } if (string.IsNullOrEmpty(siteMinderGuid)) { _logger.LogDebug(options.MissingSiteMinderGuidError); return(AuthenticateResult.Fail(options.MissingSiteMinderGuidError)); } if (string.IsNullOrEmpty(siteMinderUserType)) { _logger.LogDebug(options.MissingSiteMinderUserTypeError); return(AuthenticateResult.Fail(options.MissingSiteMinderUserTypeError)); } } else // DEV user, setup a fake session and SiteMinder headers. { if (isDeveloperLogin && _dynamicsClient != null) { _logger.LogError("Generating a Development user"); userSettings.BusinessLegalName = devCompanyId + " BusinessProfileName"; userSettings.UserDisplayName = userId + " BCeIDContactType"; // search for a matching user. var existingContact = _dynamicsClient.GetContactByName(userId, "BCeIDContactType"); if (existingContact != null) { siteMinderGuid = existingContact.Externaluseridentifier; } else { siteMinderGuid = GuidUtility.CreateIdForDynamics("contact", userSettings.UserDisplayName).ToString(); } var existingBusiness = await _dynamicsClient.GetAccountByLegalName(userSettings.BusinessLegalName); if (existingBusiness != null) { siteMinderBusinessGuid = existingBusiness.BcgovBceid; } { siteMinderBusinessGuid = GuidUtility.CreateIdForDynamics("account", userSettings.BusinessLegalName).ToString(); } siteMinderUserType = "Business"; } else if (isBCSCDeveloperLogin) { _logger.LogError("Generating a Development BC Services user"); userSettings.BusinessLegalName = null; userSettings.UserDisplayName = userId + " Associate"; siteMinderGuid = GuidUtility.CreateIdForDynamics("bcsc", userSettings.UserDisplayName).ToString(); siteMinderBusinessGuid = null; siteMinderUserType = "VerifiedIndividual"; } } // Previously the code would do a database lookup here. However there is no backing database for the users table now, // so we just do a Dynamics lookup on the siteMinderGuid. _logger.LogDebug("Loading user external id = " + siteMinderGuid); if (_dynamicsClient != null) { userSettings.AuthenticatedUser = await _dynamicsClient.LoadUser(siteMinderGuid, context.Request.Headers, _logger); } _logger.LogDebug("After getting authenticated user = "******" (" + userId + ")"); return(AuthenticateResult.Fail(options.InactivegDbUserIdError)); } if (userSettings.AuthenticatedUser != null && !String.IsNullOrEmpty(siteMinderUserType)) { userSettings.AuthenticatedUser.UserType = siteMinderUserType; } userSettings.UserType = siteMinderUserType; // This line gets the various claims for the current user. ClaimsPrincipal userPrincipal = userSettings.AuthenticatedUser.ToClaimsPrincipal(options.Scheme, userSettings.UserType); // ************************************************** // Create authenticated user // ************************************************** _logger.LogDebug("Authentication successful: " + userId); _logger.LogDebug("Setting identity and creating session for: " + userId); // create session info for the current user userSettings.UserId = userId; userSettings.UserAuthenticated = true; userSettings.IsNewUserRegistration = (userSettings.AuthenticatedUser == null); // set other session info userSettings.SiteMinderGuid = siteMinderGuid; userSettings.SiteMinderBusinessGuid = siteMinderBusinessGuid; _logger.LogDebug("Before getting contact and account ids = " + userSettings.GetJson()); if (userSettings.AuthenticatedUser != null) { userSettings.ContactId = userSettings.AuthenticatedUser.ContactId.ToString(); if (siteMinderBusinessGuid != null) // BCeID user { var account = await _dynamicsClient.GetAccountBySiteminderBusinessGuid(siteMinderBusinessGuid); if (account != null && account.Accountid != null) { userSettings.AccountId = account.Accountid; userSettings.AuthenticatedUser.AccountId = Guid.Parse(account.Accountid); } } } if (!hostingEnv.IsProduction() && (isDeveloperLogin || isBCSCDeveloperLogin)) { _logger.LogError("DEV MODE Setting identity and creating session for: " + userId); if (isDeveloperLogin) { userSettings.BusinessLegalName = devCompanyId + " BusinessProfileName"; userSettings.UserDisplayName = userId + " BCeIDContactType"; // add generated guids userSettings.SiteMinderBusinessGuid = GuidUtility.CreateIdForDynamics("account", userSettings.BusinessLegalName).ToString(); userSettings.SiteMinderGuid = GuidUtility.CreateIdForDynamics("contact", userSettings.UserDisplayName).ToString(); } else if (isBCSCDeveloperLogin) { userSettings.BusinessLegalName = null; userSettings.UserDisplayName = userId + " Associate"; // add generated guids userSettings.SiteMinderBusinessGuid = null; userSettings.SiteMinderGuid = GuidUtility.CreateIdForDynamics("bcsc", userSettings.UserDisplayName).ToString(); } if (userSettings.IsNewUserRegistration) { if (isDeveloperLogin) { // add generated guids userSettings.AccountId = userSettings.SiteMinderBusinessGuid; userSettings.ContactId = userSettings.SiteMinderGuid; } else if (isBCSCDeveloperLogin) { // set to null for now userSettings.AccountId = null; userSettings.ContactId = null; } _logger.LogDebug("New user registration:" + userSettings.UserDisplayName); _logger.LogDebug("userSettings.SiteMinderBusinessGuid:" + userSettings.SiteMinderBusinessGuid); _logger.LogDebug("userSettings.SiteMinderGuid:" + userSettings.SiteMinderGuid); _logger.LogDebug("userSettings.AccountId:" + userSettings.AccountId); _logger.LogDebug("userSettings.ContactId:" + userSettings.ContactId); } // Set account ID from authenticated user else if (userSettings.AuthenticatedUser != null) { // populate the business GUID. if (string.IsNullOrEmpty(userSettings.AccountId)) { userSettings.AccountId = userSettings.AuthenticatedUser.AccountId.ToString(); } if (string.IsNullOrEmpty(userSettings.ContactId)) { userSettings.ContactId = userSettings.AuthenticatedUser.ContactId.ToString(); } _logger.LogDebug("Returning user:"******"userSettings.AccountId:" + userSettings.AccountId); _logger.LogDebug("userSettings.ContactId:" + userSettings.ContactId); } } // add the worker settings if it is a new user. if (userSettings.IsNewUserRegistration && userSettings.NewWorker == null) { userSettings.NewWorker = new ViewModels.Worker(); userSettings.NewWorker.CopyHeaderValues(context.Request.Headers); } // add the worker settings if it is a new user. if (userSettings.IsNewUserRegistration && userSettings.NewContact == null) { userSettings.NewContact = new ViewModels.Contact(); userSettings.NewContact.CopyHeaderValues(context.Request.Headers); } // ************************************************** // Update user settings // ************************************************** UserSettings.SaveUserSettings(userSettings, context); // done! principal = userPrincipal; return(AuthenticateResult.Success(new AuthenticationTicket(principal, null, Options.Scheme))); } catch (Exception exception) { _logger.LogError(exception.Message); Console.WriteLine(exception); throw; } }
/// <summary> /// <para> /// Add Identity for authenticn. Note as of Auth 2.0, all types needed are regsitered /// under AddAuthentication. ///</para> /// <para> /// At this stage: /// - use JWT (bearer) tokens /// Currently, it is authenticated or not (no roles or claims) /// </para> /// <remarks> /// see https://github.com/aspnet/Security/issues/1310 /// </remarks> /// </summary> public static IServiceCollection AddAuthenticationWithJwtToken( this IServiceCollection services, IConfiguration configuration) { var api = configuration.GetSection(ApiDomainSettings.SectionName).Get <ApiDomainSettings>(); // Needed, well documented as a problem // see https://github.com/aspnet/Security/issues/1043 // see https://dev.to/coolgoose/setting-up-jwt-and-identity-authorizationauthentication-in-asp-net-core-4l45 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims var auth0 = configuration.GetSection(Auth0Configuration.SectionName).Get <Auth0Configuration>(); var domain = $"https://{auth0.Domain}/"; services .AddAuthentication( authenticationOptions => { /** * Authenticate using AuthenticationOptions.DefaultAuthenticateScheme to set httpContext.User */ authenticationOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; ; /** * The default scheme to use with [Authorize] attributed methods. * * NOTE: if you can't get a Context.User, it is because you don't have an [Authorize] attribute * that loads up the User onto the context. */ authenticationOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; /** * The global overriding default when any of above and others are no set. Thereotically, * this is not needed because the two above are set. * * Others that could be set see AuthenticationOptions */ authenticationOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; } ) .AddJwtBearer(AuthenticatorDefaults.ExternalAuthenticationSchemeName, options => { // see https://auth0.com/blog/securing-asp-dot-net-core-2-applications-with-jwts/ // // As requested when creating it, our API will use RS256 as the algorithm for signing tokens. // Since RS256 uses a private/public key pair, it verifies the tokens against the // public key for our Auth0 account. The ASP.NET Core JWT middleware will handle downloading // the JSON Web Key Set (JWKS) file containing the public key for us, and will use that // to verify the access_token signature. options.Authority = domain; options.Audience = auth0.Audience; // see https://www.jerriepelser.com/blog/accessing-tokens-aspnet-core-2/ // // Set to true if you want to get the value of the access_token in one of your // controller actions, you will need to retrieve the AuthenticateInfo. The access_token // will be stored inside the Properties with the key “.Token.access_token”: // // eg for this scheme "JSONWebToken" // // string accessToken = await HttpContext.GetTokenAsync("access_token"); // /* * options.SaveToken = true; */ options.Challenge = string.Format("{0} realm=\"{1}\" uri={2}", AuthenticatorDefaults.ExternalAuthenticationSchemeName, AuthenticatorDefaults.AuthenticatorAuth0Realm, api.AuthorizationUri()); options.Events = new JwtBearerEvents { /** * Read a custom authorization header for scheme name: JSONWebToken * * example: * Authorization: JSONWebToken eyJ0eXAiOiJKV1QiLCJhbG... * * Default implementation is to look for scheme: Bearer (see https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs#L63) * * This uses the event OnMessageReceived to process the header and pass it into the pipeline. * see event trigger: https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs#L54 * * * see https://andrewlock.net/a-look-behind-the-jwt-bearer-authentication-middleware-in-asp-net-core/#readauthorizationheader * related see https://stackoverflow.com/questions/41955117/custom-token-location-for-jwtbearermiddleware */ OnMessageReceived = context => { if (string.IsNullOrEmpty(context.Token)) { string authorization = context.Request.Headers["Authorization"]; // If no authorization header found, nothing to process further if (string.IsNullOrEmpty(authorization)) { return(Task.FromResult(AuthenticateResult.NoResult())); } // note the space in the prefix var schemePrefx = $"{AuthenticatorDefaults.ExternalAuthenticationSchemeName} "; if (authorization.StartsWith(schemePrefx, StringComparison.OrdinalIgnoreCase)) { // this then gets picked up further in the pipeline to be processes context.Token = authorization.Substring(schemePrefx.Length).Trim(); } // If no token found, no further work possible if (string.IsNullOrEmpty(context.Token)) { return(Task.FromResult(AuthenticateResult.NoResult())); } } return(Task.CompletedTask); }, /** * Once a token has been validated (above) then add the user to the claims. * * The design is that matching the internal id requires a database request and will be * required once per request. It is then cached and used through any actions. * * Checking Id: * * User.Claims.FindFirst(c => c.Type == UserIdClaimKey).Value */ OnTokenValidated = async context => { // we need to hand in the context Principal at this point as it has not yet // been loaded on the IHttpContextAssessor required for the UserResolverService var user = await context.HttpContext.RequestServices .GetRequiredService <IUserResolverService>() .GetPrincipleUserAsync(context.Principal); if (!user.Id.IsNullOrWhitespace()) { context.Principal.AddIdentityIdToClaims(user.Id); } } }; }); return(services); }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { // You only get client certificates over HTTPS if (!Context.Request.IsHttps) { return(AuthenticateResult.NoResult()); } var clientCertificate = await Context.Connection.GetClientCertificateAsync(); // This should never be the case, as cert authentication happens long before ASP.NET kicks in. if (clientCertificate == null) { Logger.LogDebug("No client certificate found."); return(AuthenticateResult.NoResult()); } // If we have a self signed cert, and they're not allowed, exit early and not bother with // any other validations. if (clientCertificate.IsSelfSigned() && !Options.AllowedCertificateTypes.HasFlag(CertificateTypes.SelfSigned)) { Logger.LogWarning("Self signed certificate rejected, subject was {0}", clientCertificate.Subject); return(AuthenticateResult.Fail("Options do not allow self signed certificates.")); } // If we have a chained cert, and they're not allowed, exit early and not bother with // any other validations. if (!clientCertificate.IsSelfSigned() && !Options.AllowedCertificateTypes.HasFlag(CertificateTypes.Chained)) { Logger.LogWarning("Chained certificate rejected, subject was {0}", clientCertificate.Subject); return(AuthenticateResult.Fail("Options do not allow chained certificates.")); } var chainPolicy = BuildChainPolicy(clientCertificate); try { var chain = new X509Chain { ChainPolicy = chainPolicy }; var certificateIsValid = chain.Build(clientCertificate); if (!certificateIsValid) { using (Logger.BeginScope(clientCertificate.SHA256Thumprint())) { Logger.LogWarning("Client certificate failed validation, subject was {0}", clientCertificate.Subject); foreach (var validationFailure in chain.ChainStatus) { Logger.LogWarning("{0} {1}", validationFailure.Status, validationFailure.StatusInformation); } } return(AuthenticateResult.Fail("Client certificate failed validation.")); } var validateCertificateContext = new ValidateCertificateContext(Context, Scheme, Options) { ClientCertificate = clientCertificate }; await Events.ValidateCertificate(validateCertificateContext); if (validateCertificateContext.Result != null && validateCertificateContext.Result.Succeeded) { var ticket = new AuthenticationTicket(validateCertificateContext.Principal, Scheme.Name); return(AuthenticateResult.Success(ticket)); } if (validateCertificateContext.Result != null && validateCertificateContext.Result.Failure != null) { return(AuthenticateResult.Fail(validateCertificateContext.Result.Failure)); } return(AuthenticateResult.NoResult()); } catch (Exception ex) { var authenticationFailedContext = new CertificateAuthenticationFailedContext(Context, Scheme, Options) { Exception = ex }; await Events.AuthenticationFailed(authenticationFailedContext); if (authenticationFailedContext.Result != null) { return(authenticationFailedContext.Result); } throw; } }
/// <summary> /// Process Authentication Request /// </summary> /// <returns></returns> protected override Task <AuthenticateResult> HandleAuthenticateAsync() { // get siteminder headers _logger.LogDebug("Parsing the HTTP headers for SiteMinder authentication credential"); SiteMinderAuthOptions options = new SiteMinderAuthOptions(); try { ClaimsPrincipal principal; HttpContext context = Request.HttpContext; DataAccess dataAccess = (DataAccess)context.RequestServices.GetService(typeof(DataAccess)); IHostingEnvironment hostingEnv = (IHostingEnvironment)context.RequestServices.GetService(typeof(IHostingEnvironment)); UserSettings userSettings = new UserSettings(); string userId = ""; string siteMinderGuid = ""; // ************************************************** // If this is an Error or Authentiation API - Ignore // ************************************************** string url = context.Request.GetDisplayUrl().ToLower(); if (url.Contains("/authentication/dev") || url.Contains("/error") || url.Contains(".map") || url.Contains(".js")) { return(Task.FromResult(AuthenticateResult.NoResult())); } // ************************************************** // Check if we have a Dev Environment Cookie // ************************************************** if (hostingEnv.IsDevelopment()) { string temp = context.Request.Cookies[options.DevAuthenticationTokenKey]; if (!string.IsNullOrEmpty(temp)) { userId = temp; } } // ************************************************** // Check if the user session is already created // ************************************************** try { _logger.LogInformation("Checking user session"); userSettings = UserSettings.ReadUserSettings(context); } catch { //do nothing } // is user authenticated - if so we're done if ((userSettings.UserAuthenticated && string.IsNullOrEmpty(userId)) || (userSettings.UserAuthenticated && !string.IsNullOrEmpty(userId) && !string.IsNullOrEmpty(userSettings.UserId) && userSettings.UserId == userId)) { _logger.LogInformation("User already authenticated with active session: " + userSettings.UserId); principal = userSettings.AuthenticatedUser.ToClaimsPrincipal(options.Scheme); return(Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, null, Options.Scheme)))); } // ************************************************** // Authenticate based on SiteMinder Headers // ************************************************** _logger.LogDebug("Parsing the HTTP headers for SiteMinder authentication credential"); if (string.IsNullOrEmpty(userId)) { userId = context.Request.Headers[options.SiteMinderUserNameKey]; if (string.IsNullOrEmpty(userId)) { userId = context.Request.Headers[options.SiteMinderUniversalIdKey]; } siteMinderGuid = context.Request.Headers[options.SiteMinderUserGuidKey]; // ************************************************** // Validate credentials // ************************************************** if (string.IsNullOrEmpty(userId)) { _logger.LogError(options.MissingSiteMinderUserIdError); return(Task.FromResult(AuthenticateResult.Fail(options.MissingSiteMinderGuidError))); } if (string.IsNullOrEmpty(siteMinderGuid)) { _logger.LogError(options.MissingSiteMinderGuidError); return(Task.FromResult(AuthenticateResult.Fail(options.MissingSiteMinderGuidError))); } } // ************************************************** // Validate credential against database // ************************************************** userSettings.AuthenticatedUser = hostingEnv.IsDevelopment() ? dataAccess.LoadUser(userId) : dataAccess.LoadUser(userId, siteMinderGuid); if (userSettings.AuthenticatedUser == null) { _logger.LogWarning(options.MissingDbUserIdError + " (" + userId + ")"); return(Task.FromResult(AuthenticateResult.Fail(options.MissingDbUserIdError))); } if (!userSettings.AuthenticatedUser.Active) { _logger.LogWarning(options.InactivegDbUserIdError + " (" + userId + ")"); return(Task.FromResult(AuthenticateResult.Fail(options.InactivegDbUserIdError))); } // ************************************************** // Validate / check user permissions // ************************************************** ClaimsPrincipal userPrincipal = userSettings.AuthenticatedUser.ToClaimsPrincipal(options.Scheme); if (!userPrincipal.HasClaim(User.PermissionClaim, Permission.Login) ) { _logger.LogWarning("User does not have "); return(Task.FromResult(AuthenticateResult.Fail(options.InvalidPermissions))); } // ************************************************** // Create authenticated user // ************************************************** _logger.LogInformation("Authentication successful: " + userId); _logger.LogInformation("Setting identity and creating session for: " + userId); // create session info userSettings.UserId = userId; userSettings.UserAuthenticated = true; // ************************************************** // Update user settings // ************************************************** UserSettings.SaveUserSettings(userSettings, context); // done! principal = userPrincipal; return(Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(principal, null, Options.Scheme)))); } catch (Exception exception) { _logger.LogError(exception.Message); Console.WriteLine(exception); throw; } }
/// <summary> /// Tries to validate a token on the current request /// </summary> /// <returns></returns> protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { _logger.LogTrace("HandleAuthenticateAsync called"); if (!Context.Request.Headers.ContainsKey("x-authScheme")) { return(AuthenticateResult.NoResult()); } var authScheme = Context.Request.Headers["x-authScheme"]; if (string.IsNullOrWhiteSpace(authScheme)) { return(AuthenticateResult.NoResult()); } if (!Global.SchemeRecords.ContainsKey(authScheme)) { return(AuthenticateResult.NoResult()); } var jwtScheme = Scheme.Name + authScheme; var token = Options.TokenRetriever(Context.Request); bool removeToken = false; try { if (token != null) { _logger.LogTrace("Token found: {token}", token); removeToken = true; Context.Items.Add(MultiAuthorityAuthenticationDefaults.TokenItemsKey, token); // seems to be a JWT if (token.Contains('.') && Options.SupportsJwt) { _logger.LogTrace("Token is a JWT and is supported."); Context.Items.Add(MultiAuthorityAuthenticationDefaults.EffectiveSchemeKey + Scheme.Name, jwtScheme); return(await Context.AuthenticateAsync(jwtScheme)); } else { _logger.LogTrace("JWT token seem not to be correctly configured for incoming token."); } } // set the default challenge handler to JwtBearer if supported if (Options.SupportsJwt) { Context.Items.Add(MultiAuthorityAuthenticationDefaults.EffectiveSchemeKey + Scheme.Name, jwtScheme); } return(AuthenticateResult.NoResult()); } finally { if (removeToken) { Context.Items.Remove(MultiAuthorityAuthenticationDefaults.TokenItemsKey); } } }
public Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) { return(Task.FromResult(AuthenticateResult.NoResult())); }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { var transaction = Context.Features.Get <OpenIddictServerAspNetCoreFeature>()?.Transaction ?? throw new InvalidOperationException("An unknown error occurred while retrieving the OpenIddict server context."); // Note: in many cases, the authentication token was already validated by the time this action is called // (generally later in the pipeline, when using the pass-through mode). To avoid having to re-validate it, // the authentication context is resolved from the transaction. If it's not available, a new one is created. var context = transaction.GetProperty <ProcessAuthenticationContext>(typeof(ProcessAuthenticationContext).FullName); if (context == null) { context = new ProcessAuthenticationContext(transaction); await _dispatcher.DispatchAsync(context); // Store the context object in the transaction so it can be later retrieved by handlers // that want to access the authentication result without triggering a new authentication flow. transaction.SetProperty(typeof(ProcessAuthenticationContext).FullName, context); } if (context.IsRequestHandled || context.IsRequestSkipped) { return(AuthenticateResult.NoResult()); } else if (context.IsRejected) { // Note: the missing_token error is special-cased to indicate to ASP.NET Core // that no authentication result could be produced due to the lack of token. // This also helps reducing the logging noise when no token is specified. if (string.Equals(context.Error, Errors.MissingToken, StringComparison.Ordinal)) { return(AuthenticateResult.NoResult()); } var properties = new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = context.Error, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = context.ErrorDescription, [OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = context.ErrorUri }); return(AuthenticateResult.Fail("An error occurred while authenticating the current request.", properties)); } else { // Store the token to allow any ASP.NET Core component (e.g a controller) // to retrieve it (e.g to make an API request to another application). var properties = new AuthenticationProperties(); properties.StoreTokens(new[] { new AuthenticationToken { Name = context.TokenType, Value = context.Token } }); return(AuthenticateResult.Success(new AuthenticationTicket( context.Principal, properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme))); } }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { if (!Request.Headers.ContainsKey("Authorization")) { return(AuthenticateResult.NoResult()); } string token = null; string authorization = Request.Headers["Authorization"]; // If no authorization header found, nothing to process further if (string.IsNullOrEmpty(authorization)) { return(AuthenticateResult.NoResult()); } if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { token = authorization.Substring("Bearer ".Length).Trim(); } // If no token found, no further work possible if (string.IsNullOrEmpty(token)) { return(AuthenticateResult.NoResult()); } try { string result = await Options.UserInfoEndpoint.WithOAuthBearerToken(token) .PostUrlEncodedAsync(new { client_id = Options.ClientId, client_secret = Options.ClientSecret, }) .ReceiveString(); JObject user = JObject.Parse(result); ICollection <Claim> claims = new List <Claim>(); foreach (JProperty property in user.Properties().Select(x => x)) { if (!property.Value.Any()) { claims.Add(new Claim(property.Name, (string)property.Value)); } else { foreach (JToken jToken in property.Value) { claims.Add(new Claim(property.Name, (string)jToken)); } } } ClaimsIdentity identity = new ClaimsIdentity(claims, "AuthenticationTypes.Federation"); ClaimsPrincipal principal = new ClaimsPrincipal(identity); AuthenticationTicket ticket = new AuthenticationTicket(principal, Scheme.Name); return(AuthenticateResult.Success(ticket)); } catch (FlurlHttpException e) { return(AuthenticateResult.Fail(await e.GetResponseStringAsync())); } }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { try { this.Logger.LogInformation("{LogKey:l} apikey handle", LogKeys.Authentication); if (this.Request.Host.Host.SafeEquals("localhost") && this.Options.IgnoreLocal) { // ignore for localhost var identity = new ClaimsIdentity( this.Options.Claims.Safe().Select(c => new Claim(c.Key, c.Value)) .Insert(new Claim(ClaimTypes.AuthenticationMethod, AuthenticationKeys.ApiKeyScheme)) .Insert(new Claim(ClaimTypes.Name, ClaimsIdentity.DefaultIssuer)) .DistinctBy(c => c.Type), this.Scheme.Name); var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), this.Scheme.Name); this.Logger.LogInformation($"{{LogKey:l}} apikey authenticated (name={identity.Name})", LogKeys.Authentication); return(AuthenticateResult.Success(ticket)); } string value; if (this.Request.Query.TryGetValue("apikey", out var queryValue)) { // also allow the auth header to be sent in the querystring (for easy dashboard usage) value = queryValue.ToString(); } else { if (!this.Request.Headers.ContainsKey(AuthenticationKeys.AuthorizationHeaderName)) { return(AuthenticateResult.NoResult()); //Authorization header not in request } if (!AuthenticationHeaderValue.TryParse(this.Request.Headers[AuthenticationKeys.AuthorizationHeaderName], out var headerValue)) { return(AuthenticateResult.NoResult()); //Invalid Authorization header } else { value = headerValue.Parameter; } if (!AuthenticationKeys.ApiKeyScheme.Equals(headerValue.Scheme, StringComparison.OrdinalIgnoreCase)) { return(AuthenticateResult.NoResult()); //Not a apikey authentication header } } if (value.IsNullOrEmpty()) { return(AuthenticateResult.NoResult()); //No apikey authentication value in header or query } //var context = new ApiKeyValidationContext(this.Context, this.Scheme, this.Options) { ApiKey = headerValue.Parameter }; //await this.Events.OnValidation(context); //if (context.Result != null) //{ // return context.Result; //} #pragma warning disable SA1008 // Opening parenthesis must be spaced correctly var(authenticated, claims) = this.service.Validate(value); #pragma warning restore SA1008 // Opening parenthesis must be spaced correctly if (authenticated) { var identity = new ClaimsIdentity( this.Options.Claims.Safe().Select(c => new Claim(c.Key, c.Value)).Concat(claims.Safe()) .Insert(new Claim(ClaimTypes.AuthenticationMethod, AuthenticationKeys.ApiKeyScheme)).DistinctBy(c => c.Type), this.Scheme.Name); var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), this.Scheme.Name); this.Logger.LogInformation($"{{LogKey:l}} apikey authenticated (name={identity.Name})", LogKeys.Authentication); return(AuthenticateResult.Success(ticket)); } this.Logger.LogWarning("{LogKey:l} apikey not authenticated", LogKeys.Authentication); return(AuthenticateResult.Fail("not authenticated")); } catch (Exception ex) { this.Logger.LogError(ex, $"{{LogKey:l}} {ex.Message}", LogKeys.Authentication); var context = new ErrorContext(this.Context, this.Scheme, this.Options) { Exception = ex }; if (this.Events != null) { await this.Events.Error(context); if (context.Result != null) { return(context.Result); } } throw; } }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { bool isTokenFromCookie = false; try { Logger.LogDebug("HandleAuthenticateAsync: started authentication check..."); string token = string.Empty; // check first for header if (!string.IsNullOrEmpty(Program.JwtHeader)) { var header = Request.Headers["Authorization"]; if (header.Count() > 0) { Logger.LogDebug($"HandleAuthenticateAsync: checking header named \"Authorization\" for token..."); token = header.First().Replace("Bearer ", ""); } } // look next at the cookie if (!string.IsNullOrEmpty(Program.JwtCookie)) { Logger.LogDebug($"HandleAuthenticateAsync: checking cookie named \"{Program.JwtCookie}\" for token..."); token = Request.Cookies[Program.JwtCookie]; isTokenFromCookie = true; } // shortcut if there is no token if (string.IsNullOrEmpty(token)) { Logger.LogDebug("HandleAuthenticateAsync: no token was found."); return(AuthenticateResult.NoResult()); } // validate the token var jwt = await TokenValidator.ValidateToken(token); // propogate the claims (this overload uses uri-names and dedupes) var claims = new List <Claim>(); foreach (var claim in jwt.Payload.Claims) { claims.AddLong(claim.Type, claim.Value); } // build the identity, principal, and ticket var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return(AuthenticateResult.Success(ticket)); } catch (Exception e) { Logger.LogWarning(e, "HandleAuthenticateAsync: exception..."); if (isTokenFromCookie) { Response.Cookies.Delete(Program.JwtCookie); // revoke the cookie } return(AuthenticateResult.Fail(e)); } }
//public async Task<HttpContext> Authenticate(ClientContext clientContext, string authorization, string scheme) { // var authenticationService = _serviceProvider.GetRequiredService<IAuthenticationService>(); // var ctx = new DefaultHttpContext(); // ctx.RequestServices = _serviceProvider; // if (String.IsNullOrWhiteSpace(scheme)) { // var defaultScheme = await _schemes.GetDefaultAuthenticateSchemeAsync(); // scheme = defaultScheme?.Name; // } // AuthenticateResult authenticateResult; // if (clientContext.UserValidUntil < DateTime.Now) { // if (!authorization.Contains(" ")) { // authorization = $"Bearer {authorization}"; // } // ctx.Request.Headers["Authorization"] = authorization; // authenticateResult = await authenticationService.AuthenticateAsync(ctx, scheme); // } else { // var t = new AuthenticationTicket(clientContext.User, clientContext.User.Identity.AuthenticationType); // authenticateResult = AuthenticateResult.Success(t); // } // ctx.User = authenticateResult.Principal; // clientContext.SetPrincipal(ctx.User); // return ctx; //} public async Task <PolicyAuthorizationResult> Authorize(ClientContext clientContext, string authorization, MethodInfo methodInfo) { var authorizeData = methodInfo.GetAuthorizeData(); if (!authorizeData.Any()) { return(PolicyAuthorizationResult.Success()); } var authenticationService = _serviceProvider.GetRequiredService <IAuthenticationService>(); var policyEvaluator = _serviceProvider.GetRequiredService <IPolicyEvaluator>(); var policyProvider = _serviceProvider.GetRequiredService <IAuthorizationPolicyProvider>(); if (!authorizeData.Any()) { authorizeData = methodInfo.DeclaringType?.GetCustomAttributes <AuthorizeAttribute>().ToList() ?? new List <AuthorizeAttribute>(); } var policy = await AuthorizationPolicy.CombineAsync(policyProvider, authorizeData); if (policy == null) { return(PolicyAuthorizationResult.Success()); } var ctx = new DefaultHttpContext(); ctx.RequestServices = _serviceProvider; AuthenticateResult authenticateResult = AuthenticateResult.NoResult(); Console.WriteLine($"{clientContext.UserValidUntil} - {DateTime.Now}"); if (clientContext.UserValidUntil < DateTime.Now) { if (!authorization.Contains(" ")) { authorization = $"Bearer {authorization}"; } ctx.Request.Headers["Authorization"] = authorization; foreach (var policyAuthenticationScheme in policy.AuthenticationSchemes) { authenticateResult = await authenticationService.AuthenticateAsync(ctx, policyAuthenticationScheme); if (authenticateResult.Succeeded) { clientContext.SetPrincipal(authenticateResult.Principal); break; } } } else { var t = new AuthenticationTicket(clientContext.User, clientContext.User.Identity.AuthenticationType); authenticateResult = AuthenticateResult.Success(t); } ctx.User = authenticateResult.Principal; if (methodInfo.GetCustomAttribute <AllowAnonymousAttribute>() != null) { return(PolicyAuthorizationResult.Success()); } var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, ctx, clientContext); return(authorizeResult); }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { string siteMinderUserGuidHeader = Request.Headers["SMGOV_USERGUID"]; string siteMinderUserTypeHeader = Request.Headers["SMGOV_USERTYPE"]; if (siteMinderUserGuidHeader == null || siteMinderUserTypeHeader == null) { return(AuthenticateResult.NoResult()); } if (siteMinderUserTypeHeader != ValidSiteMinderUserType) { return(AuthenticateResult.Fail("Invalid SiteMinder UserType Header.")); } var authenticatedBySiteMinderPreviously = Context.User.Identity.AuthenticationType == SiteMinder; var applicationCode = Context.User.ApplicationCode(); var participantId = Context.User.ParticipantId(); var agencyCode = Context.User.AgencyCode(); var isSupremeUser = Context.User.IsSupremeUser(); if (!authenticatedBySiteMinderPreviously) { var request = new UserInfoRequest { DeviceName = Environment.MachineName, DomainUserGuid = siteMinderUserGuidHeader, DomainUserId = Request.Headers["SM_USER"], IpAddress = Request.Headers["X-Real-IP"], TemporaryAccessGuid = "" }; var jcUserInfo = await JCUserService.GetUserInfo(request); if (jcUserInfo == null) { return(AuthenticateResult.Fail("Couldn't authenticate through JC-Interface.")); } applicationCode = "SCV"; participantId = jcUserInfo.UserPartId; agencyCode = jcUserInfo.UserDefaultAgencyCd; isSupremeUser = true; } var claims = new[] { new Claim(CustomClaimTypes.ApplicationCode, applicationCode), new Claim(CustomClaimTypes.JcParticipantId, participantId), new Claim(CustomClaimTypes.JcAgencyCode, agencyCode), new Claim(CustomClaimTypes.IsSupremeUser, isSupremeUser.ToString()) }; var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); if (!authenticatedBySiteMinderPreviously) { await Context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal); } var ticket = new AuthenticationTicket(principal, Scheme.Name); return(AuthenticateResult.Success(ticket)); }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { return(await Task.FromResult(AuthenticateResult.NoResult())); }
public Task <AuthenticateResult> AuthenticateAsync() { return(Task.FromResult(AuthenticateResult.NoResult())); }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { async Task <AuthenticateResult> DeleteLongSessionAndLogout(long sessionId) { await userManager.DeleteLongSessionAsync(sessionId); jweService.MakeLogoutCookiesAndHeaders(Response); return(AuthenticateResult.NoResult()); } AuthenticateResult Logout(string msg) { jweService.MakeLogoutCookiesAndHeaders(Response); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"\nLogout: {msg}\n"); Console.ResetColor(); return(AuthenticateResult.NoResult()); } try { var cookie = Request.Cookies[TokenClaimNames.LongToken2CoockiName]; if (cookie == null) { return(AuthenticateResult.NoResult()); } JwtSecurityToken jwtLongToken2 = jweService.ReadLong2Token(cookie); if (jwtLongToken2 == null) { return(Logout("No Long2 cookie token")); } var longToken2db = jwtLongToken2.Claims.First(x => x.Type == TokenClaimNames.LongToken2Db).Value; SunClaimsPrincipal sunClaimsPrincipal; if (Request.Headers.TryGetValue(Headers.LongToken1HeaderName, out StringValues longToken1db)) { int userId = int.Parse(jwtLongToken2.Claims.First(x => x.Type == ClaimTypes.NameIdentifier).Value); var longSessionToFind = new LongSession { UserId = userId, LongToken1 = longToken1db, LongToken2 = longToken2db }; var longSession = await userManager.FindLongSessionAsync(longSessionToFind); if (longSession == null) { return(Logout("Session not found")); } sunClaimsPrincipal = await jweService.RenewSecurityTokensAsync(Context, userId, longSession); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("\nToken renews\n"); Console.ResetColor(); } else { string authorization = Request.Headers["Authorization"]; if (string.IsNullOrEmpty(authorization)) { return(Logout("No Authorization header")); } string jwtShortToken = null; if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { jwtShortToken = authorization.Substring("Bearer ".Length).Trim(); } if (string.IsNullOrEmpty(jwtShortToken)) { return(Logout("No Bearer in Authorization header")); } var claimsPrincipal = jweService.ReadShortToken(jwtShortToken); string lat2ran_1 = jwtLongToken2.Claims.First(x => x.Type == TokenClaimNames.LongToken2Ran).Value; string lat2ran_2 = claimsPrincipal.Claims.First(x => x.Type == TokenClaimNames.LongToken2Ran).Value; long sessionId = long.Parse(jwtLongToken2.Claims.First(x => x.Type == TokenClaimNames.SessionId).Value); if (!string.Equals(lat2ran_1, lat2ran_2)) { return(await DeleteLongSessionAndLogout(sessionId)); } string lat2db = jwtLongToken2.Claims.First(x => x.Type == TokenClaimNames.LongToken2Db).Value; sunClaimsPrincipal = new SunClaimsPrincipal(claimsPrincipal, rolesCache, sessionId, lat2db); } if (jweBlackListService.IsTokenInBlackList(sunClaimsPrincipal.LongToken2Db)) { return(await DeleteLongSessionAndLogout(sunClaimsPrincipal.SessionId)); } if (sunClaimsPrincipal.Roles.ContainsKey(RoleNames.Banned)) { return(await DeleteLongSessionAndLogout(sunClaimsPrincipal.SessionId)); } var authenticationTicket = new AuthenticationTicket(sunClaimsPrincipal, SunJwt.Scheme); return(AuthenticateResult.Success(authenticationTicket)); } catch (Exception e) { return(Logout("Error " + e)); } }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { if (!Request.Headers.ContainsKey(AuthorizationHeaderName)) { //Authorization header not in request return(AuthenticateResult.NoResult()); } if (!AuthenticationHeaderValue.TryParse(Request.Headers[AuthorizationHeaderName], out AuthenticationHeaderValue headerValue)) { //Invalid Authorization header return(AuthenticateResult.NoResult()); } if (!BasicSchemeName.Equals(headerValue.Scheme, StringComparison.OrdinalIgnoreCase)) { //Not Basic authentication header return(AuthenticateResult.NoResult()); } try { if (string.IsNullOrEmpty(headerValue.Parameter)) { return(AuthenticateResult.Fail(new Abp.UI.UserFriendlyException((int)Split.Dto.ResultCode.Auth_InvalidToken, "Invalid token"))); } byte[] headerValueBytes = Convert.FromBase64String(headerValue.Parameter); string userAndPassword = Encoding.UTF8.GetString(headerValueBytes); string[] parts = userAndPassword.Split(':'); if (parts.Length != 2) { return(AuthenticateResult.Fail(new Abp.UI.UserFriendlyException((int)Split.Dto.ResultCode.Auth_InvalidAutheHeader, "Invalid Basic authentication header"))); } string tenancyName = parts[0]; string apiKey = parts[1]; string userId = ""; string tenantId = ""; if (!string.IsNullOrEmpty(tenancyName)) { var tenants = await _tenantRepository.GetAll().IgnoreQueryFilters() .Where(o => o.ApiKey == apiKey && o.TenancyName == tenancyName && !o.IsDeleted && o.IsActive).ToListAsync(); if (tenants.Count == 0) { return(AuthenticateResult.Fail(new Abp.UI.UserFriendlyException((int)Split.Dto.ResultCode.Auth_InvalidInput, "Invalid tenancyname or apikey"))); } if (!tenants[0].IsActive) { return(AuthenticateResult.Fail(new Abp.UI.UserFriendlyException((int)Split.Dto.ResultCode.Auth_RefuseAuthorization, "tenant is banish"))); } var user = await this._userRepository.GetAll().IgnoreQueryFilters().SingleAsync(o => o.UserName == "admin" && o.TenantId == tenants[0].Id); tenantId = tenants[0].Id.ToString(); userId = user.Id.ToString(); } else if (apiKey.Equals(Options.SystemApiKey)) { var user = await this._userRepository.GetAll().IgnoreQueryFilters().SingleAsync(o => o.UserName == "admin" && o.TenantId == null); userId = user.Id.ToString(); } else { return(AuthenticateResult.Fail(new Abp.UI.UserFriendlyException((int)Split.Dto.ResultCode.Auth_InvalidInput, "Invalid tenancyname or apikey"))); } var claims = new[] { new Claim(ClaimTypes.NameIdentifier, userId), new Claim(AbpClaimTypes.TenantId, tenantId), new Claim(AbpClaimTypes.UserName, StaticRoleNames.Host.Admin) }; var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return(AuthenticateResult.Success(ticket)); } catch (Exception ex) when(ex is FormatException || ex is DecoderFallbackException) { return(AuthenticateResult.Fail(new Abp.UI.UserFriendlyException((int)Split.Dto.ResultCode.Auth_InvalidToken, "Invalid token"))); } catch (Exception ex) { LogHelper.Logger.Error("basic auth", ex); return(AuthenticateResult.Fail(new Abp.UI.UserFriendlyException((int)Split.Dto.ResultCode.SytemError, "Invalid auth request"))); } }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { try { var messageReceivedContext = new MessageReceivedContext(this.Context, this.Scheme, this.Options); await this.Events.MessageReceived(messageReceivedContext); string apiKey = messageReceivedContext.ApiKey; if (string.IsNullOrEmpty(apiKey)) { string header = this.Request.Headers[this.Options.Header]; if (string.IsNullOrEmpty(header)) { this.Logger.ApiKeyValidationFailed(); return(AuthenticateResult.NoResult()); } if (header.StartsWith(this.Options.HeaderKey, StringComparison.OrdinalIgnoreCase)) { apiKey = header.Substring(this.Options.HeaderKey.Length).Trim(); var validateApiKeyContext = new ApiKeyValidatedContext(this.Context, this.Scheme, this.Options) { ApiKey = apiKey, Principal = new ClaimsPrincipal() }; await this.Events.ApiKeyValidated(validateApiKeyContext); if (validateApiKeyContext.Result != null) { this.Logger.ApiKeyValidationSucceeded(); return(validateApiKeyContext.Result); } } } this.Logger.ApiKeyValidationFailed(); return(AuthenticateResult.NoResult()); } catch (Exception ex) { this.Logger.ErrorProcessingMessage(ex); var authenticationFailedContext = new AuthenticationFailedContext(this.Context, this.Scheme, this.Options) { Exception = ex }; await this.Events.AuthenticationFailed(authenticationFailedContext); if (authenticationFailedContext.Result != null) { return(authenticationFailedContext.Result); } throw; } }
/// <summary> /// Tries to authenticate a reference token on the current request /// </summary> /// <returns></returns> protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { string token = Options.TokenRetriever(Context.Request); if (token.IsMissing()) { return(AuthenticateResult.NoResult()); } if (token.Contains('.') && Options.SkipTokensWithDots) { _logger.LogTrace("Token contains a dot - skipped because SkipTokensWithDots is set."); return(AuthenticateResult.NoResult()); } if (Options.EnableCaching) { var claims = await _cache.GetClaimsAsync(token).ConfigureAwait(false); if (claims != null) { var ticket = CreateTicket(claims); _logger.LogTrace("Token found in cache."); if (Options.SaveToken) { ticket.Properties.StoreTokens(new[] { new AuthenticationToken { Name = "access_token", Value = token } }); } return(AuthenticateResult.Success(ticket)); } _logger.LogTrace("Token is not cached."); } // Use a LazyAsync to ensure only one thread is requesting introspection for a token - the rest will wait for the result var lazyIntrospection = Options.LazyIntrospections.GetOrAdd(token, CreateLazyIntrospection); try { var response = await lazyIntrospection.Value.ConfigureAwait(false); if (response.IsError) { _logger.LogError("Error returned from introspection endpoint: " + response.Error); return(AuthenticateResult.Fail("Error returned from introspection endpoint: " + response.Error)); } if (response.IsActive) { var ticket = CreateTicket(response.Claims); if (Options.SaveToken) { ticket.Properties.StoreTokens(new[] { new AuthenticationToken { Name = "access_token", Value = token } }); } if (Options.EnableCaching) { await _cache.SetClaimsAsync(token, response.Claims, Options.CacheDuration, _logger).ConfigureAwait(false); } return(AuthenticateResult.Success(ticket)); } else { return(AuthenticateResult.Fail("Token is not active.")); } } finally { // If caching is on and it succeeded, the claims are now in the cache. // If caching is off and it succeeded, the claims will be discarded. // Either way, we want to remove the temporary store of claims for this token because it is only intended for de-duping fetch requests Options.LazyIntrospections.TryRemove(token, out _); } }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { var events = Events as BasicEvents; try { // .NET Core as of 2.0 does not support HTTP auth on sockets // This is alternative solution to anonymous access in SessionController.GetPipe() // but it only works for local connections (which may be OK for VSC but it won't work // in VSC with remote or Docker containers. //if (Uri.TryCreate(CurrentUri, UriKind.Absolute, out var uri)) { // if (uri.IsLoopback && !Request.IsHttps) { // var claims = new[] { // new Claim(ClaimTypes.Name, "RTVS"), // new Claim(Claims.RUser, string.Empty), // }; // var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, BasicDefaults.AuthenticationScheme)); // var t = new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name); // return AuthenticateResult.Success(t); // } //} // retrieve authorization header string authorization = Request.Headers[HeaderNames.Authorization]; if (string.IsNullOrEmpty(authorization)) { return(AuthenticateResult.NoResult()); } if (!authorization.StartsWith(RequestHeaderPrefix, StringComparison.OrdinalIgnoreCase)) { return(AuthenticateResult.NoResult()); } // retrieve credentials from header var encodedCredentials = authorization.Substring(RequestHeaderPrefix.Length); var decodedCredentials = default(string); try { decodedCredentials = Encoding.UTF8.GetString(Convert.FromBase64String(encodedCredentials)); } catch (Exception) { return(AuthenticateResult.Fail("Invalid basic authentication header encoding.")); } var index = decodedCredentials.IndexOf(':'); if (index == -1) { return(AuthenticateResult.Fail("Invalid basic authentication header format.")); } var username = decodedCredentials.Substring(0, index); var password = decodedCredentials.Substring(index + 1); var signInContext = new BasicSignInContext(Context, Scheme, Options) { Username = username, Password = password, }; await events.SignIn(signInContext); if (signInContext.Principal == null) { return(AuthenticateResult.Fail("Invalid basic authentication credentials.")); } var ticket = new AuthenticationTicket(signInContext.Principal, new AuthenticationProperties(), Scheme.Name); return(AuthenticateResult.Success(ticket)); } catch (Exception ex) { var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options) { Exception = ex, }; await events.AuthenticationFailed(authenticationFailedContext); if (authenticationFailedContext.Result != null) { return(authenticationFailedContext.Result); } throw; } }
public Task <AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme) { return(Task.FromResult(AuthenticateResult.NoResult())); }
public Task <AuthenticateResult> AuthenticateAsync() => Task.FromResult(AuthenticateResult.NoResult());
protected override Task <AuthenticateResult> HandleAuthenticateAsync() { //We are expecting a header such as Authorization: <Schema> <key> //If this is not present, we will return NoResult and move on to the next authentication handler. if (!Request.Headers.TryGetValue(HeaderNames.Authorization, out StringValues values) || !values.Any()) { return(Task.FromResult(AuthenticateResult.NoResult())); } if (!AuthenticationHeaderValue.TryParse(values.First(), out AuthenticationHeaderValue authHeader)) { return(Task.FromResult(AuthenticateResult.Fail("Invalid authentication header"))); } if (!string.Equals(authHeader.Scheme, Scheme.Name, StringComparison.OrdinalIgnoreCase)) { return(Task.FromResult(AuthenticateResult.NoResult())); } //The user is passing a base 64-encoded version of the secret //We will be hash this and compare it to the secret in our configuration. byte[] secret = new byte[32]; Span <byte> span = new Span <byte>(secret); if (!Convert.TryFromBase64String(authHeader.Parameter, span, out int bytesWritten) || bytesWritten < 32) { return(Task.FromResult(AuthenticateResult.Fail("Invalid Api Key format"))); } //HACK IOptionsMonitor and similiar do not properly update here even though the underlying //configuration is updated. We get the value directly from IConfiguration. var authenticationOptions = new ApiAuthenticationOptions(); IConfiguration configService = Context.RequestServices.GetRequiredService <IConfiguration>(); configService.Bind(ApiAuthenticationOptions.ConfigurationKey, authenticationOptions); string apiKeyHash = authenticationOptions.ApiKeyHash; if (apiKeyHash == null) { return(Task.FromResult(AuthenticateResult.Fail("Server does not contain Api Key"))); } if (string.IsNullOrEmpty(authenticationOptions.ApiKeyHashType)) { return(Task.FromResult(AuthenticateResult.Fail("Missing hash algorithm"))); } if (DisallowedHashAlgorithms.Contains(authenticationOptions.ApiKeyHashType, StringComparer.OrdinalIgnoreCase)) { return(Task.FromResult(AuthenticateResult.Fail($"Disallowed hash algorithm {authenticationOptions.ApiKeyHashType}"))); } using HashAlgorithm algorithm = HashAlgorithm.Create(authenticationOptions.ApiKeyHashType); if (algorithm == null) { return(Task.FromResult(AuthenticateResult.Fail($"Invalid hash algorithm {authenticationOptions.ApiKeyHashType}"))); } byte[] hashedSecret = algorithm.ComputeHash(secret); //ApiKeyHash is represented as a hex string. e.g. AABBCCDDEEFF byte[] apiKeyHashBytes = new byte[apiKeyHash.Length / 2]; for (int i = 0; i < apiKeyHash.Length; i += 2) { if (!byte.TryParse(apiKeyHash.AsSpan(i, 2), NumberStyles.HexNumber, provider: NumberFormatInfo.InvariantInfo, result: out byte resultByte)) { return(Task.FromResult(AuthenticateResult.Fail("Invalid Api Key hash"))); } apiKeyHashBytes[i / 2] = resultByte; } if (hashedSecret.SequenceEqual(apiKeyHashBytes)) { return(Task.FromResult(AuthenticateResult.Success( new AuthenticationTicket( new ClaimsPrincipal(new[] { new ClaimsIdentity(AuthConstants.ApiKeySchema) }), AuthConstants.ApiKeySchema)))); } else { return(Task.FromResult(AuthenticateResult.Fail("Invalid Api Key"))); } }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { string authHeaderValue = Request.Headers.TryGetAndReturn("Authorization").FirstOrDefault(); AuthenticationHeaderValue authHeader = null; if (!String.IsNullOrEmpty(authHeaderValue) && !AuthenticationHeaderValue.TryParse(authHeaderValue, out authHeader)) { return(AuthenticateResult.Fail("Unable to parse header")); } string scheme = authHeader?.Scheme.ToLower(); string token = null; if (authHeader != null && (scheme == BearerScheme || scheme == TokenScheme)) { token = authHeader.Parameter; } else if (authHeader != null && scheme == BasicScheme) { var authInfo = Request.GetBasicAuth(); if (authInfo != null) { if (authInfo.Username.ToLower() == "client") { token = authInfo.Password; } else if (authInfo.Password.ToLower() == "x-oauth-basic" || String.IsNullOrEmpty(authInfo.Password)) { token = authInfo.Username; } else { User user; try { user = await _userRepository.GetByEmailAddressAsync(authInfo.Username); } catch (Exception ex) { return(AuthenticateResult.Fail(ex)); } if (user == null || !user.IsActive) { return(AuthenticateResult.Fail("User is not valid")); } if (String.IsNullOrEmpty(user.Salt)) { return(AuthenticateResult.Fail("User is not valid")); } string encodedPassword = authInfo.Password.ToSaltedHash(user.Salt); if (!String.Equals(encodedPassword, user.Password)) { return(AuthenticateResult.Fail("User is not valid")); } return(AuthenticateResult.Success(CreateUserAuthenticationTicket(user))); } } } else { token = Request.GetQueryString("access_token"); if (String.IsNullOrEmpty(token)) { token = Request.GetQueryString("api_key"); } if (String.IsNullOrEmpty(token)) { token = Request.GetQueryString("apikey"); } } if (String.IsNullOrEmpty(token)) { return(AuthenticateResult.NoResult()); } var tokenRecord = await _tokenRepository.GetByIdAsync(token, o => o.Cache()); if (tokenRecord == null) { using (Logger.BeginScope(new ExceptionlessState().Property("Headers", Request.Headers))) Logger.LogWarning("Token {Token} for {Path} not found.", token, Request.Path); return(AuthenticateResult.Fail("Token is not valid")); } if (tokenRecord.ExpiresUtc.HasValue && tokenRecord.ExpiresUtc.Value < Foundatio.Utility.SystemClock.UtcNow) { using (Logger.BeginScope(new ExceptionlessState().Property("Headers", Request.Headers))) Logger.LogWarning("Token {Token} for {Path} expired on {TokenExpiresUtc}.", token, Request.Path, tokenRecord.ExpiresUtc.Value); return(AuthenticateResult.Fail("Token is not valid")); } if (!String.IsNullOrEmpty(tokenRecord.UserId)) { var user = await _userRepository.GetByIdAsync(tokenRecord.UserId, o => o.Cache()); if (user == null) { using (Logger.BeginScope(new ExceptionlessState().Property("Headers", Request.Headers))) Logger.LogWarning("Could not find user for token {Token} with user {user} for {Path}.", token, tokenRecord.UserId, Request.Path); return(AuthenticateResult.Fail("Token is not valid")); } return(AuthenticateResult.Success(CreateUserAuthenticationTicket(user, tokenRecord))); } return(AuthenticateResult.Success(CreateTokenAuthenticationTicket(tokenRecord))); }
protected override async Task <AuthenticateResult> HandleAuthenticateAsync() { if (!Request.Cookies.ContainsKey(AccessToken) || !Request.Cookies.ContainsKey(User_Id)) { Log.Error("No Access Token or User Id found."); return(await Task.FromResult(AuthenticateResult.NoResult())); } if (!AuthenticationHeaderValue.TryParse($"{"Bearer " + Request.Cookies[AccessToken]}", out AuthenticationHeaderValue headerValue)) { Log.Error("Could not Parse Token from Authentication Header."); return(await Task.FromResult(AuthenticateResult.NoResult())); } if (!AuthenticationHeaderValue.TryParse($"{"Bearer " + Request.Cookies[User_Id]}", out AuthenticationHeaderValue headerValueUid)) { Log.Error("Could not Parse User Id from Authentication Header."); return(await Task.FromResult(AuthenticateResult.NoResult())); } try { /* STEP 1. Get the Validation Parameters for our applications JWT Token */ var key = Encoding.ASCII.GetBytes(_appSettings.Secret); /* STEP 2. Create an instance of Jwt token handler */ var handler = new JwtSecurityTokenHandler(); /* STEP 3. Create an instance of Jwt token validation parameters */ TokenValidationParameters validationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, ValidateIssuer = true, ValidateAudience = true, ValidIssuer = _appSettings.Site, ValidAudience = _appSettings.Audience, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateLifetime = true, ClockSkew = TimeSpan.Zero }; /* STEP 4. Get the Data protection service instance */ var protectorProvider = _provider.GetService <IDataProtectionProvider>(); /* STEP 5. create a protector instance */ var protector = protectorProvider.CreateProtector(_dataProtectionKeys.ApplicationUserKey); /* STEP 6. Layer One Unprotect the user id */ var decryptedUid = protector.Unprotect(headerValueUid.Parameter); /* STEP 7. Layer One Unprotect the user token */ var decryptedToken = protector.Unprotect(headerValue.Parameter); /* STEP 8. Create an instance of the user tokenModel */ TokenEntities tokenModel = new TokenEntities(); /* STEP 9 Get the existing token for the user from Database using a scoped request */ using (var scope = _provider.CreateScope()) { var dbContextService = scope.ServiceProvider.GetService <ApplicationDbContext>(); var userToken = dbContextService.Tokens.Include(x => x.User) .FirstOrDefault(ut => ut.UserId == decryptedUid && ut.User.UserName == Request.Cookies[Username] && ut.User.Id == decryptedUid && ut.User.UserRole == "Administrator"); tokenModel = userToken; } /* Step 11. Check if tokenmodel is null */ if (tokenModel == null) { return(await Task.FromResult(AuthenticateResult.Fail("You are not authorized to View this Page"))); } /* STEP 12. Apply second layer of decryption using the key store in the token model */ /* STEP 12.1 Create Protector instance for layer two using token model key */ /* IMPORTANT - If no key exists or key is invalid - exception will be thrown */ IDataProtector layerTwoProtector = protectorProvider.CreateProtector(tokenModel?.EncryptionKeyJwt); string decryptedTokenLayerTwo = layerTwoProtector.Unprotect(decryptedToken); /* STEP 13. Validate the token we received - using validation parameters set in step 3 */ /* IMPORTANT - If the validation fails - the method ValidateToken will throw exception */ var validateToken = handler.ValidateToken(decryptedTokenLayerTwo, validationParameters, out var securityToken); /* STEP 14. Checking Token Signature */ if (!(securityToken is JwtSecurityToken jwtSecurityToken) || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) { return(await Task.FromResult(AuthenticateResult.Fail("Your are not authorized"))); } /* STEP 15. Extract the username from the validated token */ var username = validateToken.Claims.FirstOrDefault(claim => claim.Type == ClaimTypes.NameIdentifier)?.Value; if (Request.Cookies[Username] != username) { return(await Task.FromResult(AuthenticateResult.Fail("You are not authorized to View this Page"))); } /* STEP 16. Get User by their email */ var user = await _userManager.FindByNameAsync(username); /* STEP 17. If user does not exist return authentication failed result */ if (user == null) { return(await Task.FromResult(AuthenticateResult.Fail("You are not authorized to View this Page"))); } /* STEP 18. We need to check if the user belongs to the group of user-roles */ if (!UserRoles.Contains(user.UserRole)) { return(await Task.FromResult(AuthenticateResult.Fail("You are not authorized to View this Page"))); } /* STEP 19. Now we will create an authentication ticket, as the token is valid */ var identity = new ClaimsIdentity(validateToken.Claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return(await Task.FromResult(AuthenticateResult.Success(ticket))); } catch (Exception ex) { Log.Error("An error occurred while seeding the database {Error} {StackTrace} {InnerException} {Source}", ex.Message, ex.StackTrace, ex.InnerException, ex.Source); return(await Task.FromResult(AuthenticateResult.Fail("Your are not authorized"))); } }