Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing parameters to Azure Active Directory authentication

I have an ASP.Net MVC Application, Owin, and I'm using Azure Active Directory authentication as well.

I want to pass a parameter when the user is redirected to the Azure AD authentication page. So when the user signs in or signs up I want to pass ProjectId (int) as a parameter.

After the user signs in/up and is redirected to my Application I want to receive the ProjectId I passed as a parameter.

How can I achieve that?

edit: Adding code

// The ACR claim is used to indicate which policy was executed
public const string AcrClaimType = "http://schemas.microsoft.com/claims/authnclassreference";
public const string PolicyKey = "b2cpolicy";
private const string OidcMetadataSuffix = "/.well-known/openid-configuration";

public void ConfigureAuth(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions());

    OpenIdConnectAuthenticationOptions options = new OpenIdConnectAuthenticationOptions
    {
        // These are standard OpenID Connect parameters, with values pulled from web.config
        ClientId = ClientId,
        RedirectUri = RedirectUri,
        PostLogoutRedirectUri = RedirectUri,
        UseTokenLifetime = false,
        Notifications = new OpenIdConnectAuthenticationNotifications
        {
            AuthenticationFailed = AuthenticationFailed,
            RedirectToIdentityProvider = OnRedirectToIdentityProvider,
            SecurityTokenValidated = OnSecurityTokenValidated
        },
        Scope = "openid",
        ResponseType = "id_token",

        // The PolicyConfigurationManager takes care of getting the correct Azure AD authentication
        // endpoints from the OpenID Connect metadata endpoint.  It is included in the PolicyAuthHelpers folder.
        ConfigurationManager = new PolicyConfigurationManager(
            string.Format(CultureInfo.InvariantCulture, AadInstance, Tenant, "/v2.0", OidcMetadataSuffix),
            new[] { SignUpPolicyId, SignInPolicyId, ProfilePolicyId }),

        // This piece is optional - it is used for displaying the user's name in the navigation bar.
        TokenValidationParameters = new TokenValidationParameters
        {
            NameClaimType = "name"
        }
    };

    app.UseOpenIdConnectAuthentication(options);
}

private Task OnRedirectToIdentityProvider(
        RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
    if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
    {
        var currentPolicy =
            notification.OwinContext.Authentication.AuthenticationResponseRevoke.AuthenticationTypes
                .FirstOrDefault(x => x.StartsWith("b2c"));
        notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.Split('?')[0];
        notification.ProtocolMessage.Parameters.Add("p", currentPolicy);
    }
    else
    {
        **// The value right now for the state is sort of "hijacked" and assigned by Microsoft**
        //notification.ProtocolMessage.Parameters["state"] = "OpenIdConnect.AuthenticationProperties=sRt-teBcxsd239viWo...... ";

        var currentPolicy = notification.OwinContext.Authentication.AuthenticationResponseChallenge.Properties
            .Dictionary[PolicyKey];
        notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.Split('?')[0];
        notification.ProtocolMessage.Parameters.Add("p", currentPolicy);
    }

    return Task.FromResult(0);
}

private async Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
    await MyClass.CreatePrincipal(notification.AuthenticationTicket.Identity);
}

private Task AuthenticationFailed(
            AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
    notification.HandleResponse();
    notification.Response.Redirect("/Home/Error?message=" + notification.Exception.Message);
    return Task.FromResult(0);
}
like image 339
Bartho Bernsmann Avatar asked Jun 12 '16 05:06

Bartho Bernsmann


2 Answers

Similar to what Gaurav is suggesting, but adding a few special considerations. Basically, the state is used by the Owin middleware, so while you can inject your own stuff, you need to make sure you revert it back before the Owin middleware tries to use it otherwise you'll get auth errors.

This is effectively what I replied to a very similar question:

Custom parameter with Microsoft.Owin.Security.OpenIdConnect and AzureAD v 2.0 endpoint

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 static 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 static 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.

like image 172
Saca Avatar answered Oct 31 '22 08:10

Saca


Just add context.ProtocolMessage.SetParameter(<ParameterName>, <value>); in RedirectToIdentityProvider

Notifications = new OpenIdConnectAuthenticationNotifications()
            {
                RedirectToIdentityProvider = context =>
                    {
                        context.ProtocolMessage.SetParameter("prompt", "login");
                        return Task.FromResult(0);
                    },
                
            }
        };
like image 34
Ghanshyam Singh Avatar answered Oct 31 '22 07:10

Ghanshyam Singh