diff --git a/samples/Mvc.Server/Controllers/AuthorizationController.cs b/samples/Mvc.Server/Controllers/AuthorizationController.cs index a9ee90b4..ea4bcc61 100644 --- a/samples/Mvc.Server/Controllers/AuthorizationController.cs +++ b/samples/Mvc.Server/Controllers/AuthorizationController.cs @@ -5,6 +5,7 @@ */ using System; +using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using AspNet.Security.OpenIdConnect.Extensions; @@ -78,8 +79,13 @@ namespace Mvc.Server { new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); - ticket.SetResources(request.GetResources()); - ticket.SetScopes(request.GetScopes()); + // Set the list of scopes granted to the client application. + ticket.SetScopes(new[] { + /* openid: */ OpenIdConnectConstants.Scopes.OpenId, + /* email: */ OpenIdConnectConstants.Scopes.Email, + /* profile: */ OpenIdConnectConstants.Scopes.Profile, + /* offline_access: */ OpenIdConnectConstants.Scopes.OfflineAccess + }.Intersect(request.GetScopes())); // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme); @@ -176,8 +182,13 @@ namespace Mvc.Server { new AuthenticationProperties(), OpenIdConnectServerDefaults.AuthenticationScheme); - ticket.SetResources(request.GetResources()); - ticket.SetScopes(request.GetScopes()); + // Set the list of scopes granted to the client application. + ticket.SetScopes(new[] { + /* openid: */ OpenIdConnectConstants.Scopes.OpenId, + /* email: */ OpenIdConnectConstants.Scopes.Email, + /* profile: */ OpenIdConnectConstants.Scopes.Profile, + /* offline_access: */ OpenIdConnectConstants.Scopes.OfflineAccess + }.Intersect(request.GetScopes())); return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme); } diff --git a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs index 15bae320..e391de64 100644 --- a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs +++ b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Authentication.cs @@ -255,39 +255,6 @@ namespace OpenIddict.Infrastructure { return; } - // Ensure that the appropriate set of scopes is requested to prevent personal data leakage when possible. - if (services.Users.SupportsUserEmail && context.HttpContext.User.Identities.Any(identity => identity.IsAuthenticated) && - context.Request.HasScope(OpenIdConnectConstants.Scopes.Profile) && - !context.Request.HasScope(OpenIdConnectConstants.Scopes.Email)) { - // Skip scope validation if the user cannot be found in the database. - var user = await services.Users.GetUserAsync(context.HttpContext.User); - if (user == null) { - services.Logger.LogWarning("The authorization request was not fully validated because the profile corresponding " + - "to the logged in user was not found in the database: {Identifier}.", - context.HttpContext.User.GetClaim(ClaimTypes.NameIdentifier)); - } - - else { - // Retrieve the username and the email address associated with the user. - var username = await services.Users.GetUserNameAsync(user); - var email = await services.Users.GetEmailAsync(user); - - // Return an error if the username corresponds to the registered - // email address and if the "email" scope has not been requested. - if (!string.IsNullOrEmpty(email) && string.Equals(username, email, StringComparison.OrdinalIgnoreCase)) { - services.Logger.LogError("The authorization request was rejected because the 'email' scope was not requested: " + - "to prevent data leakage, the 'email' scope must be granted when the username " + - "is identical to the email address associated with the user profile."); - - context.Reject( - error: OpenIdConnectConstants.Errors.InvalidRequest, - description: "The 'email' scope is required."); - - return; - } - } - } - // Run additional checks for prompt=none requests. if (string.Equals(context.Request.Prompt, "none", StringComparison.Ordinal)) { // If the user is not authenticated, return an error to the client application. diff --git a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs index 24921c9e..b1453ae3 100644 --- a/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs +++ b/src/OpenIddict.Core/Infrastructure/OpenIddictProvider.Exchange.cs @@ -13,7 +13,6 @@ using AspNet.Security.OpenIdConnect.Server; using JetBrains.Annotations; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http.Authentication; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -290,40 +289,6 @@ namespace OpenIddict.Infrastructure { return; } - else if (context.Request.IsPasswordGrantType()) { - // Note: at this stage, the client credentials cannot be null as the OpenID Connect server middleware - // automatically rejects grant_type=password requests that don't specify a username/password couple. - Debug.Assert(!string.IsNullOrEmpty(context.Request.Username) && - !string.IsNullOrEmpty(context.Request.Password), "The user credentials shouldn't be null."); - - var user = await services.Users.FindByNameAsync(context.Request.Username); - if (user == null) { - services.Logger.LogWarning("The token request was not fully validated because the profile corresponding to the " + - "given username was not found in the database: {Username}.", context.Request.Username); - } - - // Return an error if the username corresponds to the registered - // email address and if the "email" scope has not been requested. - else if (services.Users.SupportsUserEmail && context.Request.HasScope(OpenIdConnectConstants.Scopes.Profile) && - !context.Request.HasScope(OpenIdConnectConstants.Scopes.Email)) { - // Retrieve the username and the email address associated with the user. - var username = await services.Users.GetUserNameAsync(user); - var email = await services.Users.GetEmailAsync(user); - - if (!string.IsNullOrEmpty(email) && string.Equals(username, email, StringComparison.OrdinalIgnoreCase)) { - services.Logger.LogError("The token request was rejected because the 'email' scope was not requested: " + - "to prevent data leakage, the 'email' scope must be granted when the username " + - "is identical to the email address associated with the user profile."); - - context.Reject( - error: OpenIdConnectConstants.Errors.InvalidRequest, - description: "The 'email' scope is required."); - - return; - } - } - } - // Invoke the rest of the pipeline to allow // the user code to handle the token request. context.SkipToNextMiddleware(); diff --git a/src/OpenIddict.Core/Managers/OpenIddictUserManager.cs b/src/OpenIddict.Core/Managers/OpenIddictUserManager.cs index 785f5389..42a2a36e 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictUserManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictUserManager.cs @@ -90,28 +90,19 @@ namespace OpenIddict { // access tokens, even if an explicit destination is not specified. identity.AddClaim(ClaimTypes.NameIdentifier, await GetUserIdAsync(user)); - // Resolve the email address associated with the user if the underlying store supports it. - var email = SupportsUserEmail ? await GetEmailAsync(user) : null; - // Only add the name claim if the "profile" scope was granted. if (scopes.Contains(OpenIdConnectConstants.Scopes.Profile)) { var username = await GetUserNameAsync(user); - // Throw an exception if the username corresponds to the registered - // email address and if the "email" scope has not been requested. - if (!scopes.Contains(OpenIdConnectConstants.Scopes.Email) && - !string.IsNullOrEmpty(email) && - string.Equals(username, email, StringComparison.OrdinalIgnoreCase)) { - throw new InvalidOperationException("The 'email' scope is required."); - } - identity.AddClaim(ClaimTypes.Name, username, OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken); } // Only add the email address if the "email" scope was granted. - if (!string.IsNullOrEmpty(email) && scopes.Contains(OpenIdConnectConstants.Scopes.Email)) { + if (SupportsUserEmail && scopes.Contains(OpenIdConnectConstants.Scopes.Email)) { + var email = await GetEmailAsync(user); + identity.AddClaim(ClaimTypes.Email, email, OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken);