예제 #1
0
        public async Task Store_Grant_And_Retrieve_It()
        {
            var key = Guid.NewGuid().ToString("N");

            var grant = new IdentityServer4.Models.PersistedGrant
            {
                Key          = key,
                Expiration   = DateTime.UtcNow.AddDays(1),
                Type         = "test",
                ClientId     = "client1",
                SubjectId    = "sub1",
                SessionId    = "session1",
                CreationTime = DateTime.UtcNow,
                Description  = "des",
                Data         = "bla bla",
                ConsumedTime = DateTime.UtcNow
            };

            await persistedGrantStore.StoreAsync(grant);

            var item = await persistedGrantStore.GetAsync(key);

            item.Should().NotBeNull();
            item.Key.Should().Be(key);
            item.Type.Should().Be(grant.Type);
            item.ClientId.Should().Be(grant.ClientId);
            item.SubjectId.Should().Be(grant.SubjectId);
            item.Data.Should().Be(grant.Data);
            item.Description.Should().Be(grant.Description);
            item.SessionId.Should().Be(grant.SessionId);
            item.CreationTime.Should().NotBe(new DateTime());
            item.Expiration.Should().NotBeNull();
            item.ConsumedTime.Should().NotBeNull();
        }
예제 #2
0
        public void CanCreateAndUpdateAndDeletePersistedGrant()
        {
            IPersistedGrantStore store = Fixture.GetService <IPersistedGrantStore>();

            Client client = CreateClient();

            Provider.AddClientAsync(client).Wait();

            PersistedGrant grant = CreateGrant(client.ClientId);

            PersistedGrant result = store.GetAsync(grant.Key).Result;

            Assert.Null(result);

            Provider.AddPersistedGrantAsync(grant).Wait();

            result = store.GetAsync(grant.Key).Result;
            Assert.NotNull(result);
            Assert.NotEqual("test", result.Data);

            result.Data = "test";

            Provider.UpdatePersistedGrantAsync(result).Wait();

            result = store.GetAsync(grant.Key).Result;
            Assert.NotNull(result);
            Assert.Equal("test", result.Data);

            Provider.RemovePersistedGrantAsync(result).Wait();

            result = store.GetAsync(grant.Key).Result;
            Assert.Null(result);
        }
        public async Task CopyAsync(string sourceKey, string destinationKey)
        {
            var source = await _innerPersistedGrantStore.GetAsync(sourceKey);

            if (source != null)
            {
                source.Key = destinationKey;
                await StoreAsync(source);
            }
        }
예제 #4
0
        /// <summary>
        /// Gets the item.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        protected async Task <T> GetItemAsync(string key)
        {
            var hashedKey = GetHashedKey(key);

            var grant = await _store.GetAsync(hashedKey);

            if (grant != null && grant.Type == _grantType)
            {
                if (!grant.Expiration.HasExpired())
                {
                    try
                    {
                        return(_serializer.Deserialize <T>(grant.Data));
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError("Failed to deserailize JSON from grant store. Exception: {0}", ex.Message);
                    }
                }
                else
                {
                    _logger.LogDebug("{grantType} grant with value: {key} found in store, but has expired.", _grantType, key);
                }
            }
            else
            {
                _logger.LogDebug("{grantType} grant with value: {key} not found in store.", _grantType, key);
            }

            return(default(T));
        }
        public async Task StoreAsync_WhenPersistedGrantStored_ExpectSuccess()
        {
            // Arrange
            var persistedGrant = UniquePersistedGrant;

            // Act
            await _persistedGrantStore.StoreAsync(persistedGrant);


            // Assert
            var foundPersistedGrant = await _persistedGrantStore.GetAsync(persistedGrant.Key);

            // Assert
            Assert.IsNotNull(foundPersistedGrant);
        }
