예제 #1
0
        private IEnumerable <string> GetDestinations(Claim claim, AuthenticationTicket ticket)
        {
            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            switch (claim.Type)
            {
            case OpenIdConnectConstants.Claims.Name:
                yield return(OpenIdConnectConstants.Destinations.AccessToken);

                if (ticket.HasScope(OpenIdConnectConstants.Scopes.Profile))
                {
                    yield return(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                yield break;

            case OpenIdConnectConstants.Claims.Email:
                yield return(OpenIdConnectConstants.Destinations.AccessToken);

                if (ticket.HasScope(OpenIdConnectConstants.Scopes.Email))
                {
                    yield return(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                yield break;

            case OpenIdConnectConstants.Claims.Role:
                yield return(OpenIdConnectConstants.Destinations.AccessToken);

                if (ticket.HasScope(OpenIddictConstants.Claims.Roles))
                {
                    yield return(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                yield break;

            // Never include the security stamp in the access and identity tokens, as it's a secret value.
            case "AspNet.Identity.SecurityStamp": yield break;

            default:
                yield return(OpenIdConnectConstants.Destinations.AccessToken);

                yield break;
            }
        }
예제 #2
0
        private async Task <AuthenticationTicket> CreateTicketAsync(
            OpenIdConnectRequest request, VanguardUser user,
            AuthenticationProperties properties = null)
        {
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var ticket = new AuthenticationTicket(principal, properties, OpenIddictServerDefaults.AuthenticationScheme);

            if (!request.IsRefreshTokenGrantType())
            {
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Profile,
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIddictConstants.Scopes.Roles
                }.Intersect(request.GetScopes()));
            }

            ticket.SetResources("vanguard-identity-management");

            foreach (var claim in ticket.Principal.Claims)
            {
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                if (claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile) ||
                    claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email) ||
                    claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            return(ticket);
        }
예제 #3
0
        private async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, ApplicationUser user,
                                                                    AuthenticationProperties properties = null)
        {
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var ticket = new AuthenticationTicket(principal, properties, OpenIdConnectServerDefaults.AuthenticationScheme);

            if (request.IsPasswordGrantType())
            {
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Profile,
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIddictConstants.Scopes.Roles,
                }.Intersect(request.GetScopes()));
            }

            ticket.SetResources(_appConfig.Jwt.Audiences);

            foreach (Claim claim in ticket.Principal.Claims.Where(x => x.Type != _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType))
            {
                List <string> destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                if (claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile) ||
                    claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email) ||
                    claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            ticket.SetAccessTokenLifetime(TimeSpan.FromHours(5));

            return(ticket);
        }
예제 #4
0
        public void HasScope_ReturnsAppropriateResult(string scope, bool result)
        {
            // Arrange
            var ticket = new AuthenticationTicket(
                new ClaimsIdentity(),
                new AuthenticationProperties());

            ticket.Properties.Dictionary[OpenIdConnectConstants.Properties.Scopes] = scope;

            // Act and assert
            Assert.Equal(result, ticket.HasScope(OpenIdConnectConstants.Scopes.OpenId));
        }
        public void HasScope_ReturnsExpectedResult(string scope, bool result)
        {
            // Arrange
            var ticket = new AuthenticationTicket(
                new ClaimsPrincipal(),
                new AuthenticationProperties(),
                nameof(AuthenticationTicket));

            ticket.Properties.Items[OpenIdConnectConstants.Properties.Scopes] = scope;

            // Act and assert
            Assert.Equal(result, ticket.HasScope());
        }
예제 #6
0
        public async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, ApplicationUser user)
        {
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var ticket = new AuthenticationTicket(principal,
                                                  new AuthenticationProperties(),
                                                  OpenIddictServerDefaults.AuthenticationScheme);


            var scopes = request.GetScopes().ToImmutableArray();

            ticket.SetScopes(scopes);
            ticket.SetResources(await _scopeManager.ListResourcesAsync(scopes));

            foreach (var claim in ticket.Principal.Claims)
            {
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            return(ticket);
        }
예제 #7
0
        private async Task <AuthenticationTicket> CreateTicketAsync(
            OpenIdConnectRequest oidcRequest, ApplicationUser user,
            AuthenticationProperties properties = null)
        {
            var principal = await signInManager.CreateUserPrincipalAsync(user);

            var ticket = new AuthenticationTicket(principal, properties,
                                                  OpenIddictServerDefaults.AuthenticationScheme);

            if (!oidcRequest.IsAuthorizationCodeGrantType())
            {
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Profile
                }.Intersect(oidcRequest.GetScopes()));
            }

            ticket.SetResources("resource_server");

            foreach (var claim in ticket.Principal.Claims)
            {
                if (claim.Type == identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                if (claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            return(ticket);
        }
        public static AuthenticationTicket CreateAuthenticationTicket(this ClaimsPrincipal principal, string securityStampClaimType)
        {
            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal,
                                                  new AuthenticationProperties(),
                                                  OpenIdConnectServerDefaults.AuthenticationScheme);

            // Set the list of scopes granted to the client application.
            ticket.SetScopes(OpenIdConnectConstants.Scopes.OpenId,
                             OpenIdConnectConstants.Scopes.Email,
                             OpenIdConnectConstants.Scopes.Profile,
                             OpenIddictConstants.Scopes.Roles);//.Intersect(request.GetScopes()));

            ticket.SetResources(ApplicationInfo.AppName);

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            foreach (var claim in from c in ticket.Principal.Claims
                     // Never include the security stamp in the access and identity tokens, as it's a secret value.
                     where c.Type != securityStampClaimType
                     select c)
            {
                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                if (IdentityClaimScopes.TryGetValue(claim.Type, out string scope) && ticket.HasScope(scope))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            return(ticket);
        }
예제 #9
0
        /// <summary>
        /// Creates a ticket for an OpenId connect request
        /// </summary>
        /// <param name="request">The OpenId connect request</param>
        /// <param name="user">The user to provide a ticket for</param>
        /// <returns>The OpenId ticket</returns>
        private async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, User user)
        {
            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await CreateUserPrincipal(user, OpenIdConnectConstants.Schemes.Bearer);

            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal,
                                                  new AuthenticationProperties(),
                                                  OpenIddictServerDefaults.AuthenticationScheme);

            // The scopes that are provided to every request
            var defaultScopes = new List <string>
            {
                OpenIdConnectConstants.Scopes.OpenId,
                OpenIddictConstants.Scopes.Roles,
            };
            // These are additional scopes that the client can also explicitly request
            var allowedScopes = new List <string>
            {
                OpenIdConnectConstants.Scopes.Email,
                OpenIdConnectConstants.Scopes.Profile,
                OpenIdConnectConstants.Scopes.OfflineAccess,
            };

            ticket.SetScopes(defaultScopes.Concat(allowedScopes.Intersect(request.GetScopes())));

            ticket.SetResources("resource-server");

            ticket.SetAccessTokenLifetime(new TimeSpan(7, 0, 0, 0));

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            return(ticket);
        }
예제 #10
0
        public async Task <IActionResult> Index(LoginModel model)
        {
            var user = await _userManager.FindByNameAsync(model.loginData.Username);

            if (user == null)
            {
                return(Unauthorized());
            }

            var result = await _signInManager.CheckPasswordSignInAsync(user, model.loginData.Password, true);

            if (!result.Succeeded)
            {
                return(Unauthorized());
            }

            var app = await _applicationManager.FindByClientIdAsync(model.client_id);

            if (user.Applications.All(x => x != app.Id))
            {
                return(Unauthorized());
            }

            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(),
                                                  OpenIdConnectServerDefaults.AuthenticationScheme);

            ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AuthorizationCode);

            var scope = model.scope.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);

            if (scope.Contains(OpenIdConnectConstants.Scopes.Profile))
            {
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Profile,
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIddictConstants.Scopes.Roles
                }.Intersect(scope));
            }

            foreach (var claim in ticket.Principal.Claims.Where(x => x.Type != _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType))
            {
                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                if (claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile) ||
                    claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }


            return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
        }
예제 #11
0
        private async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, ApplicationUser user)
        {
            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var identity = (ClaimsIdentity)principal.Identity;

            if (!string.IsNullOrEmpty(user.MobileNumber))
            {
                var mobileNumberClaim = new Claim("mobileNumber", user.MobileNumber?.ToString() ?? "", ClaimValueTypes.String);
                mobileNumberClaim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken);
                identity.AddClaim(mobileNumberClaim);
            }

            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal,
                                                  new AuthenticationProperties(),
                                                  OpenIdConnectServerDefaults.AuthenticationScheme);

            // Set the list of scopes granted to the client application.
            ticket.SetScopes(new[]
            {
                OpenIdConnectConstants.Scopes.OpenId,
                OpenIdConnectConstants.Scopes.Email,
                OpenIdConnectConstants.Scopes.Profile,
                OpenIddictConstants.Scopes.Roles
            }.Intersect(request.GetScopes()));

            ticket.SetResources(_configuration["NetSo:Audience"]);

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }


            return(ticket);
        }
        private async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest oidcRequest, User user,
                                                                    AuthenticationProperties properties = null)
        {
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var identity = (ClaimsIdentity)principal.Identity;

            AddUserInformationClaims(user, identity);

            var ticket = new AuthenticationTicket(principal, properties, OpenIddictServerDefaults.AuthenticationScheme);

            if (!oidcRequest.IsRefreshTokenGrantType())
            {
                // Set the list of scopes granted to the client application.
                // Note: the offline_access scope must be granted
                // to allow OpenIddict to return a refresh token.
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Profile,
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIddictConstants.Scopes.Roles,
                }.Intersect(oidcRequest.GetScopes()));
            }

            ticket.SetResources("resource_server");

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.
            var destinations = new List <string>
            {
                OpenIdConnectConstants.Destinations.AccessToken
            };

            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Audience && ticket.HasScope(OpenIddictConstants.Claims.Audience))

                    )
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            //var name = new Claim(OpenIdConnectConstants.Claims.GivenName, user.FullName ?? "[NA]");
            //name.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken);
            //identity.AddClaim(name);

            return(ticket);
        }
