示例#1
0
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            // Retrieve the profile of the logged in user.
            //var user = await _userManager.GetUserAsync(User);
            var user = await GetCurrentUser();

            if (user == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.ServerError,
                    ErrorDescription = "An internal error has occurred"
                }));
            }

            // Create a new authentication ticket.
            var ticket = await CreateTicketAsync(request, user);

            // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
            return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
        }
示例#2
0
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            // Retrieve the application details from the database.
            var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);

            if (application == null)
            {
                return(new JsonResult(new
                {
                    code = OpenIdConnectConstants.Errors.InvalidClient,
                    message = "Details concerning the calling client application cannot be found in the database"
                }));
            }
            var user = await _userManager.GetUserAsync(User);

            if (user == null)
            {
                return(new JsonResult(new
                {
                    code = OpenIdConnectConstants.Errors.ServerError,
                    message = "An internal error has occurred"
                }));
            }

            // Create a new authentication ticket.
            var ticket = await CreateTicketAsync(request, user);

            // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
            return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
        }
示例#3
0
        private async Task <IActionResult> Accept(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            // Retrieve the profile of the logged in user.
            var user = await _userManager.GetUserAsync(User);

            if (user == null)
            {
                // Your user in the cookie is invalid, remove cookie and retry with Authorize
                await _signInManager.SignOutAsync();

                var retryUrl = QueryHelpers.AddQueryString(Url.Action(nameof(Authorize)), new Dictionary <string, string>()
                {
                    { "response_type", request.ResponseType },
                    { "client_id", request.ClientId },
                    { "scope", request.Scope },
                    { "nonce", request.Nonce },
                    { "state", request.State },
                    { "display", request.Display },
                    { "redirect_uri", request.RedirectUri }
                });

                return(Redirect(retryUrl));
            }

            // Create a new authentication ticket.
            var ticket = await CreateTicketAsync(request, user);

            // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
            return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
        }
示例#4
0
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            // Retrieve the application details from the database.
            var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);

            if (application == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.InvalidClient,
                    ErrorDescription = "Details concerning the calling client application cannot be found in the database"
                }));
            }

            // Flow the request_id to allow OpenIddict to restore
            // the original authorization request from the cache.
            return(View(new AuthzViewModel
            {
                ApplicationName = application.DisplayName,
                RequestId = request.RequestId,
                Scope = request.Scope,
                State = request.State
            }));
        }
示例#5
0
        private AuthenticationTicket CreateTicket(
            OpenIdConnectRequest request, AuthenticateResult result,
            AuthenticationProperties properties = null)
        {
            // Create a new ClaimsIdentity containing the claims that
            // will be used to create an id_token, a token or a code.
            var identity = new ClaimsIdentity(
                result.Principal.Claims,
                OpenIdConnectServerDefaults.AuthenticationScheme,
                OpenIdConnectConstants.Claims.Name,
                OpenIdConnectConstants.Claims.Role);

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

            // Set the list of scopes granted to the client application.
            if (request.IsAuthorizationRequest() || (!request.IsAuthorizationCodeGrantType() && !request.IsRefreshTokenGrantType()))
            {
                ticket.SetScopes(new[]
                {
                    OpenIdConnectConstants.Scopes.OfflineAccess,
                    OpenIdConnectConstants.Scopes.OpenId,
                    OpenIdConnectConstants.Scopes.Address,
                    OpenIdConnectConstants.Scopes.Email,
                    OpenIdConnectConstants.Scopes.Phone,
                    OpenIdConnectConstants.Scopes.Profile
                }.Intersect(request.GetScopes()));
            }

            // The OP-Req-acr_values test consists in sending an "acr_values=1 2" parameter
            // as part of the authorization request. To indicate to the certification client
            // that the "1" reference value was satisfied, an "acr" claim is added.
            if (request.IsAuthorizationRequest() && request.HasAcrValue("1"))
            {
                identity.AddClaim(new Claim(OpenIdConnectConstants.Claims.AuthenticationContextReference, "1"));
            }

            foreach (var claim in identity.Claims)
            {
                claim.SetDestinations(destinations: GetDestinations(claim, ticket));
            }

            return(ticket);
        }
