예제 #1
0
        public override async Task <ResourceValidationResult> ValidateRequestedResourcesAsync(ResourceValidationRequest request)
        {
            var nvc   = _scopedHttpContextRequestForm.GetFormCollection();
            var token = nvc["token"];

            if (string.IsNullOrWhiteSpace(token))
            {
                token = nvc["refresh_token"];
            }
            if (!string.IsNullOrWhiteSpace(token))
            {
                if (token.StartsWith("1_"))
                {
                    // this has already been validated.
                    if (request == null)
                    {
                        throw new ArgumentNullException(nameof(request));
                    }

                    var result = new ResourceValidationResult();

                    var parsedScopesResult = _scopeParser.ParseScopeValues(request.Scopes);
                    result.ParsedScopes = parsedScopesResult.ParsedScopes;
                    return(result);
                }
            }
            return(await base.ValidateRequestedResourcesAsync(request));
        }
예제 #2
0
        protected async override Task <(string accessToken, string refreshToken)> CreateAccessTokenAsync(ValidatedTokenRequest request)
        {
            var formCollection = _scopedHttpContextRequestForm.GetFormCollection();
            var grantType      = formCollection["grant_type"];

            var tokenRequest = new TokenCreationRequest
            {
                Subject            = request.Subject,
                ValidatedResources = request.ValidatedResources,
                ValidatedRequest   = request
            };

            bool createRefreshToken;
            var  authorizedScopes = Enumerable.Empty <string>();
            IEnumerable <string> authorizedResourceIndicators = null;

            if (request.AuthorizationCode != null)
            {
                createRefreshToken = request.ValidatedResources.Resources.OfflineAccess;

                //                createRefreshToken = request.AuthorizationCode.RequestedScopes.Contains(IdentityServerConstants.StandardScopes.OfflineAccess);

                // load the client that belongs to the authorization code
                Client client = null;
                if (request.AuthorizationCode.ClientId != null)
                {
                    // todo: do we need this check?
                    client = await Clients.FindEnabledClientByIdAsync(request.AuthorizationCode.ClientId);
                }
                if (client == null)
                {
                    throw new InvalidOperationException("Client does not exist anymore.");
                }

                tokenRequest.Subject     = request.AuthorizationCode.Subject;
                tokenRequest.Description = request.AuthorizationCode.Description;

                authorizedScopes             = request.AuthorizationCode.RequestedScopes;
                authorizedResourceIndicators = request.AuthorizationCode.RequestedResourceIndicators;
            }
            else if (request.DeviceCode != null)
            {
                createRefreshToken = request.DeviceCode.AuthorizedScopes.Contains(IdentityServerConstants.StandardScopes.OfflineAccess);

                Client client = null;
                if (request.DeviceCode.ClientId != null)
                {
                    // todo: do we need this check?
                    client = await Clients.FindEnabledClientByIdAsync(request.DeviceCode.ClientId);
                }
                if (client == null)
                {
                    throw new InvalidOperationException("Client does not exist anymore.");
                }

                tokenRequest.Subject     = request.DeviceCode.Subject;
                tokenRequest.Description = request.DeviceCode.Description;

                authorizedScopes = request.DeviceCode.AuthorizedScopes;
            }
            else
            {
                createRefreshToken = request.RequestedScopes.Contains(IdentityServerConstants.StandardScopes.OfflineAccess);
                authorizedScopes   = request.ValidatedResources.RawScopeValues;
            }


            var at = await TokenService.CreateAccessTokenAsync(tokenRequest);

            object obj;

            if (_scopedStorage.TryGetValue(Constants.ScopedRequestType.OverrideTokenIssuedAtTime, out obj))
            {
                DateTime issuedAtTime = obj is DateTime ? (DateTime)obj : default;
                at.CreationTime = issuedAtTime;
            }

            var finalScopes = at.Scopes.ToList();

            if (createRefreshToken)
            {
                if (!finalScopes.Contains(IdentityServerConstants.StandardScopes.OfflineAccess))
                {
                    finalScopes.Add(IdentityServerConstants.StandardScopes.OfflineAccess);
                }
            }
            else
            {
                if (finalScopes.Contains(IdentityServerConstants.StandardScopes.OfflineAccess))
                {
                    finalScopes.Remove(IdentityServerConstants.StandardScopes.OfflineAccess);
                }
            }

            var accessToken = await TokenService.CreateSecurityTokenAsync(at);

            string refreshToken = null;

            if (createRefreshToken)
            {
                var rtRequest = new RefreshTokenCreationRequest
                {
                    Client                       = request.Client,
                    Subject                      = tokenRequest.Subject,
                    Description                  = tokenRequest.Description,
                    AuthorizedScopes             = authorizedScopes,
                    AuthorizedResourceIndicators = authorizedResourceIndicators,
                    AccessToken                  = at,
                    RequestedResourceIndicator   = request.RequestedResourceIndicator,
                };


                refreshToken = await RefreshTokenService.CreateRefreshTokenAsync(rtRequest);
            }

            if (_scopedStorage.TryGetValue(Constants.ScopedRequestType.ExtensionGrantValidationContext, out obj))
            {
                var extensionGrantValidationContext = obj as ExtensionGrantValidationContext;
                if (extensionGrantValidationContext.Request.GrantType == FluffyBunny4.Constants.GrantType.TokenExchangeMutate)
                {
                    var refreshTokenStoreGrantStoreHashAccessor   = _refreshTokenStore as IGrantStoreHashAccessor;
                    var referenceTokenStoreGrantStoreHashAccessor = _referenceTokenStore as IGrantStoreHashAccessor;

                    _scopedStorage.TryGetValue(Constants.ScopedRequestType.PersistedGrantExtra, out obj);
                    var persistedGrantExtra =
                        _scopedStorage.Get <PersistedGrantExtra>(Constants.ScopedRequestType.PersistedGrantExtra);
                    var subjectToken =
                        _scopedStorage.Get <string>(Constants.ScopedRequestType.SubjectToken);
                    var fixedSubjectToken = subjectToken.Substring(2);
                    var newKey            = referenceTokenStoreGrantStoreHashAccessor.GetHashedKey(accessToken);
                    var originalKey       = referenceTokenStoreGrantStoreHashAccessor.GetHashedKey(fixedSubjectToken);

                    await _persistedGrantStore.CopyAsync(newKey, originalKey);

                    await _persistedGrantStore.RemoveAsync(newKey);

                    if (!createRefreshToken && !string.IsNullOrWhiteSpace(persistedGrantExtra.RefreshTokenKey))
                    {
                        // need to kill the old refresh token, as this mutate didn't ask for a new one.
                        await _persistedGrantStore.RemoveAsync(persistedGrantExtra.RefreshTokenKey);
                    }
                    else
                    {
                        newKey = refreshTokenStoreGrantStoreHashAccessor.GetHashedKey(refreshToken);
                        await _persistedGrantStore.CopyAsync(newKey, persistedGrantExtra.RefreshTokenKey);

                        await _persistedGrantStore.RemoveAsync(newKey);
                    }

                    // we need to point the old access_token and refresh_token to this new set;
                    return(subjectToken, null);   // mutate doesn't get to get the refresh_token back, the original holder of it is the only owner.
                }
            }


            switch (grantType)
            {
            case FluffyBunny4.Constants.GrantType.ArbitraryIdentity:
            case FluffyBunny4.Constants.GrantType.ArbitraryToken:
            case OidcConstants.GrantTypes.DeviceCode:
            case FluffyBunny4.Constants.GrantType.TokenExchange:
            case FluffyBunny4.Constants.GrantType.TokenExchangeMutate:
                if (!accessToken.Contains('.'))
                {
                    accessToken = $"1_{accessToken}";
                }

                if (!string.IsNullOrWhiteSpace(refreshToken))
                {
                    refreshToken = $"1_{refreshToken}";
                }

                break;

            default:
                if (!accessToken.Contains('.'))
                {
                    accessToken = $"0_{accessToken}";
                }
                if (!string.IsNullOrWhiteSpace(refreshToken))
                {
                    refreshToken = $"0_{refreshToken}";
                }

                break;
            }

            return(accessToken, refreshToken);

            //       return (accessToken, null);
        }
        public async Task StoreAsync(PersistedGrant grant)
        {
            var context = GetTenantContext();

            var token = grant as FluffyBunny4.Models.PersistedGrantExtra;

            var grantType = _scopedHttpContextRequestForm.GetFormCollection()["grant_type"];

            if (grantType == "refresh_token")
            {
                if (grant.Type != IdentityServerConstants.PersistedGrantTypes.RefreshToken)
                {
                    // refresh_token coming. so save this access_token for later storage
                    _scopedStorage.AddOrUpdate(Constants.ScopedRequestType.AccessTokenPersistedGrant,
                                               grant);
                    return;

                    // store access_token for later
                }
                else
                {
                    object obj;
                    _scopedStorage.TryGetValue(Constants.ScopedRequestType.AccessTokenPersistedGrant, out obj);

                    if (obj != null)
                    {
                        var grantStored = obj as Duende.IdentityServer.Models.PersistedGrant;
                        var extra       = _entityFrameworkMapperAccessor.MapperOneToOne
                                          .Map <FluffyBunny4.Models.PersistedGrantExtra>(grantStored);

                        extra.RefreshTokenKey = grant.Key;
                        await InnerStoreAsync(extra);
                        await InnerStoreAsync(grant);

                        _scopedStorage.TryRemove(Constants.ScopedRequestType.AccessTokenPersistedGrant, out obj);
                    }
                    else
                    {
                        // the persisted grant before this was NOT a reference token, so we will assume it was a JWT
                        await InnerStoreAsync(grant);
                    }

                    return;
                }
            }
            else
            {
                object obj;
                if (_scopedStorage.TryGetValue(Constants.ScopedRequestType.ExtensionGrantValidationContext, out obj))
                {
                    var extensionGrantValidationContext = obj as ExtensionGrantValidationContext;
                    if (extensionGrantValidationContext.Request.GrantType == FluffyBunny4.Constants.GrantType.TokenExchange ||
                        extensionGrantValidationContext.Request.GrantType == FluffyBunny4.Constants.GrantType.TokenExchangeMutate)
                    {
                        if (grant.Type != IdentityServerConstants.PersistedGrantTypes.RefreshToken)
                        {
                            var offlineAccess =
                                extensionGrantValidationContext.Request.RequestedScopes.FirstOrDefault(scope =>
                                                                                                       scope == IdentityServerConstants.StandardScopes.OfflineAccess);
                            if (offlineAccess != null)
                            {
                                // refresh_token coming. so save this access_token for later storage
                                _scopedStorage.AddOrUpdate(Constants.ScopedRequestType.AccessTokenPersistedGrant,
                                                           grant);
                                return;
                            }
                            // store access_token for later
                        }
                        else
                        {
                            _scopedStorage.TryGetValue(Constants.ScopedRequestType.AccessTokenPersistedGrant, out obj);

                            if (obj != null)
                            {
                                var grantStored = obj as Duende.IdentityServer.Models.PersistedGrant;
                                var extra       = _entityFrameworkMapperAccessor.MapperOneToOne
                                                  .Map <FluffyBunny4.Models.PersistedGrantExtra>(grantStored);

                                extra.RefreshTokenKey = grant.Key;
                                await InnerStoreAsync(extra);
                                await InnerStoreAsync(grant);

                                _scopedStorage.TryRemove(Constants.ScopedRequestType.AccessTokenPersistedGrant, out obj);
                            }
                            else
                            {
                                // the persisted grant before this was NOT a reference token, so we will assume it was a JWT
                                await InnerStoreAsync(grant);
                            }

                            //_scopedStorage.TryRemove(Constants.ScopedRequestType.AccessTokenPersistedGrant, out obj);
                            // _scopedStorage.TryRemove(Constants.ScopedRequestType.ExtensionGrantValidationContext, out obj);
                            return;
                        }
                    }
                }
            }


            await InnerStoreAsync(grant);
        }