예제 #13
0
        //TODO: this is an example
        private async Task <AuthenticationTicket> CreateTicketAsync(
            OpenIdConnectRequest request,
            AuthenticateResult authResult = null)
        {
            AuthenticationProperties properties = authResult.Properties;

            var userId = authResult.Principal.Claims.FirstOrDefault(_ => _.Type == OpenIdConnectConstants.Claims.Subject)?.Value;

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

            // string userPrincipalName = _sessionStateService.Get<string>("UserPrincipalName");
            SimpleClaim simpleClaim = new SimpleClaim()
            {
                ObjectIdentifier  = userId,
                UserPrincipalName = "SomeUPN",
                GivenName         = "Joe",
                Surname           = "Citizen"
            };

            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            //var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var identity = new ClaimsIdentity(
                OpenIdConnectServerDefaults.AuthenticationScheme,
                OpenIdConnectConstants.Claims.Name,
                OpenIdConnectConstants.Claims.Role);

            // Add a "sub" claim containing the user identifier, and attach
            // the "access_token" destination to allow OpenIddict to store it
            // in the access token, so it can be retrieved from your controllers.
            identity.AddClaim(OpenIdConnectConstants.Claims.Subject, simpleClaim.ObjectIdentifier,
                              OpenIdConnectConstants.Destinations.IdentityToken);
            identity.AddClaim(OpenIdConnectConstants.Claims.Name, simpleClaim.GivenName,
                              OpenIdConnectConstants.Destinations.IdentityToken);
            identity.AddClaim(OpenIdConnectConstants.Claims.GivenName, simpleClaim.GivenName,
                              OpenIdConnectConstants.Destinations.IdentityToken);
            identity.AddClaim(OpenIdConnectConstants.Claims.FamilyName, simpleClaim.Surname,
                              OpenIdConnectConstants.Destinations.IdentityToken);
            identity.AddClaim(ClaimTypes.Upn, simpleClaim.UserPrincipalName,
                              OpenIdConnectConstants.Destinations.IdentityToken);
            // ... add other claims, if necessary.
            var principal = new ClaimsPrincipal(identity);

            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal, properties,
                                                  OpenIdConnectServerDefaults.AuthenticationScheme);

            if (!request.IsAuthorizationCodeGrantType())
            {
                // Set the list of scopes granted to the client application.
                // Note: the offline_access scope must be granted
                // to allow OpenIddict to return a refresh token.
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Profile,
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIddictConstants.Scopes.Roles
                }.Intersect(request.GetScopes()));
            }

            ticket.SetResources("resource_server");

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            return(ticket);
        }
예제 #14
0
        private async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, ApplicationUser user,
                                                                    AuthenticationProperties properties = null, string token = "")
        {
            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal, properties,
                                                  OpenIdConnectServerDefaults.AuthenticationScheme);

            if (!request.IsRefreshTokenGrantType())
            {
                // Set the list of scopes granted to the client application.
                // Note: the offline_access scope must be granted
                // to allow OpenIddict to return a refresh token.
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Profile, // "name"
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIdConnectConstants.Scopes.Phone,
                    OpenIddictConstants.Scopes.Roles,
                    //"Read",
                    //"Balance",

                    //"UserId",
                    //"Address",
                }.Intersect(request.GetScopes()));
            }

            if (!string.IsNullOrEmpty(token))///send the redisstorage token to frant using Resources parameter.
            {
                ticket.SetResources(token);
            }
            else
            {
                ticket.SetResources("resource_server");
            }
            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.PhoneNumber && ticket.HasScope(OpenIdConnectConstants.Scopes.Phone)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles))) // ||
                                                                                                                             //(claim.Type == "Read" && ticket.HasScope("Read")) || (claim.Type == "Balance" && ticket.HasScope("Balance")))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            return(ticket);
        }
예제 #15
0
        private async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, ApplicationUser user, Cliente cliente = null, AuthenticationProperties properties = null)
        {
            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);

            //identity.AddClaims(principal.Claims);

            if (cliente != null)
            {
                Claim querOferecer  = new Claim(Lust.Infra.CrossCutting.Identity.Primitives.Claims.QuerOferecer, cliente.EstaOferecendo.ToString().ToLower());
                Claim querDesfrutar = new Claim(Lust.Infra.CrossCutting.Identity.Primitives.Claims.QuerDesfrutar, cliente.EstaDesfrutando.ToString().ToLower());


                identity.AddClaim(querOferecer);
                identity.AddClaim(querDesfrutar);
            }

            principal.AddIdentity(identity);
            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal, properties,
                                                  OpenIdConnectServerDefaults.AuthenticationScheme);

            if (!request.IsRefreshTokenGrantType())
            {
                // Set the list of scopes granted to the client application.
                // Note: the offline_access scope must be granted
                // to allow OpenIddict to return a refresh token.
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Profile,
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIddictConstants.Scopes.Roles
                }.Intersect(request.GetScopes()));
            }

            ticket.SetResources("resource_server");

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.



            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)) ||
                    (claim.Type == Lust.Infra.CrossCutting.Identity.Primitives.Claims.QuerOferecer) ||
                    (claim.Type == Lust.Infra.CrossCutting.Identity.Primitives.Claims.QuerDesfrutar))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }



            return(ticket);
        }
        private async Task <bool> HandleSignInAsync(AuthenticationTicket ticket)
        {
            // Extract the OpenID Connect request from the OWIN context.
            // If it cannot be found or doesn't correspond to an authorization
            // or a token request, throw an InvalidOperationException.
            var request = Context.GetOpenIdConnectRequest();

            if (request == null || (!request.IsAuthorizationRequest() && !request.IsTokenRequest()))
            {
                throw new InvalidOperationException("An authorization or token response cannot be returned from this endpoint.");
            }

            // Note: if a response was already generated, throw an exception.
            var response = Context.GetOpenIdConnectResponse();

            if (response != null)
            {
                throw new InvalidOperationException("A response has already been sent.");
            }

            if (string.IsNullOrEmpty(ticket.Identity.GetClaim(OpenIdConnectConstants.Claims.Subject)))
            {
                throw new InvalidOperationException("The authentication ticket was rejected because " +
                                                    "the mandatory subject claim was missing.");
            }

            Logger.LogTrace("A sign-in operation was triggered: {Claims} ; {Properties}.",
                            ticket.Identity.Claims, ticket.Properties.Dictionary);

            // Prepare a new OpenID Connect response.
            response = new OpenIdConnectResponse();

            // Copy the confidentiality level associated with the request to the authentication ticket.
            if (!ticket.HasProperty(OpenIdConnectConstants.Properties.ConfidentialityLevel))
            {
                ticket.SetConfidentialityLevel(request.GetProperty <string>(OpenIdConnectConstants.Properties.ConfidentialityLevel));
            }

            // Always include the "openid" scope when the developer doesn't explicitly call SetScopes.
            // Note: the application is allowed to specify a different "scopes": in this case,
            // don't replace the "scopes" property stored in the authentication ticket.
            if (request.HasScope(OpenIdConnectConstants.Scopes.OpenId) && !ticket.HasScope())
            {
                ticket.SetScopes(OpenIdConnectConstants.Scopes.OpenId);
            }

            // When a "resources" property cannot be found in the ticket,
            // infer it from the "audiences" property.
            if (ticket.HasAudience() && !ticket.HasResource())
            {
                ticket.SetResources(ticket.GetAudiences());
            }

            // Add the validated client_id to the list of authorized presenters,
            // unless the presenters were explicitly set by the developer.
            var presenter = request.GetProperty <string>(OpenIdConnectConstants.Properties.ValidatedClientId);

            if (!string.IsNullOrEmpty(presenter) && !ticket.HasPresenter())
            {
                ticket.SetPresenters(presenter);
            }

            var notification = new ProcessSigninResponseContext(Context, Options, ticket, request, response);

            if (request.IsAuthorizationRequest())
            {
                // By default, return an authorization code if a response type containing code was specified.
                notification.IncludeAuthorizationCode = request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Code);

                // By default, return an access token if a response type containing token was specified.
                notification.IncludeAccessToken = request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Token);

                // By default, prevent a refresh token from being returned as the OAuth2 specification
                // explicitly disallows returning a refresh token from the authorization endpoint.
                // See https://tools.ietf.org/html/rfc6749#section-4.2.2 for more information.
                notification.IncludeRefreshToken = false;

                // By default, return an identity token if a response type containing code
                // was specified and if the openid scope was explicitly or implicitly granted.
                notification.IncludeIdentityToken =
                    request.HasResponseType(OpenIdConnectConstants.ResponseTypes.IdToken) &&
                    ticket.HasScope(OpenIdConnectConstants.Scopes.OpenId);
            }

            else
            {
                // By default, prevent an authorization code from being returned as this type of token
                // cannot be issued from the token endpoint in the standard OAuth2/OpenID Connect flows.
                notification.IncludeAuthorizationCode = false;

                // By default, always return an access token.
                notification.IncludeAccessToken = true;

                // By default, only return a refresh token is the offline_access scope was granted and if
                // sliding expiration is disabled or if the request is not a grant_type=refresh_token request.
                notification.IncludeRefreshToken =
                    ticket.HasScope(OpenIdConnectConstants.Scopes.OfflineAccess) &&
                    (Options.UseSlidingExpiration || !request.IsRefreshTokenGrantType());

                // By default, only return an identity token if the openid scope was granted.
                notification.IncludeIdentityToken = ticket.HasScope(OpenIdConnectConstants.Scopes.OpenId);
            }

            await Options.Provider.ProcessSigninResponse(notification);

            if (notification.HandledResponse)
            {
                Logger.LogDebug("The sign-in response was handled in user code.");

                return(true);
            }

            else if (notification.Skipped)
            {
                Logger.LogDebug("The default sign-in handling was skipped from user code.");

                return(false);
            }

            else if (notification.IsRejected)
            {
                Logger.LogError("The request was rejected with the following error: {Error} ; {Description}",
                                /* Error: */ notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                                /* Description: */ notification.ErrorDescription);

                if (request.IsAuthorizationRequest())
                {
                    return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse
                    {
                        Error = notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                        ErrorDescription = notification.ErrorDescription,
                        ErrorUri = notification.ErrorUri
                    }));
                }

                return(await SendTokenResponseAsync(new OpenIdConnectResponse
                {
                    Error = notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = notification.ErrorDescription,
                    ErrorUri = notification.ErrorUri
                }));
            }

            // Flow the changes made to the ticket.
            ticket = notification.Ticket;

            // Ensure an authentication ticket has been provided or return
            // an error code indicating that the request was rejected.
            if (ticket == null)
            {
                Logger.LogError("The request was rejected because no authentication ticket was provided.");

                if (request.IsAuthorizationRequest())
                {
                    return(await SendAuthorizationResponseAsync(new OpenIdConnectResponse
                    {
                        Error = OpenIdConnectConstants.Errors.AccessDenied,
                        ErrorDescription = "The authorization was denied by the resource owner."
                    }));
                }

                return(await SendTokenResponseAsync(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The token request was rejected by the authorization server."
                }));
            }

            if (notification.IncludeAuthorizationCode)
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                response.Code = await SerializeAuthorizationCodeAsync(ticket.Identity, properties, request, response);
            }

            if (notification.IncludeAccessToken)
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                // When receiving a grant_type=refresh_token request, determine whether the client application
                // requests a limited set of scopes and replace the corresponding properties if necessary.
                if (!string.IsNullOrEmpty(request.Scope) && request.IsTokenRequest() && request.IsRefreshTokenGrantType())
                {
                    Logger.LogDebug("The access token scopes will be limited to the scopes requested " +
                                    "by the client application: {Scopes}.", request.GetScopes());

                    // Replace the scopes initially granted by the scopes listed by the client
                    // application in the token request. Note: request.GetScopes() automatically
                    // removes duplicate entries, so additional filtering is not necessary.
                    properties.SetProperty(OpenIdConnectConstants.Properties.Scopes,
                                           new JArray(request.GetScopes()).ToString(Formatting.None));
                }

                var scopes = ticket.GetScopes();
                if ((request.IsTokenRequest() && request.IsAuthorizationCodeGrantType()) ||
                    !new HashSet <string>(scopes).SetEquals(request.GetScopes()))
                {
                    response.Scope = string.Join(" ", scopes);
                }

                response.TokenType   = OpenIdConnectConstants.TokenTypes.Bearer;
                response.AccessToken = await SerializeAccessTokenAsync(ticket.Identity, properties, request, response);

                // properties.ExpiresUtc is automatically set by SerializeAccessTokenAsync but the end user
                // is free to set a null value directly in the SerializeAccessToken event.
                if (properties.ExpiresUtc.HasValue && properties.ExpiresUtc > Options.SystemClock.UtcNow)
                {
                    var lifetime = properties.ExpiresUtc.Value - Options.SystemClock.UtcNow;

                    response.ExpiresIn = (long)(lifetime.TotalSeconds + .5);
                }
            }

            if (notification.IncludeRefreshToken)
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                response.RefreshToken = await SerializeRefreshTokenAsync(ticket.Identity, properties, request, response);
            }

            if (notification.IncludeIdentityToken)
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                response.IdToken = await SerializeIdentityTokenAsync(ticket.Identity, properties, request, response);
            }

            if (request.IsAuthorizationRequest())
            {
                return(await SendAuthorizationResponseAsync(response, ticket));
            }

            return(await SendTokenResponseAsync(response, ticket));
        }
        private async Task <bool> HandleSignInAsync(AuthenticationTicket ticket)
        {
            // Extract the OpenID Connect request from the ASP.NET Core context.
            // If it cannot be found or doesn't correspond to an authorization
            // or a token request, throw an InvalidOperationException.
            var request = Context.GetOpenIdConnectRequest();

            if (request == null || (!request.IsAuthorizationRequest() && !request.IsTokenRequest()))
            {
                throw new InvalidOperationException("An authorization or token response cannot be returned from this endpoint.");
            }

            // Note: if a response was already generated, throw an exception.
            var response = Context.GetOpenIdConnectResponse();

            if (response != null || Response.HasStarted)
            {
                throw new InvalidOperationException("A response has already been sent.");
            }

            if (string.IsNullOrEmpty(ticket.Principal.GetClaim(OpenIdConnectConstants.Claims.Subject)))
            {
                throw new InvalidOperationException("The authentication ticket was rejected because " +
                                                    "the mandatory subject claim was missing.");
            }

            Logger.LogTrace("A sign-in operation was triggered: {Claims} ; {Properties}.",
                            ticket.Principal.Claims, ticket.Properties.Items);

            // Prepare a new OpenID Connect response.
            response = new OpenIdConnectResponse();

            // Copy the confidentiality level associated with the request to the authentication ticket.
            if (!ticket.HasProperty(OpenIdConnectConstants.Properties.ConfidentialityLevel))
            {
                ticket.SetConfidentialityLevel(request.GetProperty <string>(OpenIdConnectConstants.Properties.ConfidentialityLevel));
            }

            // Always include the "openid" scope when the developer doesn't explicitly call SetScopes.
            // Note: the application is allowed to specify a different "scopes": in this case,
            // don't replace the "scopes" property stored in the authentication ticket.
            if (request.HasScope(OpenIdConnectConstants.Scopes.OpenId) && !ticket.HasScope())
            {
                ticket.SetScopes(OpenIdConnectConstants.Scopes.OpenId);
            }

            // When a "resources" property cannot be found in the ticket,
            // infer it from the "audiences" property.
            if (ticket.HasAudience() && !ticket.HasResource())
            {
                ticket.SetResources(ticket.GetAudiences());
            }

            // Add the validated client_id to the list of authorized presenters,
            // unless the presenters were explicitly set by the developer.
            var presenter = request.GetProperty <string>(OpenIdConnectConstants.Properties.ValidatedClientId);

            if (!string.IsNullOrEmpty(presenter) && !ticket.HasPresenter())
            {
                ticket.SetPresenters(presenter);
            }

            // Only return an authorization code if the request is an authorization request and has response_type=code.
            if (request.IsAuthorizationRequest() && request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Code))
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                response.Code = await SerializeAuthorizationCodeAsync(ticket.Principal, properties, request, response);
            }

            // Only return an access token if the request is a token request
            // or an authorization request that specifies response_type=token.
            if (request.IsTokenRequest() || (request.IsAuthorizationRequest() &&
                                             request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Token)))
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                // When receiving a grant_type=refresh_token request, determine whether the client application
                // requests a limited set of scopes/resources and replace the corresponding properties if necessary.
                // Note: at this stage, request.GetResources() cannot return more items than the ones that were initially granted
                // by the resource owner as the "resources" parameter is always validated when receiving the token request.
                if (request.IsTokenRequest() && request.IsRefreshTokenGrantType())
                {
                    if (!string.IsNullOrEmpty(request.Resource))
                    {
                        Logger.LogDebug("The access token resources will be limited to the resources requested " +
                                        "by the client application: {Resources}.", request.GetResources());

                        // Replace the resources initially granted by the resources listed by the client
                        // application in the token request. Note: request.GetResources() automatically
                        // removes duplicate entries, so additional filtering is not necessary.
                        properties.SetProperty(OpenIdConnectConstants.Properties.Resources,
                                               new JArray(request.GetResources()).ToString(Formatting.None));
                    }

                    if (!string.IsNullOrEmpty(request.Scope))
                    {
                        Logger.LogDebug("The access token scopes will be limited to the scopes requested " +
                                        "by the client application: {Scopes}.", request.GetScopes());

                        // Replace the scopes initially granted by the scopes listed by the client
                        // application in the token request. Note: request.GetScopes() automatically
                        // removes duplicate entries, so additional filtering is not necessary.
                        properties.SetProperty(OpenIdConnectConstants.Properties.Scopes,
                                               new JArray(request.GetScopes()).ToString(Formatting.None));
                    }
                }

                var resources = ticket.GetResources();
                if (request.IsAuthorizationCodeGrantType() || !new HashSet <string>(resources).SetEquals(request.GetResources()))
                {
                    response.Resource = string.Join(" ", resources);
                }

                var scopes = ticket.GetScopes();
                if (request.IsAuthorizationCodeGrantType() || !new HashSet <string>(scopes).SetEquals(request.GetScopes()))
                {
                    response.Scope = string.Join(" ", scopes);
                }

                response.TokenType   = OpenIdConnectConstants.TokenTypes.Bearer;
                response.AccessToken = await SerializeAccessTokenAsync(ticket.Principal, properties, request, response);

                // properties.ExpiresUtc is automatically set by SerializeAccessTokenAsync but the end user
                // is free to set a null value directly in the SerializeAccessToken event.
                if (properties.ExpiresUtc.HasValue && properties.ExpiresUtc > Options.SystemClock.UtcNow)
                {
                    var lifetime = properties.ExpiresUtc.Value - Options.SystemClock.UtcNow;

                    response.ExpiresIn = (long)(lifetime.TotalSeconds + .5);
                }
            }

            // Only return a refresh token if the request is a token request that specifies scope=offline_access.
            if (request.IsTokenRequest() && ticket.HasScope(OpenIdConnectConstants.Scopes.OfflineAccess))
            {
                // Note: when sliding expiration is disabled, don't return a new refresh token,
                // unless the token request is not a grant_type=refresh_token request.
                if (Options.UseSlidingExpiration || !request.IsRefreshTokenGrantType())
                {
                    // Make sure to create a copy of the authentication properties
                    // to avoid modifying the properties set on the original ticket.
                    var properties = ticket.Properties.Copy();

                    response.RefreshToken = await SerializeRefreshTokenAsync(ticket.Principal, properties, request, response);
                }
            }

            // Only return an identity token if the openid scope was requested and granted
            // to avoid generating and returning an unnecessary token to pure OAuth2 clients.
            if (ticket.HasScope(OpenIdConnectConstants.Scopes.OpenId))
            {
                // Note: don't return an identity token if the request is an
                // authorization request that doesn't use response_type=id_token.
                if (request.IsTokenRequest() || request.HasResponseType(OpenIdConnectConstants.ResponseTypes.IdToken))
                {
                    // Make sure to create a copy of the authentication properties
                    // to avoid modifying the properties set on the original ticket.
                    var properties = ticket.Properties.Copy();

                    response.IdToken = await SerializeIdentityTokenAsync(ticket.Principal, properties, request, response);
                }
            }

            if (request.IsAuthorizationRequest())
            {
                return(await SendAuthorizationResponseAsync(response, ticket));
            }

            return(await SendTokenResponseAsync(response, ticket));
        }
        private async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, HaloLiveApplicationUser user)
        {
            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await SignInManager.CreateUserPrincipalAsync(user);

            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal,
                                                  new AuthenticationProperties(),
                                                  OpenIdConnectServerDefaults.AuthenticationScheme);

            // Set the list of scopes granted to the client application.
            ticket.SetScopes(new[]
            {
                OpenIdConnectConstants.Scopes.OpenId,
                OpenIdConnectConstants.Scopes.Profile,
                OpenIddictConstants.Scopes.Roles
            }.Intersect(request.GetScopes()));

            ticket.SetResources("auth-server");

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == IdentityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                // We should also add the "sub" claim too for identity sake
                if ((claim.Type == OpenIdConnectConstants.Claims.Name || claim.Type == OpenIdConnectConstants.Claims.Subject) && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            return(ticket);
        }
        private async Task <AuthenticationTicket> CreateTicketAsync(
            OpenIdConnectRequest request, Users user,
            AuthenticationProperties properties = null)
        {
            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            //principal.AddIdentity(new ClaimsIdentity(new List<Claim>()
            //{
            //    new Claim("org", user.OrganizationId),
            //    new Claim(System.Security.Claims.ClaimTypes.NameIdentifier, user.Id)
            //}));
            var ci = principal.Identity as ClaimsIdentity;

            ci.AddClaim("org", user.OrganizationId);
            ci.AddClaim(OpenIdConnectConstants.Claims.Subject, user.Id);

            if (properties == null)
            {
                properties = new AuthenticationProperties();
            }


            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal, properties,
                                                  OpenIdConnectServerDefaults.AuthenticationScheme);

            if (!request.IsAuthorizationCodeGrantType() && !request.IsRefreshTokenGrantType())
            {
                // Set the list of scopes granted to the client application.
                // Note: the offline_access scope must be granted
                // to allow OpenIddict to return a refresh token.
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Profile,
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIddictConstants.Scopes.Roles
                }.Intersect(request.GetScopes()));
            }



            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }


                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            return(ticket);
        }