示例#6
0
        public async Task <IActionResult> Accept(OpenIdConnectRequest request, CancellationToken cancellationToken)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);

            if (application == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.InvalidClient,
                    ErrorDescription = "Details concerning the calling client application cannot be found in the database"
                }));
            }

            // Retrieve the profile of the logged in user.
            var user = await _userManager.GetUserAsync(User);

            if (user == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.ServerError,
                    ErrorDescription = "An internal error has occurred"
                }));
            }

            // Create a new authentication ticket.
            var ticket = await CreateTicketAsync(request, user);

            var authorization = await _authorizationManager.FindAsync(user.Id, application.Id, cancellationToken);

            if (authorization != null)
            {
                if (false == request.GetScopes().Except(authorization.Scopes).Any())
                {
                    authorization.Scopes = authorization.Scopes.Union(request.GetScopes()).ToList();

                    await _authorizationManager.UpdateAsync(authorization, cancellationToken);
                }
            }
            else
            {
                authorization = new DynamoIdentityAuthorization()
                {
                    Application = application.Id,
                    Subject     = user.Id,
                    Scopes      = ticket.GetScopes().ToList()
                };

                await _authorizationManager.CreateAsync(authorization, cancellationToken);
            }

            // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
            return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
        }
示例#7
0
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request, CancellationToken cancellationToken)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            // Retrieve the application details from the database.
            var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);

            if (application == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.InvalidClient,
                    ErrorDescription = "Details concerning the calling client application cannot be found in the database"
                }));
            }

            var user = await _userManager.GetUserAsync(User);

            if (user == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.ServerError,
                    ErrorDescription = "An internal error has occurred"
                }));
            }

            var authorization = await _authorizationManager.FindAsync(user.Id, application.Id, cancellationToken);

            if (authorization != null)
            {
                // if we didn't ask for any scopes that aren't already authorized
                if (false == request.GetScopes().Except(authorization.Scopes).Any())
                {
                    var ticket = await CreateTicketAsync(request, user);

                    return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
                }
            }

            // Flow the request_id to allow OpenIddict to restore
            // the original authorization request from the cache.
            return(View(new AuthorizeViewModel
            {
                ApplicationName = application.DisplayName,
                RequestId = request.RequestId,
                Scope = request.Scope,
                ClientId = request.ClientId,
                ResponseType = request.ResponseType,
                ResponseMode = request.ResponseMode,
                RedirectUri = request.RedirectUri,
                State = request.State,
                Nonce = request.Nonce
            }));
        }
        public void IsAuthorizationRequest_ReturnsExpectedResult(string type, bool result)
        {
            // Arrange
            var request = new OpenIdConnectRequest();

            request.SetProperty(OpenIdConnectConstants.Properties.MessageType, type);

            // Act and assert
            Assert.Equal(result, request.IsAuthorizationRequest());
        }
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            // Retrieve the application details from the database.
            var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);

            if (application == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.InvalidClient,
                    ErrorDescription = "Details concerning the calling client application cannot be found in the database"
                }));
            }

            var user = await _userManager.GetUserAsync(User);

            if (user == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.ServerError,
                    ErrorDescription = "An internal error has occurred"
                }));
            }
            if (user.IsDeleted)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.ServerError,
                    ErrorDescription = "An internal error has occurred"
                }));
            }
            // Create a new authentication ticket.
            var ticket = await CreateTicketAsync(request, user);

            // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
            return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
            // Flow the request_id to allow OpenIddict to restore
            // the original authorization request from the cache.
            //return View(new AuthorizeViewModel
            //{
            //    ApplicationName = application.DisplayName,
            //    RequestId = request.RequestId,
            //    Scope = request.Scope
            //});
        }
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            if (!User.Identity.IsAuthenticated)
            {
                // If the client application request promptless authentication,
                // return an error indicating that the user is not logged in.
                if (request.HasPrompt(OpenIdConnectConstants.Prompts.None))
                {
                    var properties = new AuthenticationProperties(new Dictionary <string, string>
                    {
                        [OpenIdConnectConstants.Properties.Error]            = OpenIdConnectConstants.Errors.LoginRequired,
                        [OpenIdConnectConstants.Properties.ErrorDescription] = "The user is not logged in."
                    });

                    // Ask OpenIddict to return a login_required error to the client application.
                    return(Forbid(properties, OpenIdConnectServerDefaults.AuthenticationScheme));
                }

                return(Challenge());
            }

            // Retrieve the application details from the database.
            var application =
                await applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);

            if (application == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.InvalidClient,
                    ErrorDescription =
                        "Details concerning the calling client application cannot be found in the database."
                }));
            }

            // Flow the request_id to allow OpenIddict to restore
            // the original authorization request from the cache.
            return(View(new AuthorizeViewModel
            {
                ApplicationName = application.DisplayName,
                RequestId = request.RequestId,
                Scope = request.Scope
            }));
        }
