Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exceptions in tokens in version 7.0.1 #1178

Open
hedzerjan opened this issue Mar 21, 2024 · 21 comments
Open

Exceptions in tokens in version 7.0.1 #1178

hedzerjan opened this issue Mar 21, 2024 · 21 comments
Assignees

Comments

@hedzerjan
Copy link

Identity server 7.01, .Net 8.0.3.

About 30% of our customers ran into the two exceptions below and could not log in. This has caused us to revert to a build using IdentityServer 6.3.6 which uses .Net 7.

We can not reproduce this ourselves. We also do not see anything that distinguishes the customers experiencing the problem to those that don't.

Microsoft.AspNetCore.Authentication.AuthenticationFailureException: An error was encountered while handling the remote login. 
---> Microsoft.IdentityModel.Tokens.SecurityTokenException: No token validator or token handler was found for the given token. 
---> System.AggregateException: One or more errors occurred. (IDX10204: Unable to validate issuer. validationParameters.ValidIssuer is null or whitespace AND validationParameters.ValidIssuers is null or empty.) (IDX30011: Unable to read XML. Expecting XmlReader to be at ns.element: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.].[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]', found: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.].[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.) (IDX14100: JWT is not well formed, there are no dots (.).The token needs to be in JWS or JWE Compact Serialization Format. (JWS): 'EncodedHeader.EndcodedPayload.EncodedSignature'. (JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'.) 
---> Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException: IDX10204: Unable to validate issuer. validationParameters.ValidIssuer is null or whitespace AND validationParameters.ValidIssuers is null or empty.   at Microsoft.IdentityModel.Tokens.Validators.ValidateIssuerAsync(String issuer, SecurityToken securityToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)   at Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateSignature(Saml2SecurityToken samlToken, String token, TokenValidationParameters validationParameters)   at Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)   at Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateTokenAsync(String token, TokenValidationParameters validationParameters)   --- End of inner exception stack trace --- 
---> (Inner Exception #1) Microsoft.IdentityModel.Xml.XmlReadException: IDX30011: Unable to read XML. Expecting XmlReader to be at ns.element: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.].[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]', found: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.].[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.   at Microsoft.IdentityModel.Xml.XmlUtil.CheckReaderOnEntry(XmlReader reader, String element, String namespace)   at Microsoft.IdentityModel.Tokens.Saml.SamlSerializer.ReadAssertion(XmlReader reader)   at Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ReadSamlToken(String token)   at Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)   at Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateTokenAsync(String token, TokenValidationParameters validationParameters)<--- 
---> (Inner Exception #2) Microsoft.IdentityModel.Tokens.SecurityTokenMalformedException: IDX14100: JWT is not well formed, there are no dots (.).The token needs to be in JWS or JWE Compact Serialization Format. (JWS): 'EncodedHeader.EndcodedPayload.EncodedSignature'. (JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'. 
---> Microsoft.IdentityModel.Tokens.SecurityTokenMalformedException: IDX14122: JWT is not a well formed JWE, there are more than four dots (.) a JWE can have at most 4 dots.The token needs to be in JWS or JWE Compact Serialization Format. (JWS): 'EncodedHeader.EndcodedPayload.EncodedSignature'. (JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'.   at Microsoft.IdentityModel.JsonWebTokens.JsonWebToken.ReadToken(String encodedJson)   at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ReadToken(String token, TokenValidationParameters validationParameters)   --- End of inner exception stack trace ---<---   --- End of inner exception stack trace ---   at Microsoft.AspNetCore.Authentication.WsFederation.WsFederationHandler.HandleRemoteAuthenticateAsync()   --- End of inner exception stack trace ---   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()   at Duende.IdentityServer.Hosting.FederatedSignOut.AuthenticationRequestHandlerWrapper.HandleRequestAsync() in /_/src/IdentityServer/Hosting/FederatedSignOut/AuthenticationRequestHandlerWrapper.cs:line 38   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)   at Duende.IdentityServer.Hosting.DynamicProviders.DynamicSchemeAuthenticationMiddleware.Invoke(HttpContext context) in /_/src/IdentityServer/Hosting/DynamicProviders/DynamicSchemes/DynamicSchemeAuthenticationMiddleware.cs:line 51   at Duende.IdentityServer.Hosting.BaseUrlMiddleware.Invoke(HttpContext context) in /_/src/IdentityServer/Hosting/BaseUrlMiddleware.cs:line 27   at TriasMVC.WebCommon.Middleware.IPFiltering.Invoke(HttpContext httpContext, IIdentityTenantService identityTenantService, ITenantRepository tenantRepository) in /_/src/WebCommon/Middleware/IPFiltering.cs:line 61   at AuthServer.MiddleWare.TenantCookieSelector.Invoke(HttpContext httpContext, IIdentityTenantService tenantProvider, ILogger`1 logger) in D:\a\1\s\src\MiddleWare\TenantCookieSelector.cs:line 48   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl.<Invoke>g__Awaited|10_0(ExceptionHandlerMiddlewareImpl middleware, HttpContext context, Task task)
Microsoft.IdentityModel.Tokens.SecurityTokenException: No token validator or token handler was found for the given token. 
---> System.AggregateException: One or more errors occurred. (IDX10204: Unable to validate issuer. validationParameters.ValidIssuer is null or whitespace AND validationParameters.ValidIssuers is null or empty.) (IDX30011: Unable to read XML. Expecting XmlReader to be at ns.element: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.].[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]', found: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.].[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.) (IDX14100: JWT is not well formed, there are no dots (.).The token needs to be in JWS or JWE Compact Serialization Format. (JWS): 'EncodedHeader.EndcodedPayload.EncodedSignature'. (JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'.) 
---> Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException: IDX10204: Unable to validate issuer. validationParameters.ValidIssuer is null or whitespace AND validationParameters.ValidIssuers is null or empty.   at Microsoft.IdentityModel.Tokens.Validators.ValidateIssuerAsync(String issuer, SecurityToken securityToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)   at Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateSignature(Saml2SecurityToken samlToken, String token, TokenValidationParameters validationParameters)   at Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)   at Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler.ValidateTokenAsync(String token, TokenValidationParameters validationParameters)   --- End of inner exception stack trace --- 
---> (Inner Exception #1) Microsoft.IdentityModel.Xml.XmlReadException: IDX30011: Unable to read XML. Expecting XmlReader to be at ns.element: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.].[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]', found: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.].[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.   at Microsoft.IdentityModel.Xml.XmlUtil.CheckReaderOnEntry(XmlReader reader, String element, String namespace)   at Microsoft.IdentityModel.Tokens.Saml.SamlSerializer.ReadAssertion(XmlReader reader)   at Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ReadSamlToken(String token)   at Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)   at Microsoft.IdentityModel.Tokens.Saml.SamlSecurityTokenHandler.ValidateTokenAsync(String token, TokenValidationParameters validationParameters)<--- 
---> (Inner Exception #2) Microsoft.IdentityModel.Tokens.SecurityTokenMalformedException: IDX14100: JWT is not well formed, there are no dots (.).The token needs to be in JWS or JWE Compact Serialization Format. (JWS): 'EncodedHeader.EndcodedPayload.EncodedSignature'. (JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'. 
---> Microsoft.IdentityModel.Tokens.SecurityTokenMalformedException: IDX14122: JWT is not a well formed JWE, there are more than four dots (.) a JWE can have at most 4 dots.The token needs to be in JWS or JWE Compact Serialization Format. (JWS): 'EncodedHeader.EndcodedPayload.EncodedSignature'. (JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'.   at Microsoft.IdentityModel.JsonWebTokens.JsonWebToken.ReadToken(String encodedJson)   at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ReadToken(String token, TokenValidationParameters validationParameters)   --- End of inner exception stack trace ---<---   --- End of inner exception stack trace ---   at Microsoft.AspNetCore.Authentication.WsFederation.WsFederationHandler.HandleRemoteAuthenticateAsync()
@hedzerjan
Copy link
Author

Any update on this? We're now having apply some really ugly patches to have our identityserver keep up with the rest of the software.

@AndersAbel
Copy link
Member

This looks like requests are handled by the WS-Federation authentication handler. Do you have a path for the request where this happends?

Could you please share some more information about your authentication setup? What external authentication schemes do you have enabled?

@hedzerjan
Copy link
Author

We have two main applications that use IdentityServer, one of which is the old one and thats uses WS-Federation to authenticate with IdentityServer. The new application uses OIDC. To support WS-Federation we use Rsk.WsFederation.DuendeIdentityServer version 8.0.0.

The external schemes that we use are OIDC, WS-Federation and Google (OAuth). We did not see a pattern of external schemes or settings that corresponded with the error happening.

The requestpath where the error occurs is the callbackpath (RemoteAuthenticationOptions.CallbackPath).

@AndersAbel
Copy link
Member

And what is the value of RemoteAuthenticationOptions.CallbackPath in this case? What scheme is it that has that path configured?

@hedzerjan
Copy link
Author

The callback path is different for every customer. The customers that were affected all had different paths and schemes.

@hedzerjan
Copy link
Author

hedzerjan commented Apr 11, 2024

Here are two examples, different handlers, different paths:

{
    "Properties": {
        "EventId": {
            "Id": 3,
            "Name": "ExceptionProcessingMessage"
        },
        "SourceContext": "Microsoft.AspNetCore.Authentication.WsFederation.WsFederationHandler",
        "RequestId": "800003a4-0000-7400-b63f-84710c7967bb",
        "RequestPath": "/Visio_ADFS",
        "MachineName": "TRIASAPP102",
        "Application": "AuthServer"
    }
}
{
    "Properties": {
        "EventId": {
            "Id": 17,
            "Name": "ExceptionProcessingMessage"
        },
        "SourceContext": "Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler",
        "RequestId": "8000039c-0000-7400-b63f-84710c7967bb",
        "RequestPath": "/siza/signin-oidc",
        "MachineName": "TRIASAPP102",
        "Application": "AuthServer"
    }
}

@hedzerjan
Copy link
Author

I just noticed, for OIDC the root exception seems to be:

Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10503: Signature validation failed. Token does not have a kid. Keys tried: '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. Number of keys in TokenValidationParameters: '1'. Number of keys in Configuration: '0'. Exceptions caught: '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.token: '[PII of type 'Microsoft.IdentityModel.JsonWebTokens.JsonWebToken' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. See https://aka.ms/IDX10503 for details.   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.ValidateTokenUsingHandlerAsync(String idToken, AuthenticationProperties properties, TokenValidationParameters validationParameters)   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync()

@AndersAbel
Copy link
Member

AndersAbel commented Apr 11, 2024

This looks like it might be caused by Microsoft.IdentityModel.* package version mismatch. Could you please validate the versions used by following the steps on https://docs.duendesoftware.com/identityserver/v7/troubleshooting/wilson/?

@hedzerjan
Copy link
Author

This is the output of the branch that was affected, which shows one faulty version. It'll take some time to try the fix, since we dan't reproduce it ourselves.


   > Microsoft.IdentityModel.Abstractions                                               7.1.2
   > Microsoft.IdentityModel.JsonWebTokens                                              7.1.2
   > Microsoft.IdentityModel.Logging                                                    7.1.2
   > Microsoft.IdentityModel.Protocols                                                  7.1.2
   > Microsoft.IdentityModel.Protocols.OpenIdConnect                                    7.0.3
   > Microsoft.IdentityModel.Protocols.WsFederation                                     7.1.2
   > Microsoft.IdentityModel.Tokens                                                     7.1.2
   > Microsoft.IdentityModel.Tokens.Saml                                                7.1.2
   > Microsoft.IdentityModel.Xml                                                        7.1.2
   > System.IdentityModel.Tokens.Jwt                                                    7.1.2

@AndersAbel
Copy link
Member

Looks like this is the reason for the error. You would need to add an explicit package reference for the Microsoft.IdentityModel.Protocols.OpenIdConnect model to pin it to the same version as the other ones.

@hedzerjan
Copy link
Author

hedzerjan commented Apr 16, 2024

We tried the fix but it did not seem to work, the Exceptions are slightly different though and I only saw them occur with customers that used OIDC with HelloID:

Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10517: Signature validation failed. The token's kid is missing. Keys tried: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey, KeyId: '', InternalId: 'YKLjhFriN4ehR7AGL2qdcnQyXcFNoU80ZaBv7OJkS4U'. , KeyId: '. Number of keys in TokenValidationParameters: '1'. Number of keys in Configuration: '0'. Exceptions caught: '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.token: '[PII of type 'Microsoft.IdentityModel.JsonWebTokens.JsonWebToken' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. See https://aka.ms/IDX10503 for details.   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.ValidateTokenUsingHandlerAsync(String idToken, AuthenticationProperties properties, TokenValidationParameters validationParameters)   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync()

Followed by:

Microsoft.AspNetCore.Authentication.AuthenticationFailureException: An error was encountered while handling the remote login. ---> Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10517: Signature validation failed. The token's kid is missing. Keys tried: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey, KeyId: '', InternalId: 'YKLjhFriN4ehR7AGL2qdcnQyXcFNoU80ZaBv7OJkS4U'. , KeyId: '. Number of keys in TokenValidationParameters: '1'. Number of keys in Configuration: '0'. Exceptions caught: '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.token: '[PII of type 'Microsoft.IdentityModel.JsonWebTokens.JsonWebToken' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. See https://aka.ms/IDX10503 for details.   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.ValidateTokenUsingHandlerAsync(String idToken, AuthenticationProperties properties, TokenValidationParameters validationParameters)   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync()   --- End of inner exception stack trace ---   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()   at Duende.IdentityServer.Hosting.FederatedSignOut.AuthenticationRequestHandlerWrapper.HandleRequestAsync() in /_/src/IdentityServer/Hosting/FederatedSignOut/AuthenticationRequestHandlerWrapper.cs:line 38   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)   at Duende.IdentityServer.Hosting.DynamicProviders.DynamicSchemeAuthenticationMiddleware.Invoke(HttpContext context) in /_/src/IdentityServer/Hosting/DynamicProviders/DynamicSchemes/DynamicSchemeAuthenticationMiddleware.cs:line 51   at Duende.IdentityServer.Hosting.BaseUrlMiddleware.Invoke(HttpContext context) in /_/src/IdentityServer/Hosting/BaseUrlMiddleware.cs:line 27   at TriasMVC.WebCommon.Middleware.IPFiltering.Invoke(HttpContext httpContext, IIdentityTenantService identityTenantService, ITenantRepository tenantRepository) in /_/src/WebCommon/Middleware/IPFiltering.cs:line 61   at AuthServer.MiddleWare.TenantCookieSelector.Invoke(HttpContext httpContext, IIdentityTenantService tenantProvider, ILogger`1 logger) in D:\a\1\s\src\MiddleWare\TenantCookieSelector.cs:line 48   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl.<Invoke>g__Awaited|10_0(ExceptionHandlerMiddlewareImpl middleware, HttpContext context, Task task)

In addition: I have not yet received confirmation that we had customers unable to log in. But the exception template in the log normally rarely occurs and now we had about 10 occurrances within 10 minutes of deploying this build.

Edit: this is the library output for the current build:

   > Microsoft.IdentityModel.Protocols.OpenIdConnect        7.5.1           7.5.1
   > Microsoft.IdentityModel.Protocols.WsFederation         7.5.1           7.5.1
   > Microsoft.IdentityModel.Tokens.Saml                    7.5.1           7.5.1
   > Microsoft.IdentityModel.Xml                            7.5.1           7.5.1
   > Microsoft.IdentityModel.Abstractions                                               7.5.1
   > Microsoft.IdentityModel.JsonWebTokens                                              7.5.1
   > Microsoft.IdentityModel.Logging                                                    7.5.1
   > Microsoft.IdentityModel.Protocols                                                  7.5.1
   > Microsoft.IdentityModel.Tokens                                                     7.5.1
   > System.IdentityModel.Tokens.Jwt                                                    7.5.1

@RolandGuijt
Copy link

In .NET 8 the code that handles tokens has been rewritten. So it might be that you use some kind of configuration that was working before but in .NET 8 doesn't work anymore.
The next step would be to check your client configuration. Can you please share the code where you configure the OpenID Connect handler on the client (services.AddOpenIdConnect..) and the configuration of the client in IdentityServer?

@hedzerjan
Copy link
Author

This is de code:

case 200:
    var metaUrl = JsonConvert.DeserializeObject<OpenIdParameters>(identityProvider.Parameters);

    services.AddAuthentication()
        .AddOpenIdConnect(identityProvider.Name, identityProvider.Name, options =>
        {
            options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
            options.SignOutScheme = IdentityServerConstants.SignoutScheme;
            options.MetadataAddress = metaUrl.MetadataUrl.ToString();
            options.ClientId = metaUrl.AppId.ToString();
            options.CallbackPath = $"/{identityProvider.Name}" + "/signin-oidc";
            options.SignedOutCallbackPath = $"/{identityProvider.Name}" + "/signed-out-callback";

            if (!metaUrl.Flow.IsNullOrEmpty())
            {
                options.ResponseType = metaUrl.Flow.ToString();
            }

            if (!metaUrl.ClientSecret.IsNullOrEmpty())
            {
                options.ClientSecret = metaUrl.ClientSecret;
                options.TokenValidationParameters.IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes(metaUrl.ClientSecret.ToString()));
            }

            options.Scope.Clear();
            options.Scope.Add("openid");
            options.Scope.Add("profile");

            options.Events.OnRedirectToIdentityProvider = context =>
            {
                return Task.CompletedTask;
            };
            options.Events.OnRedirectToIdentityProviderForSignOut = context =>
            {
                var endpointLogoutAddress = context.ProtocolMessage.IssuerAddress;

                if (endpointLogoutAddress.IsNullOrEmpty())
                {
                    endpointLogoutAddress = @"/Account/Logout?logoutId=";
                }
                context.ProtocolMessage.IssuerAddress = GetAbsoluteUri(endpointLogoutAddress, Configuration.GetValue<string>(Constants.AppSettingsKeys.WtRealm));

                return Task.CompletedTask;
            };
            options.GetClaimsFromUserInfoEndpoint = true;
        });
    break;

The metadata is json and for one of the clients who experiences the problem it is:

{
    "MetadataUrl": "https://siza.helloid.com/oauth2/v2/66bc8852-279c-428c-b8d6-3030a29bcfbb/.well-known/openid-configuration/",
    "AppId": "66bc8852-279c-428c-b8d6-3030a29bcfbb",
    "ClientSecret": "****",
    "Flow": "code id_token"
}

There are two clients involved. The one where the problem occurs has this configuration:

{
    "Id": 13,
    "Enabled": "1",
    "ClientId": "mvc",
    "ProtocolType": "oidc",
    "RequireClientSecret": "1",
    "ClientName": null,
    "Description": null,
    "ClientUri": null,
    "LogoUri": null,
    "RequireConsent": "0",
    "AllowRememberConsent": "1",
    "AlwaysIncludeUserClaimsInIdToken": "1",
    "RequirePkce": "1",
    "AllowPlainTextPkce": "0",
    "AllowAccessTokensViaBrowser": "0",
    "FrontChannelLogoutUri": "https://triasweb.nl/Home/LogoutLocal",
    "FrontChannelLogoutSessionRequired": "1",
    "BackChannelLogoutUri": null,
    "BackChannelLogoutSessionRequired": "1",
    "AllowOfflineAccess": "1",
    "IdentityTokenLifetime": 3600,
    "AccessTokenLifetime": 3600,
    "AuthorizationCodeLifetime": 300,
    "ConsentLifetime": null,
    "AbsoluteRefreshTokenLifetime": 2592000,
    "SlidingRefreshTokenLifetime": 1296000,
    "RefreshTokenUsage": 1,
    "UpdateAccessTokenClaimsOnRefresh": "0",
    "RefreshTokenExpiration": 1,
    "AccessTokenType": 0,
    "EnableLocalLogin": "1",
    "IncludeJwtId": "0",
    "AlwaysSendClientClaims": "1",
    "ClientClaimsPrefix": "client_",
    "PairWiseSubjectSalt": null,
    "Created": "2021-05-20T18:14:23.7366667",
    "Updated": null,
    "LastAccessed": null,
    "UserSsoLifetime": null,
    "UserCodeType": null,
    "DeviceCodeLifetime": 300,
    "NonEditable": "0",
    "AllowedIdentityTokenSigningAlgorithms": null,
    "RequireRequestObject": "0",
    "CibaLifetime": null,
    "PollingInterval": null,
    "CoordinateLifetimeWithUserSession": null,
    "RequireDPoP": "0",
    "InitiateLoginUri": null,
    "DPoPValidationMode": 0,
    "DPoPClockSkew": "00:00:00",
    "PushedAuthorizationLifetime": null,
    "RequirePushedAuthorization": "0"
  }

The other client has this configuration:

{
    "Id": 5,
    "Enabled": "1",
    "ClientId": "https://gz.triasweb.nl",
    "ProtocolType": "wsfed",
    "RequireClientSecret": "1",
    "ClientName": null,
    "Description": null,
    "ClientUri": null,
    "LogoUri": null,
    "RequireConsent": "1",
    "AllowRememberConsent": "1",
    "AlwaysIncludeUserClaimsInIdToken": "0",
    "RequirePkce": "0",
    "AllowPlainTextPkce": "0",
    "AllowAccessTokensViaBrowser": "0",
    "FrontChannelLogoutUri": "https://gz.triasweb.nl/",
    "FrontChannelLogoutSessionRequired": "1",
    "BackChannelLogoutUri": null,
    "BackChannelLogoutSessionRequired": "1",
    "AllowOfflineAccess": "0",
    "IdentityTokenLifetime": 3600,
    "AccessTokenLifetime": 3600,
    "AuthorizationCodeLifetime": 300,
    "ConsentLifetime": null,
    "AbsoluteRefreshTokenLifetime": 2592000,
    "SlidingRefreshTokenLifetime": 1296000,
    "RefreshTokenUsage": 1,
    "UpdateAccessTokenClaimsOnRefresh": "0",
    "RefreshTokenExpiration": 1,
    "AccessTokenType": 0,
    "EnableLocalLogin": "1",
    "IncludeJwtId": "0",
    "AlwaysSendClientClaims": "0",
    "ClientClaimsPrefix": "client_",
    "PairWiseSubjectSalt": null,
    "Created": "2020-07-21T12:32:07.9946855",
    "Updated": null,
    "LastAccessed": null,
    "UserSsoLifetime": null,
    "UserCodeType": null,
    "DeviceCodeLifetime": 300,
    "NonEditable": "0",
    "AllowedIdentityTokenSigningAlgorithms": null,
    "RequireRequestObject": "0",
    "CibaLifetime": null,
    "PollingInterval": null,
    "CoordinateLifetimeWithUserSession": null,
    "RequireDPoP": "0",
    "InitiateLoginUri": null,
    "DPoPValidationMode": 0,
    "DPoPClockSkew": "00:00:00",
    "PushedAuthorizationLifetime": null,
    "RequirePushedAuthorization": "0"
  }

@RolandGuijt
Copy link

It seems that the exceptions your getting now that the IdentityModel version mismatch is fixed have to do with the IssuerSigningKey you're using. The signing should be done using asymetric encryption instead of the symetric encryption you're using here with the client secret as a key which isn't meant for that.

Can you please remove the line setting IssuerSigningKey and any other logic for that you might have elsewhere and then see if it works as expected?

@hedzerjan
Copy link
Author

Hi Roland, we've removed the line

options.TokenValidationParameters.IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes(metaUrl.ClientSecret.ToString()));

But that caused lots of these exceptions:

Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.ValidateTokenUsingHandlerAsync(String idToken, AuthenticationProperties properties, TokenValidationParameters validationParameters)   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync()
Microsoft.AspNetCore.Authentication.AuthenticationFailureException: An error was encountered while handling the remote login. ---> Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.ValidateTokenUsingHandlerAsync(String idToken, AuthenticationProperties properties, TokenValidationParameters validationParameters)   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync()   --- End of inner exception stack trace ---   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()   at Duende.IdentityServer.Hosting.FederatedSignOut.AuthenticationRequestHandlerWrapper.HandleRequestAsync() in /_/src/IdentityServer/Hosting/FederatedSignOut/AuthenticationRequestHandlerWrapper.cs:line 38   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)   at Duende.IdentityServer.Hosting.DynamicProviders.DynamicSchemeAuthenticationMiddleware.Invoke(HttpContext context) in /_/src/IdentityServer/Hosting/DynamicProviders/DynamicSchemes/DynamicSchemeAuthenticationMiddleware.cs:line 51   at Duende.IdentityServer.Hosting.BaseUrlMiddleware.Invoke(HttpContext context) in /_/src/IdentityServer/Hosting/BaseUrlMiddleware.cs:line 27   at TriasMVC.WebCommon.Middleware.IPFiltering.Invoke(HttpContext httpContext, IIdentityTenantService identityTenantService, ITenantRepository tenantRepository) in /_/src/WebCommon/Middleware/IPFiltering.cs:line 61   at AuthServer.MiddleWare.TenantCookieSelector.Invoke(HttpContext httpContext, IIdentityTenantService tenantProvider, ILogger`1 logger) in D:\a\1\s\src\MiddleWare\TenantCookieSelector.cs:line 48   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl.<Invoke>g__Awaited|10_0(ExceptionHandlerMiddlewareImpl middleware, HttpContext context, Task task)

@RolandGuijt
Copy link

Do you have something special configured in IdentityServer for token signing? Can you share the configuration code for that? (the part starting with AddIdentityServer).

The way JWT signing works out of the box is as follows:

  • The identity provider holds a private/public key pair.
  • When a token is issued it is signed using the private key
  • To verify the token's signature the client or API needs the public key
  • The public part of the key is published in the discovery document so it is just downloaded

We recommend to not deviate from this mechanism, especially not by replacing it with symmetric encryption which is unsafe.

Hopefully with this info you can figure out what's going wrong.

@hedzerjan
Copy link
Author

hedzerjan commented May 13, 2024

Hi Roland, thanks for your patience. This is de line of code you mentioned, I think:

            var builder = services.AddIdentityServer(options =>
            {
                options.KeyManagement.Enabled = false;
                options.KeyManagement.SigningAlgorithms = new[] {
                    new SigningAlgorithmOptions("RS256") {UseX509Certificate = true}
                };
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
                options.Authentication.CookieLifetime = TimeSpan.FromHours(10);
                options.LicenseKey =  "***";
            })
                // this adds the config data from DB (clients, resources, CORS)
                .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = builder =>
                        builder.UseSqlServer(Configuration.GetConnectionString(Constants.ConnectionKeys.Identity),
                            sql => sql.MigrationsAssembly(migrationsAssembly));
                })
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = builder =>
                        builder.UseSqlServer(Configuration.GetConnectionString(Constants.ConnectionKeys.Identity),
                            sql => sql.MigrationsAssembly(migrationsAssembly));

                    // this enables automatic token cleanup. this is optional.
                    options.EnableTokenCleanup = true;
                    options.TokenCleanupInterval = 86400; // interval in seconds (default is 3600)
                })
                .AddAspNetIdentity<ApplicationUser>();

There's also this part further down:

            builder.AddSigningCredential(Configuration.GetValue<string>(Constants.AppSettingsKeys.CertificateThumbprint),
                                         StoreLocation.LocalMachine,
                                         NameType.Thumbprint);

@khamza85
Copy link

sorry to jump in, but I checked the jwks endpoint from the discovery endpoint and it returns an empty JSON. Might be related

https://siza.helloid.com/oauth2/v2/66bc8852-279c-428c-b8d6-3030a29bcfbb/.well-known/openid-configuration/jwks

@AndersAbel
Copy link
Member

I just want to check that I understand the flow right here, does it look like this?

Client (triasweb.nl) <---- OIDC ----> IdentityServer <---- OIDC -----> siza.helloid.com

If I read the error messages right, it looks like the problem is with the OIDC communication between IdentityServer and siza.helloid.com, where size.helloid.com acts as an OIDC Provider?

@hedzerjan
Copy link
Author

The flow is probably different, there are two possible flows and this might be the first one. In this case WSFed is handled by the RSK WSFed plugin:
Client (gz.triasweb.nl or a different subdomain) <---WSFed ---> IdentityServer <--- OIDC ---> siza.helloid.com
The second situation:
Client (triasweb.nl) <---OIDC ---> IdentityServer <--- OIDC ---> siza.helloid.com

@AndersAbel
Copy link
Member

Thank you for the update.

It still looks like this issue is in the OIDC flow with siza.helloid.com. On the IdentityServer side that is handled by the standard Microsoft OpenID Connect Handler. It is not part of the IdentityServer product and strictly not under our support. We can give some general advice, but cannot aid in deeper troubleshooting. In this case it looks like the reason is how siza.helloid.com works as a provider, which is definitely outside the scope of what we do support.

The good news here is that thanks to the usage of the Microsoft OpenID Connect Handler this is just another Asp.Net Core client to siza.helloid.com. There's nothing IdentityServer specific in that setup. I would recommend that you reach out to the support from helloid.com and get their help to resolve the OpenID Connect Flow. Once the basic flow works, we can help out if there's anything related to the connection to IdentityServer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants