Ejemplo n.º 1
0
        private async Task <string> GetStringAsync(string name)
        {
            var currentCulture = CultureInfo.CurrentCulture;
            var filter         = $"{nameof(LocalizedResource.CultureId)} eq '{currentCulture.Name}' and {nameof(LocalizedResource.Key)} eq '{name.Replace("'", "''")}'";

            if (!string.IsNullOrEmpty(_baseName))
            {
                filter += $" and ({nameof(LocalizedResource.BaseName)} eq null or {nameof(LocalizedResource.BaseName)} eq '{_baseName}')";
            }
            if (!string.IsNullOrEmpty(_location))
            {
                filter += $" and ({nameof(LocalizedResource.Location)} eq null or {nameof(LocalizedResource.Location)} eq '{_location}')";
            }

            var response = await _store.GetAsync(new PageRequest
            {
                Take    = 1,
                Filter  = filter,
                OrderBy = $"{nameof(LocalizedResource.BaseName)} desc,{nameof(LocalizedResource.Location)} desc"
            }).ConfigureAwait(false);

            if (response.Count == 0 && currentCulture.Name != "en")
            {
                _logger.LogWarning("Key {Key} not found for Culture {Culture}", name, currentCulture);
            }
            return(response.Items.Select(i => new LocalizedString(i.Key, i.Value)).FirstOrDefault());
        }
        /// <summary>
        /// Gets all grants for a given subject ID.
        /// </summary>
        /// <param name="subjectId">The subject identifier.</param>
        /// <returns></returns>
        public async Task <IEnumerable <Grant> > GetAllGrantsAsync(string subjectId)
        {
            var request = new PageRequest
            {
                Filter = $"{nameof(Entity.IGrant.UserId)} eq '{subjectId}'"
            };

            var consentList = (await _userConsentStore.GetAsync(request).ConfigureAwait(false)).Items
                              .Select(c => TryDeserialize <Consent>(c, c => new Grant
            {
                ClientId     = c.ClientId,
                CreationTime = c.CreationTime,
                Expiration   = c.Expiration,
                Scopes       = c.Scopes,
                SubjectId    = subjectId
            }));

            var codeList = (await _authorizationCodeStore.GetAsync(request).ConfigureAwait(false)).Items
                           .Select(c => TryDeserialize <AuthorizationCode>(c, c => new Grant
            {
                ClientId     = c.ClientId,
                CreationTime = c.CreationTime,
                Description  = c.Description,
                Expiration   = c.CreationTime.AddSeconds(c.Lifetime),
                Scopes       = c.RequestedScopes,
                SubjectId    = subjectId
            }));

            var refreshTokenList = (await _refreshTokenStore.GetAsync(request).ConfigureAwait(false)).Items
                                   .Select(t => TryDeserialize <RefreshToken>(t, t => new Grant
            {
                ClientId     = t.ClientId,
                CreationTime = t.CreationTime,
                Description  = t.Description,
                Expiration   = t.CreationTime.AddSeconds(t.Lifetime),
#if DUENDE
                Scopes = t.AuthorizedScopes,
#else
                Scopes = t.Scopes,
#endif
                SubjectId = subjectId
            }));

            var referenceTokenList = (await _referenceTokenStore.GetAsync(request).ConfigureAwait(false)).Items
                                     .Select(t => TryDeserialize <Token>(t, t => new Grant
            {
                ClientId     = t.ClientId,
                CreationTime = t.CreationTime,
                Description  = t.Description,
                Expiration   = t.CreationTime.AddSeconds(t.Lifetime),
                Scopes       = t.Scopes,
                SubjectId    = subjectId
            }));

            consentList = Join(consentList, codeList);
            consentList = Join(consentList, refreshTokenList);
            consentList = Join(consentList, referenceTokenList);

            return(consentList);
        }
