[MGNLSSO-296] Token Introspection Failure results in 500 Error Response Created: 21/Jun/23  Updated: 08/Sep/23

Status: In Progress
Project: Single Sign On
Component/s: None
Affects Version/s: 3.1.1
Fix Version/s: None

Type: Bug Priority: High
Reporter: Theocharis Koktsidis Assignee: Evzen Fochr
Resolution: Unresolved Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Magnolia Version: 6.2.27
magnolia-sso version: 3.1.1 (Due to requirement of magnolia version >6.3.x on later versions, I think this bug applies on the later versions as well)


Template:
Acceptance criteria:
[ ]* Invalid/Expired Access Tokens should result in 401 - Unauthorized responses
Task DoD:
[ ]* Doc/release notes changes? Comment present?
[ ]* Downstream builds green?
[ ]* Solution information and context easily available?
[ ]* Tests
[ ]* FixVersion filled and not yet released
[ ]  Architecture Decision Record (ADR)
Bug DoR:
[X]* Steps to reproduce, expected, and actual results filled
[X]* Affected version filled
Date of First Response:
Work Started:

 Description   

Steps to reproduce

  1. Setup SSO under /.rest path using a valid http.bearer client as described on the docs
  2. Set http.bearer.authenticator to token-introspection
  3. Use an invalid OAuth token in your request (invalid/expired)
  4. Observe response 500 - Internal Server Error instead of 401 - Unauthorized

Expected results

When using an invalid or expired token we expect an Unauthorized HTTP response.

Actual results

Instead an Internal Server Error Occurs with the following stack trace:

21-Jun-2023 16:39:15.941 SEVERE [http-nio-8080-exec-7] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [default] in context with path [] threw exception
    org.pac4j.core.exception.TechnicalException: Client credentials authentication failed. Reason: Invalid / expired access token
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
        at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.base/java.lang.Thread.run(Thread.java:834) 

Workaround

I haven't been able to find any workaround for this.

Development notes

An org.pac4j.core.exception.TechnicalException is thrown on inactive/invalid Bearer token from TokenIntrospectionAuthenticator. This exception is propagated to org.pac4j.core.engine.DefaultSecurityLogic which then wraps that exception as RuntimeException resulting in incorrect HTTP Response Status.



 Comments   
Comment by Theocharis Koktsidis [ 21/Jun/23 ]

Sample SSO config.yaml

 

path: /.rest
callbackUrl: !env ${OIDC_CALLBACK_URL}/.auth
postLogoutRedirectUri: /.magnolia/admincentral
authorizationGenerators:
  - name: fixedAuthorization
    fixed:
      targetRoles:
        - superuser

clients:
  http.bearer.id: !env ${IDS_CLIENT_ID}
  http.bearer.secret: !env ${IDS_CLIENT_SECRET}
  http.bearer.scope: !env ${IDS_SCOPES}
  http.bearer.clientAuthenticationMethod: client_secret_basic
  http.bearer.discoveryUri: !env ${IDS_HOST}/.well-known/openid-configuration
  http.bearer.preferredJwsAlgorithm: RS256
  http.bearer.authorizationGenerators: fixedAuthorization
  http.bearer.authenticator: token-introspection
Comment by Theocharis Koktsidis [ 23/Jun/23 ]

Replacing throw new TechnicalException() on the Authenticator with CredentialsException will solve this issue. As the doc of the Authenticator.validate() reads:

Validate the credentials. It should throw a {@link CredentialsException} in case of failure.

CredentialsException is a subclass of TechnicalException but is being properly handled by BaseClient.

 


 

Temporary workaround until a proper fix is established (We had to do that because we are on an older version of SSO module due to Magnolia version):

  1. Create a custom authenticator with the same functionality as existing TokenIntrospectionAuthenticator.
  2. Replace throw new TechnicalException() on invalid/expired tokens on your custom Authenticator with throw new CredentialsException()
  3. Create a Pac4jConfigProvider extension. 
@Singleton
public class Pac4jConfigProviderExtension extends Pac4jConfigProvider {

    private final static String BEARER_AUTH_CLIENT_NAME = "DirectBearerAuthClient";

    @Inject
    public Pac4jConfigProviderExtension(SsoConfig ssoMpConfig, ServerConfiguration serverConfiguration, SsoConfigYamlBridge yamlBridge) {
        super(ssoMpConfig, serverConfiguration, yamlBridge);
        fixAuthenticatorException();
    }

    private void fixAuthenticatorException() {
        Config config = this.get();
        Clients clients = config.getClients();
        for (Client client : clients.getClients()) {
            if (BEARER_AUTH_CLIENT_NAME.equals(client.getName())) {
                DirectClient bearerDirectClient = (DirectClient) client;
                TokenIntrospectionAuthenticator currAuthenticator = (TokenIntrospectionAuthenticator) bearerDirectClient.getAuthenticator();
                OidcConfiguration configuration = currAuthenticator.getConfiguration();
                bearerDirectClient.setAuthenticator(new YOUR_CUSTOM_AUTHENTICATOR_HERE(configuration));
            }
        }
    }
} 

      4. Add a dependency on your module.xml to magnolia-sso to ensure proper loading

<dependencies> 
  ...
  <dependency>
    <name>magnolia-sso</name>
    <version>3.0.1</version>
  </dependency>
</dependencies>

      5. Add your custom Pac4jConfigProvider implementation on module.xml under main

<components>
  <id>main</id>
  ...
  <component>
    <type>info.magnolia.sso.config.Pac4jConfigProvider</type>
    <implementation>your.package.name.Pac4jConfigProviderExtension</implementation>
    <scope>singleton</scope>
  </component> 
</componens> 

 

 

 

Comment by Evzen Fochr [ 08/Sep/23 ]

Dear tkoktsidis 

MGNLSSO-301 was implemented and released as part of sso 3.1.7. Can you please check if the solution is sufficient for your usecase too?

Generated at Mon Feb 12 10:52:55 CET 2024 using Jira 9.4.2#940002-sha1:46d1a51de284217efdcb32434eab47a99af2938b.