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));
        }
Exemplo n.º 5
0
 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);
        }
Exemplo n.º 7
0
        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);
        }
Exemplo n.º 10
0
        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);
        }
Exemplo n.º 16
0
        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);
        }
    }
}
Exemplo n.º 17
0
        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);
        }
    }
}