Ejemplo n.º 3
0
        public async Task <models.BackChannelAuthenticationRequest> GetByAuthenticationRequestIdAsync(string requestId)
        {
            var page = await _store.GetAsync(new PageRequest
            {
                Filter = $"{nameof(BackChannelAuthenticationRequest.SessionId)} eq '{requestId}'"
            }).ConfigureAwait(false);

            return(CreateDto(page.Items.FirstOrDefault()?.Data));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Finds the API resource by name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public async Task <Models.ApiResource> FindApiResourceAsync(string name)
        {
            var entity = await _apiStore.GetAsync(name, new GetRequest
            {
                Expand = $"{nameof(ProtectResource.ApiClaims)},{nameof(ProtectResource.ApiScopeClaims)},{nameof(ProtectResource.Secrets)},{nameof(ProtectResource.Scopes)},{nameof(ProtectResource.Properties)}"
            }).ConfigureAwait(false);

            return(entity.ToApi());
        }
        /// <summary>
        /// Gets and consume the one time token.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        public string ConsumeOneTimeToken(string id)
        {
            var token = _store.GetAsync(id, new GetRequest()).GetAwaiter().GetResult();

            if (token == null)
            {
                return(null);
            }
            _store.DeleteAsync(id).GetAwaiter().GetResult();
            return(token.Data);
        }
Ejemplo n.º 6
0
        public async Task <IEnumerable <IdentityProviderName> > GetAllSchemeNamesAsync()
        {
            var page = await _store.GetAsync(new PageRequest()).ConfigureAwait(false);

            return(page.Items.Select(p => new IdentityProviderName
            {
                DisplayName = p.DisplayName,
                Scheme = p.Id,
                Enabled = true
            }));
        }
Ejemplo n.º 7
0
        protected async Task <IActionResult> GetAsync(string id)
        {
            var model = await AdminStore.GetAsync(id);

            if (model == null)
            {
                return(NotFound());
            }

            return(Ok(AdminMapper.Map <TContract>(model)));
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Gets identity resources by scope name.
        /// </summary>
        /// <param name="scopeNames"></param>
        /// <returns></returns>
        public async Task <IEnumerable <Models.IdentityResource> > FindIdentityResourcesByScopeNameAsync(IEnumerable <string> scopeNames)
        {
            var filter   = string.Join(" or ", scopeNames.Select(s => $"{nameof(IdentityResource.Id)} eq '{s}'"));
            var response = await _identityStore.GetAsync(new PageRequest
            {
                Filter = filter,
                Expand = $"{nameof(IdentityResource.IdentityClaims)},{nameof(IdentityResource.Properties)},{nameof(IdentityResource.Resources)}"
            }).ConfigureAwait(false);

            return(response.Items.Select(e => e.ToIdentity()));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Finds the API resource by name.
        /// </summary>
        /// <param name="apiResourceNames">The name.</param>
        /// <returns></returns>
        public async Task <IEnumerable <Models.ApiResource> > FindApiResourcesByNameAsync(IEnumerable <string> apiResourceNames)
        {
            var filter   = string.Join(" or ", apiResourceNames.Select(s => $"{nameof(ProtectResource.Id)} eq '{s}'"));
            var response = await _apiStore.GetAsync(new PageRequest
            {
                Filter = filter,
                Expand = $"{nameof(ProtectResource.ApiClaims)},{nameof(ProtectResource.Secrets)},{nameof(ProtectResource.ApiScopes)},{nameof(ProtectResource.Properties)},{nameof(ProtectResource.Resources)}"
            }).ConfigureAwait(false);

            return(response.Items.Select(a => a.ToApi()));
        }
Ejemplo n.º 10
0
        public IEnumerable <LocalizedString> GetAllStrings(bool includeParentCultures)
        {
            var page = _store.GetAsync(new PageRequest
            {
                Filter = $"{nameof(LocalizedResource.CultureId)} eq '{CultureInfo.CurrentCulture.Name}'",
                Select = $"{nameof(LocalizedResource.Key)},{nameof(LocalizedResource.Value)}"
            }).ConfigureAwait(false)
                       .GetAwaiter()
                       .GetResult();

            return(page.Items
                   .Select(r => new LocalizedString(r.Key, r.Value, true)));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Finds the role who has the specified ID as an asynchronous operation.
        /// </summary>
        /// <param name="roleId">The role ID to look for.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>A <see cref="Task{TResult}"/> that result of the look up.</returns>
        public virtual async Task <TRole> FindByIdAsync(string roleId, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            ThrowIfDisposed();

            var response = await _roleStore.GetAsync(new PageRequest
            {
                Filter = $"{nameof(Role.Id)} eq '{roleId}'"
            }, cancellationToken).ConfigureAwait(false);

            if (response.Items.Any())
            {
                return(response.Items.First().ToIdentityRole <TRole>());
            }
            return(null);
        }
Ejemplo n.º 12
0
        public async Task <AuthorizationCode> GetAuthorizationCodeAsync(string code)
        {
            code = code ?? throw new ArgumentNullException(nameof(code));

            var response = await _store.GetAsync(new PageRequest
            {
                Filter = $"{nameof(Entity.AuthorizationCode.Id)} eq '{code}'",
                Select = nameof(Entity.AuthorizationCode.Data)
            }).ConfigureAwait(false);

            if (response.Count == 1)
            {
                return(_serializer.Deserialize <AuthorizationCode>(response.Items.First().Data));
            }
            return(null);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Finds the relying party by realm.
        /// </summary>
        /// <param name="realm">The realm.</param>
        /// <returns></returns>
        public async Task <RelyingParty> FindRelyingPartyByRealm(string realm)
        {
            var client = await _clientStore.GetAsync(realm, null).ConfigureAwait(false);

            var relyingPartyId = client.RelyingPartyId;
            var entity         = await _relyingPartyStore.GetAsync(relyingPartyId, new GetRequest
            {
                Expand = nameof(Entity.RelyingParty.ClaimMappings)
            }).ConfigureAwait(false);

            if (entity == null)
            {
                return(null);
            }

            return(new RelyingParty
            {
                ClaimMapping = entity.ClaimMappings.ToDictionary(m => m.FromClaimType, m => m.ToClaimType),
                DigestAlgorithm = entity.DigestAlgorithm,
                EncryptionCertificate = entity.EncryptionCertificate != null ? new X509Certificate2(entity.EncryptionCertificate) : null,
                Realm = entity.Id,
                SamlNameIdentifierFormat = entity.SamlNameIdentifierFormat,
                SignatureAlgorithm = entity.SignatureAlgorithm,
                TokenType = entity.TokenType
            });
        }
Ejemplo n.º 14
0
        private async Task UpdateRedirectUris(string clientId, ClientRegisteration registration)
        {
            var redirectUriResponse = await _clientUriStore.GetAsync(new PageRequest
            {
                Filter = $"{nameof(ClientUri.ClientId)} eq '{clientId}'"
            }).ConfigureAwait(false);

            foreach (var item in redirectUriResponse.Items)
            {
                if (!registration.RedirectUris.Any(u => u == item.Uri))
                {
                    await _clientUriStore.DeleteAsync(item.Id).ConfigureAwait(false);
                }
            }

            foreach (var redirectUri in registration.RedirectUris)
            {
                if (!redirectUriResponse.Items.Any(u => u.Uri == redirectUri))
                {
                    await _clientUriStore.CreateAsync(new ClientUri
                    {
                        ClientId = clientId,
                        Id       = Guid.NewGuid().ToString(),
                        Kind     = UriKinds.Cors | UriKinds.Redirect,
                        Uri      = redirectUri
                    }).ConfigureAwait(false);
                }
            }
        }
Ejemplo n.º 15
0
 /// <summary>
 /// Gets API scopes by scope name.
 /// </summary>
 /// <param name="scopeNames"></param>
 /// <returns></returns>
 public async Task<IEnumerable<Models.ApiScope>> FindApiScopesByNameAsync(IEnumerable<string> scopeNames)
 {
     var taskList = new List<Task<PageResponse<ApiScope>>>(scopeNames.Count());
     foreach (var name in scopeNames)
     {
         taskList.Add(_apiScopeStore.GetAsync(new PageRequest
         {
             Take = null,
             Filter = $"{nameof(ApiScope.Id)} eq '{name}'",
             Expand = $"{nameof(ApiScope.ApiScopeClaims)},{nameof(ApiScope.Properties)},{nameof(ApiScope.Resources)}"
         }));
     }
     await Task.WhenAll(taskList)
         .ConfigureAwait(false);
     return taskList.SelectMany(t => t.Result.Items.Select(s => s.ToApiScope()));
 }
Ejemplo n.º 16
0
        public async Task <TSchemeDefinition> FindBySchemeAsync(string scheme, CancellationToken cancellationToken = default)
        {
            var response = await _store.GetAsync(new PageRequest { Filter = $"{nameof(ExternalProvider.Id)} eq '{scheme}'" }, cancellationToken)
                           .ConfigureAwait(false);

            return(response.Items.Select(FromEntity).FirstOrDefault());
        }
Ejemplo n.º 17
0
        private async Task GetAllResourcesAsync()
        {
            _resources = new LocalizedResource[0];

            _currentCulture = CultureInfo.CurrentCulture;
            var parent = _currentCulture.Parent;
            var filter = $"{nameof(LocalizedResource.CultureId)} eq '{_currentCulture.Name}'";

            if (parent != null)
            {
                filter += $" or {nameof(LocalizedResource.CultureId)} eq '{_currentCulture.Parent.Name}'";
            }

            var page = await _store.GetAsync(new PageRequest
            {
                Filter  = filter,
                OrderBy = nameof(LocalizedResource.CultureId)
            }).ConfigureAwait(false);

            _resources = page.Items;
            foreach (var resource in _resources)
            {
                _keyValuePairs[resource.Key] = new LocalizedString(resource.Key, resource.Value ?? resource.Key, resource.Value == null);
            }

            ResourceReady();
        }
Ejemplo n.º 18
0
        private async Task UpdateGrantTypes(string clientId, ClientRegisteration registration)
        {
            var grantTypeResponse = await _clientGrantTypeStore.GetAsync(new PageRequest
            {
                Filter = $"{nameof(ClientGrantType.ClientId)} eq '{clientId}'"
            }).ConfigureAwait(false);

            foreach (var item in grantTypeResponse.Items)
            {
                if (!registration.GrantTypes.Any(g => g == item.GrantType))
                {
                    await _clientGrantTypeStore.DeleteAsync(item.Id).ConfigureAwait(false);
                }
            }

            foreach (var grantType in registration.GrantTypes)
            {
                if (!grantTypeResponse.Items.Any(u => u.GrantType == grantType))
                {
                    await _clientGrantTypeStore.CreateAsync(new ClientGrantType
                    {
                        ClientId  = clientId,
                        Id        = Guid.NewGuid().ToString(),
                        GrantType = grantType
                    }).ConfigureAwait(false);
                }
            }
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Gets the one time token.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        public string GetOneTimeToken(string id)
        {
            var token = _store.GetAsync(id, new GetRequest()).GetAwaiter().GetResult();

            _store.DeleteAsync(id).GetAwaiter().GetResult();
            return(token.Data);
        }
Ejemplo n.º 20
0
        public async Task <Models.DeviceCode> FindByDeviceCodeAsync(string deviceCode)
        {
            deviceCode = deviceCode ?? throw new ArgumentNullException(nameof(deviceCode));

            var response = await _store.GetAsync(new PageRequest
            {
                Filter = $"{nameof(DeviceCode.Code)} eq '{deviceCode}'",
                Select = nameof(DeviceCode.Data)
            }).ConfigureAwait(false);

            if (response.Items.Any())
            {
                return(ToModel(response.Items.First()));
            }

            return(null);
        }
Ejemplo n.º 21
0
        public async Task <Client> FindClientByIdAsync(string clientId)
        {
            var entity = await _store.GetAsync(clientId, new GetRequest
            {
                Expand = $"{nameof(Entity.Client.IdentityProviderRestrictions)},{nameof(Entity.Client.ClientClaims)},{nameof(Entity.Client.ClientSecrets)},{nameof(Entity.Client.AllowedGrantTypes)},{nameof(Entity.Client.RedirectUris)},{nameof(Entity.Client.AllowedScopes)},{nameof(Entity.Client.Properties)},{nameof(Entity.Client.Resources)}"
            }).ConfigureAwait(false);

            return(entity.ToClient());
        }
Ejemplo n.º 22
0
 public async Task <IEnumerable <Consent> > GetAllUserConsent(string subjectId)
 {
     return((await _store.GetAsync(new PageRequest
     {
         Filter = $"{nameof(UserConsent.UserId)} eq '{subjectId}'",
         Select = nameof(UserConsent.Data)
     }).ConfigureAwait(false)).Items
            .Select(c => _serializer.Deserialize <Consent>(c.Data)));
 }
Ejemplo n.º 23
0
        public async Task <Client> FindClientByIdAsync(string clientId)
        {
            var entity = await _store.GetAsync(clientId, new GetRequest
            {
                Expand = "IdentityProviderRestrictions,ClientClaims,ClientSecrets,AllowedGrantTypes,RedirectUris,AllowedScopes,Properties"
            }).ConfigureAwait(false);

            return(entity.ToClient());
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Gets identity resources by scope name.
        /// </summary>
        /// <param name="scopeNames"></param>
        /// <returns></returns>
        public async Task <IEnumerable <Models.IdentityResource> > FindIdentityResourcesByScopeAsync(IEnumerable <string> scopeNames)
        {
            var taskList = new List <Task <PageResponse <IdentityResource> > >(scopeNames.Count());

            foreach (var name in scopeNames)
            {
                taskList.Add(_identityStore.GetAsync(new PageRequest
                {
                    Filter = $"{nameof(IdentityResource.Id)} eq '{name}'",
                    Expand = $"{nameof(IdentityResource.IdentityClaims)},{nameof(IdentityResource.Properties)}"
                }));
            }
            await Task.WhenAll(taskList)
            .ConfigureAwait(false);

            return(taskList
                   .SelectMany(t => t.Result.Items.Select(e => e.ToIdentity())));
        }
Ejemplo n.º 25
0
        private async Task UpdatePropertiesAsync(string clientId, ClientRegisteration registration)
        {
            var propertiesResponse = await _clientPropertyStore.GetAsync(new PageRequest
            {
                Filter = $"{nameof(ClientProperty.ClientId)} eq '{clientId}' and ({nameof(ClientProperty.Key)} eq 'contacts' or {nameof(ClientProperty.Key)} eq 'responseTypes')"
            }).ConfigureAwait(false);

            await UpdatePropertyAsync(clientId, registration, propertiesResponse, registration.Contacts != null?string.Join("; ", registration.Contacts) : null, "contacts").ConfigureAwait(false);
            await UpdatePropertyAsync(clientId, registration, propertiesResponse, registration.ResponseTypes != null?string.Join("; ", registration.ResponseTypes) : null, "responseType").ConfigureAwait(false);
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Determines whether origin is allowed.
        /// </summary>
        /// <param name="origin">The origin.</param>
        /// <returns></returns>
        public async Task <bool> IsOriginAllowedAsync(string origin)
        {
            var corsUri   = new Uri(origin);
            var sanetized = $"{corsUri.Scheme.ToUpperInvariant()}://{corsUri.Host.ToUpperInvariant()}:{corsUri.Port}";
            var response  = await _store.GetAsync(new PageRequest
            {
                Filter = $"{nameof(ClientUri.SanetizedCorsUri)} eq '{sanetized}'",
                Select = nameof(ClientUri.SanetizedCorsUri)
            }).ConfigureAwait(false);

            return(response.Count > 0);
        }
Ejemplo n.º 27
0
        public async Task <IEnumerable <string> > GetSupportedCulturesAsync()
        {
            var response = await _cultureStore.GetAsync(new PageRequest
            {
                Select  = nameof(Culture.Id),
                OrderBy = nameof(Culture.Id)
            }).ConfigureAwait(false);

            var cultureList = new List <string>
            {
                "en"
            };

            cultureList.AddRange(response.Items.Select(c => c.Id));
            return(cultureList.Distinct());
        }
Ejemplo n.º 28
0
        /// <summary>
        /// Gets API resources by scope name.
        /// </summary>
        /// <param name="scopeNames"></param>
        /// <returns></returns>
        public async Task <IEnumerable <Models.ApiResource> > FindApiResourcesByScopeNameAsync(IEnumerable <string> scopeNames)
        {
            var filter            = string.Join(" or ", scopeNames.Select(s => $"{nameof(ApiApiScope.ApiScopeId)} eq '{s}'"));
            var apiIdListResponse = await _apiApiScopeStore.GetAsync(new PageRequest
            {
                Select = nameof(ApiApiScope.ApiId),
                Filter = filter
            }).ConfigureAwait(false);

            filter = string.Join(" or ", apiIdListResponse.Items.Select(i => $"{nameof(ProtectResource.Id)} eq '{i.ApiId}'"));
            var apiResposne = await _apiStore.GetAsync(new PageRequest
            {
                Filter = filter,
                Expand = $"{nameof(ProtectResource.ApiClaims)},{nameof(ProtectResource.Secrets)},{nameof(ProtectResource.ApiScopes)},{nameof(ProtectResource.Properties)},{nameof(ProtectResource.Resources)}"
            }).ConfigureAwait(false);

            return(apiResposne.Items.Select(r => r.ToApi()));
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Updates the registration asynchronous.
        /// </summary>
        /// <param name="clientId">The client identifier.</param>
        /// <param name="registration">The client.</param>
        /// <param name="uri">The URI.</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task <ClientRegisteration> UpdateRegistrationAsync(string clientId, ClientRegisteration registration, string uri)
        {
            var client = await GetClientAsync(clientId).ConfigureAwait(false);

            var discovery = await _discoveryResponseGenerator.CreateDiscoveryDocumentAsync(uri, uri).ConfigureAwait(false);

            Validate(registration, discovery);
            await UpdateClient(registration, client).ConfigureAwait(false);
            await UpdateRedirectUris(clientId, registration).ConfigureAwait(false);
            await UpdateGrantTypes(clientId, registration).ConfigureAwait(false);

            var resourceResponse = await _clientResourceStore.GetAsync(new PageRequest
            {
                Filter = $"{nameof(ClientGrantType.ClientId)} eq '{clientId}'"
            }).ConfigureAwait(false);

            var items          = resourceResponse.Items;
            var clientNameList = registration.ClientNames?.Where(n => n.Culture != null) ?? Array.Empty <LocalizableProperty>();
            var clientUriList  = registration.ClientUris?.Where(u => u.Culture != null) ?? Array.Empty <LocalizableProperty>();
            var logoUriList    = registration.LogoUris?.Where(u => u.Culture != null) ?? Array.Empty <LocalizableProperty>();
            var policyUriList  = registration.PolicyUris?.Where(u => u.Culture != null) ?? Array.Empty <LocalizableProperty>();
            var tosUriList     = registration.TosUris?.Where(u => u.Culture != null) ?? Array.Empty <LocalizableProperty>();

            foreach (var item in items)
            {
                await DeleteItemAsync(clientNameList, clientUriList, logoUriList, policyUriList, tosUriList, item).ConfigureAwait(false);
            }

            await AddResourceAsync(clientId, items, clientNameList).ConfigureAwait(false);
            await AddResourceAsync(clientId, items, clientUriList).ConfigureAwait(false);
            await AddResourceAsync(clientId, items, logoUriList).ConfigureAwait(false);
            await AddResourceAsync(clientId, items, policyUriList).ConfigureAwait(false);
            await AddResourceAsync(clientId, items, tosUriList).ConfigureAwait(false);

            await UpdatePropertiesAsync(clientId, registration).ConfigureAwait(false);

            registration.RegistrationToken    = null;
            registration.RegistrationUri      = null;
            registration.JwksUri              = discovery["jwks_uri"].ToString();
            registration.ClientSecret         = client.ClientSecrets.FirstOrDefault()?.Value;
            registration.ClientSecretExpireAt = client.ClientSecrets.Any() ? (int?)0 : null;

            return(registration);
        }
        /// <summary>
        /// Transforms the principal asynchronous.
        /// </summary>
        /// <param name="externalUser">The external user.</param>
        /// <param name="provider">The provider.</param>
        /// <returns></returns>
        public async Task <ClaimsPrincipal> TransformPrincipalAsync(ClaimsPrincipal externalUser, string provider)
        {
            var claims = new List <Claim>(externalUser.Claims.Count());
            var transformationsResponse = await _claimTransformationStore.GetAsync(new PageRequest
            {
                Filter = $"{nameof(ExternalClaimTransformation.Scheme)} eq '{provider}'"
            }).ConfigureAwait(false);

            var externalProvider = await _externalProviderStore.GetAsync(provider, new GetRequest()).ConfigureAwait(false);

            var transformationList          = transformationsResponse.Items;
            var defaultOutboundClaimMap     = JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap;
            var mapDefaultOutboundClaimType = externalProvider.MapDefaultOutboundClaimType;

            foreach (var claim in externalUser.Claims)
            {
                var transformation = transformationList.FirstOrDefault(t => t.FromClaimType == claim.Type);
                if (transformation != null)
                {
                    TransformClaimType(claims, claim, transformation.ToClaimType);
                    continue;
                }
                if (mapDefaultOutboundClaimType && defaultOutboundClaimMap.TryGetValue(claim.Type, out string toClaimType))
                {
                    TransformClaimType(claims, claim, toClaimType);
                    continue;
                }
                // copy the claim as-is
                claims.Add(claim);
            }

            if (externalProvider.StoreClaims)
            {
                await StoreClaims(externalUser, provider, claims).ConfigureAwait(false);

                // We store only user id claims to reduce the session cookie size to the minimum.
                // That's avoid request header too large exception.
                var newUserClaims = claims.Where(c => _userIdClaimTypes.Contains(c.Type)).Distinct().ToList();

                return(new ClaimsPrincipal(new ClaimsIdentity(newUserClaims, provider)));
            }

            return(new ClaimsPrincipal(new ClaimsIdentity(claims, provider)));
        }