Josh
Josh

Reputation: 4448

Getting the wctx parameter that Azure's ACS page requires to passively authenticate

I am supporting a solution which acts as an IDP and STS in one. Think of it as a MVC app with simple authentication against locally stored profiles. I would like to put a link on one of my pages that, when clicked, builds a SAML payload and ships it through ACS and then on to a partner's site (which in turn uses WIF to read incoming SAML2 payloads from ACS). I don't want to show another login page (such as ACS's home realm discovery page) during the journey because by the time they are clicking my link they have already been authenticated. I just want to send claims to the destination Relying Party url and I want to pass through ACS on the way there.

ACS supports something close to this with "custom login pages". You can download an HTML page that you would presumably customize and host at an IDP and have users click through when heading to the Relying Party. The HTML file sources an ACS-hosted Javascript file (IdentityProviders.js) that provides a LoginUrl as one of the JSON parameters it sucks down. LoginUrl contains a wctx parameter (that looks to be encrypted or something) that I copy and then use like this:

private SignInRequestMessage GetSignInRequestMessage() {
    SignInRequestMessage aMessage = new SignInRequestMessage(new Uri("https://something.accesscontrol.windows.net/"), "http://accesscontrol.windows.net/");
    aMessage.Reply = "http://locohost:65447/Home/SAML";
    aMessage.Realm = "https://something.accesscontrol.windows.net/v2/wsfederation";
    aMessage.Context = THE_WCTX_PARAM_I_GRABBED; 
    return aMessage;
}

The end result is that my link click carries me all the way through to the landing page within the Relying Party (http://locohost:65447/Home/SAML in this case), passing through ACS which allows for claim mapping and filtering and signature and encryption support.

I notice that when I change the Return URL in the corresponding Relying Party the wctx value is changed just slightly. My guess is that it contains the realm and return urls, though I don't understand why it needs that because I can provide those data bits programmatically as seen above. My goal is to be able to build that wctx parameter programmatically without having to grab a magic string or make an HTTP call at runtime. Can anyone offer advice?

Edit: Here is an image that outlines the desired process. Accounts are stored at the partner, not in Azure Active Directory

ACS SSO Desired Process

And here is more pseudo code that shows how I'm driving the form post to ACS with the wctx parameter

public async Task<string> DoACSSAMLPost(List<Claim> aClaimsList, ClaimsPrincipal aPrincipal, string aTokenServiceUrl) {
    // SignInRequestMessage is what is sent to ACS (see code sample above)
    SignInRequestMessage aSignInRequestMessage = await GetSignInRequestMessage();
    // sign request with private key. Public key has been installed in ACS.
    X509SigningCredentials aSigningCredentials = new X509SigningCredentials(theSigningCertificate);
    // configuration allows the token service to sign request and identifies itself as the token service
    SecurityTokenServiceConfiguration aConfig = new SecurityTokenServiceConfiguration(aTokenServiceUrl, aSigningCredentials);
    CustomSecurityTokenService aSecurityTokenService = new CustomSecurityTokenService(aConfig, aClaimsList);
    // Message is generated by the System.IdentityModel plumbing
    SignInResponseMessage aResponseMessage = FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest(aSignInRequestMessage, aPrincipal, aSecurityTokenService);
    // and the form post HTML is returned
    return aResponseMessage.WriteFormPost();
}

I can grab this param from IdentityProvider.js and build this all on the fly, but I'd like to understand a) if my approach makes sense and is the 'proper' way to go about this and b) if there is a better way to get that wctx param (or if I can cache it locally if I don't change the Return URL in the Relying Party config in ACS

Upvotes: 4

Views: 1181

Answers (1)

vibronet
vibronet

Reputation: 7394

Not sure if I grok 100% the intent. Are you trying to skip the HRD, so the authentication goes straight to the IdP of choice? If that's the case, you can simply inject "?whr=issuername" in your request to ACS. You can even send it in the original request to the RP, and extract & pass-through it in the redirectingtoidentityprovider event. You should not need to mess with the wctx parameter as its goal is to maintain state across various redirects - but it does not look like that's the goal here. HTH V.

Upvotes: 2

Related Questions