Created
December 4, 2023 04:59
-
-
Save hawjeh/3658cc6a6c0e62df4872a54e367f31ed to your computer and use it in GitHub Desktop.
Sitefinity Azure AD SAML SSO Login Integration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public void CreateUserFromSaml(Guid userId, string userEmail) | |
{ | |
try | |
{ | |
var user = userManager.GetUser(userId); | |
if (user != null) | |
{ | |
var firstName = Cache.GetData(userEmail + AuthConstant.FirstNameKey).ToString(); | |
var lastName = Cache.GetData(userEmail + AuthConstant.LastNameKey).ToString(); | |
var userProfile = userProfileManager.GetUserProfile<SitefinityProfile>(user); | |
if (userProfile != null) | |
{ | |
userProfileManager.Provider.SuppressSecurityChecks = true; | |
userProfile.FirstName = firstName; | |
userProfile.LastName = lastName; | |
userProfileManager.SaveChanges(); | |
userProfileManager.Provider.SuppressSecurityChecks = false; | |
} | |
var role = Cache.GetData(userEmail + AuthConstant.RoleKey).ToString(); | |
if (!role.IsNullOrEmpty()) | |
{ | |
var roleExists = roleManager.RoleExists(role); | |
var userRole = roleManager.GetRole(role); | |
if (userRole != null && roleExists) | |
{ | |
roleManager.Provider.SuppressSecurityChecks = true; | |
roleManager.AddUserToRole(user, userRole); | |
roleManager.SaveChanges(); | |
roleManager.Provider.SuppressSecurityChecks = false; | |
} | |
} | |
} | |
} | |
catch (Exception ex) | |
{ | |
throw ex; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Telerik.Microsoft.Practices.Unity; | |
using Telerik.Sitefinity.Abstractions; | |
using Telerik.Sitefinity.Authentication; | |
using Telerik.Sitefinity.Security.Events; | |
using Telerik.Sitefinity.Services; | |
namespace SitefinityWebApp | |
{ | |
public class Global : System.Web.HttpApplication | |
{ | |
protected void Application_Start(object sender, EventArgs e) | |
{ | |
AuthenticationModule.Initialized += this.AuthenticationModule_Initialized; | |
Bootstrapper.Bootstrapped += Bootstrapper_Bootstrapped; | |
} | |
private void AuthenticationModule_Initialized(object sender, EventArgs e) | |
{ | |
ObjectFactory.Container.RegisterType<AuthenticationProvidersInitializer, SamlAuthenticationProvidersInitializer>(new ContainerControlledLifetimeManager()); | |
} | |
private void Bootstrapper_Bootstrapped(object sender, EventArgs e) | |
{ | |
// Assign role and update user upon saml login | |
EventHub.Subscribe<UserCreated>(evt => UserCreatedEventHandler(evt)); | |
} | |
private void UserCreatedEventHandler(UserCreated eventInfo) | |
{ | |
var isSaml2p = eventInfo.ExternalProviderName == AuthConstant.SamlAuthenticationType; | |
if (isSaml2p) | |
{ | |
var userServices = new UserServices(); | |
userServices.CreateUserFromSaml(eventInfo.UserId, eventInfo.Email); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using IdentityModel; | |
using Owin; | |
using Sustainsys.Saml2; | |
using Sustainsys.Saml2.Configuration; | |
using Sustainsys.Saml2.Metadata; | |
using Sustainsys.Saml2.Owin; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Security.Claims; | |
using Telerik.Microsoft.Practices.EnterpriseLibrary.Caching; | |
using Telerik.Microsoft.Practices.EnterpriseLibrary.Caching.Expirations; | |
using Telerik.Sitefinity.Authentication; | |
using Telerik.Sitefinity.Authentication.Configuration.SecurityTokenService.ExternalProviders; | |
using Telerik.Sitefinity.Security.Claims; | |
using Telerik.Sitefinity.Services; | |
namespace SitefinityWebApp | |
{ | |
public class SamlAuthenticationProvidersInitializer : AuthenticationProvidersInitializer | |
{ | |
public virtual ICacheManager Cache | |
{ | |
get | |
{ | |
return SystemManager.GetCacheManager(CacheManagerInstance.Global); | |
} | |
} | |
public override Dictionary<string, Action<IAppBuilder, string, AuthenticationProviderElement>> GetAdditionalIdentityProviders() | |
{ | |
var additionalProviders = base.GetAdditionalIdentityProviders(); | |
additionalProviders[AuthConstant.SamlAuthenticationType] = (IAppBuilder app, string signInAsType, AuthenticationProviderElement config) => | |
{ | |
var authServicesOptions = new Saml2AuthenticationOptions(false) | |
{ | |
SPOptions = new SPOptions | |
{ | |
EntityId = new EntityId(config.GetParameter(AuthConstant.SpEntityIdParameterName)), | |
}, | |
SignInAsAuthenticationType = signInAsType, | |
AuthenticationType = AuthConstant.SamlAuthenticationType, | |
Caption = config.Title, | |
Notifications = new Saml2Notifications | |
{ | |
AcsCommandResultCreated = (result, response) => | |
{ | |
var claimsIdentity = result.Principal.Identity as ClaimsIdentity; | |
var email = GetEmailFromIdentity(claimsIdentity); | |
claimsIdentity.AddClaim(new Claim(SitefinityClaimTypes.ExternalUserEmail, email)); | |
var name = GetNameFromIdentity(claimsIdentity); | |
claimsIdentity.AddClaim(new Claim(SitefinityClaimTypes.ExternalUserName, name)); | |
var firstName = GetLastNameFromIdentity(claimsIdentity); | |
var lastName = GetFirstNameFromIdentity(claimsIdentity); | |
var role = GetRoleFromIdentity(claimsIdentity); | |
// Add custom cache for account provision use | |
Cache.Add(email + AuthConstant.FirstNameKey, firstName, CacheItemPriority.Normal, null, new AbsoluteTime(TimeSpan.FromMinutes(2))); | |
Cache.Add(email + AuthConstant.LastNameKey, lastName, CacheItemPriority.Normal, null, new AbsoluteTime(TimeSpan.FromMinutes(2))); | |
Cache.Add(email + AuthConstant.RoleKey, role, CacheItemPriority.Normal, null, new AbsoluteTime(TimeSpan.FromMinutes(2))); | |
}, | |
LogoutCommandResultCreated = commandResult => | |
{ | |
// Post logout URL | |
commandResult.Location = new Uri("/", UriKind.Relative); | |
} | |
}, | |
}; | |
authServicesOptions.IdentityProviders.Add(new IdentityProvider(new EntityId(config.GetParameter(AuthConstant.IdpEntityIdParameterName)), authServicesOptions.SPOptions) | |
{ | |
MetadataLocation = config.GetParameter(AuthConstant.IdpMetadataUrlParameterName), | |
LoadMetadata = true, | |
}); | |
app.UseSaml2Authentication(authServicesOptions); | |
}; | |
return additionalProviders; | |
} | |
private string GetNameFromIdentity(ClaimsIdentity claimsIdentity) | |
{ | |
string name = null; | |
var nameClaim = claimsIdentity.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Name); | |
if (nameClaim != null) | |
{ | |
name = nameClaim.Value; | |
} | |
else | |
{ | |
var firstName = GetFirstNameFromIdentity(claimsIdentity); | |
var lastName = GetLastNameFromIdentity(claimsIdentity); | |
name = firstName + lastName; | |
} | |
if (name.IsNullOrEmpty()) | |
{ | |
name = GetEmailFromIdentity(claimsIdentity); | |
} | |
return name; | |
} | |
private string GetFirstNameFromIdentity(ClaimsIdentity claimsIdentity) | |
{ | |
var firstName = ""; | |
var userFirstNameClaim = claimsIdentity.Claims.FirstOrDefault(x => x.Type == ClaimTypes.GivenName); | |
if (userFirstNameClaim != null) | |
{ | |
firstName = userFirstNameClaim.Value; | |
} | |
return firstName; | |
} | |
private string GetLastNameFromIdentity(ClaimsIdentity claimsIdentity) | |
{ | |
var lastName = ""; | |
var userLastNameClaim = claimsIdentity.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Surname); | |
if (userLastNameClaim != null) | |
{ | |
lastName = userLastNameClaim.Value; | |
} | |
return lastName; | |
} | |
private string GetEmailFromIdentity(ClaimsIdentity claimsIdentity) | |
{ | |
var email = ""; | |
var userEmailClaim = claimsIdentity.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Email); | |
if (userEmailClaim != null) | |
{ | |
email = userEmailClaim.Value; | |
} | |
else | |
{ | |
var jwtEmailClaim = claimsIdentity.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Email); | |
if (jwtEmailClaim != null) | |
{ | |
email = jwtEmailClaim.Value; | |
} | |
else | |
{ | |
throw new ArgumentException("Email claim not found"); | |
} | |
} | |
return email; | |
} | |
private string GetRoleFromIdentity(ClaimsIdentity claimsIdentity) | |
{ | |
var role = ""; | |
var userRoleClaim = claimsIdentity.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Role); | |
if (userRoleClaim != null) | |
{ | |
role = userRoleClaim.Value; | |
} | |
return role; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment