Skip to content
This repository has been archived by the owner on Sep 18, 2021. It is now read-only.

Custom values to external provider #1318

Closed
monotore opened this issue May 6, 2015 · 13 comments
Closed

Custom values to external provider #1318

monotore opened this issue May 6, 2015 · 13 comments
Labels

Comments

@monotore
Copy link

monotore commented May 6, 2015

I want to pass custom values to some identity providers. They support this by use of AuthenticationProperties.Dictionary.

In my scenario, I want to select a specific provider (using acr_values idp:name_of_idp) and also pass the user id to the provider. This could be possible if IdentityServer transfered acr_values and maybe login_hint to the provider in AuthenticationProperties.Dictionary.

Do IdenityServer has any way of assigning custom AuthenticationProperties.Dictionary vaues?

@brockallen
Copy link
Member

You can always handle the notifications on the IdPs you've registered. Is that not sufficient?

@monotore
Copy link
Author

monotore commented May 6, 2015

But how do I get these values in the notification handler?
AuthenticationProperties is available in notification handlers, but this instance only contain a few values as far as I can tell from the source code:

var authProp = new Microsoft.Owin.Security.AuthenticationProperties
{
    RedirectUri = Url.Route(Constants.RouteNames.LoginExternalCallback, null)
};

Logger.Info("Triggering challenge for external identity provider");

// add the id to the dictionary so we can recall the cookie id on the callback
authProp.Dictionary.Add(Constants.Authentication.SigninId, signin);
authProp.Dictionary.Add(Constants.Authentication.KatanaAuthenticationType, provider);
context.Authentication.Challenge(authProp, provider);

@brockallen
Copy link
Member

You can pass them via the OWIN environment -- this is injectable via IOwinEnvironmentService in anything in IdSvr.

@monotore
Copy link
Author

monotore commented May 6, 2015

At what stage should I add them to the OWIN environment? I have looked at IUserService.PreAuthenticateAsync(SignInMessage message). But that method is called on another http request than the one that trigger the provider, and I how should I pass values from one request to another with OWIN environment?!

@brockallen
Copy link
Member

Well, you could perhaps do something from the user service in PreAuthN to capture those values from the SignInMessage, put them into the OWIN environment, and then in the notifications events on the idP middleware extract them from the OWIN environment.

@monotore
Copy link
Author

monotore commented May 6, 2015

I'm maybe missing something, but I can't see how this is possible. The OWIN environment lifetime is for each http request. The authentication challenge that triggers the provider is in a later request than PreAuthenticateAsync. Or am I wrong? How can I then use environmen to pass values?

@brockallen
Copy link
Member

In the request to the authentication controller if there's an IdP in the SignInMessage then we skip the login page and redirect to the selected Idp. That's all in one request. PreAuthN gets called in there, so that hook (I'm 99% sure) will work.

Try it, and if you can't get it working let me know.

@monotore
Copy link
Author

monotore commented May 6, 2015

It does not look like that to me. PreAuthenticateAsync is fired by a request to /login and handeled by AuthenticationController.Login(string signin = null). This method does a redirect:

if (signInMessage.IdP.IsPresent())
{
    Logger.InfoFormat("identity provider requested, redirecting to: {0}", signInMessage.IdP);
    return Redirect(context.GetExternalProviderLoginUrl(signInMessage.IdP, signin));
}

The redirect sends a http 302 to the browser, and a new http request is made to /external?provider=myprovider&signin=7ca7957618ae3ea893b8017bd9ce65b7 and handeled by AuthenticationController.LoginExternal(string signin, string provider). LoginExternal issues the authentication challenge that thrigger the selected IdP.

The environment from AuthenticationController.Login() is gone when the second request hits AuthenticationController.LoginExternal(). One solution can be to change LoginExternal to add data from the SignInMessage (LoginExternal got it from a cookie) to the AuthenticationProperties it sends to Authentication.Challenge when issuing the challenge.

@brockallen
Copy link
Member

Ah, darn it - you're right. Sorry.

What you could do then is use the GetSignInMessage extension method to get the SignInMessage in your IdP middleware. We just added that in 1.5 a couple of weeks ago.

@monotore
Copy link
Author

monotore commented May 6, 2015

Thanks. I think that may work.

It would be great if you can make SignInMessage properties available in the dictionary of AuthenticationProperties in the future.

@monotore monotore closed this as completed May 6, 2015
@monotore monotore reopened this May 7, 2015
@monotore
Copy link
Author

monotore commented May 7, 2015

GetSignInMessage extension method requires signin identifier as argument:

public static SignInMessage GetSignInMessage(this IDictionary<string, object> env, string id)

What is the prefered way to get this identifier?
I can get it direct from the request query string (OwinContext.Request.Query["signin"]), but then my code break if you change the query string in the future.

@brockallen
Copy link
Member

For now, you'll have to use that Query param. Perhaps the extension method should do that for you -- feel free to send a PR :)

@monotore
Copy link
Author

monotore commented May 8, 2015

I found that this value is in the AuthenticationProperties, and the key has been defined in a constant. My current soltuion is this extension to AuthenticationProperties:

    public static SignInMessage GetSignInMessage(this AuthenticationProperties properties, IDictionary<string, object> env)
    {
        if (env == null)
        {
            throw new ArgumentNullException("env");
        }

        string signinId = properties.Dictionary[Constants.Authentication.SigninId];
        return env.GetSignInMessage(signinId);
    }

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants