public async Task UpdateConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes)
        {
            if (client == null) throw new ArgumentNullException("client");
            if (user == null) throw new ArgumentNullException("user");

            if (client.AllowRememberConsent)
            {
                var subject = user.GetSubjectId();
                var clientId = client.ClientId;

                if (scopes != null && scopes.Any())
                {
                    var consent = new Consent
                    {
                        Subject = subject,
                        ClientId = clientId,
                        Scopes = scopes
                    };
                    await _store.UpdateAsync(consent);
                }
                else
                {
                    await _store.RevokeAsync(subject, clientId);
                }
            }
        }
        public virtual async Task<IEnumerable<Claim>> GetIdentityTokenClaimsAsync(ClaimsPrincipal subject, Client client, IEnumerable<Scope> scopes, bool includeAllIdentityClaims, NameValueCollection request)
        {
            Logger.Debug("Getting claims for identity token");

            List<Claim> outputClaims = new List<Claim>(GetStandardSubjectClaims(subject));
            var additionalClaims = new List<string>();

            // fetch all identity claims that need to go into the id token
            foreach (var scope in scopes)
            {
                if (scope.IsOpenIdScope)
                {
                    foreach (var scopeClaim in scope.Claims)
                    {
                        if (includeAllIdentityClaims || scopeClaim.AlwaysIncludeInIdToken)
                        {
                            additionalClaims.Add(scopeClaim.Name);
                        }
                    }
                }
            }

            if (additionalClaims.Count > 0)
            {
                var claims = await _users.GetProfileDataAsync(subject.GetSubjectId(), additionalClaims);
                if (claims != null)
                {
                    outputClaims.AddRange(claims);
                }
            }

            return outputClaims;
        }
        public async Task<bool> RequiresConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes)
        {
            if (client == null) throw new ArgumentNullException("client");
            if (user == null) throw new ArgumentNullException("user");

            if (!client.RequireConsent)
            {
                return false;
            }

            // TODO: validate that this is a correct statement
            if (!client.AllowRememberConsent)
            {
                return true;
            }

            if (scopes == null || !scopes.Any())
            {
                return false;
            }
            
            var consent = await _store.LoadAsync(user.GetSubjectId(), client.ClientId);
            if (consent != null && consent.Scopes != null)
            {
                var intersect = scopes.Intersect(consent.Scopes);
                return !(scopes.Count() == intersect.Count());
            }

            return true;
        }
        public Task<IEnumerable<Claim>> GetProfileDataAsync(ClaimsPrincipal subject, IEnumerable<string> requestedClaimTypes = null) {
            var user = _users.SingleOrDefault(x => x.Subject == subject.GetSubjectId());

            if (user == null) {
                return Task.FromResult<IEnumerable<Claim>>(null);
            }
            return Task.FromResult(user.Claims.Where(x => requestedClaimTypes.Contains(x.Type)));
        }
        public async Task UpdateConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes)
        {
            if (client == null) throw new ArgumentNullException("client");
            if (user == null) throw new ArgumentNullException("user");

            if (client.AllowRememberConsent)
            {
                await _store.UpdateConsentAsync(client.ClientId, user.GetSubjectId(), scopes);
            }
        }
        public async Task<ValidationResult> ValidateAsync(NameValueCollection parameters, ClaimsPrincipal subject)
        {
            _validatedRequest.Raw = parameters;
            _validatedRequest.Subject = subject;

            if (!subject.Identity.IsAuthenticated)
            {
                return Invalid();
            }

            var idTokenHint = parameters.Get(Constants.EndSessionRequest.IdTokenHint);
            if (idTokenHint.IsPresent())
            {
                // validate id_token - no need to validate token life time
                var tokenValidationResult = await _tokenValidator.ValidateIdentityTokenAsync(idTokenHint, null, false);
                if (tokenValidationResult.IsError)
                {
                    return Invalid();
                }

                _validatedRequest.Client = tokenValidationResult.Client;

                // validate sub claim against currently logged on user
                var subClaim = tokenValidationResult.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject);
                if (subClaim != null)
                {
                    if (subject.GetSubjectId() != subClaim.Value)
                    {
                        return Invalid();
                    }
                }

                var redirectUri = parameters.Get(Constants.EndSessionRequest.PostLogoutRedirectUri);
                if (redirectUri.IsPresent())
                {
                    if (await _uriValidator.IsPostLogoutRedirecUriValidAsync(redirectUri, _validatedRequest.Client) == true)
                    {
                        _validatedRequest.PostLogOutUri = redirectUri;
                    }
                    else
                    {
                        return Invalid();
                    }

                    var state = parameters.Get(Constants.EndSessionRequest.State);
                    if (state.IsPresent())
                    {
                        _validatedRequest.State = state;
                    }
                }
            }

            return Valid();
        }
        public async Task<bool> RequiresConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes)
        {
            if (client == null) throw new ArgumentNullException("client");
            if (user == null) throw new ArgumentNullException("user");

            if (!client.RequireConsent)
            {
                return false;
            }

            return await _store.RequiresConsentAsync(client.ClientId, user.GetSubjectId(), scopes);
        }
        /// <summary>
        /// Returns claims for an identity token
        /// </summary>
        /// <param name="subject">The subject</param>
        /// <param name="client">The client</param>
        /// <param name="scopes">The requested scopes</param>
        /// <param name="includeAllIdentityClaims">Specifies if all claims should be included in the token, or if the userinfo endpoint can be used to retrieve them</param>
        /// <param name="request">The raw request</param>
        /// <returns>
        /// Claims for the identity token
        /// </returns>
        public virtual async Task<IEnumerable<Claim>> GetIdentityTokenClaimsAsync(ClaimsPrincipal subject, Client client, IEnumerable<Scope> scopes, bool includeAllIdentityClaims, ValidatedRequest request)
        {
            Logger.Info("Getting claims for identity token for subject: " + subject.GetSubjectId());

            var outputClaims = new List<Claim>(GetStandardSubjectClaims(subject));
            outputClaims.AddRange(GetOptionalClaims(subject));
            
            var additionalClaims = new List<string>();

            // if a include all claims rule exists, call the user service without a claims filter
            if (scopes.IncludesAllClaimsForUserRule(ScopeType.Identity))
            {
                Logger.Info("All claims rule found - emitting all claims for user.");

                var claims = await _users.GetProfileDataAsync(subject);
                if (claims != null)
                {
                    outputClaims.AddRange(claims);
                }

                return outputClaims;
            }

            // fetch all identity claims that need to go into the id token
            foreach (var scope in scopes)
            {
                if (scope.Type == ScopeType.Identity)
                {
                    foreach (var scopeClaim in scope.Claims)
                    {
                        if (includeAllIdentityClaims || scopeClaim.AlwaysIncludeInIdToken)
                        {
                            additionalClaims.Add(scopeClaim.Name);
                        }
                    }
                }
            }

            if (additionalClaims.Count > 0)
            {
                var claims = await _users.GetProfileDataAsync(subject, additionalClaims);
                if (claims != null)
                {
                    outputClaims.AddRange(claims);
                }
            }

            return outputClaims;
        }
        public Task UpdateConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes)
        {
            if (client.AllowRememberConsent)
            {
                var consent = new Consent
                {
                    ClientId = client.ClientId,
                    Subject = user.GetSubjectId(),
                    Scopes = string.Join(" ", scopes.OrderBy(s => s).ToArray())
                };

                _consents.Add(consent);
            }

            return Task.FromResult(0);
        }
        public Task<bool> RequiresConsentAsync(Client client, ClaimsPrincipal user, IEnumerable<string> scopes)
        {
            if (!client.RequireConsent)
            {
                return Task.FromResult(false);
            }

            var orderedScopes = string.Join(" ", scopes.OrderBy(s => s).ToArray());

            var query = from c in _consents
                        where c.ClientId == client.ClientId &&
                              c.Scopes == orderedScopes &&
                              c.Subject == user.GetSubjectId()
                        select c;

            var hit = query.FirstOrDefault();

            return Task.FromResult(hit == null);
        }
        /// <summary>
        /// Checks if consent is required.
        /// </summary>
        /// <param name="client">The client.</param>
        /// <param name="subject">The user.</param>
        /// <param name="scopes">The scopes.</param>
        /// <returns>Boolean if consent is required.</returns>
        public virtual async Task<bool> RequiresConsentAsync(Client client, ClaimsPrincipal subject, IEnumerable<string> scopes)
        {
            if (client == null) throw new ArgumentNullException("client");
            if (subject == null) throw new ArgumentNullException("subject");

            if (!client.RequireConsent)
            {
                return false;
            }

            // TODO: validate that this is a correct statement
            if (!client.AllowRememberConsent)
            {
                return true;
            }

            if (scopes == null || !scopes.Any())
            {
                return false;
            }

            // we always require consent for offline access if
            // the client has not disabled RequireConsent 
            if (scopes.Contains(Constants.StandardScopes.OfflineAccess))
            {
                return true;
            }
            
            var consent = await _store.LoadAsync(subject.GetSubjectId(), client.ClientId);
            if (consent != null && consent.Scopes != null)
            {
                var intersect = scopes.Intersect(consent.Scopes);
                return !(scopes.Count() == intersect.Count());
            }

            return true;
        }
        /// <summary>
        /// This method is called whenever claims about the user are requested (e.g. during token creation or via the userinfo endpoint)
        /// </summary>
        /// <param name="subject">The subject.</param>
        /// <param name="requestedClaimTypes">The requested claim types.</param>
        /// <returns>
        /// Claims
        /// </returns>
        public virtual Task<IEnumerable<Claim>> GetProfileDataAsync(ClaimsPrincipal subject, IEnumerable<string> requestedClaimTypes = null)
        {
            var query =
                from u in _users
                where u.Subject == subject.GetSubjectId()
                select u;
            var user = query.Single();

            var claims = new List<Claim>{
                new Claim(Constants.ClaimTypes.Subject, user.Subject),
            };

            claims.AddRange(user.Claims);
            if (requestedClaimTypes != null)
            {
                claims = claims.Where(x => requestedClaimTypes.Contains(x.Type)).ToList();
            }

            return Task.FromResult<IEnumerable<Claim>>(claims);
        }
 public Task<bool> IsActiveAsync(ClaimsPrincipal subject)
 {
     var user = Users.SingleOrDefault(x => x.Subject == subject.GetSubjectId());
     return Task.FromResult(user != null && user.AcceptedEula);
 }
        public async Task<ValidationResult> ValidateAsync(NameValueCollection parameters, ClaimsPrincipal subject)
        {
            Logger.Info("Start end session request validation");

            _validatedRequest.Raw = parameters;
            _validatedRequest.Subject = subject;

            if (!subject.Identity.IsAuthenticated && _options.AuthenticationOptions.RequireAuthenticatedUserForSignOutMessage)
            {
                Logger.Warn("User is anonymous. Ignoring end session parameters");
                return Invalid();
            }

            var idTokenHint = parameters.Get(Constants.EndSessionRequest.IdTokenHint);
            if (idTokenHint.IsPresent())
            {
                // validate id_token - no need to validate token life time
                var tokenValidationResult = await _tokenValidator.ValidateIdentityTokenAsync(idTokenHint, null, false);
                if (tokenValidationResult.IsError)
                {
                    LogError("Error validating id token hint.");
                    return Invalid();
                }

                _validatedRequest.Client = tokenValidationResult.Client;

                // validate sub claim against currently logged on user
                var subClaim = tokenValidationResult.Claims.FirstOrDefault(c => c.Type == Constants.ClaimTypes.Subject);
                if (subClaim != null && subject.Identity.IsAuthenticated)
                {
                    if (subject.GetSubjectId() != subClaim.Value)
                    {
                        LogError("Current user does not match identity token");
                        return Invalid();
                    }
                }

                var redirectUri = parameters.Get(Constants.EndSessionRequest.PostLogoutRedirectUri);
                if (redirectUri.IsPresent())
                {
                    _validatedRequest.PostLogOutUri = redirectUri;

                    if (await _uriValidator.IsPostLogoutRedirectUriValidAsync(redirectUri, _validatedRequest.Client) == false)
                    {
                        LogError("Invalid post logout URI");
                        return Invalid();
                    }

                    var state = parameters.Get(Constants.EndSessionRequest.State);
                    if (state.IsPresent())
                    {
                        _validatedRequest.State = state;
                    }
                }
            }

            LogSuccess();
            return Valid();
        }
