Setting up EPIServer authentication with Azure AD SSO

Vote:
 

Currently the EPI server is using ADFS for SSO

I can the see the following Claim Role in ADFS setup which basically map the AD Security Group to the EPI WEB Group for authentication

I just wonder if you have any guide/instruction of how to set up the EPI Applications in Azure AD for SSO? Specifically how to configure the role mapping above in Azure AD?

#246850
Jan 14, 2021 22:59
Vote:
 

Had similar question and landed here looking for an answer. It seems the documentation misses the Azure AD side of the world such as setting up roles, how sign up works when external identity provider is used (in this case Azure Ad). Any leads on that is much appreciated

#247872
Jan 29, 2021 22:38
Vote:
 

EDIT:

To clarify, we did all the role management within the epi product, not with AAD groups.  Within our organization it was easier for the business to change roles for the users right within the product as opposed to teaching them role management in AAD, or to have Service Desk handle that.

---------------------------------------

We used this project from Brad McDavid to acheive this.  We needed to tweak a little bit though.

IdentityCollection/src/bmcdavid.Episerver.SynchronizedProviderExtensions at master · bmcdavid/IdentityCollection · GitHub

There are nuget packages for this too:

bmcdavid.Episerver.SynchronizedProviderExtensions

You'll have to override some of the DI settings that the package sets up.  See this github response for what to do:

Trouble getting project working · Issue #3 · bmcdavid/IdentityCollection · GitHub

This library doesn't handle adding new users, so we had to build that too.  Let me know if you need a hand with that.  I'm contemplating creating a github project with a variation of the code we created.  It can't be exactly the same as it has my organization's name all over it.  

I created an extension method to be called in the startup.cs for easy setup as well.  This is a rough idea of where to start.  I'll have to try to flesh this out a bit with more time.

		public static IAppBuilder SetupSickKidsAuthProvider(this IAppBuilder app)
		{
			app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

			app.UseCookieAuthentication(new CookieAuthenticationOptions(){
				ExpireTimeSpan = new TimeSpan(4,0,0),
				SlidingExpiration = true
			});

			var clientId = ConfigurationManager.AppSettings["AzureAD:ClientId"];
			var tenant = ConfigurationManager.AppSettings["AzureAD:Tenant"];
			var redirectUri = ConfigurationManager.AppSettings["AzureAD:RedirectUri"];

			//This should be something related to the current site in th event of multi-site            
			string currentDomain = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);
			string postLogoutRedirectUri = currentDomain + ConfigurationManager.AppSettings["AzureAD:PostLogoutRedirectUri"];


			OpenIdConnectAuthenticationOptions authNotifications = new OpenIdConnectAuthenticationOptions
			{
				ClientId = clientId,
				Authority = tenant,
				PostLogoutRedirectUri = postLogoutRedirectUri,

				UseTokenLifetime = false, //Added this to combat the Episerver timeout issue.


				TokenValidationParameters = new TokenValidationParameters
				{
					ValidateIssuer = false,
					RoleClaimType = ClaimTypes.Role
				},

				Notifications = new OpenIdConnectAuthenticationNotifications
				{
					RedirectToIdentityProvider = context =>
					{
						context.ProtocolMessage.RedirectUri = context.Request.Uri.GetLeftPart(UriPartial.Authority) + redirectUri;


						if (context.OwinContext.Response.StatusCode == 401 && context.OwinContext.Authentication.User.Identity.IsAuthenticated)
						{
							context.OwinContext.Response.StatusCode = 403;
							context.HandleResponse();
						}

						return Task.FromResult(0);
					},
					AuthenticationFailed = context =>
					{
						context.HandleResponse();
						context.Response.Redirect("/?Error=" + context.Exception.Message);
					
						return Task.FromResult(0);
					},
					SecurityTokenValidated = async (ctx) =>
					{
						var redirectLoc = new Uri(ctx.AuthenticationTicket.Properties.RedirectUri, UriKind.RelativeOrAbsolute);

						if (redirectLoc.IsAbsoluteUri)
						{
							ctx.AuthenticationTicket.Properties.RedirectUri = redirectLoc.PathAndQuery;
						}

						//If the user doesn't have roles, don't bother adding them to the DB

						var extendedRP = ServiceLocator.Current.GetInstance<UIRoleProvider>();
						if (extendedRP != null && extendedRP.GetRolesForUser(ctx.AuthenticationTicket.Identity.Name).Count() > 0)
						{
							// Sync user and the roles to EPiServer
							var synchUserService = ServiceLocator.Current.GetInstance<ISynchronizingUserService>();
							List<string> claimList = new List<string>();
							claimList.Add(ClaimTypes.Email);
							claimList.Add(ClaimTypes.Name);

							await synchUserService.SynchronizeAsync(ctx.AuthenticationTicket.Identity, claimList);

							// Set users login date and manually assigned roles
							var extendedUserTools = ServiceLocator.Current.GetInstance<IExtendedUserTools>();
							await extendedUserTools.SetExtendedRolesAsync(ctx.AuthenticationTicket.Identity, DateTime.UtcNow);

							// Sets visitor group roles as assigned claim roles
							await extendedUserTools.AddVisitorGroupRolesAsClaimsAsync(ctx.AuthenticationTicket.Identity, new HttpContextWrapper(HttpContext.Current));
						}
					}
				}
			};

			authNotifications.Notifications.SecurityTokenReceived = (token) =>
			{
				Console.WriteLine(token);
				return Task.FromResult(0);
			};

			app.UseOpenIdConnectAuthentication(authNotifications);

			app.UseStageMarker(PipelineStage.Authenticate);

			return app;
		}
#255634
Edited, May 27, 2021 13:05
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.