예제 #20
0
        public async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, User user)
        {
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), OpenIddictServerDefaults.AuthenticationScheme);

            ticket.SetScopes(new[]
            {
                OpenIdConnectConstants.Scopes.OpenId,
                OpenIdConnectConstants.Scopes.Email,
                OpenIdConnectConstants.Scopes.Phone,
                OpenIdConnectConstants.Scopes.Profile,
                OpenIdConnectConstants.Scopes.OfflineAccess,
                OpenIddictConstants.Scopes.Roles
            }.Intersect(request.GetScopes()));
            foreach (var claim in ticket.Principal.Claims)
            {
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }
                var destinations = new List <string> {
                    OpenIdConnectConstants.Destinations.AccessToken
                };
                if ((claim.Type == OpenIdConnectConstants.Claims.Subject && ticket.HasScope(OpenIdConnectConstants.Scopes.OpenId)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)) ||
                    (claim.Type == CustomClaimTypes.Permission && ticket.HasScope(OpenIddictConstants.Claims.Roles)))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }
                claim.SetDestinations(destinations);
            }
            var identity = principal.Identity as ClaimsIdentity;

            if (ticket.HasScope(OpenIdConnectConstants.Scopes.Profile))
            {
                if (!string.IsNullOrWhiteSpace(user.JobTitle))
                {
                    identity.AddClaim(CustomClaimTypes.JobTitle, user.JobTitle, OpenIdConnectConstants.Destinations.IdentityToken);
                }
                if (!string.IsNullOrWhiteSpace(user.FullName))
                {
                    identity.AddClaim(CustomClaimTypes.FullName, user.FullName, OpenIdConnectConstants.Destinations.IdentityToken);
                }
                if (!string.IsNullOrWhiteSpace(user.Configuration))
                {
                    identity.AddClaim(CustomClaimTypes.Configuration, user.Configuration, OpenIdConnectConstants.Destinations.IdentityToken);
                }
            }

            if (ticket.HasScope(OpenIdConnectConstants.Scopes.Email))
            {
                if (!string.IsNullOrWhiteSpace(user.Email))
                {
                    identity.AddClaim(CustomClaimTypes.Email, user.Email, OpenIdConnectConstants.Destinations.IdentityToken);
                }
            }

            if (ticket.HasScope(OpenIdConnectConstants.Scopes.Phone))
            {
                if (!string.IsNullOrWhiteSpace(user.PhoneNumber))
                {
                    identity.AddClaim(CustomClaimTypes.Phone, user.PhoneNumber, OpenIdConnectConstants.Destinations.IdentityToken);
                }
            }

            return(ticket);
        }
예제 #21
0
        private async Task <bool> InvokeTokenEndpointAsync()
        {
            if (!string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase))
            {
                Logger.LogError("The token request was rejected because an invalid " +
                                "HTTP method was received: {Method}.", Request.Method);

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = "A malformed token request has been received: make sure to use POST."
                }));
            }

            // See http://openid.net/specs/openid-connect-core-1_0.html#FormSerialization
            if (string.IsNullOrEmpty(Request.ContentType))
            {
                Logger.LogError("The token request was rejected because the " +
                                "mandatory 'Content-Type' header was missing.");

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = "A malformed token request has been received: " +
                                       "the mandatory 'Content-Type' header was missing from the POST request."
                }));
            }

            // May have media/type; charset=utf-8, allow partial match.
            if (!Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
            {
                Logger.LogError("The token request was rejected because an invalid 'Content-Type' " +
                                "header was received: {ContentType}.", Request.ContentType);

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = "A malformed token request has been received: " +
                                       "the 'Content-Type' header contained an unexcepted value. " +
                                       "Make sure to use 'application/x-www-form-urlencoded'."
                }));
            }

            var form = await Request.ReadFormAsync(Context.RequestAborted);

            var request = new OpenIdConnectMessage(form.ToDictionary())
            {
                RequestType = OpenIdConnectRequestType.TokenRequest
            };

            // Store the token request in the ASP.NET context.
            Context.SetOpenIdConnectRequest(request);

            // Reject token requests missing the mandatory grant_type parameter.
            if (string.IsNullOrEmpty(request.GrantType))
            {
                Logger.LogError("The token request was rejected because the grant type was missing.");

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = "The mandatory 'grant_type' parameter was missing.",
                }));
            }

            // Reject grant_type=authorization_code requests missing the authorization code.
            // See https://tools.ietf.org/html/rfc6749#section-4.1.3
            else if (request.IsAuthorizationCodeGrantType() && string.IsNullOrEmpty(request.Code))
            {
                Logger.LogError("The token request was rejected because the authorization code was missing.");

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = "The mandatory 'code' parameter was missing."
                }));
            }

            // Reject grant_type=refresh_token requests missing the refresh token.
            // See https://tools.ietf.org/html/rfc6749#section-6
            else if (request.IsRefreshTokenGrantType() && string.IsNullOrEmpty(request.RefreshToken))
            {
                Logger.LogError("The token request was rejected because the refresh token was missing.");

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = "The mandatory 'refresh_token' parameter was missing."
                }));
            }

            // Reject grant_type=password requests missing username or password.
            // See https://tools.ietf.org/html/rfc6749#section-4.3.2
            else if (request.IsPasswordGrantType() && (string.IsNullOrEmpty(request.Username) ||
                                                       string.IsNullOrEmpty(request.Password)))
            {
                Logger.LogError("The token request was rejected because the resource owner credentials were missing.");

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.InvalidRequest,
                    ErrorDescription = "The mandatory 'username' and/or 'password' parameters " +
                                       "was/were missing from the request message."
                }));
            }

            // When client_id and client_secret are both null, try to extract them from the Authorization header.
            // See http://tools.ietf.org/html/rfc6749#section-2.3.1 and
            // http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
            if (string.IsNullOrEmpty(request.ClientId) && string.IsNullOrEmpty(request.ClientSecret))
            {
                string header = Request.Headers[HeaderNames.Authorization];
                if (!string.IsNullOrEmpty(header) && header.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase))
                {
                    try {
                        var value = header.Substring("Basic ".Length).Trim();
                        var data  = Encoding.UTF8.GetString(Convert.FromBase64String(value));

                        var index = data.IndexOf(':');
                        if (index >= 0)
                        {
                            request.ClientId     = data.Substring(0, index);
                            request.ClientSecret = data.Substring(index + 1);
                        }
                    }

                    catch (FormatException) { }
                    catch (ArgumentException) { }
                }
            }

            var validatingContext = new ValidateTokenRequestContext(Context, Options, request);
            await Options.Provider.ValidateTokenRequest(validatingContext);

            if (validatingContext.IsRejected)
            {
                Logger.LogInformation("The token request was rejected by application code.");

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = validatingContext.Error ?? OpenIdConnectConstants.Errors.InvalidClient,
                    ErrorDescription = validatingContext.ErrorDescription,
                    ErrorUri = validatingContext.ErrorUri
                }));
            }

            // Reject grant_type=client_credentials requests if validation was skipped.
            else if (validatingContext.IsSkipped && request.IsClientCredentialsGrantType())
            {
                Logger.LogError("The token request must be fully validated to use the client_credentials grant type.");

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "Client authentication is required when using client_credentials."
                }));
            }

            // Ensure that the client_id has been set from the ValidateTokenRequest event.
            else if (validatingContext.IsValidated && string.IsNullOrEmpty(request.ClientId))
            {
                Logger.LogError("The token request was validated but the client_id was not set.");

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.ServerError,
                    ErrorDescription = "An internal server error occurred."
                }));
            }

            AuthenticationTicket ticket = null;

            // See http://tools.ietf.org/html/rfc6749#section-4.1
            // and http://tools.ietf.org/html/rfc6749#section-4.1.3 (authorization code grant).
            // See http://tools.ietf.org/html/rfc6749#section-6 (refresh token grant).
            if (request.IsAuthorizationCodeGrantType() || request.IsRefreshTokenGrantType())
            {
                ticket = request.IsAuthorizationCodeGrantType() ?
                         await DeserializeAuthorizationCodeAsync(request.Code, request) :
                         await DeserializeRefreshTokenAsync(request.RefreshToken, request);

                if (ticket == null)
                {
                    Logger.LogError("The token request was rejected because the " +
                                    "authorization code or the refresh token was invalid.");

                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "Invalid ticket"
                    }));
                }

                if (!ticket.Properties.ExpiresUtc.HasValue ||
                    ticket.Properties.ExpiresUtc < Options.SystemClock.UtcNow)
                {
                    Logger.LogError("The token request was rejected because the " +
                                    "authorization code or the refresh token was expired.");

                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "Expired ticket"
                    }));
                }

                // If the client was fully authenticated when retrieving its refresh token,
                // the current request must be rejected if client authentication was not enforced.
                if (request.IsRefreshTokenGrantType() && !validatingContext.IsValidated && ticket.IsConfidential())
                {
                    Logger.LogError("The token request was rejected because client authentication " +
                                    "was required to use the confidential refresh token.");

                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "Client authentication is required to use this ticket"
                    }));
                }

                // Note: presenters may be empty during a grant_type=refresh_token request if the refresh token
                // was issued to a public client but cannot be null for an authorization code grant request.
                var presenters = ticket.GetPresenters();
                if (request.IsAuthorizationCodeGrantType() && !presenters.Any())
                {
                    Logger.LogError("The token request was rejected because the authorization " +
                                    "code didn't contain any valid presenter.");

                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = OpenIdConnectConstants.Errors.ServerError,
                        ErrorDescription = "An internal server error occurred."
                    }));
                }

                // At this stage, client_id cannot be null for grant_type=authorization_code requests,
                // as it must either be set in the ValidateClientAuthentication notification
                // by the developer or manually flowed by non-confidential client applications.
                // See https://tools.ietf.org/html/rfc6749#section-4.1.3
                if (request.IsAuthorizationCodeGrantType() && string.IsNullOrEmpty(request.ClientId))
                {
                    Logger.LogError("The token request was rejected because the mandatory 'client_id' was missing.");

                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = OpenIdConnectConstants.Errors.InvalidRequest,
                        ErrorDescription = "client_id was missing from the token request"
                    }));
                }

                // Ensure the authorization code/refresh token was issued to the client application making the token request.
                // Note: when using the refresh token grant, client_id is optional but must validated if present.
                // As a consequence, this check doesn't depend on the actual status of client authentication.
                // See https://tools.ietf.org/html/rfc6749#section-6
                // and http://openid.net/specs/openid-connect-core-1_0.html#RefreshingAccessToken
                if (!string.IsNullOrEmpty(request.ClientId) && presenters.Any() &&
                    !presenters.Contains(request.ClientId, StringComparer.Ordinal))
                {
                    Logger.LogError("The token request was rejected because the authorization " +
                                    "code was issued to a different client application.");

                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = "Ticket does not contain matching client_id"
                    }));
                }

                // Validate the redirect_uri flowed by the client application during this token request.
                // Note: for pure OAuth2 requests, redirect_uri is only mandatory if the authorization request
                // contained an explicit redirect_uri. OpenID Connect requests MUST include a redirect_uri
                // but the specifications allow proceeding the token request without returning an error
                // if the authorization request didn't contain an explicit redirect_uri.
                // See https://tools.ietf.org/html/rfc6749#section-4.1.3
                // and http://openid.net/specs/openid-connect-core-1_0.html#TokenRequestValidation
                var address = ticket.GetProperty(OpenIdConnectConstants.Properties.RedirectUri);
                if (request.IsAuthorizationCodeGrantType() && !string.IsNullOrEmpty(address))
                {
                    ticket.Properties.Items.Remove(OpenIdConnectConstants.Properties.RedirectUri);

                    if (string.IsNullOrEmpty(request.RedirectUri))
                    {
                        Logger.LogError("The token request was rejected because the mandatory 'redirect_uri' " +
                                        "parameter was missing from the grant_type=authorization_code request.");

                        return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                            Error = OpenIdConnectConstants.Errors.InvalidRequest,
                            ErrorDescription = "redirect_uri was missing from the token request"
                        }));
                    }

                    else if (!string.Equals(address, request.RedirectUri, StringComparison.Ordinal))
                    {
                        Logger.LogError("The token request was rejected because the 'redirect_uri' " +
                                        "parameter didn't correspond to the expected value.");

                        return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                            Error = OpenIdConnectConstants.Errors.InvalidGrant,
                            ErrorDescription = "Authorization code does not contain matching redirect_uri"
                        }));
                    }
                }

                if (!string.IsNullOrEmpty(request.Scope))
                {
                    // When an explicit scope parameter has been included in the token request
                    // but was missing from the authorization request, the request MUST be rejected.
                    // See http://tools.ietf.org/html/rfc6749#section-6
                    var scopes = ticket.GetScopes();
                    if (!scopes.Any())
                    {
                        Logger.LogError("The token request was rejected because the 'scope' parameter was not allowed.");

                        return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                            Error = OpenIdConnectConstants.Errors.InvalidGrant,
                            ErrorDescription = "Token request cannot contain a scope parameter" +
                                               "if the authorization request didn't contain one"
                        }));
                    }

                    // When an explicit scope parameter has been included in the token request,
                    // the authorization server MUST ensure that it doesn't contain scopes
                    // that were not allowed during the authorization request.
                    // See https://tools.ietf.org/html/rfc6749#section-6
                    else if (!new HashSet <string>(scopes).IsSupersetOf(request.GetScopes()))
                    {
                        Logger.LogError("The token request was rejected because the 'scope' parameter was not valid.");

                        return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                            Error = OpenIdConnectConstants.Errors.InvalidGrant,
                            ErrorDescription = "Token request doesn't contain a valid scope parameter"
                        }));
                    }

                    // Replace the scopes initially granted by the scopes
                    // listed by the client application in the token request.
                    ticket.SetScopes(request.GetScopes());
                }

                if (request.IsAuthorizationCodeGrantType())
                {
                    // Note: the authentication ticket is copied to avoid modifying the properties of the authorization code.
                    var context = new GrantAuthorizationCodeContext(Context, Options, request, ticket.Copy());
                    await Options.Provider.GrantAuthorizationCode(context);

                    if (!context.IsValidated)
                    {
                        // Note: use invalid_grant as the default error if none has been explicitly provided.
                        return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                            Error = context.Error ?? OpenIdConnectConstants.Errors.InvalidGrant,
                            ErrorDescription = context.ErrorDescription,
                            ErrorUri = context.ErrorUri
                        }));
                    }

                    // By default, when using the authorization code grant, the authentication ticket extracted from the
                    // authorization code is used as-is. To avoid aligning the expiration date of the generated tokens
                    // with the lifetime of the authorization code, the ticket properties are automatically reset to null.
                    if (context.Ticket.Properties.IssuedUtc == ticket.Properties.IssuedUtc)
                    {
                        context.Ticket.Properties.IssuedUtc = null;
                    }

                    if (context.Ticket.Properties.ExpiresUtc == ticket.Properties.ExpiresUtc)
                    {
                        context.Ticket.Properties.ExpiresUtc = null;
                    }

                    ticket = context.Ticket;
                }

                else
                {
                    // Note: the authentication ticket is copied to avoid modifying the properties of the refresh token.
                    var context = new GrantRefreshTokenContext(Context, Options, request, ticket.Copy());
                    await Options.Provider.GrantRefreshToken(context);

                    if (!context.IsValidated)
                    {
                        // Note: use invalid_grant as the default error if none has been explicitly provided.
                        return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                            Error = context.Error ?? OpenIdConnectConstants.Errors.InvalidGrant,
                            ErrorDescription = context.ErrorDescription,
                            ErrorUri = context.ErrorUri
                        }));
                    }

                    // By default, when using the refresh token grant, the authentication ticket extracted from the
                    // refresh token is used as-is. To avoid aligning the expiration date of the generated tokens
                    // with the lifetime of the refresh token, the ticket properties are automatically reset to null.
                    if (context.Ticket.Properties.IssuedUtc == ticket.Properties.IssuedUtc)
                    {
                        context.Ticket.Properties.IssuedUtc = null;
                    }

                    if (context.Ticket.Properties.ExpiresUtc == ticket.Properties.ExpiresUtc)
                    {
                        context.Ticket.Properties.ExpiresUtc = null;
                    }

                    ticket = context.Ticket;
                }
            }

            // See http://tools.ietf.org/html/rfc6749#section-4.3
            // and http://tools.ietf.org/html/rfc6749#section-4.3.2
            else if (request.IsPasswordGrantType())
            {
                var context = new GrantResourceOwnerCredentialsContext(Context, Options, request);
                await Options.Provider.GrantResourceOwnerCredentials(context);

                if (!context.IsValidated)
                {
                    // Note: use invalid_grant as the default error if none has been explicitly provided.
                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = context.Error ?? OpenIdConnectConstants.Errors.InvalidGrant,
                        ErrorDescription = context.ErrorDescription,
                        ErrorUri = context.ErrorUri
                    }));
                }

                ticket = context.Ticket;
            }

            // See http://tools.ietf.org/html/rfc6749#section-4.4
            // and http://tools.ietf.org/html/rfc6749#section-4.4.2
            else if (request.IsClientCredentialsGrantType())
            {
                var context = new GrantClientCredentialsContext(Context, Options, request);
                await Options.Provider.GrantClientCredentials(context);

                if (!context.IsValidated)
                {
                    // Note: use unauthorized_client as the default error if none has been explicitly provided.
                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = context.Error ?? OpenIdConnectConstants.Errors.UnauthorizedClient,
                        ErrorDescription = context.ErrorDescription,
                        ErrorUri = context.ErrorUri
                    }));
                }

                ticket = context.Ticket;
            }

            // See http://tools.ietf.org/html/rfc6749#section-8.3
            else
            {
                var context = new GrantCustomExtensionContext(Context, Options, request);
                await Options.Provider.GrantCustomExtension(context);

                if (!context.IsValidated)
                {
                    // Note: use unsupported_grant_type as the default error if none has been explicitly provided.
                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = context.Error ?? OpenIdConnectConstants.Errors.UnsupportedGrantType,
                        ErrorDescription = context.ErrorDescription,
                        ErrorUri = context.ErrorUri
                    }));
                }

                ticket = context.Ticket;
            }

            var notification = new HandleTokenRequestContext(Context, Options, request, ticket);
            await Options.Provider.HandleTokenRequest(notification);

            if (notification.HandledResponse)
            {
                return(true);
            }

            else if (notification.Skipped)
            {
                return(false);
            }

            // Flow the changes made to the ticket.
            ticket = notification.Ticket;

            // Ensure an authentication ticket has been provided:
            // a null ticket MUST result in an internal server error.
            if (ticket == null)
            {
                Logger.LogError("The token request was rejected because no authentication " +
                                "ticket was returned by application code.");

                return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                    Error = OpenIdConnectConstants.Errors.ServerError
                }));
            }

            if (validatingContext.IsValidated)
            {
                // Store a boolean indicating whether the ticket should be marked as confidential.
                ticket.Properties.Items[OpenIdConnectConstants.Properties.Confidential] = "true";
            }

            // Always include the "openid" scope when the developer doesn't explicitly call SetScopes.
            // Note: the application is allowed to specify a different "scopes": in this case,
            // don't replace the "scopes" property stored in the authentication ticket.
            if (!ticket.Properties.Items.ContainsKey(OpenIdConnectConstants.Properties.Scopes) &&
                request.HasScope(OpenIdConnectConstants.Scopes.OpenId))
            {
                ticket.Properties.Items[OpenIdConnectConstants.Properties.Scopes] = OpenIdConnectConstants.Scopes.OpenId;
            }

            string audiences;

            // When a "resources" property cannot be found in the authentication properties, infer it from the "audiences" property.
            if (!ticket.Properties.Items.ContainsKey(OpenIdConnectConstants.Properties.Resources) &&
                ticket.Properties.Items.TryGetValue(OpenIdConnectConstants.Properties.Audiences, out audiences))
            {
                ticket.Properties.Items[OpenIdConnectConstants.Properties.Resources] = audiences;
            }

            var response = new OpenIdConnectMessage();

            // Note: by default, an access token is always returned, but the client application can use the "response_type" parameter
            // to only include specific types of tokens. When this parameter is missing, an access token is always generated.
            if (string.IsNullOrEmpty(request.ResponseType) || request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Token))
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                string resources;
                if (!properties.Items.TryGetValue(OpenIdConnectConstants.Properties.Resources, out resources))
                {
                    Logger.LogInformation("No explicit resource has been associated with the authentication ticket: " +
                                          "the access token will thus be issued without any audience attached.");
                }

                // Note: when the "resource" parameter added to the OpenID Connect response
                // is identical to the request parameter, keeping it is not necessary.
                if (request.IsAuthorizationCodeGrantType() || (!string.IsNullOrEmpty(request.Resource) &&
                                                               !string.Equals(request.Resource, resources, StringComparison.Ordinal)))
                {
                    response.Resource = resources;
                }

                // Note: when the "scope" parameter added to the OpenID Connect response
                // is identical to the request parameter, keeping it is not necessary.
                string scopes;
                properties.Items.TryGetValue(OpenIdConnectConstants.Properties.Scopes, out scopes);
                if (request.IsAuthorizationCodeGrantType() || (!string.IsNullOrEmpty(request.Scope) &&
                                                               !string.Equals(request.Scope, scopes, StringComparison.Ordinal)))
                {
                    response.Scope = scopes;
                }

                response.TokenType   = OpenIdConnectConstants.TokenTypes.Bearer;
                response.AccessToken = await SerializeAccessTokenAsync(ticket.Principal, properties, request, response);

                // Ensure that an access token is issued to avoid returning an invalid response.
                // See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Combinations
                if (string.IsNullOrEmpty(response.AccessToken))
                {
                    Logger.LogError("An error occurred during the serialization of the " +
                                    "access token and a null value was returned.");

                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = OpenIdConnectConstants.Errors.ServerError,
                        ErrorDescription = "no valid access token was issued"
                    }));
                }

                // properties.ExpiresUtc is automatically set by SerializeAccessTokenAsync but the end user
                // is free to set a null value directly in the SerializeAccessToken event.
                if (properties.ExpiresUtc.HasValue && properties.ExpiresUtc > Options.SystemClock.UtcNow)
                {
                    var lifetime   = properties.ExpiresUtc.Value - Options.SystemClock.UtcNow;
                    var expiration = (long)(lifetime.TotalSeconds + .5);

                    response.ExpiresIn = expiration.ToString(CultureInfo.InvariantCulture);
                }
            }

            // Note: by default, an identity token is always returned when the "openid" scope has been requested,
            // but the client application can use the "response_type" parameter to only include specific types of tokens.
            // When this parameter is missing, an identity token is always generated.
            if (ticket.HasScope(OpenIdConnectConstants.Scopes.OpenId) &&
                (string.IsNullOrEmpty(request.ResponseType) || request.HasResponseType(OpenIdConnectConstants.ResponseTypes.IdToken)))
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                response.IdToken = await SerializeIdentityTokenAsync(ticket.Principal, properties, request, response);

                // Ensure that an identity token is issued to avoid returning an invalid response.
                // See http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse
                // and http://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse
                if (string.IsNullOrEmpty(response.IdToken))
                {
                    Logger.LogError("An error occurred during the serialization of the " +
                                    "identity token and a null value was returned.");

                    return(await SendErrorPayloadAsync(new OpenIdConnectMessage {
                        Error = OpenIdConnectConstants.Errors.ServerError,
                        ErrorDescription = "no valid identity token was issued"
                    }));
                }
            }

            // Note: by default, a refresh token is always returned when the "offline_access" scope has been requested,
            // but the client application can use the "response_type" parameter to only include specific types of tokens.
            // When this parameter is missing, a refresh token is always generated.
            if (ticket.HasScope(OpenIdConnectConstants.Scopes.OfflineAccess) &&
                (!request.IsRefreshTokenGrantType() || Options.UseSlidingExpiration) &&
                (string.IsNullOrEmpty(request.ResponseType) || request.HasResponseType(OpenIdConnectConstants.Parameters.RefreshToken)))
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                response.RefreshToken = await SerializeRefreshTokenAsync(ticket.Principal, properties, request, response);
            }

            var payload = new JObject();

            foreach (var parameter in response.Parameters)
            {
                payload.Add(parameter.Key, parameter.Value);
            }

            var responseNotification = new ApplyTokenResponseContext(Context, Options, ticket, request, payload);
            await Options.Provider.ApplyTokenResponse(responseNotification);

            if (responseNotification.HandledResponse)
            {
                return(true);
            }

            else if (responseNotification.Skipped)
            {
                return(false);
            }

            using (var buffer = new MemoryStream())
                using (var writer = new JsonTextWriter(new StreamWriter(buffer))) {
                    payload.WriteTo(writer);
                    writer.Flush();

                    Response.ContentLength = buffer.Length;
                    Response.ContentType   = "application/json;charset=UTF-8";

                    Response.Headers[HeaderNames.CacheControl] = "no-cache";
                    Response.Headers[HeaderNames.Pragma]       = "no-cache";
                    Response.Headers[HeaderNames.Expires]      = "-1";

                    buffer.Seek(offset: 0, loc: SeekOrigin.Begin);
                    await buffer.CopyToAsync(Response.Body, 4096, Context.RequestAborted);

                    return(true);
                }
        }
