Introduction
Custom authorization for Azure active directory B2C using OWIN.
Background
Azure Active Directory B2C is a highly available, global, identity management service for consumer-facing applications that scales to hundreds of millions of identities.
There are no specific roles that are supported in B2C yet, but as a work-around, this can be achieved by making use of attributes. PS: Azure AD B2C is still in preview and is planned to be rolled out by MAY '16.
Using the Code
Authentication
public static string SignUpPolicyId = ConfigurationManager.AppSettings["b2c:SignUpPolicyId"];
public static string SignInPolicyId = ConfigurationManager.AppSettings["b2c:SignInPolicyId"];
public static string ProfilePolicyId = ConfigurationManager.AppSettings["b2c:UserProfilePolicyId"];
private static string clientIdB2C = ConfigurationManager.AppSettings["b2c:ClientId"];
public static string aadInstanceB2C = ConfigurationManager.AppSettings["b2c:AadInstance"];
private static string tenantIdB2C = ConfigurationManager.AppSettings["b2c:Tenant"];
private static string postLogoutRedirectUriB2C = ConfigurationManager.AppSettings["b2c:RedirectUri"];
public static readonly string Authority = aadInstance + tenantId;
string graphResourceId = "https://graph.windows.net";
OpenIdConnectAuthenticationOptions options = new OpenIdConnectAuthenticationOptions
{
ClientId = clientIdB2C,
RedirectUri = postLogoutRedirectUriB2C,
AuthenticationType = "B2C",
PostLogoutRedirectUri = postLogoutRedirectUriB2C,
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = OnRedirectToIdentityProvider,
},
Scope = "openid",
ResponseType = "id_token",
ConfigurationManager = new PolicyConfigurationManager(
string.Format(CultureInfo.InvariantCulture, aadInstanceB2C +
"", tenantIdB2C, "/v2.0", OIDCMetadataSuffix),
new string[] { SignUpPolicyId, SignInPolicyId, ProfilePolicyId }),
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
},
};
app.UseOpenIdConnectAuthentication(options);
If user id has to be passed to the authentication page from application's custom input, add the below code in OnRedirectToIdentityProvide
? method.
if (notification.OwinContext.Authentication.AuthenticationResponseChallenge.
Properties.Dictionary.ContainsKey("login_hint"))?{
notification.ProtocolMessage.LoginHint = notification.OwinContext.
Authentication.AuthenticationResponseChallenge.Properties.Dictionary["login_hint"];
}
Now, from the controller, call the authentication challenge, specifying the signin policy ID and any other custom parameters (ex: login_hint
) in the Sign In method.
HttpContext.GetOwinContext().Authentication.Challenge(
new AuthenticationProperties(
new Dictionary<string, string>
{
{Startup.PolicyKey, Startup.SignInPolicyId}, {"login_hint", UserID }
})
{
RedirectUri = "/",
}, "B2C");
Once the authentication challenge is called, it routes to the appropriate AD login page when the authentication is taken care and will be routed back to the application (with url specified in postloguturl
).
In Azure B2C, as roles are supported (at least for now, create an attribute for every user while signing up to authorize users on specific roles / attributes. Custom attributes are not supported in B2C yet, but the value of an attribute is a free text. For example, consider setting the JobTitle
attribute of a user as 'Administrator
' (can be set from Azure portal for a simple test).
Once the attribute is set, get the claim details of the user signed in which will return all attributes associated with the user account.
var UserRole = (from claim in ClaimsPrincipal.Current.Claims
where claim.Type.Equals("jobTitle") select claim.Value).FirstOrDefault();
UserRole
will now contain 'Administrator
' as value based on which we can authorize the user. This can be overwritten in ?OnAuthorization
method to create a custom authorization attribute and can be called in the below way.
In controller:
[CustomAuthorize("Administrator")]
public ActionResult Claims_Admin()
{
return View("ClaimsAdmin");
}
Extended Authorization:
public override void OnAuthorization(System.Web.Mvc.AuthorizationContext context)
{
if (context.RequestContext.HttpContext.Request.IsAuthenticated)
{
var UserRole = (from claim in ClaimsPrincipal.Current.Claims where
claim.Type.Equals("jobTitle") select claim.Value).FirstOrDefault();