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}