예제 #22
0
        private async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, ApplicationUser user)
        {
            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(),
                                                  OpenIddictServerDefaults.AuthenticationScheme);


            //if (!request.IsRefreshTokenGrantType())
            //{
            // Set the list of scopes granted to the client application.
            // Note: the offline_access scope must be granted
            // to allow OpenIddict to return a refresh token.
            ticket.SetScopes(new[]
            {
                OpenIdConnectConstants.Scopes.OpenId,
                OpenIdConnectConstants.Scopes.Email,
                OpenIdConnectConstants.Scopes.Phone,
                OpenIdConnectConstants.Scopes.Profile,
                OpenIdConnectConstants.Scopes.OfflineAccess,
                OpenIddictConstants.Scopes.Roles
            }.Intersect(request.GetScopes()));
            //}

            //ticket.SetResources("quickapp-api");

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }


                var destinations = new List <string> {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if (claim.Type == OpenIdConnectConstants.Claims.Subject &&
                    ticket.HasScope(OpenIdConnectConstants.Scopes.OpenId) ||
                    claim.Type == OpenIdConnectConstants.Claims.Name &&
                    ticket.HasScope(OpenIdConnectConstants.Scopes.Profile) ||
                    claim.Type == OpenIdConnectConstants.Claims.Role &&
                    ticket.HasScope(OpenIddictConstants.Claims.Roles) ||
                    claim.Type == CustomClaimTypes.Permission && ticket.HasScope(OpenIddictConstants.Claims.Roles))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }


                claim.SetDestinations(destinations);
            }


            var identity = principal.Identity as ClaimsIdentity;


            if (ticket.HasScope(OpenIdConnectConstants.Scopes.Email))
            {
                if (!string.IsNullOrWhiteSpace(user.Email))
                {
                    identity.AddClaim(CustomClaimTypes.Email, user.Email,
                                      OpenIdConnectConstants.Destinations.IdentityToken);
                }
            }

            if (ticket.HasScope(OpenIdConnectConstants.Scopes.Phone))
            {
                if (!string.IsNullOrWhiteSpace(user.PhoneNumber))
                {
                    identity.AddClaim(CustomClaimTypes.Phone, user.PhoneNumber,
                                      OpenIdConnectConstants.Destinations.IdentityToken);
                }
            }


            return(ticket);
        }
