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}