I am using Sitecore 10.1 and I want to do federation authentication on the CM server. When I am clicking on "Log in with keycloak" button it is redirecting to Keycloak
URL and after entering my username and password, it is coming back to the Sitecore login page.
But it is showing the error message "You do not have access to the system. If you think this is wrong, please contact the system administrator."
Below is OnSecurityTokenValidated
, I am getting IsAuthenticated
true and getting claims as well.
Below is my code:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/"
xmlns:env="http://www.sitecore.net/xmlconfig/env/" xmlns:zone="http://www.sitecore.net/xmlconfig/zone/">
<sitecore role:require="ContentManagement or Standalone">
<pipelines>
<owin.identityProviders>
<processor type="XXX.KeycloakIdentityProvider, XXX.Website" resolve="true" />
</owin.identityProviders>
</pipelines>
<federatedAuthentication type="Sitecore.Owin.Authentication.Configuration.FederatedAuthenticationConfiguration, Sitecore.Owin.Authentication">
<identityProvidersPerSites hint="list:AddIdentityProvidersPerSites">
<!-- Defines a list of providers assigned to all sites. -->
<mapEntry name="all sites" type="Sitecore.Owin.Authentication.Collections.IdentityProvidersPerSitesMapEntry, Sitecore.Owin.Authentication" resolve="true">
<sites hint="list">
<site>regexp:.*</site>
</sites>
<identityProviders hint="list:AddIdentityProvider">
<identityProvider ref="federatedAuthentication/identityProviders/identityProvider[@id='keycloak']" />
</identityProviders>
<externalUserBuilder type="Sitecore.Owin.Authentication.Services.DefaultExternalUserBuilder, Sitecore.Owin.Authentication" resolve="true">
<IsPersistentUser>false</IsPersistentUser>
</externalUserBuilder>
</mapEntry>
</identityProvidersPerSites>
<identityProviders>
<identityProvider id="keycloak" type="Sitecore.Owin.Authentication.Configuration.DefaultIdentityProvider, Sitecore.Owin.Authentication">
<param desc="name">$(id)</param>
<param desc="domainManager" type="Sitecore.Abstractions.BaseDomainManager" resolve="true" />
<caption>Log in with keycloak</caption>
<icon>/sitecore/shell/themes/standard/Custom/24x24/msazure.png</icon>
<domain>sitecore</domain>
<enabled>true</enabled>
<transformations hint="list:AddTransformation">
<transformation name="Idp Claim" type="Sitecore.Owin.Authentication.Services.SetIdpClaimTransform, Sitecore.Owin.Authentication" />
<transformation name="set id_token claim" type="Sitecore.Owin.Authentication.Services.SaveIdTokenInClaim, Sitecore.Owin.Authentication" />
<transformation type="Sitecore.Owin.Authentication.Services.DefaultTransformation, Sitecore.Owin.Authentication">
<sources hint="raw:AddSource">
<claim name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" />
</sources>
<targets hint="raw:AddTarget">
<claim name="Email" />
</targets>
<keepSource>false</keepSource>
</transformation>
</transformations>
</identityProvider>
</identityProviders>
<propertyInitializer type="Sitecore.Owin.Authentication.Services.PropertyInitializer, Sitecore.Owin.Authentication">
<maps hint="list">
<map name="set SSO FullName" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication" resolve="true" patch:source="Project.NAC.AzureAD.config">
<data hint="raw:AddData">
<source name="full_name" />
<target name="FullName" />
</data>
</map>
<map name="Given Name" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication" resolve="true">
<data hint="raw:AddData">
<source name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" />
<target name="Name" />
</data>
</map>
</maps>
</propertyInitializer>
</federatedAuthentication>
</sitecore>
</configuration>
public class KeycloakIdentityProvider : IdentityProvidersProcessor
{
protected override string IdentityProviderName => "keycloak";
private string ClientId => Settings.GetSetting(KeycloakSettings.ClientId, "");
private string ClientSecret => Settings.GetSetting(KeycloakSettings.ClientSecret, "");
private string Authority => Settings.GetSetting(KeycloakSettings.Authority, "");
private string OAuthRedirectUri => Settings.GetSetting(KeycloakSettings.OAuthRedirectUri, "");
private string MetadataAddress => Settings.GetSetting(KeycloakSettings.MetadataAddress, "");
private readonly string idToken = "id_token";
private readonly string accessDeniedRelativePath = "/custom/errorpages/Forbidden.aspx";
public KeycloakIdentityProvider(FederatedAuthenticationConfiguration federatedAuthenticationConfiguration, Microsoft.Owin.Infrastructure.ICookieManager cookieManager, BaseSettings settings) : base(federatedAuthenticationConfiguration, cookieManager, settings)
{
}
protected IdentityProvider IdentityProvider { get; set; }
protected override void ProcessCore(IdentityProvidersArgs args)
{
Assert.ArgumentNotNull(args, "args");
IdentityProvider = this.GetIdentityProvider();
var identityProvider = this.GetIdentityProvider();
var saveSigninToken = identityProvider.TriggerExternalSignOut;
var options = new OpenIdConnectAuthenticationOptions
{
RequireHttpsMetadata = false,
MetadataAddress = MetadataAddress,
ClientId = ClientId,
ClientSecret = ClientSecret,
Authority = Authority,
RedirectUri = GetCallbackUrl(args),
ResponseType = OpenIdConnectResponseType.Code,
Scope = OpenIdConnectScope.OpenIdProfile + " " + OpenIdConnectScope.OfflineAccess,
AuthenticationType = IdentityProvider.Name,
RedeemCode = true,
TokenValidationParameters = new TokenValidationParameters
{
SaveSigninToken = saveSigninToken
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = (AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification) =>
{
Log.Info("code entered the authentication failed event", this);
if (notification.Exception != null)
{
Log.Info($"Keycloak authorization fail with exception.\n {notification.Exception.Message}", this);
notification.HandleResponse();
if (notification.Exception.Message.Contains("IDX21323"))
{
notification.HandleResponse();
notification.OwinContext.Authentication.Challenge();
return System.Threading.Tasks.Task.CompletedTask;
}
}
notification.HandleResponse();
notification.Response.Redirect(accessDeniedRelativePath);
return System.Threading.Tasks.Task.CompletedTask;
},
SecurityTokenValidated = OnSecurityTokenValidated,
RedirectToIdentityProvider = notification =>
{
Log.Info("code entered the RedirectToIdentityProvider event", this);
if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
{
notification.ProtocolMessage.SetParameter("kc_idp_hint", "saml");
}
if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
var idTokenClaim = notification.OwinContext.Authentication.User.FindFirst(idToken);
if (idTokenClaim != null)
notification.ProtocolMessage.IdTokenHint = idTokenClaim.Value;
}
return System.Threading.Tasks.Task.CompletedTask;
}
}
};
args.App.UseKentorOwinCookieSaver();
args.App.UseOpenIdConnectAuthentication(options);
}
private System.Threading.Tasks.Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
var identityProvider = this.GetIdentityProvider();
var identity = notification.AuthenticationTicket.Identity;
foreach (var current in identityProvider.Transformations)
{
current.Transform(identity, new TransformationContext(this.FederatedAuthenticationConfiguration, identityProvider));
}
return System.Threading.Tasks.Task.CompletedTask;
}
private string GetCallbackUrl(IdentityProvidersArgs args)
{
string settingValue = Settings.GetSetting("Sitecore.CM.LoadBalanceDNS");
var hostName = string.IsNullOrEmpty(settingValue) ? HttpContext.Current.Request.Url.AbsoluteUri : settingValue;
return string.Concat(hostName, "/", OAuthRedirectUri);
}
private void HandleAuthorizationError(AuthorizationCodeReceivedNotification notification)
{
// Log Error
notification.HandleResponse();
notification.Response.Redirect(accessDeniedRelativePath);
}
}