예제 #23
0
        private async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, User user)
        {
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), OpenIddictServerDefaults.AuthenticationScheme);

            ticket.SetScopes(new[]
            {
                OpenIdConnectConstants.Scopes.OpenId,
                OpenIdConnectConstants.Scopes.Email,
                OpenIdConnectConstants.Scopes.Phone,
                OpenIdConnectConstants.Scopes.Profile,
                OpenIdConnectConstants.Scopes.OfflineAccess,
                OpenIddictConstants.Scopes.Roles
            }.Intersect(request.GetScopes()));

            //ticket.SetResources("aurelia-api");

            // Add destinations to the claims based on the type
            foreach (var claim in ticket.Principal.Claims)
            {
                // Don't include
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }


                var destinations = new List <string> {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIdConnectConstants.Claims.Subject && ticket.HasScope(OpenIdConnectConstants.Scopes.OpenId)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)) ||
                    (claim.Type == Claims.Permission && ticket.HasScope(OpenIddictConstants.Claims.Roles))
                    )
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }


                claim.SetDestinations(destinations);
            }

            //Additional scopes and claims can be addedd if need be
            //var identity = principal.Identity as ClaimsIdentity;
            //if (ticket.HasScope(OpenIdConnectConstants.Scopes.Profile))
            //{
            //    if (!string.IsNullOrWhiteSpace(user.JobTitle))
            //        identity.AddClaim(CustomClaimTypes.JobTitle, user.JobTitle, OpenIdConnectConstants.Destinations.IdentityToken);

            //    if (!string.IsNullOrWhiteSpace(user.Configuration))
            //        identity.AddClaim(CustomClaimTypes.Configuration, user.Configuration, OpenIdConnectConstants.Destinations.IdentityToken);
            //}

            //if (ticket.HasScope(OpenIdConnectConstants.Scopes.Email))
            //{
            //    if (!string.IsNullOrWhiteSpace(user.Email))
            //        identity.AddClaim(CustomClaimTypes.Email, user.Email, OpenIdConnectConstants.Destinations.IdentityToken);
            //}

            //if (ticket.HasScope(OpenIdConnectConstants.Scopes.Phone))
            //{
            //    if (!string.IsNullOrWhiteSpace(user.PhoneNumber))
            //        identity.AddClaim(CustomClaimTypes.Phone, user.PhoneNumber, OpenIdConnectConstants.Destinations.IdentityToken);
            //}


            return(ticket);
        }
        private async Task <AuthenticationTicket> CreateTicketAsync(
            OpenIdConnectRequest request, ApplicationUser user,
            AuthenticationProperties properties = null)
        {
            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal,
                                                  properties ?? new AuthenticationProperties(),
                                                  OpenIdConnectServerDefaults.AuthenticationScheme);
            // Set the list of scopes granted to the client application.
            // Note: the offline_access scope must be granted
            // to allow OpenIddict to return a refresh token.

            var roleNames = await _userManager.GetRolesAsync(user);

            var identity = ticket.Principal.Identity as ClaimsIdentity;

            if (!request.IsAuthorizationCodeGrantType())
            {
                var scopes = new List <string>
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Profile,
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIddictConstants.Scopes.Roles
                }.Intersect(request.GetScopes()).ToList();
                ticket.SetScopes(scopes);
            }

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.
            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)))
                {
                    var type = claim.Type;
                    claim.SetDestinations(OpenIdConnectConstants.Destinations.IdentityToken,
                                          OpenIdConnectConstants.Destinations.AccessToken);
                }
                else
                {
                    claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken);
                }
            }


            if (_appOptions.TokenGeneration.Audiences.Any())
            {
                foreach (var audience in _appOptions.TokenGeneration.Audiences)
                {
                    ticket.SetAudiences(audience);
                }
            }

            if (_appOptions.TokenGeneration.Resources.Any())
            {
                foreach (var resource in _appOptions.TokenGeneration.Resources)
                {
                    ticket.SetResources(resource);
                }
            }

            if (_appOptions.TokenGeneration.IncludeUserIdClaim)
            {
                AddUserIdClaim(ticket, user);
            }

            ticket.SetAccessTokenLifetime(TimeSpan.FromSeconds(_appOptions.TokenGeneration.AccessTokenLifetime));
            ticket.SetIdentityTokenLifetime(TimeSpan.FromSeconds(_appOptions.TokenGeneration.IdentityTokenLifetime));
            ticket.SetRefreshTokenLifetime(TimeSpan.FromSeconds(_appOptions.TokenGeneration.RefreshTokenLifetime));

            return(ticket);
        }
