I read this article: Secure ASP.NET Web API 2 using Azure AD B2C – Part 2
At step 3 app.UseOAuthBearerAuthentication
is called 3 times... one for each policy.
I'm testing with only 2 policies: SignInPolicyId
and SignUpPolicyId
.
However when I do:
app.UseOAuthBearerAuthentication(CreateBearerOptionsForPolicy(SignInPolicyId))
app.UseOAuthBearerAuthentication(CreateBearerOptionsForPolicy(SignUpPolicyId));
and pass a Provider
with its OnValidateIdentity
to deal with validating claims, etc. I then try to filter by the policy like this:
private OAuthBearerAuthenticationOptions CreateBearerOptionsForPolicy(string policy)
{
var metadataEndpoint = string.Format(AadInstance, TenantId, policy);
TokenValidationParameters tvps = new TokenValidationParameters
{
// This is where you specify that your API only accepts tokens from its own clients
ValidAudience = ClientId,
AuthenticationType = policy,
NameClaimType = "http://schemas.microsoft.com/identity/claims/objectidentifier",
ValidateIssuer = true
};
return new OAuthBearerAuthenticationOptions
{
AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider(metadataEndpoint)),
Provider = new OAuthBearerAuthenticationProvider
{
OnValidateIdentity = async context =>
{
try
{
var policyName = identity.FindFirst("http://schemas.microsoft.com/claims/authnclassreference")?.Value;
if (policyName == B2CSignInPolicyId.ToLower()) // Sign In Only policy...
{
// Run specific code here for the policy that just sent a token back to the application...
}
Problem: the policy that is being executed @ Azure B2C, that is, the one that I'm calling is the Sign In
policy, but the provider code is called twice. Once for each policy I registered including the Sign Up
one.
Question: is there any better way of doing this so that we get the right Provider executed? If the Sign In
policy is the one being called, execute just the Sign In
provider and vice versa.
Edit:
I'm experiencing the same issue described here (sequence contains more than one element): http://bitoftech.net/2016/08/24/secure-aspnet-web-api-2-azure-ad-b2c/#comment-96913
This is the exception:
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)\r\n at Microsoft.Owin.Security.AuthenticationManager.d__20.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.HostAuthenticationFilter.d__4.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.AuthenticationFilterResult.d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ExceptionFilterResult.d__6.MoveNext()
Somehow I got it working with only one call to:
app.UseOAuthBearerAuthentication(CreateBearerOptionsForPolicy(DefaultPolicyId));
Note that I passed just a default policy, let's say the Sign In
one.
For other policies it's also hitting the OnValidateIdentity
delegate.
Regarding the policy name we need to customize the custom policy even further and return the Policy Id claim as described here.
This other answer @ SO helps in understanding that.
With that setup, when the policy is executed we can get the policy name by looking at TFP
(Trusted Framework Policy) claim like in the following screenshot: