001/*-
002 * #%L
003 * Smile CDR - CDR
004 * %%
005 * Copyright (C) 2016 - 2025 Smile CDR, Inc.
006 * %%
007 * All rights reserved.
008 * #L%
009 */
010package ca.cdr.api.model.json.oauth;
011
012import ca.uhn.fhir.model.api.IModelJson;
013import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
014import com.fasterxml.jackson.annotation.JsonAnySetter;
015import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
016import com.fasterxml.jackson.annotation.JsonProperty;
017import com.fasterxml.jackson.core.JsonProcessingException;
018import com.fasterxml.jackson.databind.ObjectMapper;
019import io.swagger.v3.oas.annotations.media.Schema;
020
021import java.lang.reflect.Field;
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027/**
028 * OpenId is built off of oauth2
029 * <a href="https://openid.net/specs/openid-connect-discovery-1_0.html">
030 *   Open id spec.</a>
031 *   <a href="https://datatracker.ietf.org/doc/html/rfc8414#section-3.2">OAuth 2 spec</a>
032 * NB: Some properties are not listed as "required" because they are required
033 *              for most cases, but not all auth servers will require them.
034 *              This model is meant to be usable for *all* .well-known endpoints
035 *              (not just SMILE ones), so we will leave them as unrequired (default: optional)
036 * NB2: There may be other properties provided (this is a non-exhaustive list).
037 */
038@JsonIgnoreProperties(ignoreUnknown = true)
039@Schema(
040                name = "OpenIdWellKnownOpenIdConfigurationResponse",
041                description = "This object represents the response from an Identity Provider's .well-known endpoint.")
042public class OpenIdWellKnownOpenIdConfigurationResponse implements IModelJson {
043
044        /* CHECKSTYLE.OFF: RegexpSingleLine - these json property names are spec compliant and should not be changed */
045
046        /**
047         * Authorization server's issuer identifier url
048         */
049        @JsonProperty(value = "issuer", required = true)
050        private String myIssuer;
051
052        /**
053         * URL of the authorization server's authorization endpoint
054         * REQUIRED unless no grant types are supported that use authorization endpoint
055         */
056        @JsonProperty("authorization_endpoint")
057        private String myAuthorizationEndpoint;
058
059        /**
060         * URL of the auth server's token endpoint
061         * REQUIRED unless only the implicit grant type is supported
062         */
063        @JsonProperty("token_endpoint")
064        private String myTokenEndpoint;
065
066        /**
067         * JSON array of subject identifier types that this OP supports
068         * (pairwise, public)
069         */
070        @JsonProperty(value = "subject_types_supported", required = true)
071        private List<String> mySubjectTypesSupported;
072
073        /**
074         * URL of the auth server's JWK Set document
075         */
076        @JsonProperty(value = "jwks_uri", required = false)
077        private String myJwkUri;
078
079        /**
080         * URL of the auth server's OAuth 2.0 Dynamic Client Registration Endpoint
081         */
082        @JsonProperty(value = "registration_endpoint", required = false)
083        private String myDynamicClientRegistrationEndpoint;
084
085        /**
086         * JSON array containing a list of the OAuth 2.0 "scopes" values that this auth
087         * server supports.
088         * RECOMMENDED
089         */
090        @JsonProperty("scopes_supported")
091        private List<String> mySupportedScopes;
092
093        /**
094         * JSON array containing a list of the oauth 2.0 "response_type" values
095         * that this auth server supports.
096         */
097        @JsonProperty(value = "response_types_supported", required = true)
098        private List<String> mySupportedResponseTypes;
099
100        /**
101         * JSON array containing a list of the oauth 2.0 "response_mode" values that this
102         * auth server supports
103         */
104        @JsonProperty(value = "response_modes_supported", required = false)
105        private List<String> mySupportedResponseModes;
106
107        /**
108         * JSON array containing a list of the oauth
109         * 2.0 grant type values that this auth server supports
110         */
111        @JsonProperty(value = "grant_types_supported", required = false)
112        private List<String> mySupportedGrantTypes;
113
114        /**
115         * JSON array containing a list of the client authentication methods supported by this token
116         * endpoint
117         */
118        @JsonProperty(value = "token_endpoint_auth_methods_supported", required = false)
119        private List<String> mySupportedAuthenticationMethods;
120
121        /**
122         * JSON array of list of the JWS Signing algorithms supported by
123         * the token endpoint for the signature on the JWT used
124         * to authenticate the client at the token endpoint
125         */
126        @JsonProperty(value = "token_endpoint_auth_signing_alg_values_supported", required = false)
127        private List<String> mySupportedJWSSigningAlgorithms;
128
129        /**
130         * URL of the auth server's oauth 2.0
131         * revocation endpoint
132         */
133        @JsonProperty(value = "revocation_endpoint", required = false)
134        private String myRevocationEndpoint;
135
136        /**
137         * JSON array of client auth methods supported by this
138         * revocation endpoint.
139         */
140        @JsonProperty(value = "revocation_endpoint_auth_methods_supported", required = false)
141        private List<String> mySupportedAuthMethodsForRevocation;
142
143        /**
144         * JSON array of the JWS signing algorithms supported by the
145         * revocation endpoint for the signature on the JWT used to authenticate the client.
146         */
147        @JsonProperty(value = "revocation_endpoint_auth_signing_alg_values_supported", required = false)
148        private List<String> myRevocationEndpointSigningAlgorithms;
149
150        /**
151         * URL of the auth server's oauth2.0 introspection endpoint
152         */
153        @JsonProperty(value = "introspection_endpoint", required = false)
154        private String myIntrospectionEndpoint;
155
156        /**
157         * JSON array of the client auth methods supported by this introspection
158         * endpoint.
159         */
160        @JsonProperty(value = "introspection_endpoint_auth_methods_supported", required = false)
161        private List<String> mySupportedIntrospectionEndpointAuthMethods;
162
163        /**
164         * User info url.
165         * RECOMMENDED
166         */
167        @JsonProperty("userinfo_endpoint")
168        private String myUserInfoEndpoint;
169
170        /**
171         * JSON array of signing algs supported for id token
172         */
173        @JsonProperty(value = "id_token_signing_alg_values_supported", required = true)
174        private List<String> mySupportedIdTokenSigningAlgs;
175
176        /**
177         * JSON array containing a list of proof key for code exchange (PCKE flow) code
178         * challenge methods supported by this auth server
179         */
180        @JsonProperty(value = "code_challenge_methods_supported", required = false)
181        private List<String> myCodeChallengeMethodsSupported;
182
183        /* CHECKSTYLE.ON: RegexpSingleLine */
184
185        /**
186         * We will store all unknown properties in a map during deserialization;
187         * if these properties are not in fact "unknown" but part of the spec,
188         * please add them above, but leave this map.
189         */
190        private final Map<String, Object> myUnknownProperties = new HashMap<>();
191
192        public String getIssuer() {
193                return myIssuer;
194        }
195
196        public void setIssuer(String theIssuer) {
197                myIssuer = theIssuer;
198        }
199
200        public String getAuthorizationEndpoint() {
201                return myAuthorizationEndpoint;
202        }
203
204        public void setAuthorizationEndpoint(String theAuthorizationEndpoint) {
205                myAuthorizationEndpoint = theAuthorizationEndpoint;
206        }
207
208        public String getTokenEndpoint() {
209                return myTokenEndpoint;
210        }
211
212        public void setTokenEndpoint(String theTokenEndpoint) {
213                myTokenEndpoint = theTokenEndpoint;
214        }
215
216        public String getJwkUri() {
217                return myJwkUri;
218        }
219
220        public void setJwkUri(String theJwkUri) {
221                myJwkUri = theJwkUri;
222        }
223
224        public String getDynamicClientRegistrationEndpoint() {
225                return myDynamicClientRegistrationEndpoint;
226        }
227
228        public void setDynamicClientRegistrationEndpoint(String theDynamicClientRegistrationEndpoint) {
229                myDynamicClientRegistrationEndpoint = theDynamicClientRegistrationEndpoint;
230        }
231
232        public List<String> getSupportedScopes() {
233                if (mySupportedScopes == null) {
234                        mySupportedScopes = new ArrayList<>();
235                }
236                return mySupportedScopes;
237        }
238
239        public void setSupportedScopes(List<String> theSupportedScopes) {
240                mySupportedScopes = theSupportedScopes;
241        }
242
243        public void addSupportedScope(String theScope) {
244                getSupportedScopes().add(theScope);
245        }
246
247        public List<String> getSupportedResponseTypes() {
248                if (mySupportedResponseTypes == null) {
249                        mySupportedResponseTypes = new ArrayList<>();
250                }
251                return mySupportedResponseTypes;
252        }
253
254        public void setSupportedResponseTypes(List<String> theSupportedResponseTypes) {
255                mySupportedResponseTypes = theSupportedResponseTypes;
256        }
257
258        public void addSupportedResponseType(String theResponseType) {
259                getSupportedResponseTypes().add(theResponseType);
260        }
261
262        public List<String> getSupportedResponseModes() {
263                if (mySupportedResponseModes == null) {
264                        mySupportedResponseModes = new ArrayList<>();
265                }
266                return mySupportedResponseModes;
267        }
268
269        public void setSupportedResponseModes(List<String> theSupportedResponseModes) {
270                mySupportedResponseModes = theSupportedResponseModes;
271        }
272
273        public void addSupportedResponseMode(String theMode) {
274                getSupportedResponseModes().add(theMode);
275        }
276
277        public List<String> getSupportedGrantTypes() {
278                if (mySupportedGrantTypes == null) {
279                        mySupportedGrantTypes = new ArrayList<>();
280                }
281                return mySupportedGrantTypes;
282        }
283
284        public void setSupportedGrantTypes(List<String> theSupportedGrantTypes) {
285                mySupportedGrantTypes = theSupportedGrantTypes;
286        }
287
288        public void addSupportedGrantType(String theGrantType) {
289                getSupportedGrantTypes().add(theGrantType);
290        }
291
292        public List<String> getSupportedAuthenticationMethods() {
293                if (mySupportedAuthenticationMethods == null) {
294                        mySupportedAuthenticationMethods = new ArrayList<>();
295                }
296                return mySupportedAuthenticationMethods;
297        }
298
299        public void setSupportedAuthenticationMethods(List<String> theSupportedAuthenticationMethods) {
300                mySupportedAuthenticationMethods = theSupportedAuthenticationMethods;
301        }
302
303        public void addSupportedAuthenticationMethod(String theMethod) {
304                getSupportedAuthenticationMethods().add(theMethod);
305        }
306
307        public List<String> getSupportedJWSSigningAlgorithms() {
308                if (mySupportedJWSSigningAlgorithms == null) {
309                        mySupportedJWSSigningAlgorithms = new ArrayList<>();
310                }
311                return mySupportedJWSSigningAlgorithms;
312        }
313
314        public void setSupportedJWSSigningAlgorithms(List<String> theSupportedJWSSigningAlgorithms) {
315                mySupportedJWSSigningAlgorithms = theSupportedJWSSigningAlgorithms;
316        }
317
318        public void addSupportedJWSSigningAlgorithm(String theAlg) {
319                getSupportedJWSSigningAlgorithms().add(theAlg);
320        }
321
322        public String getRevocationEndpoint() {
323                return myRevocationEndpoint;
324        }
325
326        public void setRevocationEndpoint(String theRevocationEndpoint) {
327                myRevocationEndpoint = theRevocationEndpoint;
328        }
329
330        public List<String> getSupportedAuthMethodsForRevocation() {
331                if (mySupportedAuthMethodsForRevocation == null) {
332                        mySupportedAuthMethodsForRevocation = new ArrayList<>();
333                }
334                return mySupportedAuthMethodsForRevocation;
335        }
336
337        public void setSupportedAuthMethodsForRevocation(List<String> theSupportedAuthMethodsForRevocation) {
338                mySupportedAuthMethodsForRevocation = theSupportedAuthMethodsForRevocation;
339        }
340
341        public void addSupportedAuthMethodForRevocation(String theMethod) {
342                getSupportedAuthenticationMethods().add(theMethod);
343        }
344
345        public List<String> getRevocationEndpointSigningAlgorithms() {
346                if (myRevocationEndpointSigningAlgorithms == null) {
347                        myRevocationEndpointSigningAlgorithms = new ArrayList<>();
348                }
349                return myRevocationEndpointSigningAlgorithms;
350        }
351
352        public void setRevocationEndpointSigningAlgorithms(List<String> theRevocationEndpointSigningAlgorithms) {
353                myRevocationEndpointSigningAlgorithms = theRevocationEndpointSigningAlgorithms;
354        }
355
356        public void addRevocationEndpointSigningAlgorithm(String theAlg) {
357                getRevocationEndpointSigningAlgorithms().add(theAlg);
358        }
359
360        public String getIntrospectionEndpoint() {
361                return myIntrospectionEndpoint;
362        }
363
364        public void setIntrospectionEndpoint(String theIntrospectionEndpoint) {
365                myIntrospectionEndpoint = theIntrospectionEndpoint;
366        }
367
368        public List<String> getSupportedIntrospectionEndpointAuthMethods() {
369                if (mySupportedIntrospectionEndpointAuthMethods == null) {
370                        mySupportedIntrospectionEndpointAuthMethods = new ArrayList<>();
371                }
372                return mySupportedIntrospectionEndpointAuthMethods;
373        }
374
375        public void setSupportedIntrospectionEndpointAuthMethods(
376                        List<String> theSupportedIntrospectionEndpointAuthMethods) {
377                mySupportedIntrospectionEndpointAuthMethods = theSupportedIntrospectionEndpointAuthMethods;
378        }
379
380        public void addSupportedIntrospectionEndpointAuthMethod(String theMethod) {
381                getSupportedIntrospectionEndpointAuthMethods().add(theMethod);
382        }
383
384        public String getUserInfoEndpoint() {
385                return myUserInfoEndpoint;
386        }
387
388        public void setUserInfoEndpoint(String theUserInfoEndpoint) {
389                myUserInfoEndpoint = theUserInfoEndpoint;
390        }
391
392        public List<String> getSupportedIdTokenSigningAlgs() {
393                if (mySupportedIdTokenSigningAlgs == null) {
394                        mySupportedIdTokenSigningAlgs = new ArrayList<>();
395                }
396                return mySupportedIdTokenSigningAlgs;
397        }
398
399        public void setSupportedIdTokenSigningAlgs(List<String> theSupportedIdTokenSigningAlgs) {
400                mySupportedIdTokenSigningAlgs = theSupportedIdTokenSigningAlgs;
401        }
402
403        public void addSupportedIdTokenSigningAlg(String theAlg) {
404                getSupportedIdTokenSigningAlgs().add(theAlg);
405        }
406
407        public List<String> getCodeChallengeMethodsSupported() {
408                if (myCodeChallengeMethodsSupported == null) {
409                        myCodeChallengeMethodsSupported = new ArrayList<>();
410                }
411                return myCodeChallengeMethodsSupported;
412        }
413
414        public void setCodeChallengeMethodsSupported(List<String> theCodeChallengeMethodsSupported) {
415                myCodeChallengeMethodsSupported = theCodeChallengeMethodsSupported;
416        }
417
418        public void addCodeChallengeMethodSupported(String theCode) {
419                getCodeChallengeMethodsSupported().add(theCode);
420        }
421
422        public List<String> getSubjectTypesSupported() {
423                if (mySubjectTypesSupported == null) {
424                        mySubjectTypesSupported = new ArrayList<>();
425                }
426                return mySubjectTypesSupported;
427        }
428
429        public void setSubjectTypesSupported(List<String> theSubjectTypesSupported) {
430                mySubjectTypesSupported = theSubjectTypesSupported;
431        }
432
433        public void addSubjectTypeSupported(String theType) {
434                getSubjectTypesSupported().add(theType);
435        }
436
437        @JsonAnySetter
438        public void add(String theProp, Object theVal) {
439                myUnknownProperties.put(theProp, theVal);
440        }
441
442        Map<String, Object> getUnknownProperties() {
443                return myUnknownProperties;
444        }
445
446        Map<String, Object> toMap() {
447                Map<String, Object> map = new HashMap<>();
448                Field[] fields = OpenIdWellKnownOpenIdConfigurationResponse.class.getDeclaredFields();
449
450                try {
451                        for (Field field : fields) {
452                                if (field.isAnnotationPresent(JsonProperty.class)) {
453                                        Object value = field.get(this);
454                                        if (value != null) {
455                                                // we want the names to be whatever's in the json annotation
456                                                JsonProperty jsonProperty = field.getAnnotation(JsonProperty.class);
457                                                String name = jsonProperty.value();
458                                                map.put(name, value);
459                                        }
460                                }
461                        }
462                } catch (IllegalAccessException ex) {
463                        throw new InternalErrorException(ex);
464                }
465
466                map.putAll(myUnknownProperties);
467
468                return map;
469        }
470
471        @Override
472        public String toString() {
473                ObjectMapper mapper = new ObjectMapper();
474                Map<String, Object> map = toMap();
475
476                try {
477                        return mapper.writeValueAsString(map);
478                } catch (JsonProcessingException ex) {
479                        throw new InternalErrorException(ex);
480                }
481        }
482}