001/*-
002 * #%L
003 * Smile CDR - CDR
004 * %%
005 * Copyright (C) 2016 - 2026 Smile CDR, Inc.
006 * %%
007 * All rights reserved.
008 * #L%
009 */
010package ca.cdr.api.security;
011
012import ca.cdr.api.annotations.CdrPublicAPI;
013import ca.cdr.api.model.json.oauth.OpenIdWellKnownOpenIdConfigurationResponseJson;
014import ca.uhn.fhir.rest.client.api.IClientInterceptor;
015import jakarta.annotation.Nullable;
016
017/**
018 * Factory class for creating and configuring instances of {@link ClientAuthInterceptor}.
019 */
020@CdrPublicAPI
021public class ClientAuthInterceptorFactory {
022
023        private static IClientAuthSelector ourIClientAuthSelector;
024
025        /**
026         * Creates an instance of {@link IClientInterceptor} initialized with the given client authentication state.
027         * <p>
028         * The returned interceptor discovers the token endpoint by fetching the <code>.well-known</code>
029         * configuration of the authorization server derived from {@link ClientAuthParams#getBaseUrl()}
030         * (or, when no base url is configured, from the first intercepted request). Callers which have
031         * already resolved that configuration should use
032         * {@link #create(ClientAuthParams, OpenIdWellKnownOpenIdConfigurationResponseJson)} instead.
033         * </p>
034         *
035         * @param theClientAuthParams The {@link ClientAuthParams} object containing the parameters
036         *                           to be used for configuring the interceptor.
037         * @return An instance of {@link IClientInterceptor} configured from the provided parameters.
038         */
039        public static IClientInterceptor create(ClientAuthParams theClientAuthParams) {
040                return create(theClientAuthParams, null);
041        }
042
043        /**
044         * Creates an instance of {@link IClientInterceptor} initialized with the given client authentication
045         * state and, optionally, an already resolved well-known configuration.
046         * <p>
047         * When <code>theResolvedWellKnownConfig</code> is non-null it is pre-seeded into the interceptor state,
048         * which suppresses <code>.well-known</code> discovery entirely: the token endpoint it carries is used
049         * as-is for the token request, and for the <code>aud</code> claim of the private_key_jwt flow.
050         * When it is null the behaviour is identical to {@link #create(ClientAuthParams)}, meaning discovery
051         * is performed against the authorization server derived from {@link ClientAuthParams#getBaseUrl()}.
052         * </p>
053         * <p>
054         * A fresh {@link ClientAuthState} is built on every call, so each returned interceptor caches its
055         * access token independently.
056         * </p>
057         *
058         * @param theClientAuthParams The {@link ClientAuthParams} object containing the parameters
059         *                           to be used for configuring the interceptor.
060         * @param theResolvedWellKnownConfig The already resolved well-known configuration to use, or
061         *                           <code>null</code> to let the interceptor discover it.
062         * @return An instance of {@link IClientInterceptor} configured from the provided parameters.
063         */
064        public static IClientInterceptor create(
065                        ClientAuthParams theClientAuthParams,
066                        @Nullable OpenIdWellKnownOpenIdConfigurationResponseJson theResolvedWellKnownConfig) {
067                if (ourIClientAuthSelector == null) {
068                        throw new IllegalStateException("IClientAuthSelector was not set");
069                }
070                ClientAuthState clientAuthState = new ClientAuthState(theClientAuthParams);
071                if (theResolvedWellKnownConfig != null) {
072                        clientAuthState.setWellKnownConfig(theResolvedWellKnownConfig);
073                }
074                return new ClientAuthInterceptor(ourIClientAuthSelector, clientAuthState);
075        }
076
077        public static void setClientAuthSelector(IClientAuthSelector theClientAuthSelector) {
078                ourIClientAuthSelector = theClientAuthSelector;
079        }
080}