예제 #25
0
        private async Task <AuthenticationTicket> CreateTicketAsync(
            IUser user, object application, object authorization,
            OpenIdConnectRequest request, AuthenticationProperties properties = null)
        {
            Debug.Assert(request.IsAuthorizationRequest() || request.IsTokenRequest(),
                         "The request should be an authorization or token request.");

            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var identity = (ClaimsIdentity)principal.Identity;

            // Note: while ASP.NET Core Identity uses the legacy WS-Federation claims (exposed by the ClaimTypes class),
            // OpenIddict uses the newer JWT claims defined by the OpenID Connect specification. To ensure the mandatory
            // subject claim is correctly populated (and avoid an InvalidOperationException), it's manually added here.
            if (string.IsNullOrEmpty(principal.FindFirstValue(OpenIddictConstants.Claims.Subject)))
            {
                identity.AddClaim(new Claim(OpenIddictConstants.Claims.Subject, await _userManager.GetUserIdAsync(user)));
            }

            // Create a new authentication ticket holding the user identity.
            var ticket = new AuthenticationTicket(principal, properties,
                                                  OpenIddictServerDefaults.AuthenticationScheme);

            if (request.IsAuthorizationRequest() || (!request.IsAuthorizationCodeGrantType() &&
                                                     !request.IsRefreshTokenGrantType()))
            {
                // Set the list of scopes granted to the client application.
                // Note: the offline_access scope must be granted
                // to allow OpenIddict to return a refresh token.
                ticket.SetScopes(request.GetScopes());
                ticket.SetResources(await GetResourcesAsync(request.GetScopes()));

                // If the request is an authorization request, automatically create
                // a permanent authorization to avoid requiring explicit consent for
                // future authorization or token requests containing the same scopes.
                if (authorization == null && request.IsAuthorizationRequest())
                {
                    authorization = await _authorizationManager.CreateAsync(
                        principal : ticket.Principal,
                        subject : await _userManager.GetUserIdAsync(user),
                        client : await _applicationManager.GetIdAsync(application),
                        type : OpenIddictConstants.AuthorizationTypes.Permanent,
                        scopes : ImmutableArray.CreateRange(ticket.GetScopes()),
                        properties : ImmutableDictionary.CreateRange(ticket.Properties.Items));
                }

                if (authorization != null)
                {
                    // Attach the authorization identifier to the authentication ticket.
                    ticket.SetProperty(OpenIddictConstants.Properties.InternalAuthorizationId,
                                       await _authorizationManager.GetIdAsync(authorization));
                }
            }

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            foreach (var claim in ticket.Principal.Claims)
            {
                // Never include the security stamp in the access and identity tokens, as it's a secret value.
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }

                var destinations = new List <string>
                {
                    OpenIddictConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIddictConstants.Claims.Name && ticket.HasScope(OpenIddictConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIddictConstants.Claims.Email && ticket.HasScope(OpenIddictConstants.Scopes.Email)) ||
                    (claim.Type == OpenIddictConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)))
                {
                    destinations.Add(OpenIddictConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            return(ticket);
        }
예제 #26
0
        private IEnumerable <string> GetDestinations(Claim claim, AuthenticationTicket ticket)
        {
            switch (claim.Type)
            {
            // Note: always include acr and auth_time in the identity token as they must be flowed
            // from the authorization endpoint to the identity token returned from the token endpoint.
            case OpenIdConnectConstants.Claims.AuthenticationContextReference:
            case OpenIdConnectConstants.Claims.AuthenticationTime:
                yield return(OpenIdConnectConstants.Destinations.IdentityToken);

                yield break;

            // Note: the name claim is always included, even if
            // the profile scope is not requested nor granted.
            case OpenIdConnectConstants.Claims.Name:
                yield return(OpenIdConnectConstants.Destinations.AccessToken);

                yield return(OpenIdConnectConstants.Destinations.IdentityToken);

                yield break;

            case OpenIdConnectConstants.Claims.Subject:
            case OpenIdConnectConstants.Claims.Gender:
            case OpenIdConnectConstants.Claims.GivenName:
            case OpenIdConnectConstants.Claims.MiddleName:
            case OpenIdConnectConstants.Claims.FamilyName:
            case OpenIdConnectConstants.Claims.Nickname:
            case OpenIdConnectConstants.Claims.PreferredUsername:
            case OpenIdConnectConstants.Claims.Birthdate:
            case OpenIdConnectConstants.Claims.Profile:
            case OpenIdConnectConstants.Claims.Picture:
            case OpenIdConnectConstants.Claims.Website:
            case OpenIdConnectConstants.Claims.Locale:
            case OpenIdConnectConstants.Claims.Zoneinfo:
            case OpenIdConnectConstants.Claims.UpdatedAt:
                yield return(OpenIdConnectConstants.Destinations.AccessToken);

                if (ticket.HasScope(OpenIdConnectConstants.Scopes.Profile))
                {
                    yield return(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                yield break;

            case OpenIdConnectConstants.Claims.Email:
                yield return(OpenIdConnectConstants.Destinations.AccessToken);

                if (ticket.HasScope(OpenIdConnectConstants.Scopes.Email))
                {
                    yield return(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                yield break;

            case OpenIdConnectConstants.Claims.PhoneNumber:
                yield return(OpenIdConnectConstants.Destinations.AccessToken);

                if (ticket.HasScope(OpenIdConnectConstants.Scopes.Phone))
                {
                    yield return(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                yield break;

            case OpenIdConnectConstants.Claims.Address:
                yield return(OpenIdConnectConstants.Destinations.AccessToken);

                if (ticket.HasScope(OpenIdConnectConstants.Scopes.Address))
                {
                    yield return(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                yield break;

            default:
                yield return(OpenIdConnectConstants.Destinations.AccessToken);

                yield break;
            }
        }
        private async Task <bool> HandleSignInAsync(AuthenticationTicket ticket)
        {
            // Extract the OpenID Connect request from the ASP.NET context.
            // If it cannot be found or doesn't correspond to an authorization
            // or a token request, throw an InvalidOperationException.
            var request = Context.GetOpenIdConnectRequest();

            if (request == null || (!request.IsAuthorizationRequest() && !request.IsTokenRequest()))
            {
                throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint.");
            }

            // Note: if an OpenID Connect response was already generated, throw an exception.
            var response = Context.GetOpenIdConnectResponse();

            if (response != null)
            {
                throw new InvalidOperationException("An OpenID Connect response has already been sent.");
            }

            if (!ticket.Principal.HasClaim(claim => claim.Type == ClaimTypes.NameIdentifier))
            {
                throw new InvalidOperationException("The authentication ticket was rejected because it didn't " +
                                                    "contain the mandatory ClaimTypes.NameIdentifier claim.");
            }

            // Prepare a new OpenID Connect response.
            response = new OpenIdConnectResponse();

            if (request.IsAuthorizationRequest())
            {
                response.RedirectUri = request.RedirectUri;
                response.State       = request.State;

                // Keep the code_challenge, code_challenge_method, nonce and redirect_uri parameters for later comparison.
                ticket.SetProperty(OpenIdConnectConstants.Properties.CodeChallenge, request.CodeChallenge);
                ticket.SetProperty(OpenIdConnectConstants.Properties.CodeChallengeMethod, request.CodeChallengeMethod);
                ticket.SetProperty(OpenIdConnectConstants.Properties.Nonce, request.Nonce);
                ticket.SetProperty(OpenIdConnectConstants.Properties.RedirectUri, request.RedirectUri);
            }

            // Copy the confidentiality level associated with the request to the authentication ticket.
            if (!ticket.HasProperty(OpenIdConnectConstants.Properties.ConfidentialityLevel))
            {
                ticket.SetProperty(OpenIdConnectConstants.Properties.ConfidentialityLevel,
                                   request.GetProperty(OpenIdConnectConstants.Properties.ConfidentialityLevel));
            }

            // Always include the "openid" scope when the developer doesn't explicitly call SetScopes.
            // Note: the application is allowed to specify a different "scopes": in this case,
            // don't replace the "scopes" property stored in the authentication ticket.
            if (!ticket.HasProperty(OpenIdConnectConstants.Properties.Scopes) && request.HasScope(OpenIdConnectConstants.Scopes.OpenId))
            {
                ticket.SetProperty(OpenIdConnectConstants.Properties.Scopes, OpenIdConnectConstants.Scopes.OpenId);
            }

            // When a "resources" property cannot be found in the ticket, infer it from the "audiences" property.
            if (!ticket.HasProperty(OpenIdConnectConstants.Properties.Resources))
            {
                ticket.SetProperty(OpenIdConnectConstants.Properties.Resources,
                                   ticket.GetProperty(OpenIdConnectConstants.Properties.Audiences));
            }

            // Only return an authorization code if the request is an authorization request and has response_type=code.
            if (request.IsAuthorizationRequest() && request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Code))
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                // properties.IssuedUtc and properties.ExpiresUtc are always
                // explicitly set to null to avoid aligning the expiration date
                // of the authorization code with the lifetime of the other tokens.
                properties.IssuedUtc = properties.ExpiresUtc = null;

                response.Code = await SerializeAuthorizationCodeAsync(ticket.Principal, properties, request, response);
            }

            // Only return an access token if the request is a token request
            // or an authorization request that specifies response_type=token.
            if (request.IsTokenRequest() || (request.IsAuthorizationRequest() &&
                                             request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Token)))
            {
                // Make sure to create a copy of the authentication properties
                // to avoid modifying the properties set on the original ticket.
                var properties = ticket.Properties.Copy();

                // When receiving a grant_type=refresh_token request, determine whether the client application
                // requests a limited set of scopes/resources and replace the corresponding properties if necessary.
                // Note: at this stage, request.GetResources() cannot return more items than the ones that were initially granted
                // by the resource owner as the "resources" parameter is always validated when receiving the token request.
                if (request.IsTokenRequest() && request.IsRefreshTokenGrantType())
                {
                    if (!string.IsNullOrEmpty(request.Resource))
                    {
                        // Replace the resources initially granted by the resources listed by the client application in the token request.
                        // Note: request.GetResources() automatically removes duplicate entries, so additional filtering is not necessary.
                        properties.SetProperty(OpenIdConnectConstants.Properties.Resources, string.Join(" ", request.GetResources()));
                    }

                    if (!string.IsNullOrEmpty(request.Scope))
                    {
                        // Replace the scopes initially granted by the scopes listed by the client application in the token request.
                        // Note: request.GetScopes() automatically removes duplicate entries, so additional filtering is not necessary.
                        properties.SetProperty(OpenIdConnectConstants.Properties.Scopes, string.Join(" ", request.GetScopes()));
                    }
                }

                var resources = properties.GetProperty(OpenIdConnectConstants.Properties.Resources);
                if (request.IsAuthorizationCodeGrantType() || (!string.IsNullOrEmpty(resources) &&
                                                               !string.IsNullOrEmpty(request.Resource) &&
                                                               !string.Equals(request.Resource, resources, StringComparison.Ordinal)))
                {
                    response.Resource = resources;
                }

                var scopes = properties.GetProperty(OpenIdConnectConstants.Properties.Scopes);
                if (request.IsAuthorizationCodeGrantType() || (!string.IsNullOrEmpty(scopes) &&
                                                               !string.IsNullOrEmpty(request.Scope) &&
                                                               !string.Equals(request.Scope, scopes, StringComparison.Ordinal)))
                {
                    response.Scope = scopes;
                }

                response.TokenType   = OpenIdConnectConstants.TokenTypes.Bearer;
                response.AccessToken = await SerializeAccessTokenAsync(ticket.Principal, properties, request, response);

                // properties.ExpiresUtc is automatically set by SerializeAccessTokenAsync but the end user
                // is free to set a null value directly in the SerializeAccessToken event.
                if (properties.ExpiresUtc.HasValue && properties.ExpiresUtc > Options.SystemClock.UtcNow)
                {
                    var lifetime = properties.ExpiresUtc.Value - Options.SystemClock.UtcNow;

                    response.ExpiresIn = (long)(lifetime.TotalSeconds + .5);
                }
            }

            // Only return a refresh token if the request is a token request that specifies scope=offline_access.
            if (request.IsTokenRequest() && ticket.HasScope(OpenIdConnectConstants.Scopes.OfflineAccess))
            {
                // Note: when sliding expiration is enabled, don't return a new refresh token,
                // unless the token request is not a grant_type=refresh_token request.
                if (!request.IsRefreshTokenGrantType() || Options.UseSlidingExpiration)
                {
                    // Make sure to create a copy of the authentication properties
                    // to avoid modifying the properties set on the original ticket.
                    var properties = ticket.Properties.Copy();

                    response.RefreshToken = await SerializeRefreshTokenAsync(ticket.Principal, properties, request, response);
                }
            }

            // Only return an identity token if the openid scope was requested and granted
            // to avoid generating and returning an unnecessary token to pure OAuth2 clients.
            if (ticket.HasScope(OpenIdConnectConstants.Scopes.OpenId))
            {
                // Note: don't return an identity token if the request is an
                // authorization request that doesn't use response_type=id_token.
                if (request.IsTokenRequest() || request.HasResponseType(OpenIdConnectConstants.ResponseTypes.IdToken))
                {
                    // Make sure to create a copy of the authentication properties
                    // to avoid modifying the properties set on the original ticket.
                    var properties = ticket.Properties.Copy();

                    // properties.IssuedUtc and properties.ExpiresUtc are always
                    // explicitly set to null to avoid aligning the expiration date
                    // of the identity token with the lifetime of the other tokens.
                    properties.IssuedUtc = properties.ExpiresUtc = null;

                    response.IdToken = await SerializeIdentityTokenAsync(ticket.Principal, properties, request, response);
                }
            }

            if (request.IsAuthorizationRequest())
            {
                return(await SendAuthorizationResponseAsync(response, ticket));
            }

            return(await SendTokenResponseAsync(response, ticket));
        }
        private async Task <AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, User user, AuthenticationProperties properties = null)
        {
            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            var ticket = new AuthenticationTicket(principal, properties,
                                                  OpenIdConnectServerDefaults.AuthenticationScheme);

            if (!request.IsAuthorizationCodeGrantType() && !request.IsRefreshTokenGrantType())
            {
                // Set the list of scopes granted to the client application.
                // Note: the offline_access scope must be granted
                // to allow OpenIddict to return a refresh token.
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Profile,
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIddictConstants.Scopes.Roles
                }.Intersect(request.GetScopes()));
            }

            // Note: by default, claims are NOT automatically included in the access and identity tokens.
            // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
            // whether they should be included in access tokens, in identity tokens or in both.

            foreach (var claim in principal.Claims)
            {
                if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType)
                {
                    continue;
                }
                var destinations = new List <string>
                {
                    OpenIdConnectConstants.Destinations.AccessToken
                };

                // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application.
                // The other claims will only be added to the access_token, which is encrypted when using the default format.
                if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) ||
                    (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles)))
                {
                    destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken);
                }

                claim.SetDestinations(destinations);
            }

            ticket.Properties.AllowRefresh = true;
            //   var roles = principal.Claims.Where(c => c.Type == ClaimTypes.Role).ToList();
            //     ticket.Properties.Items.Add(new KeyValuePair<string, string>("roles", string.Join(", ", roles.Select(r => r.Value))));
            //  ticket.Properties.ExpiresUtc = DateTimeOffset.Now.AddDays(14);
            //  ticket.Properties.IsPersistent = false;

            await UpdateIpAddressForUser(user.Id);

            return(ticket);
        }