示例#11
0
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            if (request == null)
            {
                throw new System.ArgumentNullException(nameof(request));
            }

            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            // Check if a user is authenticated. If not, challenge the GitHub authentication handler
            if (!User.Identity.IsAuthenticated)
            {
                return(Challenge("Google"));
            }

            var response = await _bus.RequestAsync <GetOrCreateUserRequest, GetOrCreateUserResponse>(new GetOrCreateUserRequest(User.FindFirstValue(ClaimTypes.Email)));

            var userId = response.Id;

            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var identity = new ClaimsIdentity("OpenIddict");

            identity.AddClaim(OpenIdConnectConstants.Claims.Subject, userId.ToString(),
                              OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken);
            identity.AddClaim(OpenIdConnectConstants.Claims.Name, User.FindFirstValue(ClaimTypes.Name),
                              OpenIdConnectConstants.Destinations.IdentityToken);
            identity.AddClaim(OpenIdConnectConstants.Claims.Email, User.FindFirstValue(ClaimTypes.Email),
                              OpenIdConnectConstants.Destinations.IdentityToken);
            identity.AddClaim(OpenIdConnectConstants.Claims.EmailVerified, "true",
                              OpenIdConnectConstants.Destinations.IdentityToken); // We'll assume email is verified since we get it from GitHub
            var principal = new ClaimsPrincipal(identity);

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

            ticket.SetIdentityTokenLifetime(TimeSpan.FromDays(1));

            // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
            return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
        }
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddServer().UseMvc() is correctly called.");

            // Retrieve the application details from the database.
            var application = await _applicationManager.FindByClientIdAsync(request.ClientId);

            if (application == null)
            {
                return(BadRequest("Details concerning the calling client application cannot be found in the database"));
            }

            // Flow the request_id to allow OpenIddict to restore
            // the original authorization request from the cache.
            return(Redirect($"/Login?ApplicationName={await _applicationManager.GetDisplayNameAsync(application)}&RequestId={request.RequestId}&Scope={request.Scope}"));
        }
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            if (!User.Identity.IsAuthenticated)
            {
                // If the client application request promptless authentication,
                // return an error indicating that the user is not logged in.
                if (request.HasPrompt(OpenIdConnectConstants.Prompts.None))
                {
                    var properties = new AuthenticationProperties(new Dictionary <string, string>
                    {
                        [OpenIdConnectConstants.Properties.Error]            = OpenIdConnectConstants.Errors.LoginRequired,
                        [OpenIdConnectConstants.Properties.ErrorDescription] = "The user is not logged in."
                    });

                    // Ask OpenIddict to return a login_required error to the client application.
                    return(Forbid(properties, OpenIdConnectServerDefaults.AuthenticationScheme));
                }

                return(Challenge());
            }

            // Retrieve the profile of the logged in user.
            var user = await _userManager.GetUserAsync(User);

            if (user == null)
            {
                return(BadRequest(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The username/password couple is invalid."
                }));
            }

            // Create a new authentication ticket.
            var ticket = await CreateTicketAsync(request, user);

            // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
            return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
        }