예제 #6
0
        public void PersistedGrantStore()
        {
            IPersistedGrantStore store = Fixture.GetService <IPersistedGrantStore>();

            Client client = CreateClient();

            Provider.AddClientAsync(client).Wait();

            PersistedGrant grant1 = CreateGrant(client.ClientId, "aaa", "t1");
            PersistedGrant grant2 = CreateGrant(client.ClientId, "aaa");
            PersistedGrant grant3 = CreateGrant(client.ClientId, "aaa");
            PersistedGrant grant4 = CreateGrant(client.ClientId);
            PersistedGrant grant5 = CreateGrant(client.ClientId);

            store.StoreAsync(grant1).Wait();
            store.StoreAsync(grant2).Wait();
            store.StoreAsync(grant3).Wait();
            store.StoreAsync(grant4).Wait();
            store.StoreAsync(grant5).Wait();

            List <PersistedGrant> results = store.GetAllAsync("aaa").Result?.ToList();

            Assert.Equal(3, results.Count);

            store.RemoveAllAsync("aaa", grant1.ClientId, "t1").Wait();

            results = store.GetAllAsync("aaa").Result?.ToList();
            Assert.Equal(2, results.Count);

            store.RemoveAllAsync("aaa", grant1.ClientId).Wait();

            results = store.GetAllAsync("aaa").Result?.ToList();
            Assert.Empty(results);

            PersistedGrant result = store.GetAsync(grant5.Key).Result;

            Assert.NotNull(result);

            store.RemoveAsync(grant5.Key);
            result = store.GetAsync(grant5.Key).Result;
            Assert.Null(result);
        }
예제 #7
0
        async Task <T> GetItem <T>(string key, string type)
        {
            key = HashKey(key, type);

            var grant = await _store.GetAsync(key);

            if (grant != null && grant.Type == type)
            {
                return(_serializer.Deserialize <T>(grant.Data));
            }

            return(default(T));
        }
        protected async Task <T> GetItemAsync(string key)
        {
            key = GetHashedKey(key);

            var grant = await _store.GetAsync(key);

            if (grant != null && grant.Type == _grantType)
            {
                return(_serializer.Deserialize <T>(grant.Data));
            }

            return(default(T));
        }
예제 #9
0
        /// <summary>
        /// Gets the item.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        protected async Task <T> GetItemAsync(string key)
        {
            key = GetHashedKey(key);

            var grant = await _store.GetAsync(key);

            if (grant != null && grant.Type == _grantType && !grant.Expiration.HasExpired())
            {
                try
                {
                    return(_serializer.Deserialize <T>(grant.Data));
                }
                catch (Exception ex)
                {
                    _logger.LogError("Failed to deserailize JSON from grant store. Exception: {0}", ex.Message);
                }
            }

            return(default(T));
        }
예제 #10
0
        public async Task Persist_Grant_Get()
        {
            var persistedGrant = await _persistedGrantStore.GetAsync(_currentId);

            persistedGrant.Should().NotBeNull();

            persistedGrant.ClientId.Should().Be(_currentPersistedGrant.ClientId);
            persistedGrant.CreationTime.Should().Be(_currentPersistedGrant.CreationTime);
            persistedGrant.Data.Should().Be(_currentPersistedGrant.Data);
            persistedGrant.Expiration.Should().Be(_currentPersistedGrant.Expiration);
            persistedGrant.Key.Should().Be(_currentPersistedGrant.Key);
            persistedGrant.SubjectId.Should().Be(_currentPersistedGrant.SubjectId);
            persistedGrant.Type.Should().Be(_currentPersistedGrant.Type);

            Thread.Sleep(5000);

            persistedGrant = await _persistedGrantStore.GetAsync(_currentId);

            persistedGrant.Should().BeNull();
        }
예제 #11
0
    public async Task FindClientByIdAsync_Should_Return_Null_If_Not_Found()
    {
        var persistentGrant = await _persistedGrantStore.GetAsync("not-existing-id");

        persistentGrant.ShouldBeNull();
    }
        async Task <PersistedGrant> GetAsync(string key)
        {
            var actual = await _persistedGrantStore.GetAsync(key);

            return(actual);
        }
