public async Task When_Passing_Expired_RefreshToken_Then_Result_Should_Be_Returned() { var parameter = new IntrospectionParameter { TokenTypeHint = CoreConstants.StandardTokenTypeHintNames.RefreshToken, Token = "token" }; var grantedToken = new GrantedToken { Scope = "scope", ClientId = "client_id", IdTokenPayLoad = new JwtPayload { { OpenIdClaimTypes.Subject, "tester" }, { StandardClaimNames.Audiences, new[] { "audience" } } }, CreateDateTime = DateTimeOffset.UtcNow.AddYears(-1), ExpiresIn = 0 }; _tokenStoreStub.Setup(a => a.GetRefreshToken(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync(() => grantedToken); var response = await _postIntrospectionAction .Execute(parameter, CancellationToken.None) .ConfigureAwait(false) as Option <OauthIntrospectionResponse> .Result; var result = response.Item; Assert.False(result.Active); }
public async Task When_Passing_Active_AccessToken_Then_Result_Should_Be_Returned() { const string clientId = "client_id"; const string subject = "subject"; const string audience = "audience"; var audiences = new[] { audience }; var parameter = new IntrospectionParameter { TokenTypeHint = CoreConstants.StandardTokenTypeHintNames.AccessToken, Token = "token" }; var grantedToken = new GrantedToken { Scope = "scope", ClientId = clientId, IdTokenPayLoad = new JwtPayload { { OpenIdClaimTypes.Subject, subject }, { StandardClaimNames.Audiences, audiences } }, CreateDateTime = DateTimeOffset.UtcNow, ExpiresIn = 20000 }; _tokenStoreStub.Setup(a => a.GetAccessToken(It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns(() => Task.FromResult(grantedToken)); var response = await _postIntrospectionAction .Execute(parameter, CancellationToken.None) .ConfigureAwait(false) as Option <OauthIntrospectionResponse> .Result; var result = response.Item; Assert.True(result.Active); Assert.Equal(audience, result.Audience); Assert.Equal(subject, result.Subject); }
private AuthenticateInstruction CreateAuthenticateInstruction( IntrospectionParameter introspectionParameter, AuthenticationHeaderValue authenticationHeaderValue) { var result = new AuthenticateInstruction { ClientAssertion = introspectionParameter.ClientAssertion, ClientAssertionType = introspectionParameter.ClientAssertionType, ClientIdFromHttpRequestBody = introspectionParameter.ClientId, ClientSecretFromHttpRequestBody = introspectionParameter.ClientSecret }; if (authenticationHeaderValue != null && !string.IsNullOrWhiteSpace(authenticationHeaderValue.Parameter)) { var parameters = GetParameters(authenticationHeaderValue.Parameter); if (parameters != null && parameters.Count() == 2) { result.ClientIdFromAuthorizationHeader = parameters[0]; result.ClientSecretFromAuthorizationHeader = parameters[1]; } } return(result); }
public string GetPayload(IntrospectionParameter parameter, AuthenticationHeaderValue authenticationHeaderValue) { if (parameter == null) { throw new ArgumentNullException(nameof(parameter)); } var jsonObj = new JObject(); jsonObj.Add("token", parameter.Token); jsonObj.Add("token_type_hint", parameter.Token); jsonObj.Add("client_id", parameter.ClientId); jsonObj.Add("client_secret", parameter.ClientSecret); jsonObj.Add("client_assertion", parameter.ClientAssertion); jsonObj.Add("client_assertion_type", parameter.ClientAssertionType); var clientId = GetClientId(authenticationHeaderValue); if (string.IsNullOrWhiteSpace(clientId)) { clientId = parameter.ClientId; } var result = new Payload { Authorization = authenticationHeaderValue, Content = jsonObj, ClientId = clientId }; return(JsonConvert.SerializeObject(result)); }
public IntrospectionRequestReceived(string id, string processId, IntrospectionParameter parameter, AuthenticationHeaderValue authHeaderValue, int order) { Id = id; ProcessId = processId; Parameter = parameter; AuthenticationHeader = authHeaderValue; Order = order; }
public async Task When_Passing_Active_AccessToken_Then_Result_Should_Be_Returned() { // ARRANGE InitializeFakeObjects(); const string clientId = "client_id"; const string subject = "subject"; const string audience = "audience"; var authenticationHeaderValue = new AuthenticationHeaderValue("Basic", "ClientId:ClientSecret".Base64Encode()); var audiences = new[] { audience }; var parameter = new IntrospectionParameter { TokenTypeHint = Constants.StandardTokenTypeHintNames.RefreshToken, Token = "token" }; var client = new AuthenticationResult(new Core.Common.Models.Client { ClientId = clientId }, null); var grantedToken = new GrantedToken { ClientId = clientId, IdTokenPayLoad = new JwsPayload { { Jwt.Constants.StandardResourceOwnerClaimNames.Subject, subject }, { StandardClaimNames.Audiences, audiences } }, CreateDateTime = DateTime.UtcNow, ExpiresIn = 20000 }; _authenticateClientStub.Setup(a => a.AuthenticateAsync(It.IsAny <AuthenticateInstruction>(), null)) .Returns(Task.FromResult(client)); _tokenStoreStub.Setup(a => a.GetRefreshToken(It.IsAny <string>())) .Returns(() => Task.FromResult((GrantedToken)null)); _tokenStoreStub.Setup(a => a.GetAccessToken(It.IsAny <string>())) .Returns(() => Task.FromResult(grantedToken)); // ACT var result = await _postIntrospectionAction.Execute(parameter, authenticationHeaderValue, null); // ASSERTS Assert.NotNull(result); Assert.True(result.Active); Assert.True(result.Audience == audience); Assert.True(result.Subject == subject); }
public void When_No_Token_Is_Specified_Then_Exception_Is_Thrown() { // ARRANGE InitializeFakeObjects(); var parameter = new IntrospectionParameter(); // ACT & ASSERT var exception = Assert.Throws <IdentityServerException>(() => _introspectionParameterValidator.Validate(parameter)); Assert.True(exception.Code == ErrorCodes.InvalidRequestCode); Assert.True(exception.Message == string.Format(ErrorDescriptions.MissingParameter, Constants.IntrospectionRequestNames.Token)); }
public void When_Passing_Valid_Parameter_To_PostIntrospection_Then_Operation_Is_Called() { // ARRANGE InitializeFakeObjects(); var parameter = new IntrospectionParameter(); // ACT _introspectionActions.PostIntrospection(parameter, null); // ASSERT _postIntrospectionActionStub.Verify(p => p.Execute(It.IsAny <IntrospectionParameter>(), It.IsAny <AuthenticationHeaderValue>())); }
public async Task When_Client_Cannot_Be_Authenticated_Then_Exception_Is_Thrown() { // ARRANGE InitializeFakeObjects(); var parameter = new IntrospectionParameter(); _authenticateClientStub.Setup(a => a.AuthenticateAsync(It.IsAny <AuthenticateInstruction>())) .Returns(Task.FromResult(new AuthenticationResult(null, null))); // ACT & ASSERT var exception = await Assert.ThrowsAsync <IdentityServerException>(() => _postIntrospectionAction.Execute(parameter, null)); Assert.True(exception.Code == ErrorCodes.InvalidClient); }
public void When_Passing_Valid_Parameter_Then_No_Exception_Is_Thrown() { // ARRANGE InitializeFakeObjects(); var parameter = new IntrospectionParameter { Token = "token" }; // ACT var exception = Record.Exception(() => _introspectionParameterValidator.Validate(parameter)); // ASSERT Assert.Null(exception); }
public void Validate(IntrospectionParameter introspectionParameter) { if (introspectionParameter == null) { throw new ArgumentNullException(nameof(introspectionParameter)); } // Read this RFC for more information if (string.IsNullOrWhiteSpace(introspectionParameter.Token)) { throw new IdentityServerException( ErrorCodes.InvalidRequestCode, string.Format(ErrorDescriptions.MissingParameter, Constants.IntrospectionRequestNames.Token)); } }
public async Task WhenAccessTokenCannotBeExtractedThenTokenIsInactive() { var parameter = new IntrospectionParameter { ClientId = "test", ClientSecret = "test", TokenTypeHint = CoreConstants.StandardTokenTypeHintNames.AccessToken, Token = "token" }; _tokenStoreStub.Setup(a => a.GetAccessToken(It.IsAny <string>(), It.IsAny <CancellationToken>())) .ReturnsAsync(() => null); var response = await _postIntrospectionAction.Execute(parameter, CancellationToken.None) .ConfigureAwait(false) as Option <OauthIntrospectionResponse> .Result; Assert.False(response.Item.Active); }
public async Task <IntrospectionResult> PostIntrospection(IntrospectionParameter introspectionParameter, AuthenticationHeaderValue authenticationHeaderValue) { if (introspectionParameter == null) { throw new ArgumentNullException(nameof(introspectionParameter)); } var processId = Guid.NewGuid().ToString(); try { _eventPublisher.Publish(new IntrospectionRequestReceived(Guid.NewGuid().ToString(), processId, _payloadSerializer.GetPayload(introspectionParameter, authenticationHeaderValue), authenticationHeaderValue, 0)); var result = await _postIntrospectionAction.Execute(introspectionParameter, authenticationHeaderValue); _eventPublisher.Publish(new IntrospectionResultReturned(Guid.NewGuid().ToString(), processId, _payloadSerializer.GetPayload(result), 1)); return(result); } catch (IdentityServerException ex) { _eventPublisher.Publish(new OpenIdErrorReceived(Guid.NewGuid().ToString(), processId, ex.Code, ex.Message, 1)); throw; } }
public async Task When_AccessToken_Cannot_Be_Extracted_Then_Exception_Is_Thrown() { // ARRANGE InitializeFakeObjects(); var parameter = new IntrospectionParameter { TokenTypeHint = Constants.StandardTokenTypeHintNames.AccessToken, Token = "token" }; var client = new AuthenticationResult(new Core.Common.Models.Client(), null); _authenticateClientStub.Setup(a => a.AuthenticateAsync(It.IsAny <AuthenticateInstruction>(), null)) .Returns(Task.FromResult(client)); _tokenStoreStub.Setup(a => a.GetAccessToken(It.IsAny <string>())) .Returns(() => Task.FromResult((GrantedToken)null)); _tokenStoreStub.Setup(a => a.GetRefreshToken(It.IsAny <string>())) .Returns(() => Task.FromResult((GrantedToken)null)); // ACT & ASSERTS var exception = await Assert.ThrowsAsync <IdentityServerException>(() => _postIntrospectionAction.Execute(parameter, null, null)); Assert.True(exception.Code == ErrorCodes.InvalidToken); Assert.True(exception.Message == ErrorDescriptions.TheTokenIsNotValid); }
public async Task <IntrospectionResult> Execute( IntrospectionParameter introspectionParameter, AuthenticationHeaderValue authenticationHeaderValue, string issuerName) { // 1. Validate the parameters if (introspectionParameter == null) { throw new ArgumentNullException(nameof(introspectionParameter)); } if (string.IsNullOrWhiteSpace(introspectionParameter.Token)) { throw new ArgumentNullException(nameof(introspectionParameter.Token)); } _introspectionParameterValidator.Validate(introspectionParameter); // 2. Authenticate the client var instruction = CreateAuthenticateInstruction(introspectionParameter, authenticationHeaderValue); var authResult = await _authenticateClient.AuthenticateAsync(instruction, issuerName); if (authResult.Client == null) { throw new IdentityServerException(ErrorCodes.InvalidClient, authResult.ErrorMessage); } // 3. Retrieve the token type hint var tokenTypeHint = Constants.StandardTokenTypeHintNames.AccessToken; if (Constants.AllStandardTokenTypeHintNames.Contains(introspectionParameter.TokenTypeHint)) { tokenTypeHint = introspectionParameter.TokenTypeHint; } // 4. Trying to fetch the information about the access_token || refresh_token GrantedToken grantedToken = null; if (tokenTypeHint == Constants.StandardTokenTypeHintNames.AccessToken) { grantedToken = await _tokenStore.GetAccessToken(introspectionParameter.Token); if (grantedToken == null) { grantedToken = await _tokenStore.GetRefreshToken(introspectionParameter.Token); } } else { grantedToken = await _tokenStore.GetRefreshToken(introspectionParameter.Token); if (grantedToken == null) { grantedToken = await _tokenStore.GetAccessToken(introspectionParameter.Token); } } // 5. Throw an exception if there's no granted token if (grantedToken == null) { throw new IdentityServerException( ErrorCodes.InvalidToken, ErrorDescriptions.TheTokenIsNotValid); } // 6. Fill-in parameters //// TODO : Specifiy the other parameters : NBF & JTI var result = new IntrospectionResult { Scope = grantedToken.Scope, ClientId = grantedToken.ClientId, Expiration = grantedToken.ExpiresIn, TokenType = grantedToken.TokenType }; // 7. Fill-in the other parameters if (grantedToken.IdTokenPayLoad != null) { var audiences = string.Empty; var audiencesArr = grantedToken.IdTokenPayLoad.GetArrayClaim(StandardClaimNames.Audiences); var issuedAt = grantedToken.IdTokenPayLoad.Iat; var issuer = grantedToken.IdTokenPayLoad.Issuer; var subject = grantedToken.IdTokenPayLoad.GetClaimValue(Jwt.Constants.StandardResourceOwnerClaimNames.Subject); var userName = grantedToken.IdTokenPayLoad.GetClaimValue(Jwt.Constants.StandardResourceOwnerClaimNames.Name); if (audiencesArr.Any()) { audiences = string.Join(" ", audiencesArr); } result.Audience = audiences; result.IssuedAt = issuedAt; result.Issuer = issuer; result.Subject = subject; result.UserName = userName; } // 8. Based on the expiration date disable OR enable the introspection result var expirationDateTime = grantedToken.CreateDateTime.AddSeconds(grantedToken.ExpiresIn); var tokenIsExpired = DateTime.UtcNow > expirationDateTime; if (tokenIsExpired) { result.Active = false; } else { result.Active = true; } return(result); }
public async Task <Option <UmaIntrospectionResponse> > Execute( IntrospectionParameter introspectionParameter, CancellationToken cancellationToken) { var introspectionParameterToken = introspectionParameter.Token; if (string.IsNullOrWhiteSpace(introspectionParameterToken)) { return(new ErrorDetails { Status = HttpStatusCode.BadRequest, Title = ErrorCodes.InvalidToken, Detail = Strings.TheTokenDoesntExist }); } // Read this RFC for more information - https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-federated-authz-2.0.html#introspection-endpoint // 3. Retrieve the token type hint var tokenTypeHint = CoreConstants.StandardTokenTypeHintNames.AccessToken; if (CoreConstants.AllStandardTokenTypeHintNames.Contains(introspectionParameter.TokenTypeHint)) { tokenTypeHint = introspectionParameter.TokenTypeHint; } // 4. Trying to fetch the information about the access_token || refresh_token var grantedToken = tokenTypeHint switch { CoreConstants.StandardTokenTypeHintNames.AccessToken => await _tokenStore .GetAccessToken(introspectionParameterToken, cancellationToken) .ConfigureAwait(false), CoreConstants.StandardTokenTypeHintNames.RefreshToken => await _tokenStore .GetRefreshToken(introspectionParameterToken, cancellationToken) .ConfigureAwait(false), _ => null }; // 5. Return an error if there's no granted token if (grantedToken == null) { return(new ErrorDetails { Title = ErrorCodes.InvalidGrant, Detail = Strings.TheTokenIsNotValid }); } // 6. Fill-in parameters //// default : Specify the other parameters : NBF & JTI var result = new UmaIntrospectionResponse { //Scope = grantedToken.Scope.Split(' ', StringSplitOptions.RemoveEmptyEntries), ClientId = grantedToken.ClientId, Expiration = grantedToken.ExpiresIn, TokenType = grantedToken.TokenType }; if (grantedToken.UserInfoPayLoad != null) { var subject = grantedToken.IdTokenPayLoad?.GetClaimValue(OpenIdClaimTypes.Subject); if (!string.IsNullOrWhiteSpace(subject)) { result = result with { Subject = subject }; } } // 7. Fill-in the other parameters if (grantedToken.IdTokenPayLoad != null) { var audiencesArr = grantedToken.IdTokenPayLoad.GetArrayValue(StandardClaimNames.Audiences); var subject = grantedToken.IdTokenPayLoad.GetClaimValue(OpenIdClaimTypes.Subject); var userName = grantedToken.IdTokenPayLoad.GetClaimValue(OpenIdClaimTypes.Name); result = result with { Audience = string.Join(" ", audiencesArr), IssuedAt = grantedToken.IdTokenPayLoad.Iat ?? 0, Issuer = grantedToken.IdTokenPayLoad.Iss }; if (!string.IsNullOrWhiteSpace(subject)) { result = result with { Subject = subject }; } if (!string.IsNullOrWhiteSpace(userName)) { result = result with { UserName = userName }; } } // 8. Based on the expiration date disable OR enable the introspection resultKind var expirationDateTime = grantedToken.CreateDateTime.AddSeconds(grantedToken.ExpiresIn); result = result with { Active = DateTimeOffset.UtcNow < expirationDateTime }; return(result); } } }
public async Task <Option <OauthIntrospectionResponse> > Execute( IntrospectionParameter introspectionParameter, CancellationToken cancellationToken) { // Read this RFC for more information - https://www.rfc-editor.org/rfc/rfc7662.txt // 3. Retrieve the token type hint var tokenTypeHint = CoreConstants.StandardTokenTypeHintNames.AccessToken; if (CoreConstants.AllStandardTokenTypeHintNames.Contains(introspectionParameter.TokenTypeHint)) { tokenTypeHint = introspectionParameter.TokenTypeHint; } // 4. Trying to fetch the information about the access_token || refresh_token var introspectionParameterToken = introspectionParameter.Token; var grantedToken = tokenTypeHint switch { _ when introspectionParameterToken == null => null, CoreConstants.StandardTokenTypeHintNames.AccessToken => await _tokenStore .GetAccessToken(introspectionParameterToken, cancellationToken) .ConfigureAwait(false), CoreConstants.StandardTokenTypeHintNames.RefreshToken => await _tokenStore .GetRefreshToken(introspectionParameterToken, cancellationToken) .ConfigureAwait(false), _ => null }; // 5. Return an error if there's no granted token if (grantedToken == null) { return(new OauthIntrospectionResponse()); } // 6. Fill-in parameters //// default : Specify the other parameters : NBF & JTI var result = new OauthIntrospectionResponse { Scope = grantedToken.Scope.Split(' ', StringSplitOptions.RemoveEmptyEntries), ClientId = grantedToken.ClientId, Expiration = grantedToken.ExpiresIn, TokenType = grantedToken.TokenType }; if (grantedToken.UserInfoPayLoad != null) { var subject = grantedToken.IdTokenPayLoad?.GetClaimValue(OpenIdClaimTypes.Subject); if (!string.IsNullOrWhiteSpace(subject)) { result = result with { Subject = subject }; } } // 7. Fill-in the other parameters if (grantedToken.IdTokenPayLoad != null) { var audiencesArr = grantedToken.IdTokenPayLoad.GetArrayValue(StandardClaimNames.Audiences); var subject = grantedToken.IdTokenPayLoad.GetClaimValue(OpenIdClaimTypes.Subject); var userName = grantedToken.IdTokenPayLoad.GetClaimValue(OpenIdClaimTypes.Name); result = result with { Audience = string.Join(" ", audiencesArr), IssuedAt = grantedToken.IdTokenPayLoad.Iat ?? 0, Issuer = grantedToken.IdTokenPayLoad.Iss }; if (!string.IsNullOrWhiteSpace(subject)) { result = result with { Subject = subject }; } if (!string.IsNullOrWhiteSpace(userName)) { result = result with { UserName = userName }; } } // 8. Based on the expiration date disable OR enable the introspection resultKind var expirationDateTime = grantedToken.CreateDateTime.AddSeconds(grantedToken.ExpiresIn); result = result with { Active = DateTimeOffset.UtcNow < expirationDateTime }; return(result); } } }