Browse Source

Fix OpenIddictManager.CreateIdentityAsync to avoid storing null email addresses as claims

pull/102/head
Kévin Chalet 10 years ago
parent
commit
5c09b2ef8e
  1. 14
      src/OpenIddict.Core/OpenIddictManager.cs
  2. 23
      src/OpenIddict.Core/OpenIddictProvider.Authentication.cs
  3. 21
      src/OpenIddict.Core/OpenIddictProvider.Exchange.cs
  4. 5
      src/OpenIddict.Core/OpenIddictProvider.Userinfo.cs

14
src/OpenIddict.Core/OpenIddictManager.cs

@ -68,15 +68,17 @@ namespace OpenIddict {
// access tokens, even if an explicit destination is not specified. // access tokens, even if an explicit destination is not specified.
identity.AddClaim(ClaimTypes.NameIdentifier, await Services.Users.GetUserIdAsync(user)); identity.AddClaim(ClaimTypes.NameIdentifier, await Services.Users.GetUserIdAsync(user));
// Resolve the username and the email address associated with the user. // Resolve the email address associated with the user if the underlying store supports it.
var username = await Services.Users.GetUserNameAsync(user); var email = Services.Users.SupportsUserEmail ? await Services.Users.GetEmailAsync(user) : null;
var email = await Services.Users.GetEmailAsync(user);
// Only add the name claim if the "profile" scope was granted. // Only add the name claim if the "profile" scope was granted.
if (scopes.Contains(OpenIdConnectConstants.Scopes.Profile)) { if (scopes.Contains(OpenIdConnectConstants.Scopes.Profile)) {
var username = await Services.Users.GetUserNameAsync(user);
// Throw an exception if the username corresponds to the registered // Throw an exception if the username corresponds to the registered
// email address and if the "email" scope has not been requested. // email address and if the "email" scope has not been requested.
if (!scopes.Contains(OpenIdConnectConstants.Scopes.Email) && if (!scopes.Contains(OpenIdConnectConstants.Scopes.Email) &&
!string.IsNullOrEmpty(email) &&
string.Equals(username, email, StringComparison.OrdinalIgnoreCase)) { string.Equals(username, email, StringComparison.OrdinalIgnoreCase)) {
throw new InvalidOperationException("The 'email' scope is required."); throw new InvalidOperationException("The 'email' scope is required.");
} }
@ -87,7 +89,7 @@ namespace OpenIddict {
} }
// Only add the email address if the "email" scope was granted. // Only add the email address if the "email" scope was granted.
if (scopes.Contains(OpenIdConnectConstants.Scopes.Email)) { if (!string.IsNullOrEmpty(email) && scopes.Contains(OpenIdConnectConstants.Scopes.Email)) {
identity.AddClaim(ClaimTypes.Email, email, identity.AddClaim(ClaimTypes.Email, email,
OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken); OpenIdConnectConstants.Destinations.IdentityToken);
@ -96,8 +98,8 @@ namespace OpenIddict {
if (Services.Users.SupportsUserRole && scopes.Contains(OpenIddictConstants.Scopes.Roles)) { if (Services.Users.SupportsUserRole && scopes.Contains(OpenIddictConstants.Scopes.Roles)) {
foreach (var role in await Services.Users.GetRolesAsync(user)) { foreach (var role in await Services.Users.GetRolesAsync(user)) {
identity.AddClaim(identity.RoleClaimType, role, identity.AddClaim(identity.RoleClaimType, role,
OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.AccessToken,
OpenIdConnectConstants.Destinations.IdentityToken); OpenIdConnectConstants.Destinations.IdentityToken);
} }
} }

23
src/OpenIddict.Core/OpenIddictProvider.Authentication.cs

@ -79,16 +79,19 @@ namespace OpenIddict {
// Return an error if the username corresponds to the registered // Return an error if the username corresponds to the registered
// email address and if the "email" scope has not been requested. // email address and if the "email" scope has not been requested.
if (context.Request.HasScope(OpenIdConnectConstants.Scopes.Profile) && if (services.Users.SupportsUserEmail && context.Request.HasScope(OpenIdConnectConstants.Scopes.Profile) &&
!context.Request.HasScope(OpenIdConnectConstants.Scopes.Email) && !context.Request.HasScope(OpenIdConnectConstants.Scopes.Email)) {
string.Equals(await services.Users.GetUserNameAsync(user), // Retrieve the username and the email address associated with the user.
await services.Users.GetEmailAsync(user), var username = await services.Users.GetUserNameAsync(user);
StringComparison.OrdinalIgnoreCase)) { var email = await services.Users.GetEmailAsync(user);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest, if (!string.IsNullOrEmpty(email) && string.Equals(username, email, StringComparison.OrdinalIgnoreCase)) {
description: "The 'email' scope is required."); context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
return; description: "The 'email' scope is required.");
return;
}
} }
} }

21
src/OpenIddict.Core/OpenIddictProvider.Exchange.cs

@ -234,16 +234,19 @@ namespace OpenIddict {
// Return an error if the username corresponds to the registered // Return an error if the username corresponds to the registered
// email address and if the "email" scope has not been requested. // email address and if the "email" scope has not been requested.
if (context.Request.HasScope(OpenIdConnectConstants.Scopes.Profile) && if (services.Users.SupportsUserEmail && context.Request.HasScope(OpenIdConnectConstants.Scopes.Profile) &&
!context.Request.HasScope(OpenIdConnectConstants.Scopes.Email) && !context.Request.HasScope(OpenIdConnectConstants.Scopes.Email)) {
string.Equals(await services.Users.GetUserNameAsync(user), // Retrieve the username and the email address associated with the user.
await services.Users.GetEmailAsync(user), var username = await services.Users.GetUserNameAsync(user);
StringComparison.OrdinalIgnoreCase)) { var email = await services.Users.GetEmailAsync(user);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
description: "The 'email' scope is required.");
return; if (!string.IsNullOrEmpty(email) && string.Equals(username, email, StringComparison.OrdinalIgnoreCase)) {
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
description: "The 'email' scope is required.");
return;
}
} }
var identity = await services.Applications.CreateIdentityAsync(user, context.Request.GetScopes()); var identity = await services.Applications.CreateIdentityAsync(user, context.Request.GetScopes());

5
src/OpenIddict.Core/OpenIddictProvider.Userinfo.cs

@ -50,7 +50,7 @@ namespace OpenIddict {
} }
// Only add the email address details if the "email" scope was present in the access token. // Only add the email address details if the "email" scope was present in the access token.
if (context.Ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) { if (services.Users.SupportsUserEmail && context.Ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) {
context.Email = await services.Users.GetEmailAsync(user); context.Email = await services.Users.GetEmailAsync(user);
// Only add the "email_verified" claim // Only add the "email_verified" claim
@ -61,7 +61,8 @@ namespace OpenIddict {
}; };
// Only add the phone number details if the "phone" scope was present in the access token. // Only add the phone number details if the "phone" scope was present in the access token.
if (context.Ticket.HasScope(OpenIdConnectConstants.Scopes.Phone)) { if (services.Users.SupportsUserPhoneNumber &&
context.Ticket.HasScope(OpenIdConnectConstants.Scopes.Phone)) {
context.PhoneNumber = await services.Users.GetPhoneNumberAsync(user); context.PhoneNumber = await services.Users.GetPhoneNumberAsync(user);
// Only add the "phone_number_verified" // Only add the "phone_number_verified"

Loading…
Cancel
Save