OnlyOneEA
OnlyOneEA

Reputation: 203

SecurityTokenInvalidAudienceException: IDX10214: Audience validation failed

I'm developing an ASP.NET Core 2 app using Identity and Sustainsys.Saml2 (for SAML auth). I've made the necessary configurations in the Startup.cs file. Now when I run the project and try to login using the SAML2 (as an external login), I get the following error after enter my credentials:

SecurityTokenInvalidAudienceException: IDX10214: Audience validation failed. Audiences: '[PII is hidden]'. Did not match: validationParameters.ValidAudience: '[PII is hidden]' or validationParameters.ValidAudiences: '[PII is hidden]'. Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable audiences, SecurityToken securityToken, TokenValidationParameters validationParameters) Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateConditions(Saml2SecurityToken samlToken, TokenValidationParameters validationParameters) Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateToken(string token, TokenValidationParameters validationParameters, out SecurityToken validatedToken) Sustainsys.Saml2.Saml2P.Saml2Response+d__60.MoveNext() System.Collections.Generic.List..ctor(IEnumerable collection) System.Linq.Enumerable.ToList(IEnumerable source) Sustainsys.Saml2.Saml2P.Saml2Response.GetClaims(IOptions options, IDictionary relayData) Sustainsys.Saml2.WebSso.AcsCommand.ProcessResponse(IOptions options, Saml2Response samlResponse, StoredRequestState storedRequestState) Sustainsys.Saml2.WebSso.AcsCommand.Run(HttpRequestData request, IOptions options) Sustainsys.Saml2.AspNetCore2.Saml2Handler+d__12.MoveNext() System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__6.MoveNext() System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware+d__4.MoveNext() System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+d__6.MoveNext() System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+d__6.MoveNext() System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+d__7.MoveNext()

I'm not understanding what does this mean. Am I missing something?

Here's what I have in the Startup file

services.AddAuthentication()
        .AddSaml2(options => 
        {
            var spOptions = new SPOptions
            {
                EntityId = new EntityId("https://localhost:44373/Saml2"),
                ReturnUrl = new Uri("https://localhost:44373"),
                MinIncomingSigningAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1",                  
            };                

            options.SPOptions = spOptions;
            options.IdentityProviders.Add(new IdentityProvider(new EntityId("https://www.example.com/SSO/SAML/App"), options.SPOptions)
            {
                AllowUnsolicitedAuthnResponse = false,                  
                MetadataLocation = "https://www.example.com/SSO/SAMLMetadata/App",                  
                LoadMetadata = true,                  
            }); 
        });

Thanks in advance...

Upvotes: 15

Views: 63688

Answers (3)

in my case the issuer and audience for the JwtSecurityToken were omitted. In my derived class UserService: IUserService I defined the issuer and audience variables in the function generateJwtToken. They variables must match services.AddJwtBearer variables in the startup.csv for ValidIssuer and ValidAudience. see(https://dotnetcoretutorials.com/2020/01/15/creating-and-validating-jwt-tokens-in-asp-net-core/).

quote:

The Issuer and Audience are funny things because realistically, you probably won’t have a lot of use for them. Issuer is “who” created this token, for example your website, and Audience is “who” the token is supposed to be read by. So a good example might be that when a user logs in, your authentication api (auth.mywebsite.com) would be the issuer, but your general purposes API is the expected audience (api.mywebsite.com). These are actually free text fields so they don’t have to be anything in particular, but later on when we validate the issuer/audience, we will need to know what they are.

public class UserService : IUserService {

private string generateJwtToken(long userId)
            {
                var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.Secret));
                var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
                var tokenOptions = new JwtSecurityToken(
                    issuer: "http://localhost:5000",
                    audience: "http://localhost:5000",
                    claims: new List<Claim> {
                        new Claim(ClaimTypes.Name, userId.ToString()),
                        new Claim(ClaimTypes.Role, "Operator")
                    },
                    expires: DateTime.UtcNow.AddDays(7),
                    signingCredentials: signinCredentials
                );
                var tokenString = new JwtSecurityTokenHandler().WriteToken(tokenOptions);
                return tokenString;

            }

}

startup.cs

public void ConfigureServices(IServiceCollection services)
        {

services.AddAuthentication(opt =>
            {
                opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(opt =>
            {
                opt.RequireHttpsMetadata = false;
                opt.SaveToken = true;
                opt.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidIssuer = "http://localhost:5000",
                    ValidAudience = "http://localhost:5000"
                };
            });

}

Upvotes: 0

Eric
Eric

Reputation: 3147

IDX10214: Check this section if you are using Microsoft.Identity.Web version 1.4.1 or similar and you get this exception (literally copied, and you have to change the log levels in appsettings.json to get to see this):

info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[1]
      Failed to validate the token.
      Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException: IDX10214: Audience validation failed. Audiences: 'System.String'. Did not match: validationParameters.ValidAudience: 'System.String' or validationParameters.ValidAudiences: 'System.String'.
         at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
         at Microsoft.Identity.Web.Resource.RegisterValidAudience.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
         at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
         at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateAudience(IEnumerable`1 audiences, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
         at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
         at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
         at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()

Would be so much more helpful to actually see the value of those System.String's. And if it didn't matter whether you use a GUID or something memorizable and readable.

Essentially you have to add the Audience property to appsettings.json and that must be equal to the Application ID URI in the Azure portal. I had no luck whatsoever hacking the ClientId and have that match the Application ID URI. That isn't the final solution to this - AFAIK that must still be equal to the Application (client) ID in the Azure portal, i.e. a GUID without any prefixes or suffixes.

Upvotes: 4

NamiraJV
NamiraJV

Reputation: 666

As far as I know, this error clearly states that audience that came in your SAML-token is different from the value in your Startup configuration. It might be helpful to compare these values. Sometimes the validation fails due to case-sensitive comparison, so you should pay attention in which case your audiencies are in token and configuration.

According to the source code (Saml2Response) and as Anders Abel pointed out, ValidAudience property is initialized from SPOptions.EntityId that you configure here:

var spOptions = new SPOptions
{
    EntityId = new EntityId("https://localhost:44373/Saml2"),
    ReturnUrl = new Uri("https://localhost:44373"),
    MinIncomingSigningAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1",                  
};

So you should compare the EntityId value, that you have configured with the value in your saml-token, which might look like this:

<saml:Audience>The value here should be the same as in your startup configuration</saml:Audience>

Upvotes: 19

Related Questions