IdentityServer / IdentityServer3

OpenID Connect Provider and OAuth 2.0 Authorization Server Framework for ASP.NET 4.x/Katana
https://identityserver.github.io/Documentation/
Apache License 2.0
2.01k stars 764 forks source link

WS-Federation and CallbackPath in WsFederationAuthenticationOptions #1068

Closed protoforge closed 9 years ago

protoforge commented 9 years ago

The docs mention:

"For backwards compatibility reasons, the WS-Federation middleware listens to all incoming requests and inspects them for incoming token posts. This is not an issue if you only have one WS-Federation middleware configured, but if you have more than one, you need to set an explicit and unique CallbackPath property that matches the reply URL configuration on the IdP."

And MSDN says: "Computed from Wreply if not provided."

I have this use-case and I'm struggling to find the correct syntax. For two (or more) arbitrary ADFS systems, what's needed? I get a runtime error if it doesn't start with a leading slash, and POST errors with anything else.

var adfs_A = new WsFederationAuthenticationOptions
{
    AuthenticationType = "adfs_one",
    Caption = "ADFS (A)",
    SignInAsAuthenticationType = signInAsType,
    MetadataAddress = "https://server.domainA.example/federationmetadata/2007-06/federationmetadata.xml",        
    Wtrealm = "urn:client_a",
    //CallbackPath = new PathString("/?????"),
};
app.UseWsFederationAuthentication(adfs_A);

var adfs_B = new WsFederationAuthenticationOptions
{
    AuthenticationType = "adfs_two",
    Caption = "ADFS (B)",
    SignInAsAuthenticationType = signInAsType,
    MetadataAddress = "https://server.domainB.example/federationmetadata/2007-06/federationmetadata.xml",
    Wtrealm = "urn:client_b",
    //CallbackPath = new PathString("/?????"),
};
app.UseWsFederationAuthentication(adfs_B);  
leastprivilege commented 9 years ago

unfortunately it must be the full path (including vdirs IIRC).

protoforge commented 9 years ago

So if my current idsvr is deployed as the 'ID' application like this: https://idsvr.mydomain.org/ID (which totally works fine for a single ADFS server), would I need to somehow define separate (but identical) route mappings for the ID server, and then have each ADFS server use that new URI in its RP configuration?

var factory = new MyIdentityServerFactory();
// factory configuration....

var options = new IdentityServerOptions()
    {
        Factory = factory
    });

app.UseIdentityServer(options);

// stuff .......

var adfs_A = new WsFederationAuthenticationOptions
{
    AuthenticationType = "adfs_one",
    Caption = "ADFS (A)",
    SignInAsAuthenticationType = signInAsType,
    MetadataAddress = "https://server.domainA.example/federationmetadata/2007-06/federationmetadata.xml",        
    Wtrealm = "urn:client_a",
    CallbackPath = new PathString("/ID/adfs_one"),
};
app.UseWsFederationAuthentication(adfs_A);

var adfs_B = new WsFederationAuthenticationOptions
{
    AuthenticationType = "adfs_two",
    Caption = "ADFS (B)",
    SignInAsAuthenticationType = signInAsType,
    MetadataAddress = "https://server.domainB.example/federationmetadata/2007-06/federationmetadata.xml",
    Wtrealm = "urn:client_b",
    CallbackPath = new PathString("/ID/adfs_two"),
};
app.UseWsFederationAuthentication(adfs_B);  

Update: The extra path given in the callback appears to automatically be supported as a valid route for the ADFS server to post back to. This wasn't immediately obvious to me. As long as the path isn't already used, things appear to work OK.

leastprivilege commented 9 years ago

Why do you want multiple instance of idsrv?

Let's say idsrv is installed on:

https://idsrv.com

then adfs1 - would use a reply url of https://idsrv.com/adfs1 and callbackpath would be /adfs1

then adfs1 - would use a reply url of https://idsrv.com/adfs2 and callbackpath would be /adfs2

protoforge commented 9 years ago

Why do you want multiple instance of idsrv?

I don't!

then adfs1 - would use a reply url of https://idsrv.com/adfs1 and callbackpath would be /adfs1

I'll try again... My initial attempt at specifying something arbitrary here resulted in a POST error. I therefore assumed the url would need to be an instance of the actual idsvr site.

brockallen commented 9 years ago

You might want to setup a standalone sample app using the WS-Fed middleware to get used to configuring it (and the CallbackPath). That way you'll have more understanding setting up 2 of them with IdSvr.

protoforge commented 9 years ago

setup a standalone sample app using the WS-Fed middleware

Yes - I'll probably give that a try. Thank you.

It's definitely a challenge dealing with ADFS system(s). I'm also having to convince the customer to add another claim to ensure a Subject identifier (Name ID) is sent. They don't like doing anything that deviates from their 'standard' configuration.

brockallen commented 9 years ago

Well they should already be sending some unique value for the user. It doesn't have to be a sub claim but we do need to identify it.

-Brock

On Mar 13, 2015, at 3:50 PM, protoforge notifications@github.com wrote:

setup a standalone sample app using the WS-Fed middleware

Yes - I'll probably give that a try. Thank you.

It's definitely a challenge dealing with ADFS system(s). I'm also having to convince the customer to add another claim to ensure a Subject identifier (Name ID) is sent. They don't like doing anything that deviates from their 'standard' configuration.

— Reply to this email directly or view it on GitHub.

leastprivilege commented 9 years ago

By default ADFS only emits the authentication time and instant claim which is not very useful.

If emitting a NameId claim is too hard for them - you can still do some mapping in the WS-Fed SecurityTokenValidated notification before the claims arrive in idsrv. We need either NameId or sub.

leastprivilege commented 9 years ago

any update?

protoforge commented 9 years ago

I updated my code above. Things appear to be working OK now. As mentioned, the trick is to just enter something unique (and unused) in the callback paths.