protected override async Task <AuthenticationTicket> AuthenticateCoreAsync() { string requestToken = null; string authorization = Request.Headers["Authorization"]; if (string.IsNullOrEmpty(authorization)) { return(null); } if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { requestToken = authorization.Substring("Bearer ".Length).Trim(); } if (string.IsNullOrEmpty(requestToken)) { return(null); } TokenValidator tokenValidator = Context.Environment.ResolveDependency <TokenValidator>(); TokenValidationResult result = await tokenValidator.ValidateAccessTokenAsync(requestToken, Options.ExpectedScope); if (result.IsError) { return(null); } AuthenticationProperties properties = new AuthenticationProperties(); ClaimsIdentity identity = new ClaimsIdentity(result.Claims, Options.AuthenticationType); return(new AuthenticationTicket(identity, properties)); }
internal async Task <IHttpActionResult> ProcessRequest(NameValueCollection parameters) { var token = parameters.Get("token"); if (token.IsMissing()) { var error = "token is missing"; Logger.Error(error); await RaiseFailureEventAsync(error); return(BadRequest(_localizationService.GetMessage(MessageIds.MissingToken))); } var result = await _validator.ValidateAccessTokenAsync(token, parameters.Get("expectedScope")); if (result.IsError) { Logger.Info("Returning error: " + result.Error); await RaiseFailureEventAsync(result.Error); return(BadRequest(result.Error)); } var response = result.Claims.ToClaimsDictionary(); Logger.Info("End access token validation request"); await RaiseSuccessEventAsync(); return(Json(response)); }
public async Task <IHttpActionResult> Get() { Logger.Info("Start access token validation request"); if (!_options.Endpoints.AccessTokenValidationEndpoint.IsEnabled) { Logger.Warn("Endpoint is disabled. Aborting"); return(NotFound()); } var parameters = Request.RequestUri.ParseQueryString(); var token = parameters.Get("token"); if (token.IsMissing()) { Logger.Error("token is missing."); return(BadRequest(Messages.MissingToken)); } var result = await _validator.ValidateAccessTokenAsync(token, parameters.Get("expectedScope")); if (result.IsError) { Logger.Info("Returning error: " + result.Error); return(BadRequest(result.Error)); } var response = result.Claims.ToClaimsDictionary(); Logger.Debug(JsonConvert.SerializeObject(response, Formatting.Indented)); Logger.Info("Returning access token claims"); return(Json(response)); }
public async Task <IHttpActionResult> GetUserInfo(HttpRequestMessage request) { Logger.Info("Start userinfo request"); if (!_options.Endpoints.UserInfoEndpoint.IsEnabled) { Logger.Warn("Endpoint is disabled. Aborting"); return(NotFound()); } var tokenUsageResult = await _tokenUsageValidator.ValidateAsync(request); if (tokenUsageResult.TokenFound == false) { return(Error(Constants.ProtectedResourceErrors.InvalidToken)); } var tokenResult = await _tokenValidator.ValidateAccessTokenAsync( tokenUsageResult.Token, Constants.StandardScopes.OpenId); if (tokenResult.IsError) { return(Error(tokenResult.Error)); } // pass scopes/claims to profile service var subject = tokenResult.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject).Value; var scopes = tokenResult.Claims.Where(c => c.Type == Constants.ClaimTypes.Scope).Select(c => c.Value); var payload = await _generator.ProcessAsync(subject, scopes); return(new UserInfoResult(payload)); }
public async Task <CustomGrantValidationResult> ValidateAsync(ValidatedTokenRequest request) { CustomGrantValidationResult grantResult = null; var param = request.Raw.Get("token"); if (string.IsNullOrWhiteSpace(param)) { grantResult = new CustomGrantValidationResult(Constants.TokenErrors.InvalidRequest); } var result = _validator.ValidateAccessTokenAsync(param).Result; if (result.IsError) { grantResult = new CustomGrantValidationResult(result.Error); } var subjectClaim = result.Claims.FirstOrDefault(x => x.Type == "sub"); if (subjectClaim == null) { grantResult = new CustomGrantValidationResult(Constants.TokenErrors.InvalidRequest); } if (grantResult == null) { grantResult = new CustomGrantValidationResult(subjectClaim.Value, "access_token"); } return(await Task.FromResult(grantResult)); }
public async Task <IHttpActionResult> GetUserInfo(HttpRequestMessage request) { Logger.Info("Start userinfo request"); var tokenUsageResult = await _tokenUsageValidator.ValidateAsync(request.GetOwinContext()); if (tokenUsageResult.TokenFound == false) { var error = "No token found."; Logger.Error(error); await RaiseFailureEventAsync(error); return(Error(Constants.ProtectedResourceErrors.InvalidToken)); } Logger.Info("Token found: " + tokenUsageResult.UsageType.ToString()); var tokenResult = await _tokenValidator.ValidateAccessTokenAsync( tokenUsageResult.Token, Constants.StandardScopes.OpenId); if (tokenResult.IsError) { Logger.Error(tokenResult.Error); await RaiseFailureEventAsync(tokenResult.Error); return(Error(tokenResult.Error)); } // pass scopes/claims to profile service var tokenClaims = tokenResult.Claims; if (!tokenClaims.Any(x => x.Type == Constants.ClaimTypes.Subject)) { var error = "Token contains no sub claim"; Logger.Error(error); await RaiseFailureEventAsync(error); return(Error(Constants.ProtectedResourceErrors.InvalidToken)); } var userClaims = tokenClaims.Where(x => !Constants.OidcProtocolClaimTypes.Contains(x.Type) || Constants.AuthenticateResultClaimTypes.Contains(x.Type)); var scopes = tokenResult.Claims.Where(c => c.Type == Constants.ClaimTypes.Scope).Select(c => c.Value); var payload = await _generator.ProcessAsync(userClaims, scopes, tokenResult.Client); Logger.Info("End userinfo request"); await RaiseSuccessEventAsync(); return(new UserInfoResult(payload)); }
public async Task <IHttpActionResult> Get() { Logger.Info("Start access token validation request"); if (!_options.Endpoints.EnableAccessTokenValidationEndpoint) { var error = "Endpoint is disabled. Aborting"; Logger.Warn(error); RaiseFailureEvent(error); return(NotFound()); } var parameters = Request.RequestUri.ParseQueryString(); var token = parameters.Get("token"); if (token.IsMissing()) { var error = "token is missing"; Logger.Error(error); RaiseFailureEvent(error); return(BadRequest(_localizationService.GetMessage(MessageIds.MissingToken))); } var result = await _validator.ValidateAccessTokenAsync(token, parameters.Get("expectedScope")); if (result.IsError) { Logger.Info("Returning error: " + result.Error); RaiseFailureEvent(result.Error); return(BadRequest(result.Error)); } var response = result.Claims.ToClaimsDictionary(); Logger.Info("End access token validation request"); RaiseSuccessEvent(); return(Json(response)); }
Task <CustomGrantValidationResult> ICustomGrantValidator.ValidateAsync(ValidatedTokenRequest request) { CustomGrantValidationResult grantResult = null; var param = request.Raw.Get("token"); if (string.IsNullOrWhiteSpace(param)) { grantResult = new CustomGrantValidationResult(Constants.TokenErrors.InvalidRequest); } var result = _validator.ValidateAccessTokenAsync(param).Result; if (result.IsError) { grantResult = new CustomGrantValidationResult(result.Error); } var subjectClaim = result.Claims.FirstOrDefault(x => x.Type == "sub"); if (subjectClaim == null) { grantResult = new CustomGrantValidationResult(Constants.TokenErrors.InvalidRequest); } if (grantResult == null) { var subject = subjectClaim.Value; grantResult = new CustomGrantValidationResult(subject, "access_token", new Claim[] { new Claim(P5.IdentityServerCore.Constants.ClaimTypes.AccountGuid, Guid.NewGuid().ToString()), }); } return(Task.FromResult(grantResult)); }
/// <summary>Validates the Custom grant request</summary> /// <param name="request"></param> /// <returns></returns> public async Task <CustomGrantValidationResult> ValidateAsync(ValidatedTokenRequest request) { var userAccessToken = request.Raw.Get("access_token"); var clientRefererToken = request.Raw.Get("client_referer"); if (string.IsNullOrWhiteSpace(userAccessToken)) { return(new CustomGrantValidationResult(Constants.TokenErrors.InvalidRequest)); } if (string.IsNullOrWhiteSpace(clientRefererToken)) { return(new CustomGrantValidationResult(Constants.TokenErrors.InvalidRequest)); } var result = await validator.ValidateAccessTokenAsync(userAccessToken).ConfigureAwait(false); if (result.IsError || result.Claims == null) { return(new CustomGrantValidationResult(Constants.TokenErrors.InvalidRequest)); } var subjectClaim = result.Claims.FirstOrDefault(x => x.Type == Constants.ClaimTypes.Subject); if (subjectClaim == null) { return(new CustomGrantValidationResult(Constants.TokenErrors.InvalidRequest)); } var client = result.Client; if (client == null || !client.RedirectUris.Any(x => x.IndexOf(clientRefererToken, StringComparison.OrdinalIgnoreCase) >= 0)) { return(new CustomGrantValidationResult(Constants.TokenErrors.InvalidRequest)); } return(new CustomGrantValidationResult(subjectClaim.Value, "access_token")); }
public async Task Create_and_Validate_JWT_AccessToken_Valid() { var tokenService = new DefaultTokenService( null, _settings, null, null); var token = new Token(Constants.TokenTypes.AccessToken) { Audience = string.Format(Constants.AccessTokenAudience, _settings.IssuerUri), Issuer = _settings.IssuerUri, Lifetime = 60, Client = await _clients.FindClientByIdAsync("client") }; var jwt = await tokenService.CreateSecurityTokenAsync(token); var validator = new TokenValidator(_settings, null, null, new DebugLogger()); var result = await validator.ValidateAccessTokenAsync(jwt); Assert.IsFalse(result.IsError); Assert.IsNotNull(result.Claims); }
public async Task <IHttpActionResult> Get(HttpRequestMessage request) { Logger.Info("Start userinfo request"); if (!_options.Endpoints.UserInfoEndpoint.IsEnabled) { Logger.Warn("Endpoint is disabled. Aborting"); return(NotFound()); } var authorizationHeader = request.Headers.Authorization; if (authorizationHeader == null || !authorizationHeader.Scheme.Equals(Constants.TokenTypes.Bearer) || authorizationHeader.Parameter.IsMissing()) { return(Error(Constants.ProtectedResourceErrors.InvalidToken)); } var result = await _tokenValidator.ValidateAccessTokenAsync( authorizationHeader.Parameter, Constants.StandardScopes.OpenId); if (result.IsError) { return(Error(result.Error)); } // pass scopes/claims to profile service var subject = result.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject).Value; var scopes = result.Claims.Where(c => c.Type == Constants.ClaimTypes.Scope).Select(c => c.Value); var payload = await _generator.ProcessAsync(subject, scopes); return(new UserInfoResult(payload)); }
public override async Task <CompleteRegistrationRequestValidationResult> Validate(NameValueCollection parameters, string accessToken = null) { Logger.LogDebug($"[{nameof(CompleteRegistrationRequestValidator)}] Started trusted device registration request validation."); // The access token needs to be valid and have at least the openid scope. var tokenValidationResult = await TokenValidator.ValidateAccessTokenAsync(accessToken, IdentityServerConstants.StandardScopes.OpenId); if (tokenValidationResult.IsError) { return(Error(tokenValidationResult.Error, "Provided access token is not valid.")); } // The access token must have at lease a 'sub' and 'client_id' claim. var claimsToValidate = new[] { JwtClaimTypes.Subject, JwtClaimTypes.ClientId }; foreach (var claim in claimsToValidate) { var claimValue = tokenValidationResult.Claims.SingleOrDefault(x => x.Type == claim)?.Value; if (string.IsNullOrWhiteSpace(claimValue)) { return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken, $"Access token must contain the '{claim}' claim.")); } } // Get 'code' parameter and retrieve it from the store. var code = parameters.Get(RegistrationRequestParameters.Code); if (string.IsNullOrWhiteSpace(code)) { return(Error(OidcConstants.TokenErrors.InvalidGrant, $"Parameter '{nameof(RegistrationRequestParameters.Code)}' is not specified.")); } var authorizationCode = await CodeChallengeStore.GetAuthorizationCode(code); if (authorizationCode == null) { return(Error(OidcConstants.TokenErrors.InvalidGrant, "Authorization code is invalid.")); } // Validate that the consumer specified all required parameters. var parametersToValidate = new List <string> { RegistrationRequestParameters.CodeSignature, RegistrationRequestParameters.CodeVerifier, RegistrationRequestParameters.DeviceId, RegistrationRequestParameters.DevicePlatform }; if (authorizationCode.InteractionMode == InteractionMode.Fingerprint) { parametersToValidate.Add(RegistrationRequestParameters.PublicKey); } if (authorizationCode.InteractionMode == InteractionMode.Pin) { parametersToValidate.Add(RegistrationRequestParameters.Pin); } var otpAuthenticatedValue = tokenValidationResult.Claims.FirstOrDefault(x => x.Type == BasicClaimTypes.OtpAuthenticated)?.Value; var otpAuthenticated = !string.IsNullOrWhiteSpace(otpAuthenticatedValue) && bool.Parse(otpAuthenticatedValue); if (!otpAuthenticated) { parametersToValidate.Add(RegistrationRequestParameters.OtpCode); } foreach (var parameter in parametersToValidate) { var parameterValue = parameters.Get(parameter); if (string.IsNullOrWhiteSpace(parameterValue)) { return(Error(OidcConstants.TokenErrors.InvalidGrant, $"Parameter '{parameter}' is not specified.")); } } var isValidPlatform = Enum.TryParse(typeof(DevicePlatform), parameters.Get(RegistrationRequestParameters.DevicePlatform), out var platform); if (!isValidPlatform) { return(Error(OidcConstants.TokenErrors.InvalidRequest, $"Parameter '{nameof(RegistrationRequestParameters.DevicePlatform)}' does not have a valid value.")); } // Load client and validate that it allows the 'password' flow. var client = await LoadClient(tokenValidationResult); if (client == null) { return(Error(OidcConstants.AuthorizeErrors.UnauthorizedClient, $"Client is unknown or not enabled.")); } if (client.AllowedGrantTypes.Except(Constants.RequiredGrantTypes).Any()) { return(Error(OidcConstants.AuthorizeErrors.UnauthorizedClient, $"Client not authorized any of the following grant types: {string.Join(", ", Constants.RequiredGrantTypes)}")); } // Validate authorization code against code verifier given by the client. var codeVerifier = parameters.Get(RegistrationRequestParameters.CodeVerifier); var authorizationCodeValidationResult = await ValidateAuthorizationCode(code, authorizationCode, codeVerifier, parameters.Get(RegistrationRequestParameters.DeviceId), client); if (authorizationCodeValidationResult.IsError) { return(Error(authorizationCodeValidationResult.Error, authorizationCodeValidationResult.ErrorDescription)); } // Validate given public key against signature for fingerprint. string publicKey = null; if (authorizationCode.InteractionMode == InteractionMode.Fingerprint) { publicKey = parameters.Get(RegistrationRequestParameters.PublicKey); var codeSignature = parameters.Get(RegistrationRequestParameters.CodeSignature); var publicKeyValidationResult = ValidateSignature(publicKey, code, codeSignature); if (publicKeyValidationResult.IsError) { return(Error(publicKeyValidationResult.Error, publicKeyValidationResult.ErrorDescription)); } } // Find requested scopes. var requestedScopes = tokenValidationResult.Claims.Where(claim => claim.Type == JwtClaimTypes.Scope).Select(claim => claim.Value).ToList(); // Create principal from incoming access token excluding protocol claims. var claims = tokenValidationResult.Claims.Where(x => !Constants.ProtocolClaimsFilter.Contains(x.Type)); var principal = Principal.Create("TrustedDevice", claims.ToArray()); var userId = tokenValidationResult.Claims.Single(x => x.Type == JwtClaimTypes.Subject).Value; // Validate OTP code, if needed. if (!otpAuthenticated) { var totpResult = await TotpService.Verify( principal : principal, code : parameters.Get(RegistrationRequestParameters.OtpCode), purpose : Constants.TrustedDeviceOtpPurpose(userId, authorizationCode.DeviceId) ); if (!totpResult.Success) { return(Error(totpResult.Error)); } } // Finally return result. return(new CompleteRegistrationRequestValidationResult { IsError = false, Client = client, DeviceId = authorizationCode.DeviceId, DeviceName = parameters.Get(RegistrationRequestParameters.DeviceName), DevicePlatform = (DevicePlatform)platform, InteractionMode = authorizationCode.InteractionMode, Pin = parameters.Get(RegistrationRequestParameters.Pin), Principal = principal, PublicKey = publicKey, RequestedScopes = requestedScopes, UserId = userId }); }
public virtual async Task ValidateAsync(ExtensionGrantValidationContext context) { var accessToken = context.Request.Raw["access_token"]; if (accessToken.IsNullOrWhiteSpace()) { context.Result = new GrantValidationResult { IsError = true, Error = "invalid_access_token" }; return; } var result = await TokenValidator.ValidateAccessTokenAsync(accessToken); if (result.IsError) { context.Result = new GrantValidationResult { IsError = true, Error = result.Error, ErrorDescription = result.ErrorDescription }; return; } using (CurrentPrincipalAccessor.Change(result.Claims)) { if (!Guid.TryParse(context.Request.Raw["LinkUserId"], out var linkUserId)) { context.Result = new GrantValidationResult { IsError = true, Error = "invalid_link_user_id" }; return; } Guid?linkTenantId = null; if (!context.Request.Raw["LinkTenantId"].IsNullOrWhiteSpace()) { if (!Guid.TryParse(context.Request.Raw["LinkTenantId"], out var parsedGuid)) { context.Result = new GrantValidationResult { IsError = true, Error = "invalid_link_tenant_id" }; return; } linkTenantId = parsedGuid; } var isLinked = await IdentityLinkUserManager.IsLinkedAsync( new IdentityLinkUserInfo(CurrentUser.GetId(), CurrentTenant.Id), new IdentityLinkUserInfo(linkUserId, linkTenantId), true); if (isLinked) { using (CurrentTenant.Change(linkTenantId)) { var user = await UserManager.GetByIdAsync(linkUserId); var sub = await UserManager.GetUserIdAsync(user); var additionalClaims = new List <Claim>(); await AddCustomClaimsAsync(additionalClaims, user, context); context.Result = new GrantValidationResult( sub, GrantType, additionalClaims.ToArray() ); } } else { context.Result = new GrantValidationResult { IsError = true, Error = Localizer["TheTargetUserIsNotLinkedToYou"] }; } } }
public override async Task <InitRegistrationRequestValidationResult> Validate(NameValueCollection parameters, string accessToken = null) { Logger.LogDebug($"{nameof(InitRegistrationRequestValidator)}: Started trusted device registration request validation."); // The access token needs to be valid and have at least the openid scope. var tokenValidationResult = await TokenValidator.ValidateAccessTokenAsync(accessToken, IdentityServerConstants.StandardScopes.OpenId); if (tokenValidationResult.IsError) { return(Error(tokenValidationResult.Error, "Provided access token is not valid.")); } // The access token must have a 'sub' and 'client_id' claim. var claimsToValidate = new[] { JwtClaimTypes.Subject, JwtClaimTypes.ClientId }; foreach (var claim in claimsToValidate) { var claimValue = tokenValidationResult.Claims.SingleOrDefault(x => x.Type == claim)?.Value; if (string.IsNullOrWhiteSpace(claimValue)) { return(Error(OidcConstants.ProtectedResourceErrors.InvalidToken, $"Access token must contain the '{claim}' claim.")); } } // Validate that the consumer specified all required parameters. var parametersToValidate = new[] { RegistrationRequestParameters.CodeChallenge, RegistrationRequestParameters.DeviceId, RegistrationRequestParameters.Mode }; foreach (var parameter in parametersToValidate) { var parameterValue = parameters.Get(parameter); if (string.IsNullOrWhiteSpace(parameterValue)) { return(Error(OidcConstants.TokenErrors.InvalidRequest, $"Parameter '{parameter}' is not specified.")); } } var isValidInteraction = Enum.TryParse <InteractionMode>(parameters.Get(RegistrationRequestParameters.Mode), ignoreCase: true, out var mode); if (!isValidInteraction) { return(Error(OidcConstants.TokenErrors.InvalidRequest, $"Parameter '{RegistrationRequestParameters.Mode}' used for registration is not valid.")); } var deliveryChannelParameter = parameters.Get(RegistrationRequestParameters.DeliveryChannel) ?? nameof(TotpDeliveryChannel.Sms); var isValidDeliveryChannel = Enum.TryParse <TotpDeliveryChannel>(deliveryChannelParameter, ignoreCase: true, out var deliveryChannel); if (!isValidDeliveryChannel) { return(Error(OidcConstants.TokenErrors.InvalidRequest, $"Parameter '{RegistrationRequestParameters.DeliveryChannel}' is not valid.")); } if (deliveryChannel is not TotpDeliveryChannel.Sms and not TotpDeliveryChannel.Viber) { return(Error(OidcConstants.TokenErrors.InvalidRequest, $"Allowed values for parameter '{RegistrationRequestParameters.DeliveryChannel}' are {nameof(TotpDeliveryChannel.Sms)} and {nameof(TotpDeliveryChannel.Viber)}.")); } // Load client and validate that it allows the 'password' flow. var client = await LoadClient(tokenValidationResult); if (client == null) { return(Error(OidcConstants.AuthorizeErrors.UnauthorizedClient, "Client is unknown or not enabled.")); } if (client.AllowedGrantTypes.Except(Constants.RequiredGrantTypes).Any()) { return(Error(OidcConstants.AuthorizeErrors.UnauthorizedClient, $"Client not authorized any of the following grant types: {string.Join(", ", Constants.RequiredGrantTypes)}")); } // Find requested scopes. var requestedScopes = tokenValidationResult.Claims.Where(claim => claim.Type == JwtClaimTypes.Scope).Select(claim => claim.Value).ToList(); // Create principal from incoming access token excluding protocol claims. var claims = tokenValidationResult.Claims.Where(x => !Constants.ProtocolClaimsFilter.Contains(x.Type)); var principal = Principal.Create("TrustedDevice", claims.ToArray()); var userId = tokenValidationResult.Claims.Single(x => x.Type == JwtClaimTypes.Subject).Value; // Finally return result. return(new InitRegistrationRequestValidationResult { IsError = false, Client = client, CodeChallenge = parameters.Get(RegistrationRequestParameters.CodeChallenge), DeviceId = parameters.Get(RegistrationRequestParameters.DeviceId), InteractionMode = mode, Principal = principal, RequestedScopes = requestedScopes, UserId = userId, DeliveryChannel = deliveryChannel }); }