-->

How do I send a value through AD-B2C using openid-

2019-09-15 06:20发布

问题:

I am currently developing an application using AD-B2C as my identity provider. This is integrated into the solution using their guidelines at AD B2C graph, which uses openid-connect (to the best of my understanding at least).

I need to use a form of email activation (outside of their register policy) and as such I need to be able to pass a value from the URL in the email, through the sign-up process at B2C and back to the redirection URL.

I read somewhere that a parameter called "state" can be used for this:

State: A value included in the request that will also be returned in the token response. It can be a string of any content that you want. A randomly generated unique value is typically used for preventing cross-site request forgery attacks. The state is also used to encode information about the user's state in the app before the authentication request occurred, such as the page they were on or the policy being executed.

I have tried to append a value to the redirection that happens when transferring the user to the B2C, but I don't know how.

if (!Request.IsAuthenticated)
        { // go to login page
            HttpContext.GetOwinContext().Authentication.Challenge(
                  new AuthenticationProperties() { RedirectUri = "/" }, Startup.SignUpSignInPolicyId);
        }

The policy is stored in the startup.auth.cs file...

// B2C policy identifiers
    public static string SignUpPolicyId = ConfigurationManager.AppSettings["ida:SignUpPolicyId"];
    public static string SignInPolicyId = ConfigurationManager.AppSettings["ida:SignInPolicyId"];
    public static string SignUpSignInPolicyId = ConfigurationManager.AppSettings["ida:SignUpSignInPolicyId"];
    public static string ProfilePolicyId = ConfigurationManager.AppSettings["ida:UserProfilePolicyId"];
    public static string PasswordResetPolicyId = ConfigurationManager.AppSettings["ida:PasswordResetPolicyId"];

....and is run during the ConfigureAuth method:

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

        app.UseCookieAuthentication(new CookieAuthenticationOptions()
        {
            CookieHttpOnly = true,
            ExpireTimeSpan = TimeSpan.FromHours(1),
        });

        // Configure OpenID Connect middleware for each policy
        app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(SignUpPolicyId));
        app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(ProfilePolicyId));
        app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(SignInPolicyId));
        app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(SignUpSignInPolicyId));
        app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(PasswordResetPolicyId));
    }

which calls:

private OpenIdConnectAuthenticationOptions CreateOptionsFromPolicy(string policy)
    {
        return new OpenIdConnectAuthenticationOptions
        {
            // For each policy, give OWIN the policy-specific metadata address, and
            // set the authentication type to the id of the policy
            MetadataAddress = String.Format(aadInstance, tenant, policy),
            AuthenticationType = policy,

            // These are standard OpenID Connect parameters, with values pulled from web.config
            ClientId = clientId,
            RedirectUri = redirectUri,
            PostLogoutRedirectUri = redirectUri,
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = AuthenticationFailed,
            },
            Scope = "openid",
            ResponseType = "id_token",
            //// This piece is optional - it is used for displaying the user's name in the navigation bar.
            //TokenValidationParameters = new TokenValidationParameters
            //{
            //    NameClaimType = "name",
            //},
        };

    }

How do I pass a value like: (simplified example:)

if (!Request.IsAuthenticated)
        { // go to login page
            HttpContext.GetOwinContext().Authentication.Challenge(
                  new AuthenticationProperties() { RedirectUri = "/" }, Startup.SignUpSignInPolicyId, new { state = "value=uniquetoken&token=secrets" });
        } 

When these methods and policies are set on runtime ? Furthermore if I am heading in a completely wrong direction, where do I go from here?

Any help is appreciated :)

Best Regards

回答1:

To pass a value when we use the OpenIdConnect protocol, we can add the value to the state as you mentioned.

We can pass this value before it redirect it to the identity data provider(Azure AD) using RedirectToIdentityProvider. After that we can extract the custom values we added using the MessageReceived when a protocol message is first received.

Here is the code sample for your reference:

new OpenIdConnectAuthenticationOptions
{
    // For each policy, give OWIN the policy-specific metadata address, and
    // set the authentication type to the id of the policy
    MetadataAddress = String.Format(aadInstance, tenant, policy),
    AuthenticationType = policy,

    // These are standard OpenID Connect parameters, with values pulled from web.config
    ClientId = clientId,
    RedirectUri = redirectUri,
    PostLogoutRedirectUri = redirectUri,
    Notifications = new OpenIdConnectAuthenticationNotifications
    {
        AuthenticationFailed = AuthenticationFailed,
        RedirectToIdentityProvider= OnRedirectToIdentityProvider,
        MessageReceived= OnMessageReceived
    },
    Scope = "openid",
    ResponseType = "id_token",

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

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);
}

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);
}