@@ -385,6 +394,7 @@ else
private string _redirecturl;
private string _identifierclaimtype;
private string _emailclaimtype;
+ private string _roleclaimtype;
private string _domainfilter;
private string _createusers;
@@ -436,8 +446,9 @@ else
_parameters = SettingService.GetSetting(settings, "ExternalLogin:Parameters", "");
_pkce = SettingService.GetSetting(settings, "ExternalLogin:PKCE", "false");
_redirecturl = PageState.Uri.Scheme + "://" + PageState.Alias.Name + "/signin-" + _providertype;
- _identifierclaimtype = SettingService.GetSetting(settings, "ExternalLogin:IdentifierClaimType", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier");
- _emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress");
+ _identifierclaimtype = SettingService.GetSetting(settings, "ExternalLogin:IdentifierClaimType", "sub");
+ _emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "email");
+ _roleclaimtype = SettingService.GetSetting(settings, "ExternalLogin:RoleClaimType", "");
_domainfilter = SettingService.GetSetting(settings, "ExternalLogin:DomainFilter", "");
_createusers = SettingService.GetSetting(settings, "ExternalLogin:CreateUsers", "true");
@@ -555,6 +566,7 @@ else
settings = SettingService.SetSetting(settings, "ExternalLogin:PKCE", _pkce, true);
settings = SettingService.SetSetting(settings, "ExternalLogin:IdentifierClaimType", _identifierclaimtype, true);
settings = SettingService.SetSetting(settings, "ExternalLogin:EmailClaimType", _emailclaimtype, true);
+ settings = SettingService.SetSetting(settings, "ExternalLogin:RoleClaimType", _roleclaimtype, true);
settings = SettingService.SetSetting(settings, "ExternalLogin:DomainFilter", _domainfilter, true);
settings = SettingService.SetSetting(settings, "ExternalLogin:CreateUsers", _createusers, true);
diff --git a/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx
index 2568b5a9..90cce059 100644
--- a/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx
+++ b/Oqtane.Client/Resources/Modules/Admin/Users/Index.resx
@@ -211,25 +211,25 @@
Allow Login?
- The Authority Url or Issuer Url associated with the OpenID Connect provider
+ The authority url or issuer url associated with the identity providerAuthority:
- The endpoint for obtaining an Authorization Code
+ The endpoint for obtaining an authorization codeAuthorization Url:
- The Client ID from the provider
+ The client id for the identity providerClient ID:
- The Client Secret from the provider
+ The client secret for the identity providerClient Secret:
@@ -247,7 +247,7 @@
Domain Filter:
- The name of the email address claim provided by the provider
+ The name of the email address claim provided by the identity providerEmail Claim:
@@ -259,7 +259,7 @@
Lockout Settings
- The discovery endpoint for obtaining metadata for this provider. Only specify if the OpenID Connect provider does not use the standard approach (ie. /.well-known/openid-configuration)
+ The discovery endpoint for obtaining metadata for this identity provider. Only specify if the identity provider does not use the standard approach (ie. /.well-known/openid-configuration)Metadata Url:
@@ -268,7 +268,7 @@
Password Settings
- Indicate if the provider supports Proof Key for Code Exchange (PKCE)
+ Indicate if the identity provider supports proof key for code exchange (PKCE)Use PKCE?
@@ -286,25 +286,25 @@
Provider Type:
- The Redirect Url (or Callback Url) which usually needs to be registered with the provider
+ The redirect url (or callback url) which usually needs to be registered with the identity providerRedirect Url:
- A list of Scopes to request from the provider (separated by commas). If none are specified, standard Scopes will be used by default.
+ A list of scopes to request from the identity provider (separated by commas). If none are specified, standard Scopes will be used by default.Scopes:
- The endpoint for obtaining an Auth Token
+ The endpoint for obtaining an auth tokenToken Url:
- The endpoint for obtaining user information. This should be an API or Page Url which contains the users email address.
+ The endpoint for obtaining user information. This should be an API endpoint or page url which contains the users email address.User Info Url:
@@ -373,15 +373,21 @@
Last Login
- The name of the unique user identifier claim provided by the provider
+ The name of the unique user identifier claim provided by the identity providerIdentifier Claim:
- Optionally specify any additional parameters as name/value pairs to send to the provider (separated by commas if there are multiple).
+ Optionally specify any additional parameters as name/value pairs to send to the identity provider (separated by commas if there are multiple).Parameters:
+
+ Optionally provide the name of the role claim provided by the identity provider. These roles will be used in addition to any internal user roles assigned within the site.
+
+
+ Role Claim Type:
+
\ No newline at end of file
diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs
index fec61c63..f21f53c9 100644
--- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs
+++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
+using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Net;
@@ -157,6 +158,9 @@ namespace Microsoft.Extensions.DependencyInjection
public static IServiceCollection ConfigureOqtaneAuthenticationOptions(this IServiceCollection services, IConfigurationRoot Configuration)
{
+ // prevent remapping of claims
+ JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
+
// settings defined in appsettings
services.Configure(Configuration);
services.Configure(Configuration);
diff --git a/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs b/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs
index 4d28a043..a5d703fd 100644
--- a/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs
+++ b/Oqtane.Server/Extensions/OqtaneSiteAuthenticationBuilderExtensions.cs
@@ -56,6 +56,10 @@ namespace Oqtane.Extensions
options.ClientId = sitesettings.GetValue("ExternalLogin:ClientId", "");
options.ClientSecret = sitesettings.GetValue("ExternalLogin:ClientSecret", "");
options.UsePkce = bool.Parse(sitesettings.GetValue("ExternalLogin:PKCE", "false"));
+ if (!string.IsNullOrEmpty(sitesettings.GetValue("ExternalLogin:RoleClaimType", "")))
+ {
+ options.TokenValidationParameters.RoleClaimType = sitesettings.GetValue("ExternalLogin:RoleClaimType", "");
+ }
options.Scope.Clear();
foreach (var scope in sitesettings.GetValue("ExternalLogin:Scopes", "openid,profile,email").Split(',', StringSplitOptions.RemoveEmptyEntries))
{
@@ -230,6 +234,18 @@ namespace Oqtane.Extensions
var identity = await ValidateUser(email, id, claims, context.HttpContext);
if (identity.Label == ExternalLoginStatus.Success)
{
+ // external roles
+ if (!string.IsNullOrEmpty(context.HttpContext.GetSiteSettings().GetValue("ExternalLogin:RoleClaimType", "")))
+ {
+ foreach (var claim in context.Principal.Claims.Where(item => item.Type == ClaimTypes.Role))
+ {
+ if (!identity.Claims.Any(item => item.Type == ClaimTypes.Role && item.Value == claim.Value))
+ {
+ identity.AddClaim(new Claim(ClaimTypes.Role, claim.Value));
+ }
+ }
+ }
+
identity.AddClaim(new Claim("access_token", context.SecurityToken.RawData));
context.Principal = new ClaimsPrincipal(identity);
}