public async Task <IActionResult> Authorize() { var request = HttpContext.GetOpenIdConnectRequest(); 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, OpenIddictServerDefaults.AuthenticationScheme)); } return(Challenge()); } // 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 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); // Set the list of scopes granted to the client application. var scopes = request.GetScopes().ToImmutableArray(); ticket.SetScopes(scopes); ticket.SetResources(await _scopeManager.ListResourcesAsync(scopes)); foreach (var claim in ticket.Principal.Claims) { claim.SetDestinations(GetDestinations(claim, ticket)); } // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme)); }
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); // Set the list of scopes granted to the client application. var scopes = request.GetScopes().ToImmutableArray(); ticket.SetScopes(scopes); ticket.SetResources(await _scopeManager.ListResourcesAsync(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; } 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); }
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); }
private async Task <AuthenticationTicket> CreateTicketAsync( OpenIdConnectRequest request, User user, AuthenticationProperties authenticationProperties = null) { var scopes = _openIddictOptions .Scopes .Intersect(request.GetScopes()) .ToImmutableArray(); var identity = await CreateIdentityFromUserAsync(user, scopes); var ticket = new AuthenticationTicket( new ClaimsPrincipal(identity), authenticationProperties ?? new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); ticket.SetResources(await _scopeManager.ListResourcesAsync(scopes)); ticket.SetAudiences(request.ClientId); ticket.SetScopes(scopes); return(ticket); }
public async Task <IActionResult> Authorize() { var request = HttpContext.GetOpenIddictServerRequest() ?? throw new InvalidOperationException("The OpenID Connect request cannot be retrieved."); // Retrieve the user principal stored in the authentication cookie. // If it can't be extracted, redirect the user to the login page. var result = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme); if (result == null || !result.Succeeded) { // If the client application requested promptless authentication, // return an error indicating that the user is not logged in. if (request.HasPrompt(Prompts.None)) { return(Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is not logged in." }))); } return(Challenge( authenticationSchemes: IdentityConstants.ApplicationScheme, properties: new AuthenticationProperties { RedirectUri = Request.PathBase + Request.Path + QueryString.Create( Request.HasFormContentType ? Request.Form.ToList() : Request.Query.ToList()) })); } // If prompt=login was specified by the client application, // immediately return the user agent to the login page. if (request.HasPrompt(Prompts.Login)) { // To avoid endless login -> authorization redirects, the prompt=login flag // is removed from the authorization request payload before redirecting the user. var prompt = string.Join(" ", request.GetPrompts().Remove(Prompts.Login)); var parameters = Request.HasFormContentType ? Request.Form.Where(parameter => parameter.Key != Parameters.Prompt).ToList() : Request.Query.Where(parameter => parameter.Key != Parameters.Prompt).ToList(); parameters.Add(KeyValuePair.Create(Parameters.Prompt, new StringValues(prompt))); return(Challenge( authenticationSchemes: IdentityConstants.ApplicationScheme, properties: new AuthenticationProperties { RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters) })); } // If a max_age parameter was provided, ensure that the cookie is not too old. // If it's too old, automatically redirect the user agent to the login page. if (request.MaxAge != null && result.Properties?.IssuedUtc != null && DateTimeOffset.UtcNow - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value)) { if (request.HasPrompt(Prompts.None)) { return(Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is not logged in." }))); } return(Challenge( authenticationSchemes: IdentityConstants.ApplicationScheme, properties: new AuthenticationProperties { RedirectUri = Request.PathBase + Request.Path + QueryString.Create( Request.HasFormContentType ? Request.Form.ToList() : Request.Query.ToList()) })); } // Retrieve the profile of the logged in user. var user = await _userManager.GetUserAsync(result.Principal) ?? throw new InvalidOperationException("The user details cannot be retrieved."); // Retrieve the application details from the database. var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ?? throw new InvalidOperationException("Details concerning the calling client application cannot be found."); // Retrieve the permanent authorizations associated with the user and the calling client application. var authorizations = await _authorizationManager.FindAsync( subject : await _userManager.GetUserIdAsync(user), client : await _applicationManager.GetIdAsync(application), status : Statuses.Valid, type : AuthorizationTypes.Permanent, scopes : request.GetScopes()).ToListAsync(); switch (await _applicationManager.GetConsentTypeAsync(application)) { // If the consent is external (e.g when authorizations are granted by a sysadmin), // immediately return an error if no authorization can be found in the database. case ConsentTypes.External when !authorizations.Any(): return(Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The logged in user is not allowed to access this client application." }))); // If the consent is implicit or if an authorization was found, // return an authorization response without displaying the consent form. case ConsentTypes.Implicit: case ConsentTypes.External when authorizations.Any(): case ConsentTypes.Explicit when authorizations.Any() && !request.HasPrompt(Prompts.Consent): var principal = await _signInManager.CreateUserPrincipalAsync(user); // Note: in this sample, the granted scopes match the requested scope // but you may want to allow the user to uncheck specific scopes. // For that, simply restrict the list of scopes before calling SetScopes. principal.SetScopes(request.GetScopes()); principal.SetResources(await _scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync()); // Automatically create a permanent authorization to avoid requiring explicit consent // for future authorization or token requests containing the same scopes. var authorization = authorizations.LastOrDefault(); if (authorization == null) { authorization = await _authorizationManager.CreateAsync( principal : principal, subject : await _userManager.GetUserIdAsync(user), client : await _applicationManager.GetIdAsync(application), type : AuthorizationTypes.Permanent, scopes : principal.GetScopes()); } principal.SetInternalAuthorizationId(await _authorizationManager.GetIdAsync(authorization)); foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim, principal)); } return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); // At this point, no authorization was found in the database and an error must be returned // if the client application specified prompt=none in the authorization request. case ConsentTypes.Explicit when request.HasPrompt(Prompts.None): case ConsentTypes.Systematic when request.HasPrompt(Prompts.None): return(Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "Interactive user consent is required." }))); // In every other case, render the consent form. default: return(View(new AuthorizeViewModel { ApplicationName = await _applicationManager.GetDisplayNameAsync(application), Scope = request.Scope })); } }
public async Task <IActionResult> Exchange() { var request = HttpContext.GetOpenIdConnectRequest(); if (request.IsClientCredentialsGrantType()) { var application = await _applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted); if (application == null) { throw new InvalidOperationException("The application details cannot be found in the database."); } var identity = new ClaimsIdentity( OpenIddictServerDefaults.AuthenticationScheme, OpenIdConnectConstants.Claims.Name, OpenIdConnectConstants.Claims.Role); identity.AddClaim(OpenIdConnectConstants.Claims.Name, application.DisplayName, OpenIdConnectConstants.Destinations.AccessToken); identity.AddClaim(OpenIdConnectConstants.Claims.ClientId, application.ClientId, OpenIddictConstants.Destinations.AccessToken); var ticket = new AuthenticationTicket( new ClaimsPrincipal(identity), new AuthenticationProperties(), OpenIddictServerDefaults.AuthenticationScheme); var scopes = request.GetScopes().ToImmutableArray(); ticket.SetResources(await _scopeManager.ListResourcesAsync(scopes)); return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme)); } else if (request.IsAuthorizationCodeGrantType() || request.IsRefreshTokenGrantType()) { var info = await HttpContext.AuthenticateAsync(OpenIddictServerDefaults.AuthenticationScheme); var user = await _userManager.GetUserAsync(info.Principal); if (user == null) { return(BadRequest(new OpenIdConnectResponse() { Error = OpenIdConnectConstants.Errors.InvalidGrant, ErrorDescription = "The authorization code is no longer valid." })); } if (!await _signInManager.CanSignInAsync(user)) { return(BadRequest(new OpenIdConnectResponse() { Error = OpenIdConnectConstants.Errors.InvalidGrant, ErrorDescription = "The user is no longer allowed to sign in." })); } var ticket = await this.CreateTicketAsync(user, request, new AuthenticationProperties()); return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme)); } else if (request.IsPasswordGrantType()) { var user = await _userManager.FindByNameAsync(request.Username); if (user == null) { var properties = new AuthenticationProperties(new Dictionary <string, string> { [OpenIdConnectConstants.Properties.Error] = OpenIdConnectConstants.Errors.InvalidGrant, [OpenIdConnectConstants.Properties.ErrorDescription] = "The username/password couple is invalid." }); return(Forbid(properties, OpenIddictServerDefaults.AuthenticationScheme)); } var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, true); if (!result.Succeeded) { var properties = new AuthenticationProperties(new Dictionary <string, string> { [OpenIdConnectConstants.Properties.Error] = OpenIdConnectConstants.Errors.InvalidGrant, [OpenIdConnectConstants.Properties.ErrorDescription] = "The username/password couple is invalid." }); return(Forbid(properties, OpenIddictServerDefaults.AuthenticationScheme)); } var ticket = await CreateTicketAsync(user, request, new AuthenticationProperties()); return(SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme)); } throw new NotImplementedException("The specified grant type is not implemented."); }
public async Task <IActionResult> Exchange() { var request = HttpContext.GetOpenIddictServerRequest() ?? throw new InvalidOperationException("The OpenID Connect request cannot be retrieved."); if (request.IsPasswordGrantType()) { var user = await _userManager.FindByNameAsync(request.Username); if (user == null) { return(Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The username/password is invalid." }))); } // Validate the username/password parameters and ensure the account is not locked out. var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, lockoutOnFailure : false); if (!result.Succeeded) { return(Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The username/password is invalid." }))); } var principal = await _signInManager.CreateUserPrincipalAsync(user); // Note: in this sample, the granted scopes match the requested scope // but you may want to allow the user to uncheck specific scopes. // For that, simply restrict the list of scopes before calling SetScopes. principal.SetScopes(request.GetScopes()); principal.SetResources(await _scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync()); foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim, principal)); } // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); } else if (request.IsAuthorizationCodeGrantType() || request.IsDeviceCodeGrantType() || request.IsRefreshTokenGrantType()) { // Retrieve the claims principal stored in the authorization code/device code/refresh token. var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal; // Retrieve the user profile corresponding to the authorization code/refresh token. // Note: if you want to automatically invalidate the authorization code/refresh token // when the user password/roles change, use the following line instead: // var user = _signInManager.ValidateSecurityStampAsync(info.Principal); var user = await _userManager.GetUserAsync(principal); if (user == null) { return(Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." }))); } // Ensure the user is still allowed to sign in. if (!await _signInManager.CanSignInAsync(user)) { return(Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." }))); } foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim, principal)); } // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); } throw new InvalidOperationException("The specified grant type is not supported."); }