Example #15
0
        private static void PerformTwoFactorAuthentication(PostAuthenticationContext context,
            ClaimsPrincipal authenticatedUser)
        {
            var twoFactorTokenService = new TwoFactorTokenService();
            if (twoFactorTokenService.HasVerifiedTwoFactorCode(authenticatedUser.GetSubjectId()))
            {
                return;
            }

            twoFactorTokenService.GenerateTwoFactorCodeFor(authenticatedUser.GetSubjectId());

            context.AuthenticateResult =
                new AuthenticateResult("~/twofactorauthentication", authenticatedUser.GetSubjectId(),
                    authenticatedUser.GetName(), authenticatedUser.Claims);
        }
        internal async Task<IEndpointResult> ProcessAuthorizeRequestAsync(NameValueCollection parameters, ClaimsPrincipal user, ConsentResponse consent)
        {
            if (user != null)
            {
                _logger.LogTrace("User in authorize request: name:{0}, sub:{1}", user.GetName(), user.GetSubjectId());
            }
            else
            {
                _logger.LogTrace("No user present in authorize request");
            }

            // validate request
            var result = await _validator.ValidateAsync(parameters, user);
            if (result.IsError)
            {
                return await ErrorPageAsync(
                    result.ErrorType, 
                    result.Error, 
                    result.ValidatedRequest);
            }

            var request = result.ValidatedRequest;

            // determine user interaction
            var interactionResult = await _interactionGenerator.ProcessInteractionAsync(request, consent);
            if (interactionResult.IsError)
            {
                return await ErrorPageAsync(
                    interactionResult.Error.ErrorType,
                    interactionResult.Error.Error,
                    request);
            }
            if (interactionResult.IsLogin)
            {
                return await LoginPageAsync(request);
            }
            if (interactionResult.IsConsent)
            {
                return await ConsentPageAsync(request);
            }

            // issue response
            return await SuccessfulAuthorizationAsync(request);
        }
        private string GetKey(ClaimsPrincipal subject, IEnumerable<string> requestedClaimTypes)
        {
            var sub = subject.GetSubjectId();
            if (requestedClaimTypes == null) return sub;

            return sub + ":" + requestedClaimTypes.OrderBy(x => x).Aggregate((x, y) => x + "," + y);
        }
        /// <summary>
        /// Gets the standard subject claims.
        /// </summary>
        /// <param name="subject">The subject.</param>
        /// <returns>A list of standard claims</returns>
        protected virtual IEnumerable<Claim> GetStandardSubjectClaims(ClaimsPrincipal subject)
        {
            var claims = new List<Claim>
            {
                new Claim(Constants.ClaimTypes.Subject, subject.GetSubjectId()),
                new Claim(Constants.ClaimTypes.AuthenticationMethod, subject.GetAuthenticationMethod()),
                new Claim(Constants.ClaimTypes.AuthenticationTime, subject.GetAuthenticationTimeEpoch().ToString(), ClaimValueTypes.Integer),
                new Claim(Constants.ClaimTypes.IdentityProvider, subject.GetIdentityProvider()),
            };

            return claims;
        }
        /// <summary>
        /// This method gets called whenever identity server needs to determine if the user is valid or active (e.g. during token issuance or validation)
        /// </summary>
        /// <param name="subject">The subject.</param>
        /// <returns>
        /// true or false
        /// </returns>
        /// <exception cref="System.ArgumentNullException">subject</exception>
        public virtual Task<bool> IsActiveAsync(ClaimsPrincipal subject)
        {
            if (subject == null) throw new ArgumentNullException("subject");

            var query =
                from u in _users
                where
                    u.Subject == subject.GetSubjectId()
                select u;

            var user = query.SingleOrDefault();

            if (user == null)
            {
                return Task.FromResult(false);
            }

            return Task.FromResult(user.Enabled);
        }