Closed Tratcher closed 6 years ago
Good catch. Open a new issue for the events class please.
@lzandman There doesnt appear to be a good event hook for wsignoutcleanup1.0. The best place for this is probably custom middleware till its implemented in the WsFederationHandler itself.
Heres a quick example.. I did not test it as im using a custom wsfederationhandler (Till preview 2 comes out) and have it directly in there instead.
app.Use((context, next) =>
{
var request = context.Request;
// could look for a specific path as well...
if (request.Query.TryGetValue("wa", out var wa) && wa == "wsignoutcleanup1.0")
{
// Your signin scheme probably cookies
request.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Task.CompletedTask;
}
return next();
});
This would need to be before app.UseAuthentication();
@Zoxive Thanks. It seems to work.
@Tratcher I've opened an issue for the WsFederationEvents class: https://github.com/aspnet/Security/issues/1520
For a different scenario I had to disable the automatic redirect to ADFS signin. I did this by handling the RedirectToIdentityProvider event and calling HandleResponse(). It now returns a 401 status. The calling client then acts on that 401 by calling a different controller action and this controller action has to do the actual redirection to ADFS. For this it has to determine the full ADFS URL. In our legacy app I call FederatedAuthentication.WSFederationAuthenticationModule.CreateSignInRequest(). What would be the equivalent of that in AspnetCore?
@lzandman there is no equivalent, and I don't expect that flow to work with the current implementation. At a minimum you'd be missing the state and correlation cookie. See AllowUnsolicitedLogins above.
Are you trying to use this for an API endpoint / SPA application?
@Tratcher Yes. We have an Angular client app that calls Web API endpoints. When it hasn't yet been authenticated, the endpoints will redirect to ADFS. We don't want that. We want to handle login from the Angular client itself. So the endpoints should return a 401, on which the client can act and handle the login. For this we have a separate login controller and in this controller we need to determine the ADFS sign-in URL (the URL that the initial endpoint call would have sent us to, if we hadn't disabled its automatic RedirectToIdentityProvider).
WsFed is not intended for direct use with WebApis. Look up JwtBearer + Identity Server samples.
@Tratcher I know. But we have a working app using regular .Net. We're first trying a direct port of it to AspNetCore. Exploring other, more relevant/future-proof solutions later.
Then this new handler won't help you much as you've already implemented most of it as a controller. To get the APIs you need you need to go down one layer to IdentityModel. Look and the handler implementation and see what it's calling.
My understanding from the thread above is that MetadataAddress parsing newer ADFS metadata xml is broken until some other libraries come in sync. I was able to get this working by doing my own parsing, and thought I'd share a gist based on that code and a few notes for others having issues with this:
So auth is working (using a nightly build), when I hit my site directly. We have a portal, using the same WSFed endpoint, that loads my site in an IFRAME. Using Fiddler, I can see that our STS sees I'm signed in (to the portal) and the IFRAME redirects back to my site
/signin-wsfed but then in my site's logfiles I can see the attached error. error.txt
I've disabled token validation as much as I know how:
.AddWsFederation(options => { options.Wtrealm = Configuration["Authentication:WSFederation:Realm"]; options.MetadataAddress = Configuration["Authentication:WSFederation:Metadata"]; options.RequireHttpsMetadata = false; options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = false, ValidateAudience = false, ValidateIssuerSigningKey = false }; })
Strikes me as odd that Fiddler says the request is made over HTTPS but the logfile says HTTP (I've changed the URL in the attachment, but just the hostname part). I'm really not sure what's going on here. Please can someone offer some thoughts?
Can you share the fiddler trace?
Working on getting the Fiddler trace - the behaviour I described earlier is inconsistent. I've attached my ConfigureServices method's code ConfigureServices.txt
The code drops into the OnRemoteFailure event and the exception I'm getting is SecurityTokenException: No token validator was found for the given token.
I appreciate your help @Tratcher!
Update: 2.0.0-preview2 is now available and includes several fixes for reported issues. https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.WsFederation/2.0.0-preview2
We anticipate this will be the last prerelease, please try it and let us know if everything is working as expected. If all goes well we'll release the final build in a few weeks.
I'm able to confirm this update fixes the issue I had parsing metadata xml. It also removed the need to set o.TokenValidationParameters.NameClaimType and o.TokenValidationParameters.RoleClaimType
Hi everyone! Could someone post a full example of using this lib with sample .net core 2.0 app with ws-fed authorization?
There's minimal sample in the branch: https://github.com/aspnet/Security/blob/rel/2.0.0-ws-preview2/samples/WsFedSample/Startup.cs
From the application's perspective this provider works the same way as OpenIdConnect or Facebook. You can use it with either the "Work or School Accounts" or "Individual User Accounts" templates.
Running into an issue parsing Saml tokens with empty AttributeValue
nodes using preview 2.
Filed an issue over at https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/847
Thanks Chris.
I was able to get the WSFedSample working. We will continue to work through this implementation and report any issues we run into.
Are we still on track to have the final release out in the next few weeks?
Yes, especially if we get more positive feedback.
I am using preview2 and I followed @Zoxive sample. I am able to set the configuration correctly and am able to get the idp server's login page. But after authentication and redirect from idp to my localhost, it throws this error: Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10503: Signature validation failed. (full message attached) error.txt
update: Originally I got this error: 'Microsoft.IdentityModel.Xml.XmlValidationException: IDX30207: SignatureMethod is not supported: 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'. rsa-sha1 not supported error.txt then I changed the ID server to use sha2, which resulted in the other error about validation failure.
@brentschmaltz can you take a look?
I am also using preview2, and have followed the preceding discussion. Many of your comments were helpful, especially @lzandman 's. But I'm still having an infinite loop redirect issue and want to make sure I've configured things correctly on my side.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddWsFederation(options =>
{
options.Wtrealm = "http://myapp.azurewebsites.net/";
options.MetadataAddress = "https://myidp.com/FederationMetadata/2007-06/FederationMetadata.xml";
options.Wreply = "https://localhost:44313/signin-wsfed";
})
.AddCookie();
services.AddMvc();
}
Request/Response loop
Request
GET https://localhost:44313/
Response
302
location: https://myidp.com/?wtrealm=http%3A%2F%2Fmyapp.azurewebsites.net%2F&wa=wsignin1.0&wreply=https%3A%2F%2Flocalhost%3A44313%2Fsignin-wsfed&wctx=CfDJ8AefLzqrkelOjmQtHNwHJJv2eB7jSuMoASukKZtJ-Kf9PwPh0g7jXmdfpct3pnLqJi9iYtNRHj937py-g5eEkI2_V6qv1xhSAGdTan5MNCw8zHUt0Kgqcc4rWd3kNzi8BbJenl71MHfG11AztMeAh4fYhQrOYPlk69cPFFk7QCmUZVuzUbRjjXHusK7voLAL7IQaLOy6G9-c-pS--rSZkmM5dRQkxcwYa6m4PqK7tTS9
set-cookie :.AspNetCore.Correlation.WsFederation.rhQwjeG1hWLCa9TsldhzAywHVEdk2-WQz61zESZ87wc=N; expires=Mon, 11 Dec 2017 14:44:20 GMT; path=/signin-wsfed; secure; httponly
Request
GET https://myidp.com/?wtrealm=http%3A%2F%2Fmyapp.azurewebsites.net%2F&wa=wsignin1.0&wreply=https%3A%2F%2Flocalhost%3A44313%2Fsignin-wsfed&wctx=CfDJ8AefLzqrkelOjmQtHNwHJJv2eB7jSuMoASukKZtJ-Kf9PwPh0g7jXmdfpct3pnLqJi9iYtNRHj937py-g5eEkI2_V6qv1xhSAGdTan5MNCw8zHUt0Kgqcc4rWd3kNzi8BbJenl71MHfG11AztMeAh4fYhQrOYPlk69cPFFk7QCmUZVuzUbRjjXHusK7voLAL7IQaLOy6G9-c-pS--rSZkmM5dRQkxcwYa6m4PqK7tTS9
Response
200
Cache-Control: no-cache, no-store
Content-Type: text/html; charset=utf-8
Set-Cookie: bt=; domain=myidp.com; expires=Tue, 12-Oct-1999 00:00:00 GMT; path=/; secure; HttpOnly
Set-Cookie: qa_IMSStsSiteRPCookie=My Sandbox App: http://myapp.azurewebsites.net=pvuy%2bpCDeZ%2flLWsPsrhIBe88tsNmzA9MsYFKLPEOtmi05NwPZotU0w%3d%3d; domain=myidp.com; path=/
Request
POST https://localhost:44313/signin-wsfed
cookie: .AspNetCore.Correlation.WsFederation.rhQwjeG1hWLCa9TsldhzAywHVEdk2-WQz61zESZ87wc=N
origin: https://myidp.com
referer: https://myidp.com/?wtrealm=http%3A%2F%2Fmyapp.azurewebsites.net%2F&wa=wsignin1.0&wreply=https%3A%2F%2Flocalhost%3A44313%2Fsignin-wsfed&wctx=CfDJ8AefLzqrkelOjmQtHNwHJJv2eB7jSuMoASukKZtJ-Kf9PwPh0g7jXmdfpct3pnLqJi9iYtNRHj937py-g5eEkI2_V6qv1xhSAGdTan5MNCw8zHUt0Kgqcc4rWd3kNzi8BbJenl71MHfG11AztMeAh4fYhQrOYPlk69cPFFk7QCmUZVuzUbRjjXHusK7voLAL7IQaLOy6G9-c-pS--rSZkmM5dRQkxcwYa6m4PqK7tTS9
Response
302
location: https://myidp.com/?wtrealm=http%3A%2F%2Fmyapp.azurewebsites.net%2F&wa=wsignin1.0&wreply=https%3A%2F%2Flocalhost%3A44313%2Fsignin-wsfed&wctx=CfDJ8AefLzqrkelOjmQtHNwHJJuzaseK_4GJuFNDu2FWTCHJoIsVxj8mnEUYkhP5TZoLqqlCsfn-g7TCLerk0tBEkyDhaeagXBMudoTVcQvmQKT6BQav8jNtBSj4kJkBGyty5iIyhyoEjw9FNJitXrknSu4GXG8rHWXiy0YSJKzgu2eP-aeGIZqFSDWJvyjRWEJQQadTSRbpvAnvosnVKeKRHNYCAtiUr6CrPA294kBL4r-YwOyU2i-iowTeR6rywYv0ZA
set-cookie: .AspNetCore.Correlation.WsFederation.QQiApF7s-8b2A79yT6L4CdRKiUQXajmS12-LcOAY8Dk=N; expires=Mon, 11 Dec 2017 14:44:21 GMT; path=/signin-wsfed; secure; httponly
The first and last requests have the same basic response, though I was expecting the last response to close the authentication loop and redirect me back to https://localhost:44313/
. But instead, this cycle repeats indefinitely. The second response in the cycle always returns a different cookie name with the same value, so eventually there are hundreds of aspnet cookies being sent in the third request.
Does anything stick out as wrong on my side?
Thanks.
@itslittlejohn what do you have in Startup.Configure? You may be missing UseAuthentication, or it may be in the wrong order.
Note you shouldn't need to set Wreply.
That was it! I positioned app.UseAuthentication();
to the top and it's working. Thanks!
One follow up question. Say you want to access the saml token from an MVC action method once the user has been authenticated? I've been looking for a way to do that, but
(User.Identity as ClaimsIdentity).BootstrapContext
is returning null
.
@brentschmaltz are you setting the BootstrapContext for WsFed?
No, I'm not. Now that I think about it, in our old ASP.NET WebForms app we're migrating from, we are setting <identityConfiguration saveBootstrapContext="true">
in the web.config. Is this even the right approach for .net core? Essentially we would use the bootstrap context to get the Token
string in order to make some REST calls.
UPDATE
I found this link which caused me to realize I wasn't saving the token. But setting this causes 5 cookies to be set and I get 400. The size of the request headers is too long.
This reminded me that we've had SessionToken.IsReferenceMode = true
set, but I can't find anything like this in the wsfed module.
So assuming this is the right approach, is there something like IsReferenceMode = true
in this module?
UPDATE 2
I discovered that it is possible to implement your own "reference mode" by setting options.SessionStore
inside the AddCookie
callback. See this for what I followed.
Hi, I have been monitoring this issue for a while and am waiting for the final release. But as of the new preview 2 version, I tend to give it a try.
My questions are:
Is this used in ASP.Net Core 2.0.0 API clients and in the IdentityServer4?
Or is this only used in the client code?
I am interested into integrating that into IdentityServer4 running in a Docker image on .Net Core 2.
And are there samples for the integration into IdentityServer4?
Thanks for any help, Lothar
@lollisoft I am currently working on what you describe. Using it as an identity provider you consume it is not that hard if you find out how to configure it. You can get to a pretty good solution if you do it like I described in this StackOverFlow-Post - use the OnTicketReceived-EventHandler from the question together with the code in the response and you are good to go. Thanks to @leastprivilege for helping me out there. But be aware that I tried it with the MVC-example and not with an API client.
For providing a WSFederation-server you have to build against the .Net-Framework 4.6.1 and can use this example as starting point. Regarding to my issue there this WSFederation-preview-release does not help with getting it to full .Net Core, although I had a quick look at the new Identity-stuff over here and it might be possible to use it as there are also methods like "WriteMetaData", but it's quite different and I had too many knowledge-gaps to port it to pure .Net Core. There are also still quite some open issues there.
Why do I need the full framework for a WSFederation-server?
I have read that there are two components (XmlEncrypt and XmlDSig) missing in .Net core. (https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/500)
Why is that so complicated to provide equivalent code for these missing functionalities?
In the above topic, I read that it is blocked because they want to also make performance improvements. They also write, one could take the code into .Net core at their own to get it working without API changes and performance improvements.
Is anyone doing this and like to share?
@lollisoft this is not suitable for WebApi clients, it's for interactive clients similar to the OpenIdConnect and Facebook providers. It should be interchangeable with those types of providers in IdentityServer4 samples.
@Tratcher I don't speak about WebApi clients that run on the client machines. I meant WebApi's that use ws federation as clients, if they came from a ws federated scenario (like login from sharepoint). But I may have an understanding issue about all the auth and federation stuff. I think, the ws fed way is only for applications that do not have OAuth capabilities, such as Sharepoint.
I want to be able to support ws fed within .Net core and like to integrade a sharepoint application into the sample I like to create for my project.
But nevertheless I probably have to read a good book about identity, oauth flows and ws fed scenarios to understand the whole picture.
Currently I am running a net tcp binding (WCF) based Identity provider, but that lacks of the REST capabilities and oauth. I plan to attempt replacing that with IdentityServer4, but then it needs a ws federation capability. The overall plan is also to move toward .Net core at all.
All is still a bit vague and yet only an idea I try to follow :-)
@lollisoft I have an fork where I try to port the example of WsFederation Implementation from @leastprivilege to aspnet core 2.0. (see here https://github.com/616b2f/IdentityServer4.WsFederation).
It's not ready but it's a starting point, any help wellcome.
I'll try to help where I can. I just have setup a new Windows 10 Pro machine in a VM, well licensed. Until an official release is made, I'll use a full framework, but test out aspnet core 2.0 in paralell.
First I have a look at your code and I'll give it a first test to compile and get it running here.
We've done a bit of testing against 2.0.0-preview2
and things seemed to be OK for us. Does anyone have any idea when we might be able to expect the final version released?
we are also eagerly waiting for the final release. we are working on a POC, we are planning to switch to different SSO provider if the final release is not going to be available soon. The Ws federation authentication/authorization feature works very well in asp.net core. it would be great if you release the final version soon. thank you
We're almost ready but you all keep sending us feedback 😄 . The new signout cleanup feature isn't working with ADFS so I'm re-designing that (https://github.com/aspnet/Security/issues/1581). The IdentityModel folks have also gotten a lot of feedback and need another week or two to address it.
Cool, thanks for the update! We'll keep our eyes peeled for the announcement.
Keep up the good work 👍
Hi, I managed to get this working and users can log in with signed secure tokens. However an encrypted and signed tokens does not work. I can see you do not provide a SecurityTokenHandler for encrypted tokens. Is this something you plan to support?
Encrypted tokens aren't supported in this release. See https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/734.
Hello @Tratcher ! What about encrypted saml1 tokens? Will be they supported?
@Veikedo not yet. You already found the thread in https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/734.
I'm having an issue getting this to work in my environment. The code appears to be making contact to the IdP and it is returning the assertion URL with the SAML token. However, the FedAuth cookie is not getting created upon the assertion call. I end up in what appears to be an endless redirect loop.
Any ideas what would be causing the cookie to not be created?
My Startup.cs can be viewed here: https://gist.github.com/ryanbuening/d3f8b151b168c4729b518b2157737318.
Can you share a Fiddler trace and application logs?
@Tratcher sorry for annoying, but do I understand correctly that enabling saml assertion encryption is overkill?
Can you share a Fiddler trace and application logs?
@Tratcher I sent an email to Tratcher at outlook.com. Thanks.
hi, I am trying to get this added to my existing Core 2.0 + Angular 5 CLI app. I am using the preview template for it. Issue is even after adding the standard configuration, redirect doesn't happen for authentication ! I don't know If I need to add any redirect from Angular for it. But once my app has triggered, I don't think I can add a callback to login then ! Any suggestions on this ? Thanks.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddWsFederation(options =>
{
options.Wtrealm = "[AppID URI from Azure]";
options.MetadataAddress = "[Federation Metadata XML address from Azure]";
})
.AddCookie();
services.AddMvc();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
@AnshulKhandelwal02 this is because your Angular (JavascriptServices) middleware lives outside of MVC pipeline. You need to use smth like this
internal class SpaAuthMiddleware
{
private readonly RequestDelegate _next;
public SpaAuthMiddleware(RequestDelegate next)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
}
public async Task Invoke(HttpContext context, IAuthorizationService authorizationService)
{
if (!context.User.Identity.IsAuthenticated)
{
await context.ChallengeAsync().ConfigureAwait(false);
}
else
{
await _next(context).ConfigureAwait(false);
}
}
}
public static class SpaAuthAppBuilderExtensions
{
public static IApplicationBuilder UseSpaAuthentication(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<SpaAuthMiddleware>();
}
}
Your Startup.Configure method should be smth like this
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseMiddleware<WsFederationAuthCleanupMiddleware>();
app.UseAuthentication();
app.UseSpaAuthentication();
app.UseSpaStaticFiles();
app.UseMvcWithDefaultRoute();
app.UseSpa(spa => {
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
// Run SPA separately => to start Angular server run 'npm start' inside 'ClientApp' folder
// see also https://github.com/aspnet/JavaScriptServices/issues/1288#issuecomment-346003334
spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
// Run asp.net and spa together. Just hit F5
// spa.UseAngularCliServer("start");
}
});
}
WsFederation preview support is now available for ASP.NET Core 2.0.0. The Microsoft.AspNetCore.Authentication.WsFederation 2.0.0-preview1 package is available at https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.WsFederation/. This is a standalone preview that targets netstandard2.0 and should work with existing ASP.NET Core 2.0.0 applications (.NET Core 2.0 or .NET 4.6.1). A non-preview ASP.NET Core 2.0.0 compatible package will follow once we’ve addressed your feedback.
The code is available at https://github.com/aspnet/security/tree/rel/2.0.0-ws-preview1 and issues can be filed at https://github.com/aspnet/security/issues. Please give us a 👍 from the reactions menu on this post if you have successfully used this component and are ready for the final release.
This component is a port from Microsoft.Owin.Security.WsFederation and uses many of the same mechanics. It has also been updated to integrate with ASP.NET Core 2.0’s authentication model. See the samples below.
Aside from updating the usage pattern to match ASP.NET Core, there are also some functional changes to be aware of. A. This component no longer checks every form post request for sign-in messages by default. Sign-in callbacks are restricted to the "/signin-wsfed" path by default. The CallbackPath can be changed to the application root “/” used by some auth providers if you also enable SkipUnrecognizedRequests to allow sharing that request path with other components. B. This component no longer allows unsolicited logins by default. That WsFederation protocol feature is susceptible to XSRF attacks. See the AllowUnsolicitedLogins option to opt into that feature if your application requires it.
Samples:
For applications only using WsFederation (similar to using OpenIdConnect):
For applications using WsFederation with Identity: