November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
Hi Santiago
Do you have code to change the Redirect URL before sending users to the Federation endpoint?
Look at this documentation page (it is for OpenID, but the concept is the same). Copy the method HandleMultiSiteReturnUrl
and use it in the RedirectToIdentityProvider
delegate method.
This will tell the Federation endpoint to send the user back to Episerver on the site the user attempted to visit (not default to the primary site).
Hi Stefan,
Thank you for your reply! Here is the code I'm using with WS-Federation, the sample you are pointed out is using OpenId and I don't know what is the alternative for WS-Federation
public class Startup
{
private static readonly Lazy<ConfigurationService> _configurationService =
new Lazy<ConfigurationService>(() => ServiceLocator.Current.GetInstance<ConfigurationService>());
const string _logoutUrl = "/util/logout.aspx";
public void Configuration(IAppBuilder app)
{
//Enable cookie authentication, used to store the claims between requests
app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
});
//Enable federated authentication
app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions()
{
//Trusted URL to federation server meta data
MetadataAddress = _configurationService.Value.GetAppSetting("SSO:MetadataAddress"),
//Value of Wtreal must *exactly* match what is configured in the federation server
Wtrealm = _configurationService.Value.GetAppSetting("SSO:WTRealm"),
Notifications = new WsFederationAuthenticationNotifications()
{
RedirectToIdentityProvider = 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();
}
//XHR requests cannot handle redirects to a login screen, return 401
if (ctx.OwinContext.Response.StatusCode == 401 && IsXhrRequest(ctx.OwinContext.Request))
{
ctx.HandleResponse();
}
return Task.FromResult(0);
},
SecurityTokenValidated = (ctx) =>
{
//Increases the timeout
ctx.AuthenticationTicket.Properties.ExpiresUtc = DateTime.UtcNow.AddDays(1);
ctx.AuthenticationTicket.Properties.IsPersistent = true;
//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;
}
if (ctx.AuthenticationTicket.Identity.HasClaim(Global.Claims.Group, Global.MembershipConstants.ADFSsAdmins))
{
ctx.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Role, Global.MembershipConstants.WebAdmins));
}
else if (ctx.AuthenticationTicket.Identity.HasClaim(Global.Claims.Group, Global.MembershipConstants.ADFSUsers))
{
ctx.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Role, Global.MembershipConstants.WebEditors));
}
if (!ctx.AuthenticationTicket.Identity.HasClaim(x => x.Type == ClaimTypes.Name))
{
var username = ctx.AuthenticationTicket.Identity.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier);
if (username != null)
{
ctx.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Name, username.Value));
}
}
ctx.OwinContext.Authentication.SignIn(ctx.AuthenticationTicket.Identity);
//Sync user and the roles to EPiServer in the background
ServiceLocator.Current.GetInstance<ISynchronizingUserService>().SynchronizeAsync(ctx.AuthenticationTicket.Identity);
return Task.FromResult(0);
}
}
});
//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);
});
});
//Tell antiforgery to use the name claim
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
}
private static bool IsXhrRequest(IOwinRequest request)
{
const string xRequestedWith = "X-Requested-With";
var query = request.Query;
if ((query != null) && (query[xRequestedWith] == "XMLHttpRequest"))
{
return true;
}
var headers = request.Headers;
return (headers != null) && (headers[xRequestedWith] == "XMLHttpRequest");
}
}
Could you provide some guidance on what should I do? Thanks
Hi Santiago
You can still add the HandleMultiSiteReturnUrl
method from the page I linked to. But instead of setting context.ProtocolMessage.RedirectUri
in the method, you can try setting context.ProtocolMessage.Wreply
property to the current URL.
Hi Stefan, thanks for your quick reply!
I added the Wreply:
private void HandleMultiSiteReturnUrl(
RedirectToIdentityProviderNotification<WsFederationMessage, WsFederationAuthenticationOptions> context)
{
// here you change the context.ProtocolMessage.RedirectUri to corresponding siteurl
// this is a sample of how to change redirecturi in the multi-tenant environment
if (context.ProtocolMessage.Wreply == null)
{
var currentUrl = HttpContext.Current.Request.Url;
context.ProtocolMessage.Wreply = new UriBuilder(
currentUrl.Scheme,
currentUrl.Host,
currentUrl.Port).ToString();
}
}
But the OwinResponse is throwing 401:
and I'm getting the same infinite loop until I get the error thrown by the provider:
The scenario is this one. I have a main site which is https://www.mainsite.edu. Then, the client added a new requirement where they want a microsite with a domain like this https://microsite.mainsite.edu. When I clicked on the home page of the new site, Episerver redirects to the other domain and I think the SSO tries to login against that new domain but it's not recognized since the only relaying party defined is www.mainsite.edu. I assume their IT team should add that new domain as a relaying party too? or how can we skip that validation since microsite.mainsite.edu is a "subdomain" of www.mainsite.edu?
It would be great if Epi doesn't redirect to another domain when you are editing another site.
I implemented SSO to get access to the CMS, it is using Federated security with WS-Federation protocol.
It was working fine until a new client requirement came: they need a new microsite.
What I did, on my local, is to create a new page under the root item and set it as the home page for the new site.
When I try to edit the new home page, it tries to redirect to another hostname but it seems it’s conflicting with the wtrealm defined and it provokes an infinite loop.
Is there a way we could edit the new site but stay in the same hostname (my local in this case) and avoid those redirects?
Here is a recording of what’s happening: https://share.getcloudapp.com/12uKRZxD
Please, if you can help me and provide some guidance will be much appreciated.
Thanks in advance.