/// <summary> /// Custom validation logic for access tokens. /// </summary> /// <param name="result">The validation result so far.</param> /// <returns> /// The validation result /// </returns> public virtual async Task<TokenValidationResult> ValidateAccessTokenAsync(TokenValidationResult result) { if (result.IsError) { return result; } // make sure user is still active (if sub claim is present) var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject); if (subClaim != null) { var principal = Principal.Create("tokenvalidator", result.Claims.ToArray()); if (result.ReferenceTokenId.IsPresent()) { principal.Identities.First().AddClaim(new Claim(JwtClaimTypes.ReferenceTokenId, result.ReferenceTokenId)); } var isActiveCtx = new IsActiveContext(principal, result.Client); await _profile.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { _logger.LogWarning("User marked as not active: {subject}", subClaim.Value); result.IsError = true; result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken; result.Claims = null; return result; } } // make sure client is still active (if client_id claim is present) var clientClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.ClientId); if (clientClaim != null) { var client = await _clients.FindClientByIdAsync(clientClaim.Value); if (client == null || client.Enabled == false) { _logger.LogWarning("Client deleted or disabled: {clientId}", clientClaim.Value); result.IsError = true; result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken; result.Claims = null; return result; } } return result; }
/// <summary> /// This method gets called whenever identity server needs to determine if the user is valid or active (e.g. during token issuance or validation) /// </summary> /// <param name="context">The context.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException">subject</exception> public Task IsActiveAsync(IsActiveContext context) { if (context.Subject == null) throw new ArgumentNullException("subject"); var query = from u in _users where u.Subject == context.Subject.GetSubjectId() select u; var user = query.SingleOrDefault(); context.IsActive = (user != null) && user.Enabled; return Task.FromResult(0); }
public Task IsActiveAsync(IsActiveContext context) { return Task.FromResult(0); }
private async Task<TokenRequestValidationResult> ValidateRefreshTokenRequestAsync(NameValueCollection parameters) { _logger.LogTrace("Start validation of refresh token request"); var refreshTokenHandle = parameters.Get(OidcConstants.TokenRequest.RefreshToken); if (refreshTokenHandle.IsMissing()) { var error = "Refresh token is missing"; LogError(error); await RaiseRefreshTokenRefreshFailureEventAsync(null, error); return Invalid(OidcConstants.TokenErrors.InvalidRequest); } if (refreshTokenHandle.Length > _options.InputLengthRestrictions.RefreshToken) { var error = "Refresh token too long"; LogError(error); await RaiseRefreshTokenRefreshFailureEventAsync(null, error); return Invalid(OidcConstants.TokenErrors.InvalidGrant); } _validatedRequest.RefreshTokenHandle = refreshTokenHandle; ///////////////////////////////////////////// // check if refresh token is valid ///////////////////////////////////////////// var refreshToken = await _refreshTokens.GetAsync(refreshTokenHandle); if (refreshToken == null) { var error = "Refresh token is invalid"; LogWarn(error); await RaiseRefreshTokenRefreshFailureEventAsync(refreshTokenHandle, error); return Invalid(OidcConstants.TokenErrors.InvalidGrant); } ///////////////////////////////////////////// // check if refresh token has expired ///////////////////////////////////////////// if (refreshToken.CreationTime.HasExceeded(refreshToken.LifeTime)) { var error = "Refresh token has expired"; LogWarn(error); await RaiseRefreshTokenRefreshFailureEventAsync(refreshTokenHandle, error); await _refreshTokens.RemoveAsync(refreshTokenHandle); return Invalid(OidcConstants.TokenErrors.InvalidGrant); } ///////////////////////////////////////////// // check if client belongs to requested refresh token ///////////////////////////////////////////// if (_validatedRequest.Client.ClientId != refreshToken.ClientId) { LogError(string.Format("Client {0} tries to refresh token belonging to client {1}", _validatedRequest.Client.ClientId, refreshToken.ClientId)); await RaiseRefreshTokenRefreshFailureEventAsync(refreshTokenHandle, "Invalid client binding"); return Invalid(OidcConstants.TokenErrors.InvalidGrant); } ///////////////////////////////////////////// // check if client still has offline_access scope ///////////////////////////////////////////// if (!_validatedRequest.Client.AllowAccessToAllScopes) { if (!_validatedRequest.Client.AllowedScopes.Contains(Constants.StandardScopes.OfflineAccess)) { var error = "Client does not have access to offline_access scope anymore"; LogError(error); await RaiseRefreshTokenRefreshFailureEventAsync(refreshTokenHandle, error); return Invalid(OidcConstants.TokenErrors.InvalidGrant); } } _validatedRequest.RefreshToken = refreshToken; ///////////////////////////////////////////// // make sure user is enabled ///////////////////////////////////////////// var principal = IdentityServerPrincipal.FromSubjectId(_validatedRequest.RefreshToken.SubjectId, refreshToken.AccessToken.Claims); var isActiveCtx = new IsActiveContext(principal, _validatedRequest.Client); await _profile.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { var error = "User has been disabled: " + _validatedRequest.RefreshToken.SubjectId; LogError(error); await RaiseRefreshTokenRefreshFailureEventAsync(refreshTokenHandle, error); return Invalid(OidcConstants.TokenErrors.InvalidRequest); } _logger.LogInformation("Validation of refresh token request success"); return Valid(); }
private async Task<TokenRequestValidationResult> ValidateAuthorizationCodeRequestAsync(NameValueCollection parameters) { _logger.LogTrace("Start validation of authorization code token request"); ///////////////////////////////////////////// // check if client is authorized for grant type ///////////////////////////////////////////// if (!_validatedRequest.Client.AllowedGrantTypes.ToList().Contains(GrantType.Code) && !_validatedRequest.Client.AllowedGrantTypes.ToList().Contains(GrantType.Hybrid)) { LogError("Client not authorized for code flow"); return Invalid(OidcConstants.TokenErrors.UnauthorizedClient); } ///////////////////////////////////////////// // validate authorization code ///////////////////////////////////////////// var code = parameters.Get(OidcConstants.TokenRequest.Code); if (code.IsMissing()) { var error = "Authorization code is missing."; LogError(error); await RaiseFailedAuthorizationCodeRedeemedEventAsync(null, error); return Invalid(OidcConstants.TokenErrors.InvalidGrant); } if (code.Length > _options.InputLengthRestrictions.AuthorizationCode) { var error = "Authorization code is too long."; LogError(error); await RaiseFailedAuthorizationCodeRedeemedEventAsync(null, error); return Invalid(OidcConstants.TokenErrors.InvalidGrant); } _validatedRequest.AuthorizationCodeHandle = code; var authZcode = await _authorizationCodes.GetAsync(code); if (authZcode == null) { LogError("Invalid authorization code: " + code); await RaiseFailedAuthorizationCodeRedeemedEventAsync(code, "Invalid handle"); return Invalid(OidcConstants.TokenErrors.InvalidGrant); } await _authorizationCodes.RemoveAsync(code); ///////////////////////////////////////////// // populate session id ///////////////////////////////////////////// if (authZcode.SessionId.IsPresent()) { _validatedRequest.SessionId = authZcode.SessionId; } ///////////////////////////////////////////// // validate client binding ///////////////////////////////////////////// if (authZcode.Client.ClientId != _validatedRequest.Client.ClientId) { LogError(string.Format("Client {0} is trying to use a code from client {1}", _validatedRequest.Client.ClientId, authZcode.Client.ClientId)); await RaiseFailedAuthorizationCodeRedeemedEventAsync(code, "Invalid client binding"); return Invalid(OidcConstants.TokenErrors.InvalidGrant); } ///////////////////////////////////////////// // validate code expiration ///////////////////////////////////////////// if (authZcode.CreationTime.HasExceeded(_validatedRequest.Client.AuthorizationCodeLifetime)) { var error = "Authorization code is expired"; LogError(error); await RaiseFailedAuthorizationCodeRedeemedEventAsync(code, error); return Invalid(OidcConstants.TokenErrors.InvalidGrant); } _validatedRequest.AuthorizationCode = authZcode; ///////////////////////////////////////////// // validate redirect_uri ///////////////////////////////////////////// var redirectUri = parameters.Get(OidcConstants.TokenRequest.RedirectUri); if (redirectUri.IsMissing()) { var error = "Redirect URI is missing."; LogError(error); await RaiseFailedAuthorizationCodeRedeemedEventAsync(code, error); return Invalid(OidcConstants.TokenErrors.UnauthorizedClient); } if (redirectUri.Equals(_validatedRequest.AuthorizationCode.RedirectUri, StringComparison.Ordinal) == false) { var error = "Invalid redirect_uri: " + redirectUri; LogError(error); await RaiseFailedAuthorizationCodeRedeemedEventAsync(code, error); return Invalid(OidcConstants.TokenErrors.UnauthorizedClient); } ///////////////////////////////////////////// // validate scopes are present ///////////////////////////////////////////// if (_validatedRequest.AuthorizationCode.RequestedScopes == null || !_validatedRequest.AuthorizationCode.RequestedScopes.Any()) { var error = "Authorization code has no associated scopes."; LogError(error); await RaiseFailedAuthorizationCodeRedeemedEventAsync(code, error); return Invalid(OidcConstants.TokenErrors.InvalidRequest); } ///////////////////////////////////////////// // make sure user is enabled ///////////////////////////////////////////// var isActiveCtx = new IsActiveContext(_validatedRequest.AuthorizationCode.Subject, _validatedRequest.Client); await _profile.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { var error = "User has been disabled: " + _validatedRequest.AuthorizationCode.Subject; LogError(error); await RaiseFailedAuthorizationCodeRedeemedEventAsync(code, error); return Invalid(OidcConstants.TokenErrors.InvalidRequest); } _logger.LogInformation("Validation of authorization code token request success"); await RaiseSuccessfulAuthorizationCodeRedeemedEventAsync(); return Valid(); }
/// <summary> /// Custom validation logic for identity tokens. /// </summary> /// <param name="result">The validation result so far.</param> /// <returns> /// The validation result /// </returns> public virtual async Task<TokenValidationResult> ValidateIdentityTokenAsync(TokenValidationResult result) { // make sure user is still active (if sub claim is present) var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject); if (subClaim != null) { var principal = Principal.Create("tokenvalidator", result.Claims.ToArray()); var isActiveCtx = new IsActiveContext(principal, result.Client); await _profile.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { _logger.LogWarning("User marked as not active: {subject}", subClaim.Value); result.IsError = true; result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken; result.Claims = null; return result; } } return result; }
public Task IsActiveAsync(IsActiveContext context) { context.IsActive = true; return Task.FromResult(0); }
internal async Task<InteractionResponse> ProcessLoginAsync(ValidatedAuthorizeRequest request) { if (request.PromptMode == OidcConstants.PromptModes.Login) { // remove prompt so when we redirect back in from login page // we won't think we need to force a prompt again request.Raw.Remove(OidcConstants.AuthorizeRequest.Prompt); _logger.LogInformation("Redirecting to login page because of prompt=login"); return new InteractionResponse() { IsLogin = true }; } // unauthenticated user var isAuthenticated = request.Subject.Identity.IsAuthenticated; // user de-activated bool isActive = false; if (isAuthenticated) { var isActiveCtx = new IsActiveContext(request.Subject, request.Client); await _profile.IsActiveAsync(isActiveCtx); isActive = isActiveCtx.IsActive; } if (!isAuthenticated || !isActive) { if (!isAuthenticated) _logger.LogInformation("User is not authenticated."); else if (!isActive) _logger.LogInformation("User is not active."); // prompt=none means user must be signed in already if (request.PromptMode == OidcConstants.PromptModes.None) { _logger.LogInformation("prompt=none was requested but user is not authenticated/active."); return new InteractionResponse { Error = new AuthorizeError { ErrorType = ErrorTypes.Client, Error = OidcConstants.AuthorizeErrors.LoginRequired, ResponseMode = request.ResponseMode, ErrorUri = request.RedirectUri, State = request.State } }; } return new InteractionResponse() { IsLogin = true }; } // check current idp var currentIdp = request.Subject.GetIdentityProvider(); // check if idp login hint matches current provider var idp = request.GetIdP(); if (idp.IsPresent()) { if (idp != currentIdp) { _logger.LogInformation("Current IdP is not the requested IdP. Redirecting to login"); _logger.LogInformation("Current: {0} -- Requested: {1}", currentIdp, idp); return new InteractionResponse() { IsLogin = true }; } } // check authentication freshness if (request.MaxAge.HasValue) { var authTime = request.Subject.GetAuthenticationTime(); if (DateTimeOffsetHelper.UtcNow > authTime.AddSeconds(request.MaxAge.Value)) { _logger.LogInformation("Requested MaxAge exceeded."); return new InteractionResponse() { IsLogin = true }; } } // check idp restrictions if (request.Client.IdentityProviderRestrictions != null && request.Client.IdentityProviderRestrictions.Any()) { if (!request.Client.IdentityProviderRestrictions.Contains(currentIdp)) { _logger.LogWarning("User is logged in with idp: {0}, but idp not in client restriction list.", currentIdp); return new InteractionResponse() { IsLogin = true }; } } // check if idp is local and local logins are not allowed if (currentIdp == Constants.BuiltInIdentityProvider) { if (_options.AuthenticationOptions.EnableLocalLogin == false || request.Client.EnableLocalLogin == false) { _logger.LogWarning("User is logged in with local idp, but local logins not enabled."); return new InteractionResponse() { IsLogin = true }; } } return new InteractionResponse(); }