예제 #13
0
 public Task <PersistedGrant> GetAsync(string key)
 {
     return(_inMemoryPersistedGrantStore.GetAsync(key));
 }
 public Task <PersistedGrant> GetAsync(string key)
 {
     return(_persistedGrantStoreImplementation.GetAsync(key));
 }
        public async Task <Models.PersistedGrant> GetAsync(string key)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(key))
                {
                    throw new ArgumentNullException(
                              "key cant be null or white space", nameof(key));
                }

                var cacheKey = Utilities.CreateCachedPersistedGrantStoreKey(key);

                var cachedPersistedGrant = await _getPersistedGrantPolicy
                                           .ExecuteAsync(async() =>
                {
                    return(await Task.Run(() =>
                                          _handle.cache.Get <PersistedGrant>(cacheKey)
                                          ).ConfigureAwait(false));
                }).ConfigureAwait(false);

                Models.PersistedGrant persistedGrant = null;

                if (cachedPersistedGrant == null)
                {
                    persistedGrant = await _inner.GetAsync(key);

                    if (persistedGrant != null)
                    {
                        if (_debugLoggingEnabled)
                        {
                            _logger.LogDebug(
                                $"Cache Miss: Persisted grant {key}" +
                                $"acquired from IPersistedGrantStore");
                        }
                        var item = new CacheItem(persistedGrant.ToEntity())
                        {
                            Tags =
                                Utilities.CreateCachePersistedGrantStoreTags(
                                    persistedGrant),
                            Expiration =
                                Utilities.DetermineCachePersistedGrantStoreExpiration
                                (
                                    persistedGrant,
                                    _handle.options)
                        };

                        bool result = await _setFallBackPolicy
                                      .ExecuteAsync(async() =>
                        {
                            await _handle.cache.InsertAsync(cacheKey, item)
                            .ConfigureAwait(false);
                            return(true);
                        }).ConfigureAwait(false);

                        if (_errorLoggingEnabled && !result)
                        {
                            _logger.LogError(
                                $"Caching problems with persistant store cache");
                        }
                    }
                    else
                    {
                        if (_debugLoggingEnabled)
                        {
                            _logger.LogDebug(
                                $"Persisted grant {key} not found");
                        }
                    }
                }
                else
                {
                    persistedGrant = cachedPersistedGrant.ToModel();
                    if (_debugLoggingEnabled)
                    {
                        _logger.LogDebug(
                            $"Cache Hit: Persisted grant {key}" +
                            $"acquired from NCache");
                    }
                }

                return(persistedGrant);
            }
            catch (Exception ex)
            {
                if (_errorLoggingEnabled)
                {
                    _logger.LogError(
                        ex,
                        $"something went wrong with GetAsync for {key}");
                }
                throw;
            }
        }
        public async Task ValidateAsync(ExtensionGrantValidationContext context)
        {
            var client = context.Request.Client as ClientExtra;

            _scopedTenantRequestContext.Context.Client = client;
            _scopedOverrideRawScopeValues.IsOverride   = true;
            var externalServices = await _externalServicesStore.GetExternalServicesAsync();

            var form  = context.Request.Raw;
            var error = false;
            var los   = new List <string>();

            // make sure nothing is malformed
            bool err = false;


            // optional stuff;
            var accessTokenLifetimeOverride = form.Get(Constants.AccessTokenLifetime);

            if (!string.IsNullOrWhiteSpace(accessTokenLifetimeOverride))
            {
                int accessTokenLifetime = 0;
                if (int.TryParse(accessTokenLifetimeOverride, out accessTokenLifetime))
                {
                    if (accessTokenLifetime > 0 && accessTokenLifetime <= client.AccessTokenLifetime)
                    {
                        context.Request.AccessTokenLifetime = accessTokenLifetime;
                    }
                    else
                    {
                        los.Add($"{Constants.AccessTokenLifetime}:{accessTokenLifetimeOverride} is out of range.");
                        err = true;
                    }
                }
            }
            error = error || err;
            err   = false;

            // MUST have subject
            // -------------------------------------------------------------------
            var subjectToken = form.Get(FluffyBunny4.Constants.TokenExchangeTypes.SubjectToken);

            if (string.IsNullOrWhiteSpace(subjectToken))
            {
                err = true;
                los.Add($"{FluffyBunny4.Constants.TokenExchangeTypes.SubjectToken} is required");
            }
            error = error || err;
            err   = false;

            // MUST have SubjectTokenType
            // -------------------------------------------------------------------
            var subjectTokenType = form.Get(FluffyBunny4.Constants.TokenExchangeTypes.SubjectTokenType);

            if (string.IsNullOrWhiteSpace(subjectTokenType))
            {
                err = true;
                los.Add($"{FluffyBunny4.Constants.TokenExchangeTypes.SubjectTokenType} is required");
            }
            error = error || err;
            err   = false;

            if (error)
            {
                context.Result.IsError = true;
                context.Result.Error   = string.Join <string>(" | ", los);
                _logger.LogError($"context.Result.Error");
                return;
            }

            DateTime     tokenIssuedAtTime;
            List <Claim> claims;
            var          subject = "";

            switch (subjectTokenType)
            {
            case FluffyBunny4.Constants.TokenExchangeTypes.AccessToken:
                if (subjectToken.Contains('.'))
                {
                    err = true;
                    los.Add($"failed to validate, not a reference_token: {FluffyBunny4.Constants.TokenExchangeTypes.SubjectTokenType}={subjectTokenType},{FluffyBunny4.Constants.TokenExchangeTypes.AccessToken}={subjectToken}");
                }
                var validatedResultAccessToken = await _tokenValidator.ValidateAccessTokenAsync(subjectToken);

                if (validatedResultAccessToken.IsError)
                {
                    err = true;
                    los.Add($"failed to validate: {FluffyBunny4.Constants.TokenExchangeTypes.SubjectTokenType}={subjectTokenType},{FluffyBunny4.Constants.TokenExchangeTypes.AccessToken}={subjectToken}");
                }
                subject = validatedResultAccessToken.Claims
                          .Where(item => item.Type == JwtClaimTypes.Subject)
                          .Select(item => item.Value)
                          .FirstOrDefault();
                if (string.IsNullOrWhiteSpace(subject))
                {
                    err = true;
                    los.Add($"subject does not exist: {FluffyBunny4.Constants.TokenExchangeTypes.SubjectTokenType}={subjectTokenType},{FluffyBunny4.Constants.TokenExchangeTypes.SubjectToken}={subjectToken}");
                }


                claims = validatedResultAccessToken.Claims.ToList();
                var amr = claims.FirstOrDefault(claim => claim.Type == JwtClaimTypes.AuthenticationMethod &&
                                                claim.Value == Constants.GrantType.TokenExchange);

                if (amr == null)
                {
                    err = true;
                    los.Add($"failed to validate, missing amr={Constants.GrantType.TokenExchange}: {FluffyBunny4.Constants.TokenExchangeTypes.SubjectTokenType}={subjectTokenType},{FluffyBunny4.Constants.TokenExchangeTypes.AccessToken}={subjectToken}");
                }

                var issuedAt = claims.FirstOrDefault(claim => claim.Type == JwtClaimTypes.IssuedAt);
                if (issuedAt == null)
                {
                    err = true;
                    los.Add(
                        $"failed to validate, {JwtClaimTypes.IssuedAt} is missing: {FluffyBunny4.Constants.TokenExchangeTypes.SubjectTokenType}={subjectTokenType},{FluffyBunny4.Constants.TokenExchangeTypes.AccessToken}={subjectToken}");
                }

                var            unixSeconds    = Convert.ToInt64(issuedAt.Value);
                DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(unixSeconds);

                tokenIssuedAtTime = dateTimeOffset.UtcDateTime;

                var referenceTokenStoreGrantStoreHashAccessor = _referenceTokenStore as IGrantStoreHashAccessor;
                var fixedSubjectToken        = subjectToken.Substring(2);
                var hashKey                  = referenceTokenStoreGrantStoreHashAccessor.GetHashedKey(fixedSubjectToken);
                var accessTokenPersitedGrant = await _persistedGrantStore.GetAsync(hashKey);

                if (accessTokenPersitedGrant == null)
                {
                    err = true;
                    los.Add($"failed to validate, accessTokenPersitedGrant is missing: {FluffyBunny4.Constants.TokenExchangeTypes.SubjectTokenType}={subjectTokenType},{FluffyBunny4.Constants.TokenExchangeTypes.AccessToken}={subjectToken}");
                }

                var accessTokenPersitedGrantExtra = accessTokenPersitedGrant as PersistedGrantExtra;
                _scopedStorage.AddOrUpdate(Constants.ScopedRequestType.SubjectToken, subjectToken);
                _scopedStorage.AddOrUpdate(Constants.ScopedRequestType.PersistedGrantExtra, accessTokenPersitedGrantExtra);

                var requestedScopes = context.Request.RequestedScopes.ToList();
                if (!string.IsNullOrWhiteSpace(accessTokenPersitedGrantExtra.RefreshTokenKey))
                {
                    _scopedOverrideRawScopeValues.Scopes.Add(IdentityServerConstants.StandardScopes.OfflineAccess);
                    _scopedOptionalClaims.Claims.Add(new Claim(JwtClaimTypes.Scope, IdentityServerConstants.StandardScopes.OfflineAccess));
                    if (!requestedScopes.Contains(IdentityServerConstants.StandardScopes.OfflineAccess))
                    {
                        requestedScopes.Add(IdentityServerConstants.StandardScopes.OfflineAccess);
                    }
                }
                else
                {
                    if (requestedScopes.Contains(IdentityServerConstants.StandardScopes.OfflineAccess))
                    {
                        requestedScopes.Remove(IdentityServerConstants.StandardScopes.OfflineAccess);
                    }
                }

                context.Request.RequestedScopes = requestedScopes;
                break;


            default:
                throw new Exception($"not supported: {FluffyBunny4.Constants.TokenExchangeTypes.SubjectTokenType}={subjectTokenType},{FluffyBunny4.Constants.TokenExchangeTypes.SubjectToken}={subjectToken}");
                break;
            }
            error = error || err;
            err   = false;
            if (error)
            {
                context.Result.IsError = true;
                context.Result.Error   = string.Join <string>(" | ", los);
                _logger.LogError($"context.Result.Error");
                return;
            }


            var finalCustomPayload = new Dictionary <string, object>();

            var requestedScopesRaw = form[Constants.Scope].Split(' ').ToList();

            var consentAuthorizeResponseTasks = new List <Task <ConsentAuthorizeResponseContainer <PostContext> > >();
            var requestedServiceScopes        = GetServiceToScopesFromRequest(requestedScopesRaw);

            foreach (var serviceScopeSet in requestedServiceScopes)
            {
                var externalService = await _externalServicesStore.GetExternalServiceByNameAsync(serviceScopeSet.Key);

                if (externalService == null)
                {
                    _logger.LogError($"external service: {serviceScopeSet.Key} does not exist");
                    continue;
                }

                var discoCache =
                    await _consentDiscoveryCacheAccessor.GetConsentDiscoveryCacheAsync(serviceScopeSet.Key);

                var doco = await discoCache.GetAsync();

                if (doco.IsError)
                {
                    // OPINION: If I have a lot of external services it it probably better to let this continue even it if
                    //          results in an access_token that is missing this bad service's scopes.

                    _logger.LogError(doco.Error);
                    continue;
                }

                List <string> scopes = null;
                switch (doco.AuthorizationType)
                {
                case Constants.AuthorizationTypes.Implicit:
                    scopes = null;
                    break;

                case Constants.AuthorizationTypes.SubjectAndScopes:
                    scopes = serviceScopeSet.Value;
                    break;
                }

                if (doco.AuthorizationType == Constants.AuthorizationTypes.Implicit)
                {
                    _scopedOverrideRawScopeValues.Scopes.AddRange(serviceScopeSet.Value);
                }
                else
                {
                    var request = new ConsentAuthorizeRequest
                    {
                        AuthorizeType = doco.AuthorizationType,
                        Scopes        = scopes,
                        Subject       = subject,
                        Requester     = new ConsentAuthorizeRequest.ClientRequester()
                        {
                            ClientDescription = client.Description,
                            ClientId          = client.ClientId,
                            ClientName        = client.ClientName,
                            Namespace         = client.Namespace,
                            Tenant            = client.TenantName
                        }
                    };


                    // How to send many requests in parallel in ASP.Net Core
                    // https://www.michalbialecki.com/2018/04/19/how-to-send-many-requests-in-parallel-in-asp-net-core/
                    var task = _consentExternalService.PostAuthorizationRequestAsync(doco, request, new PostContext()
                    {
                        ServiceScopeSet   = serviceScopeSet,
                        DiscoveryDocument = doco
                    });
                    consentAuthorizeResponseTasks.Add(task);
                }
            }
            var consentAuthorizeResponses = await Task.WhenAll(consentAuthorizeResponseTasks);

            foreach (var consentAuthorizeResponse in consentAuthorizeResponses)
            {
                var response        = consentAuthorizeResponse.Response;
                var serviceScopeSet = consentAuthorizeResponse.Context.ServiceScopeSet;
                var doco            = consentAuthorizeResponse.Context.DiscoveryDocument;

                if (response.Error != null)
                {
                    _logger.LogError($"ExternalService:{serviceScopeSet.Key},Error:{response.Error.Message}");
                }
                else if (response.Authorized)
                {
                    switch (doco.AuthorizationType)
                    {
                    case Constants.AuthorizationTypes.SubjectAndScopes:
                        // make sure no funny business is coming in from the auth call.
                        var serviceRoot = $"{_tokenExchangeOptions.BaseScope}{serviceScopeSet.Key}";
                        var query       = (from item in response.Scopes
                                           where item.StartsWith(serviceRoot)
                                           select item);
                        _scopedOverrideRawScopeValues.Scopes.AddRange(query);
                        if (response.Claims != null && response.Claims.Any())
                        {
                            foreach (var cac in response.Claims)
                            {
                                // namespace the claims.
                                _scopedOptionalClaims.Claims.Add(new Claim($"{serviceScopeSet.Key}.{cac.Type}",
                                                                           cac.Value));
                            }
                        }

                        if (response.CustomPayload != null)
                        {
                            finalCustomPayload.Add(serviceScopeSet.Key, response.CustomPayload);
                        }

                        break;
                    }
                }
                _logger.LogInformation($"ExternalService:{serviceScopeSet.Key},Authorized:{response.Authorized}");
            }

            if (finalCustomPayload.Any())
            {
                _scopedOptionalClaims.Claims.Add(new Claim(
                                                     Constants.CustomPayload,
                                                     _serializer.Serialize(finalCustomPayload),
                                                     IdentityServerConstants.ClaimValueTypes.Json));
            }
            claims = new List <Claim>
            {
                // in this case we want to preserve that the original came from Constants.GrantType.TokenExchange
                new Claim(JwtClaimTypes.AuthenticationMethod, Constants.GrantType.TokenExchange)
            };

            context.Result = new GrantValidationResult(subject, GrantType, tokenIssuedAtTime, claims);
            _scopedStorage.AddOrUpdate(Constants.ScopedRequestType.ExtensionGrantValidationContext, context);
            _scopedStorage.AddOrUpdate(Constants.ScopedRequestType.OverrideTokenIssuedAtTime, tokenIssuedAtTime);
            return;
        }