Hi Le
As you wrote, when setting the Wtrealm
property at startup, it is not in the context of any request. So it can only be set to a default value.
But you could try implementing a delegate method for the Notifications.
RedirectToIdentityProvider
property. That will be called when the middleware is just about to redirect. So there you could try getting the domain name of the current request and then set the Wtrealm property of that specific redirect action.
Hi Stefan Holm Olsen,
Thank for your reply
Unfortunately, I tried but it didn't work and also throw an exception from adfs, i think MetadataAddress and Wtrealm have to set earlier than method Notifications
Now i just want adfs redirect correct the domain when user login from
for example:
- user access abc.com.sg and click login -> redirect to adfs -> enter username and pw -> adfs redicet back to abc.com.sg
- user access abc.com.vn and click login -> redirect to adfs -> enter username and pw -> adfs redicet back to abc.com.vn
Do you have any suggestion?
public class Startup
{
const string LogoutUrl = "/util/logout.aspx";
public void Configuration(IAppBuilder app)
{
// Add CMS integration for ASP.NET Identity
app.AddCmsAspNetIdentity<SiteUser>();
//app.AddCmsAspNetIdentity<SiteUser>(new ApplicationOptions()
//{
// ConnectionStringName = _connectionStringHandler.Commerce.Name
//});
//federated authentication
app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
});
// au
app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions()
{
//URL to federation server meta data
//AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType,
MetadataAddress = ConfigurationManager.AppSettings["MetadataAddress"],
//Value of Wtrealm must *exactly* match what is configured in the federation server
Wtrealm = ConfigurationManager.AppSettings["AdfsWtRealm"],
UseTokenLifetime = false,
Notifications = new WsFederationAuthenticationNotifications()
{
RedirectToIdentityProvider = (ctx) =>
{
HandleMultiSitereturnUrl(ctx);
//To avoid a redirect loop to the federation server send 403 when user is authenticated but does not have access
if (ctx.OwinContext.Response.StatusCode == 401 && ctx.OwinContext.Authentication.User.Identity.IsAuthenticated)
{
ctx.OwinContext.Response.StatusCode = 403;
ctx.HandleResponse();
}
return Task.FromResult(0);
},
SecurityTokenValidated = (ctx) =>
{
//Ignore scheme/host name in redirect Uri to make sure a redirect to HTTPS does not redirect back to HTTP
var redirectUri = new Uri(ctx.AuthenticationTicket.Properties.RedirectUri, UriKind.RelativeOrAbsolute);
if (redirectUri.IsAbsoluteUri)
{
ctx.AuthenticationTicket.Properties.RedirectUri = redirectUri.PathAndQuery;
}
//Sync user and the roles to EPiServer in the background
ServiceLocator.Current.GetInstance<ISynchronizingUserService>().SynchronizeAsync(ctx.AuthenticationTicket.Identity);
return Task.FromResult(0);
}
},
});
// local Episerver authentication
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager<ApplicationUser>, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => manager.GenerateUserIdentityAsync(user))
}
});
//Add stage marker to make sure WsFederation runs on Authenticate (before URL Authorization and virtual roles)
app.UseStageMarker(PipelineStage.Authenticate);
//Remap logout to a federated logout
app.Map(LogoutUrl, map =>
{
map.Run(ctx =>
{
ctx.Authentication.SignOut();
return Task.FromResult(0);
});
});
app.Use((context, task) =>
{
if (context.Request.Uri.PathAndQuery.Contains("remote.jpg.ashx"))
return task.Invoke();
var customHeaders = ServiceLocator.Current.GetInstance<SiteSettingsHandler>().SiteSettings
.SecurityHeaders;
if (customHeaders == null || !customHeaders.Any())
return task.Invoke();
foreach (var securityHeader in customHeaders)
{
if(!context.Response.Headers.ContainsKey((securityHeader.Name)))
context.Response.Headers.Add(securityHeader.Name, new[] { securityHeader.Value});
}
return task.Invoke();
});
//Tell antiforgery to use the name claim
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
}
private void HandleMultiSitereturnUrl(
RedirectToIdentityProviderNotification<Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage,
WsFederationAuthenticationOptions> context)
{
context.Options.Wtrealm = "https://" + HttpContext.Current.Request.Url.Host;
}
}
Regards,
Thang Le
Hi Stefan,
After tried some solution. I have solved OWIN for multiple sites by setting the Wreply property to the actual site URL before redirecting to ADFS.
I also have to specify all sites as Endpoints in the ADFS Relying Party Trust configuration for the installation.
This way we can have only one IIS site for multiple EPiServer sites using ADFS.
All sites will use the same Relying Party Trust definition in ADFS som the same set of claims will be issued for all sites.
private void HandleMultiSitereturnUrl(
RedirectToIdentityProviderNotification<Microsoft.IdentityModel.Protocols.WsFederation.WsFederationMessage,
WsFederationAuthenticationOptions> context)
{
context.ProtocolMessage.Wreply = SiteDefinition.Current.SiteUrl.ToString().TrimEnd('/');
}
Regards,
Thang Le
Hi,
My webapp host on DXC as mutiple sites and intergrated with ADFS.
I want to set Wtrealm property based on domain. But in startup it's init too early to catch domain name. So i can't handle return uri based on multisite
For examle:
if user access domain
abc.com.sg then Wtrealm = abc.com.sg
abc.com.vn then Wtrealm = abc.com.vn
Code example
Regards,
Thang Le