Custom parameter with Microsoft.Owin.Security.Open

2019-04-12 03:23发布

问题:

I am migrating my Azure AD secured application to the v2.0 endpoint.

I need to pass a custom parameter to the reply uri. With former Azure AD endpoint I did it by adding a usual query parameter to the reply url. e.g. https://myserver.com/myredirect_uri?mycustomparamerter=myvalue

Unfortunately, with endpoint 2.0 I received an error saying that the reply uri does not match the one registered. Of course my custom parameter value is dynamic and I cannot hardcode it.

I was looking to exploit the 'state' parameter described in OAUTH flow. However, I am using Microsoft.Owin.Security.OpenIdConnect and it looks the parameter is already set so I cannot exploit it. I am using an implementation of the flow that is based on MVC that looks like this sample.

Can you suggest a workaround so my server receive a custom parameter in the reply url that have been set on the flow start?

回答1:

Not sure if there's an official way to do what you're asking but one way you could technically inject and extract extra values through the auth flow is via OWIN's notifications.

In Startup.Auth.cs, when you setup the OpenIdConnectAuthenticationOptions you'd add the following:

app.UseOpenIdConnectAuthentication(
  new OpenIdConnectAuthenticationOptions
  {
    //...
    Notifications = new OpenIdConnectAuthenticationNotifications
    {
      RedirectToIdentityProvider = OnRedirectToIdentityProvider,
      MessageReceived = OnMessageReceived
    },
  });

And use RedirectToIdentityProvider to inject your parameter, something along the lines of:

private Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
  var stateQueryString = notification.ProtocolMessage.State.Split('=');
  var protectedState = stateQueryString[1];
  var state = notification.Options.StateDataFormat.Unprotect(protectedState);
  state.Dictionary.Add("mycustomparameter", "myvalue");
  notification.ProtocolMessage.State = stateQueryString[0] + "=" + notification.Options.StateDataFormat.Protect(state);
  return Task.FromResult(0);
}

And then use MessageReceived to extract it, like so:

private Task OnMessageReceived(MessageReceivedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
  string mycustomparameter;
  var protectedState = notification.ProtocolMessage.State.Split('=')[1];
  var state = notification.Options.StateDataFormat.Unprotect(protectedState);
  state.Dictionary.TryGetValue("mycustomparameter", out mycustomparameter);
  return Task.FromResult(0);
}

You'd obviously need to improve/harden this but this should get you going barring a better overall approach.