示例#14
0
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            // Retrieve the application details from the database.
            var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);

            if (application == null)
            {
                return(View("Error", new ErrorViewModel
                {
                    Error = OpenIdConnectConstants.Errors.InvalidClient,
                    ErrorDescription = "Details concerning the calling client application cannot be found in the database"
                }));
            }

            return(await Accept(request));
        }
        public async Task <IActionResult> Accept(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddServer().UseMvc() is correctly called.");

            // Retrieve the profile of the logged in user.
            var user = await _userManager.FindByEmailAsync(request.Username);

            await _signInManager.PasswordSignInAsync(user, request.Password, true, false);

            if (user == null)
            {
                return(BadRequest("User not found."));
            }

            // Create a new authentication ticket.
            var ticket = await CreateTicketAsync(request, user);

            // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
            return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
        }
        public async Task <IActionResult> Authorize(OpenIdConnectRequest request)
        {
            Debug.Assert(request.IsAuthorizationRequest(),
                         "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
                         "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

            // Check if a user is authenticated. If not, challenge the GitHub authentication handler
            if (!User.Identity.IsAuthenticated)
            {
                return(Challenge("GitHub"));
            }

            // Create a new ClaimsPrincipal containing the claims that
            // will be used to create an id_token, a token or a code.
            var identity = new ClaimsIdentity("OpenIddict");

            identity.AddClaim(OpenIdConnectConstants.Claims.Subject, User.FindFirstValue(ClaimTypes.NameIdentifier),
                              OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken);
            identity.AddClaim(OpenIdConnectConstants.Claims.Name, User.FindFirstValue(ClaimTypes.Name),
                              OpenIdConnectConstants.Destinations.IdentityToken);
            identity.AddClaim(OpenIdConnectConstants.Claims.Email, User.FindFirstValue(ClaimTypes.Email),
                              OpenIdConnectConstants.Destinations.IdentityToken);
            identity.AddClaim(OpenIdConnectConstants.Claims.EmailVerified, "true",
                              OpenIdConnectConstants.Destinations.IdentityToken); // We'll assume email is verified since we get it from GitHub
            identity.AddClaim(OpenIdConnectConstants.Claims.Picture, User.FindFirstValue("github:avatar"),
                              OpenIdConnectConstants.Destinations.IdentityToken);
            var principal = new ClaimsPrincipal(identity);

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

            // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
            return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme));
        }
示例#17
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);
        }
示例#18
0
        private IEnumerable <(string property, string parameter, OpenIdConnectParameter value)> GetParameters(
            OpenIdConnectRequest request, AuthenticationProperties properties)
        {
            Debug.Assert(properties != null, "The authentication properties shouldn't be null.");

            Debug.Assert(request != null, "The request shouldn't be null.");
            Debug.Assert(request.IsAuthorizationRequest() || request.IsLogoutRequest() || request.IsTokenRequest(),
                         "The request should be an authorization, logout or token request.");

            foreach (var property in properties.Items)
            {
                if (string.IsNullOrEmpty(property.Key))
                {
                    continue;
                }

                if (string.IsNullOrEmpty(property.Value))
                {
                    continue;
                }

                if (property.Key.EndsWith(OpenIddictConstants.PropertyTypes.Boolean))
                {
                    var name = property.Key.Substring(
                        /* index: */ 0,
                        /* length: */ property.Key.LastIndexOf(OpenIddictConstants.PropertyTypes.Boolean));

                    bool value;

                    try
                    {
                        value = bool.Parse(property.Value);
                    }

                    catch (Exception exception)
                    {
                        Logger.LogWarning(exception, "An error occurred while parsing the public property " +
                                          "'{Name}' from the authentication ticket.", name);

                        continue;
                    }

                    yield return(property.Key, name, value);
                }

                else if (property.Key.EndsWith(OpenIddictConstants.PropertyTypes.Integer))
                {
                    var name = property.Key.Substring(
                        /* index: */ 0,
                        /* length: */ property.Key.LastIndexOf(OpenIddictConstants.PropertyTypes.Integer));

                    long value;

                    try
                    {
                        value = long.Parse(property.Value, CultureInfo.InvariantCulture);
                    }

                    catch (Exception exception)
                    {
                        Logger.LogWarning(exception, "An error occurred while parsing the public property " +
                                          "'{Name}' from the authentication ticket.", name);

                        continue;
                    }

                    yield return(property.Key, name, value);
                }

                else if (property.Key.EndsWith(OpenIddictConstants.PropertyTypes.Json))
                {
                    var name = property.Key.Substring(
                        /* index: */ 0,
                        /* length: */ property.Key.LastIndexOf(OpenIddictConstants.PropertyTypes.Json));

                    if (request.IsAuthorizationRequest() || request.IsLogoutRequest())
                    {
                        Logger.LogWarning("The JSON property '{Name}' was excluded as it was not " +
                                          "compatible with the OpenID Connect response type.", name);

                        continue;
                    }

                    JToken value;

                    try
                    {
                        value = JToken.Parse(property.Value);
                    }

                    catch (Exception exception)
                    {
                        Logger.LogWarning(exception, "An error occurred while deserializing the public JSON " +
                                          "property '{Name}' from the authentication ticket.", name);

                        continue;
                    }

                    yield return(property.Key, name, value);
                }

                else if (property.Key.EndsWith(OpenIddictConstants.PropertyTypes.String))
                {
                    var name = property.Key.Substring(
                        /* index: */ 0,
                        /* length: */ property.Key.LastIndexOf(OpenIddictConstants.PropertyTypes.String));

                    yield return(property.Key, name, property.Value);
                }

                continue;
            }
        }
        private async Task <string> SerializeIdentityTokenAsync(
            ClaimsPrincipal principal, AuthenticationProperties properties,
            OpenIdConnectRequest request, OpenIdConnectResponse response)
        {
            // Replace the principal by a new one containing only the filtered claims.
            // Actors identities are also filtered (delegation scenarios).
            principal = principal.Clone(claim =>
            {
                // Never exclude the subject claim.
                if (string.Equals(claim.Type, OpenIdConnectConstants.Claims.Subject, StringComparison.OrdinalIgnoreCase))
                {
                    return(true);
                }

                // Claims whose destination is not explicitly referenced or doesn't
                // contain "id_token" are not included in the identity token.
                if (!claim.HasDestination(OpenIdConnectConstants.Destinations.IdentityToken))
                {
                    Logger.LogDebug("'{Claim}' was excluded from the identity token claims.", claim.Type);

                    return(false);
                }

                return(true);
            });

            // Remove the destinations from the claim properties.
            foreach (var claim in principal.Claims)
            {
                claim.Properties.Remove(OpenIdConnectConstants.Properties.Destinations);
            }

            var identity = (ClaimsIdentity)principal.Identity;

            // Create a new ticket containing the updated properties and the filtered principal.
            var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);

            ticket.Properties.IssuedUtc  = Options.SystemClock.UtcNow;
            ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc +
                                           (ticket.GetIdentityTokenLifetime() ?? Options.IdentityTokenLifetime);

            ticket.SetUsage(OpenIdConnectConstants.Usages.IdentityToken);

            // Associate a random identifier with the identity token.
            ticket.SetTicketId(Guid.NewGuid().ToString());

            // Remove the unwanted properties from the authentication ticket.
            ticket.RemoveProperty(OpenIdConnectConstants.Properties.AccessTokenLifetime)
            .RemoveProperty(OpenIdConnectConstants.Properties.AuthorizationCodeLifetime)
            .RemoveProperty(OpenIdConnectConstants.Properties.ClientId)
            .RemoveProperty(OpenIdConnectConstants.Properties.CodeChallenge)
            .RemoveProperty(OpenIdConnectConstants.Properties.CodeChallengeMethod)
            .RemoveProperty(OpenIdConnectConstants.Properties.IdentityTokenLifetime)
            .RemoveProperty(OpenIdConnectConstants.Properties.RedirectUri)
            .RemoveProperty(OpenIdConnectConstants.Properties.RefreshTokenLifetime);

            ticket.SetAudiences(ticket.GetPresenters());

            var notification = new SerializeIdentityTokenContext(Context, Options, request, response, ticket)
            {
                Issuer = Context.GetIssuer(Options),
                SecurityTokenHandler = Options.IdentityTokenHandler,
                SigningCredentials   = Options.SigningCredentials.FirstOrDefault(key => key.Key is AsymmetricSecurityKey)
            };

            await Options.Provider.SerializeIdentityToken(notification);

            if (notification.HandledResponse || !string.IsNullOrEmpty(notification.IdentityToken))
            {
                return(notification.IdentityToken);
            }

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

            if (!ReferenceEquals(ticket, notification.Ticket))
            {
                throw new InvalidOperationException("The authentication ticket cannot be replaced.");
            }

            if (notification.SecurityTokenHandler == null)
            {
                return(null);
            }

            // Extract the main identity from the principal.
            identity = (ClaimsIdentity)ticket.Principal.Identity;

            if (string.IsNullOrEmpty(identity.GetClaim(OpenIdConnectConstants.Claims.Subject)))
            {
                throw new InvalidOperationException("The authentication ticket was rejected because " +
                                                    "it doesn't contain the mandatory subject claim.");
            }

            // Note: identity tokens must be signed but an exception is made by the OpenID Connect specification
            // when they are returned from the token endpoint: in this case, signing is not mandatory, as the TLS
            // server validation can be used as a way to ensure an identity token was issued by a trusted party.
            // See http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation for more information.
            if (notification.SigningCredentials == null && request.IsAuthorizationRequest())
            {
                throw new InvalidOperationException("A signing key must be provided.");
            }

            // Store the "unique_id" property as a claim.
            identity.AddClaim(OpenIdConnectConstants.Claims.JwtId, ticket.GetTicketId());

            // Store the "usage" property as a claim.
            identity.AddClaim(OpenIdConnectConstants.Claims.Usage, ticket.GetUsage());

            // Store the "confidentiality_level" property as a claim.
            var confidentiality = ticket.GetProperty(OpenIdConnectConstants.Properties.ConfidentialityLevel);

            if (!string.IsNullOrEmpty(confidentiality))
            {
                identity.AddClaim(OpenIdConnectConstants.Claims.ConfidentialityLevel, confidentiality);
            }

            // Store the audiences as claims.
            foreach (var audience in notification.Audiences)
            {
                identity.AddClaim(OpenIdConnectConstants.Claims.Audience, audience);
            }

            // If a nonce was present in the authorization request, it MUST
            // be included in the id_token generated by the token endpoint.
            // See http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
            var nonce = request.Nonce;

            if (request.IsAuthorizationCodeGrantType())
            {
                // Restore the nonce stored in the authentication
                // ticket extracted from the authorization code.
                nonce = ticket.GetProperty(OpenIdConnectConstants.Properties.Nonce);
            }

            if (!string.IsNullOrEmpty(nonce))
            {
                identity.AddClaim(OpenIdConnectConstants.Claims.Nonce, nonce);
            }

            if (notification.SigningCredentials != null && (!string.IsNullOrEmpty(response.Code) ||
                                                            !string.IsNullOrEmpty(response.AccessToken)))
            {
                using (var algorithm = OpenIdConnectServerHelpers.GetHashAlgorithm(notification.SigningCredentials.Algorithm))
                {
                    // Create an authorization code hash if necessary.
                    if (!string.IsNullOrEmpty(response.Code))
                    {
                        var hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(response.Code));

                        // Note: only the left-most half of the hash of the octets is used.
                        // See http://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken
                        identity.AddClaim(OpenIdConnectConstants.Claims.CodeHash, Base64UrlEncoder.Encode(hash, 0, hash.Length / 2));
                    }

                    // Create an access token hash if necessary.
                    if (!string.IsNullOrEmpty(response.AccessToken))
                    {
                        var hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(response.AccessToken));

                        // Note: only the left-most half of the hash of the octets is used.
                        // See http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken
                        identity.AddClaim(OpenIdConnectConstants.Claims.AccessTokenHash, Base64UrlEncoder.Encode(hash, 0, hash.Length / 2));
                    }
                }
            }

            // Extract the presenters from the authentication ticket.
            var presenters = notification.Presenters.ToArray();

            switch (presenters.Length)
            {
            case 0: break;

            case 1:
                identity.AddClaim(OpenIdConnectConstants.Claims.AuthorizedParty, presenters[0]);
                break;

            default:
                Logger.LogWarning("Multiple presenters have been associated with the identity token " +
                                  "but the JWT format only accepts single values.");

                // Only add the first authorized party.
                identity.AddClaim(OpenIdConnectConstants.Claims.AuthorizedParty, presenters[0]);
                break;
            }

            var token = notification.SecurityTokenHandler.CreateToken(new SecurityTokenDescriptor
            {
                Subject            = identity,
                Issuer             = notification.Issuer,
                SigningCredentials = notification.SigningCredentials,
                IssuedAt           = notification.Ticket.Properties.IssuedUtc?.UtcDateTime,
                NotBefore          = notification.Ticket.Properties.IssuedUtc?.UtcDateTime,
                Expires            = notification.Ticket.Properties.ExpiresUtc?.UtcDateTime
            });

            return(notification.SecurityTokenHandler.WriteToken(token));
        }