mitreid-connect
公開メンバ関数 | 静的公開変数類 | 非公開メンバ関数 | 非公開変数類 | 静的非公開変数類 | 全メンバ一覧
org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint クラス
org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint 連携図
Collaboration graph

公開メンバ関数

String registerNewClient (@RequestBody String jsonString, Model m)
 
String readClientConfiguration (@PathVariable("id") String clientId, Model m, OAuth2Authentication auth)
 
String updateClient (@PathVariable("id") String clientId, @RequestBody String jsonString, Model m, OAuth2Authentication auth)
 
String deleteClient (@PathVariable("id") String clientId, Model m, OAuth2Authentication auth)
 

静的公開変数類

static final String URL = "register"
 

非公開メンバ関数

ClientDetailsEntity validateScopes (ClientDetailsEntity newClient) throws ValidationException
 
ClientDetailsEntity validateResponseTypes (ClientDetailsEntity newClient) throws ValidationException
 
ClientDetailsEntity validateGrantTypes (ClientDetailsEntity newClient) throws ValidationException
 
ClientDetailsEntity validateRedirectUris (ClientDetailsEntity newClient) throws ValidationException
 
ClientDetailsEntity validateAuth (ClientDetailsEntity newClient) throws ValidationException
 
ClientDetailsEntity validateSoftwareStatement (ClientDetailsEntity newClient) throws ValidationException
 
OAuth2AccessTokenEntity rotateRegistrationTokenIfNecessary (OAuth2Authentication auth, ClientDetailsEntity client)
 

非公開変数類

ClientDetailsEntityService clientService
 
OAuth2TokenEntityService tokenService
 
SystemScopeService scopeService
 
BlacklistedSiteService blacklistService
 
ConfigurationPropertiesBean config
 
OIDCTokenService connectTokenService
 
AssertionValidator assertionValidator
 

静的非公開変数類

static final Logger logger = LoggerFactory.getLogger(DynamicClientRegistrationEndpoint.class)
 

詳解

関数詳解

◆ deleteClient()

String org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.deleteClient ( @PathVariable("id") String  clientId,
Model  m,
OAuth2Authentication  auth 
)
inline

Delete the indicated client from the system.

引数
clientId
m
auth
戻り値
417  {
418 
419  ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
420 
421  if (client != null && client.getClientId().equals(auth.getOAuth2Request().getClientId())) {
422 
423  clientService.deleteClient(client);
424 
425  m.addAttribute(HttpCodeView.CODE, HttpStatus.NO_CONTENT); // http 204
426 
427  return HttpCodeView.VIEWNAME;
428  } else {
429  // client mismatch
430  logger.error("readClientConfiguration failed, client ID mismatch: "
431  + clientId + " and " + auth.getOAuth2Request().getClientId() + " do not match.");
432  m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); // http 403
433 
434  return HttpCodeView.VIEWNAME;
435  }
436  }
static final Logger logger
Definition: DynamicClientRegistrationEndpoint.java:144
void deleteClient(ClientDetailsEntity client)
ClientDetailsEntity loadClientByClientId(String clientId)
ClientDetailsEntityService clientService
Definition: DynamicClientRegistrationEndpoint.java:120

◆ readClientConfiguration()

String org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.readClientConfiguration ( @PathVariable("id") String  clientId,
Model  m,
OAuth2Authentication  auth 
)
inline

Get the meta information for a client.

引数
clientId
m
auth
戻り値
281  {
282 
283  ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
284 
285  if (client != null && client.getClientId().equals(auth.getOAuth2Request().getClientId())) {
286 
287  try {
288  OAuth2AccessTokenEntity token = rotateRegistrationTokenIfNecessary(auth, client);
289  RegisteredClient registered = new RegisteredClient(client, token.getValue(), config.getIssuer() + "register/" + UriUtils.encodePathSegment(client.getClientId(), "UTF-8"));
290 
291  // send it all out to the view
292  m.addAttribute("client", registered);
293  m.addAttribute(HttpCodeView.CODE, HttpStatus.OK); // http 200
294 
295  return ClientInformationResponseView.VIEWNAME;
296  } catch (UnsupportedEncodingException e) {
297  logger.error("Unsupported encoding", e);
298  m.addAttribute(HttpCodeView.CODE, HttpStatus.INTERNAL_SERVER_ERROR);
299  return HttpCodeView.VIEWNAME;
300  }
301 
302  } else {
303  // client mismatch
304  logger.error("readClientConfiguration failed, client ID mismatch: "
305  + clientId + " and " + auth.getOAuth2Request().getClientId() + " do not match.");
306  m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); // http 403
307 
308  return HttpCodeView.VIEWNAME;
309  }
310  }
OAuth2AccessTokenEntity rotateRegistrationTokenIfNecessary(OAuth2Authentication auth, ClientDetailsEntity client)
Definition: DynamicClientRegistrationEndpoint.java:756
ConfigurationPropertiesBean config
Definition: DynamicClientRegistrationEndpoint.java:132
static final Logger logger
Definition: DynamicClientRegistrationEndpoint.java:144
ClientDetailsEntity loadClientByClientId(String clientId)
String getIssuer()
Definition: ConfigurationPropertiesBean.java:100
ClientDetailsEntityService clientService
Definition: DynamicClientRegistrationEndpoint.java:120

◆ registerNewClient()

String org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.registerNewClient ( @RequestBody String  jsonString,
Model  m 
)
inline

Create a new Client, issue a client ID, and create a registration access token.

引数
jsonString
m
p
戻り値
154  {
155 
156  ClientDetailsEntity newClient = null;
157  try {
158  newClient = ClientDetailsEntityJsonProcessor.parse(jsonString);
159  } catch (JsonSyntaxException e) {
160  // bad parse
161  // didn't parse, this is a bad request
162  logger.error("registerNewClient failed; submitted JSON is malformed");
163  m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); // http 400
164  return HttpCodeView.VIEWNAME;
165  }
166 
167  if (newClient != null) {
168  // it parsed!
169 
170  //
171  // Now do some post-processing consistency checks on it
172  //
173 
174  // clear out any spurious id/secret (clients don't get to pick)
175  newClient.setClientId(null);
176  newClient.setClientSecret(null);
177 
178  // do validation on the fields
179  try {
180  newClient = validateSoftwareStatement(newClient); // need to handle the software statement first because it might override requested values
181  newClient = validateScopes(newClient);
182  newClient = validateResponseTypes(newClient);
183  newClient = validateGrantTypes(newClient);
184  newClient = validateRedirectUris(newClient);
185  newClient = validateAuth(newClient);
186  } catch (ValidationException ve) {
187  // validation failed, return an error
188  m.addAttribute(JsonErrorView.ERROR, ve.getError());
189  m.addAttribute(JsonErrorView.ERROR_MESSAGE, ve.getErrorDescription());
190  m.addAttribute(HttpCodeView.CODE, ve.getStatus());
191  return JsonErrorView.VIEWNAME;
192  }
193 
194  if (newClient.getTokenEndpointAuthMethod() == null) {
195  newClient.setTokenEndpointAuthMethod(AuthMethod.SECRET_BASIC);
196  }
197 
198  if (newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_BASIC ||
199  newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_JWT ||
200  newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_POST) {
201 
202  // we need to generate a secret
203  newClient = clientService.generateClientSecret(newClient);
204  }
205 
206  // set some defaults for token timeouts
207  if (config.isHeartMode()) {
208  // heart mode has different defaults depending on primary grant type
209  if (newClient.getGrantTypes().contains("authorization_code")) {
210  newClient.setAccessTokenValiditySeconds((int)TimeUnit.HOURS.toSeconds(1)); // access tokens good for 1hr
211  newClient.setIdTokenValiditySeconds((int)TimeUnit.MINUTES.toSeconds(5)); // id tokens good for 5min
212  newClient.setRefreshTokenValiditySeconds((int)TimeUnit.HOURS.toSeconds(24)); // refresh tokens good for 24hr
213  } else if (newClient.getGrantTypes().contains("implicit")) {
214  newClient.setAccessTokenValiditySeconds((int)TimeUnit.MINUTES.toSeconds(15)); // access tokens good for 15min
215  newClient.setIdTokenValiditySeconds((int)TimeUnit.MINUTES.toSeconds(5)); // id tokens good for 5min
216  newClient.setRefreshTokenValiditySeconds(0); // no refresh tokens
217  } else if (newClient.getGrantTypes().contains("client_credentials")) {
218  newClient.setAccessTokenValiditySeconds((int)TimeUnit.HOURS.toSeconds(6)); // access tokens good for 6hr
219  newClient.setIdTokenValiditySeconds(0); // no id tokens
220  newClient.setRefreshTokenValiditySeconds(0); // no refresh tokens
221  }
222  } else {
223  newClient.setAccessTokenValiditySeconds((int)TimeUnit.HOURS.toSeconds(1)); // access tokens good for 1hr
224  newClient.setIdTokenValiditySeconds((int)TimeUnit.MINUTES.toSeconds(10)); // id tokens good for 10min
225  newClient.setRefreshTokenValiditySeconds(null); // refresh tokens good until revoked
226  }
227 
228  // this client has been dynamically registered (obviously)
229  newClient.setDynamicallyRegistered(true);
230 
231  // this client can't do token introspection
232  newClient.setAllowIntrospection(false);
233 
234  // now save it
235  try {
236  ClientDetailsEntity savedClient = clientService.saveNewClient(newClient);
237 
238  // generate the registration access token
239  OAuth2AccessTokenEntity token = connectTokenService.createRegistrationAccessToken(savedClient);
240  token = tokenService.saveAccessToken(token);
241 
242  // send it all out to the view
243 
244  RegisteredClient registered = new RegisteredClient(savedClient, token.getValue(), config.getIssuer() + "register/" + UriUtils.encodePathSegment(savedClient.getClientId(), "UTF-8"));
245  m.addAttribute("client", registered);
246  m.addAttribute(HttpCodeView.CODE, HttpStatus.CREATED); // http 201
247 
248  return ClientInformationResponseView.VIEWNAME;
249  } catch (UnsupportedEncodingException e) {
250  logger.error("Unsupported encoding", e);
251  m.addAttribute(HttpCodeView.CODE, HttpStatus.INTERNAL_SERVER_ERROR);
252  return HttpCodeView.VIEWNAME;
253  } catch (IllegalArgumentException e) {
254  logger.error("Couldn't save client", e);
255 
256  m.addAttribute(JsonErrorView.ERROR, "invalid_client_metadata");
257  m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Unable to save client due to invalid or inconsistent metadata.");
258  m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); // http 400
259 
260  return JsonErrorView.VIEWNAME;
261  }
262  } else {
263  // didn't parse, this is a bad request
264  logger.error("registerNewClient failed; submitted JSON is malformed");
265  m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); // http 400
266 
267  return HttpCodeView.VIEWNAME;
268  }
269 
270  }
OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity accessToken)
ClientDetailsEntity saveNewClient(ClientDetailsEntity client)
ConfigurationPropertiesBean config
Definition: DynamicClientRegistrationEndpoint.java:132
static final Logger logger
Definition: DynamicClientRegistrationEndpoint.java:144
ClientDetailsEntity validateGrantTypes(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:462
ClientDetailsEntity validateSoftwareStatement(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:614
void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds)
Definition: ClientDetailsEntity.java:511
ClientDetailsEntity validateScopes(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:438
ClientDetailsEntity validateRedirectUris(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:557
OAuth2TokenEntityService tokenService
Definition: DynamicClientRegistrationEndpoint.java:123
ClientDetailsEntity validateResponseTypes(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:455
OAuth2AccessTokenEntity createRegistrationAccessToken(ClientDetailsEntity client)
ClientDetailsEntity generateClientSecret(ClientDetailsEntity client)
ClientDetailsEntity validateAuth(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:581
OIDCTokenService connectTokenService
Definition: DynamicClientRegistrationEndpoint.java:135
String getIssuer()
Definition: ConfigurationPropertiesBean.java:100
boolean isHeartMode()
Definition: ConfigurationPropertiesBean.java:250
ClientDetailsEntityService clientService
Definition: DynamicClientRegistrationEndpoint.java:120

◆ rotateRegistrationTokenIfNecessary()

OAuth2AccessTokenEntity org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.rotateRegistrationTokenIfNecessary ( OAuth2Authentication  auth,
ClientDetailsEntity  client 
)
inlineprivate
756  {
757 
758  OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) auth.getDetails();
759  OAuth2AccessTokenEntity token = tokenService.readAccessToken(details.getTokenValue());
760 
761  if (config.getRegTokenLifeTime() != null) {
762 
763  try {
764  // Re-issue the token if it has been issued before [currentTime - validity]
765  Date validToDate = new Date(System.currentTimeMillis() - config.getRegTokenLifeTime() * 1000);
766  if(token.getJwt().getJWTClaimsSet().getIssueTime().before(validToDate)) {
767  logger.info("Rotating the registration access token for " + client.getClientId());
769  OAuth2AccessTokenEntity newToken = connectTokenService.createRegistrationAccessToken(client);
770  tokenService.saveAccessToken(newToken);
771  return newToken;
772  } else {
773  // it's not expired, keep going
774  return token;
775  }
776  } catch (ParseException e) {
777  logger.error("Couldn't parse a known-valid token?", e);
778  return token;
779  }
780  } else {
781  // tokens don't expire, just return it
782  return token;
783  }
784  }
OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity accessToken)
ConfigurationPropertiesBean config
Definition: DynamicClientRegistrationEndpoint.java:132
static final Logger logger
Definition: DynamicClientRegistrationEndpoint.java:144
Long getRegTokenLifeTime()
Definition: ConfigurationPropertiesBean.java:153
OAuth2TokenEntityService tokenService
Definition: DynamicClientRegistrationEndpoint.java:123
OAuth2AccessTokenEntity createRegistrationAccessToken(ClientDetailsEntity client)
OAuth2AccessTokenEntity readAccessToken(String accessTokenValue)
OIDCTokenService connectTokenService
Definition: DynamicClientRegistrationEndpoint.java:135
void revokeAccessToken(OAuth2AccessTokenEntity accessToken)

◆ updateClient()

String org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.updateClient ( @PathVariable("id") String  clientId,
@RequestBody String  jsonString,
Model  m,
OAuth2Authentication  auth 
)
inline

Update the metainformation for a given client.

引数
clientId
jsonString
m
auth
戻り値
322  {
323 
324 
325  ClientDetailsEntity newClient = null;
326  try {
327  newClient = ClientDetailsEntityJsonProcessor.parse(jsonString);
328  } catch (JsonSyntaxException e) {
329  // bad parse
330  // didn't parse, this is a bad request
331  logger.error("updateClient failed; submitted JSON is malformed");
332  m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); // http 400
333  return HttpCodeView.VIEWNAME;
334  }
335  ClientDetailsEntity oldClient = clientService.loadClientByClientId(clientId);
336 
337  if (newClient != null && oldClient != null // we have an existing client and the new one parsed
338  && oldClient.getClientId().equals(auth.getOAuth2Request().getClientId()) // the client passed in the URI matches the one in the auth
339  && oldClient.getClientId().equals(newClient.getClientId()) // the client passed in the body matches the one in the URI
340  ) {
341 
342  // a client can't ask to update its own client secret to any particular value
343  newClient.setClientSecret(oldClient.getClientSecret());
344 
345  // we need to copy over all of the local and SECOAUTH fields
346  newClient.setAccessTokenValiditySeconds(oldClient.getAccessTokenValiditySeconds());
347  newClient.setIdTokenValiditySeconds(oldClient.getIdTokenValiditySeconds());
348  newClient.setRefreshTokenValiditySeconds(oldClient.getRefreshTokenValiditySeconds());
349  newClient.setDynamicallyRegistered(true); // it's still dynamically registered
350  newClient.setAllowIntrospection(false); // dynamically registered clients can't do introspection -- use the resource registration instead
351  newClient.setAuthorities(oldClient.getAuthorities());
352  newClient.setClientDescription(oldClient.getClientDescription());
353  newClient.setCreatedAt(oldClient.getCreatedAt());
354  newClient.setReuseRefreshToken(oldClient.isReuseRefreshToken());
355 
356  // do validation on the fields
357  try {
358  newClient = validateSoftwareStatement(newClient); // need to handle the software statement first because it might override requested values
359  newClient = validateScopes(newClient);
360  newClient = validateResponseTypes(newClient);
361  newClient = validateGrantTypes(newClient);
362  newClient = validateRedirectUris(newClient);
363  newClient = validateAuth(newClient);
364  } catch (ValidationException ve) {
365  // validation failed, return an error
366  m.addAttribute(JsonErrorView.ERROR, ve.getError());
367  m.addAttribute(JsonErrorView.ERROR_MESSAGE, ve.getErrorDescription());
368  m.addAttribute(HttpCodeView.CODE, ve.getStatus());
369  return JsonErrorView.VIEWNAME;
370  }
371 
372  try {
373  // save the client
374  ClientDetailsEntity savedClient = clientService.updateClient(oldClient, newClient);
375 
376  OAuth2AccessTokenEntity token = rotateRegistrationTokenIfNecessary(auth, savedClient);
377 
378  RegisteredClient registered = new RegisteredClient(savedClient, token.getValue(), config.getIssuer() + "register/" + UriUtils.encodePathSegment(savedClient.getClientId(), "UTF-8"));
379 
380  // send it all out to the view
381  m.addAttribute("client", registered);
382  m.addAttribute(HttpCodeView.CODE, HttpStatus.OK); // http 200
383 
384  return ClientInformationResponseView.VIEWNAME;
385  } catch (UnsupportedEncodingException e) {
386  logger.error("Unsupported encoding", e);
387  m.addAttribute(HttpCodeView.CODE, HttpStatus.INTERNAL_SERVER_ERROR);
388  return HttpCodeView.VIEWNAME;
389  } catch (IllegalArgumentException e) {
390  logger.error("Couldn't save client", e);
391 
392  m.addAttribute(JsonErrorView.ERROR, "invalid_client_metadata");
393  m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Unable to save client due to invalid or inconsistent metadata.");
394  m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); // http 400
395 
396  return JsonErrorView.VIEWNAME;
397  }
398  } else {
399  // client mismatch
400  logger.error("updateClient failed, client ID mismatch: "
401  + clientId + " and " + auth.getOAuth2Request().getClientId() + " do not match.");
402  m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); // http 403
403 
404  return HttpCodeView.VIEWNAME;
405  }
406  }
OAuth2AccessTokenEntity rotateRegistrationTokenIfNecessary(OAuth2Authentication auth, ClientDetailsEntity client)
Definition: DynamicClientRegistrationEndpoint.java:756
void setClientSecret(String clientSecret)
Definition: ClientDetailsEntity.java:425
ConfigurationPropertiesBean config
Definition: DynamicClientRegistrationEndpoint.java:132
static final Logger logger
Definition: DynamicClientRegistrationEndpoint.java:144
ClientDetailsEntity validateGrantTypes(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:462
ClientDetailsEntity updateClient(ClientDetailsEntity oldClient, ClientDetailsEntity newClient)
ClientDetailsEntity validateSoftwareStatement(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:614
ClientDetailsEntity validateScopes(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:438
ClientDetailsEntity validateRedirectUris(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:557
ClientDetailsEntity validateResponseTypes(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:455
ClientDetailsEntity validateAuth(ClientDetailsEntity newClient)
Definition: DynamicClientRegistrationEndpoint.java:581
ClientDetailsEntity loadClientByClientId(String clientId)
String getIssuer()
Definition: ConfigurationPropertiesBean.java:100
ClientDetailsEntityService clientService
Definition: DynamicClientRegistrationEndpoint.java:120

◆ validateAuth()

ClientDetailsEntity org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.validateAuth ( ClientDetailsEntity  newClient) throws ValidationException
inlineprivate
581  {
582  if (newClient.getTokenEndpointAuthMethod() == null) {
583  newClient.setTokenEndpointAuthMethod(AuthMethod.SECRET_BASIC);
584  }
585 
586  if (newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_BASIC ||
587  newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_JWT ||
588  newClient.getTokenEndpointAuthMethod() == AuthMethod.SECRET_POST) {
589 
590  if (Strings.isNullOrEmpty(newClient.getClientSecret())) {
591  // no secret yet, we need to generate a secret
592  newClient = clientService.generateClientSecret(newClient);
593  }
594  } else if (newClient.getTokenEndpointAuthMethod() == AuthMethod.PRIVATE_KEY) {
595  if (Strings.isNullOrEmpty(newClient.getJwksUri()) && newClient.getJwks() == null) {
596  throw new ValidationException("invalid_client_metadata", "JWK Set URI required when using private key authentication", HttpStatus.BAD_REQUEST);
597  }
598 
599  newClient.setClientSecret(null);
600  } else if (newClient.getTokenEndpointAuthMethod() == AuthMethod.NONE) {
601  newClient.setClientSecret(null);
602  } else {
603  throw new ValidationException("invalid_client_metadata", "Unknown authentication method", HttpStatus.BAD_REQUEST);
604  }
605  return newClient;
606  }
ClientDetailsEntity generateClientSecret(ClientDetailsEntity client)
ClientDetailsEntityService clientService
Definition: DynamicClientRegistrationEndpoint.java:120

◆ validateGrantTypes()

ClientDetailsEntity org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.validateGrantTypes ( ClientDetailsEntity  newClient) throws ValidationException
inlineprivate
462  {
463  // set default grant types if needed
464  if (newClient.getGrantTypes() == null || newClient.getGrantTypes().isEmpty()) {
465  if (newClient.getScope().contains("offline_access")) { // client asked for offline access
466  newClient.setGrantTypes(Sets.newHashSet("authorization_code", "refresh_token")); // allow authorization code and refresh token grant types by default
467  } else {
468  newClient.setGrantTypes(Sets.newHashSet("authorization_code")); // allow authorization code grant type by default
469  }
470  if (config.isDualClient()) {
471  Set<String> extendedGrandTypes = newClient.getGrantTypes();
472  extendedGrandTypes.add("client_credentials");
473  newClient.setGrantTypes(extendedGrandTypes);
474  }
475  }
476 
477  // filter out unknown grant types
478  // TODO: make this a pluggable service
479  Set<String> requestedGrantTypes = new HashSet<>(newClient.getGrantTypes());
480  requestedGrantTypes.retainAll(
481  ImmutableSet.of("authorization_code", "implicit",
482  "password", "client_credentials", "refresh_token",
483  "urn:ietf:params:oauth:grant_type:redelegate"));
484 
485  // don't allow "password" grant type for dynamic registration
486  if (newClient.getGrantTypes().contains("password")) {
487  // return an error, you can't dynamically register for the password grant
488  throw new ValidationException("invalid_client_metadata", "The password grant type is not allowed in dynamic registration on this server.", HttpStatus.BAD_REQUEST);
489  }
490 
491  // don't allow clients to have multiple incompatible grant types and scopes
492  if (newClient.getGrantTypes().contains("authorization_code")) {
493 
494  // check for incompatible grants
495  if (newClient.getGrantTypes().contains("implicit") ||
496  (!config.isDualClient() && newClient.getGrantTypes().contains("client_credentials"))) {
497  // return an error, you can't have these grant types together
498  throw new ValidationException("invalid_client_metadata", "Incompatible grant types requested: " + newClient.getGrantTypes(), HttpStatus.BAD_REQUEST);
499  }
500 
501  if (newClient.getResponseTypes().contains("token")) {
502  // return an error, you can't have this grant type and response type together
503  throw new ValidationException("invalid_client_metadata", "Incompatible response types requested: " + newClient.getGrantTypes() + " / " + newClient.getResponseTypes(), HttpStatus.BAD_REQUEST);
504  }
505 
506  newClient.getResponseTypes().add("code");
507  }
508 
509  if (newClient.getGrantTypes().contains("implicit")) {
510 
511  // check for incompatible grants
512  if (newClient.getGrantTypes().contains("authorization_code") ||
513  (!config.isDualClient() && newClient.getGrantTypes().contains("client_credentials"))) {
514  // return an error, you can't have these grant types together
515  throw new ValidationException("invalid_client_metadata", "Incompatible grant types requested: " + newClient.getGrantTypes(), HttpStatus.BAD_REQUEST);
516  }
517 
518  if (newClient.getResponseTypes().contains("code")) {
519  // return an error, you can't have this grant type and response type together
520  throw new ValidationException("invalid_client_metadata", "Incompatible response types requested: " + newClient.getGrantTypes() + " / " + newClient.getResponseTypes(), HttpStatus.BAD_REQUEST);
521  }
522 
523  newClient.getResponseTypes().add("token");
524 
525  // don't allow refresh tokens in implicit clients
526  newClient.getGrantTypes().remove("refresh_token");
527  newClient.getScope().remove(SystemScopeService.OFFLINE_ACCESS);
528  }
529 
530  if (newClient.getGrantTypes().contains("client_credentials")) {
531 
532  // check for incompatible grants
533  if (!config.isDualClient() &&
534  (newClient.getGrantTypes().contains("authorization_code") || newClient.getGrantTypes().contains("implicit"))) {
535  // return an error, you can't have these grant types together
536  throw new ValidationException("invalid_client_metadata", "Incompatible grant types requested: " + newClient.getGrantTypes(), HttpStatus.BAD_REQUEST);
537  }
538 
539  if (!newClient.getResponseTypes().isEmpty()) {
540  // return an error, you can't have this grant type and response type together
541  throw new ValidationException("invalid_client_metadata", "Incompatible response types requested: " + newClient.getGrantTypes() + " / " + newClient.getResponseTypes(), HttpStatus.BAD_REQUEST);
542  }
543 
544  // don't allow refresh tokens or id tokens in client_credentials clients
545  newClient.getGrantTypes().remove("refresh_token");
546  newClient.getScope().remove(SystemScopeService.OFFLINE_ACCESS);
547  newClient.getScope().remove(SystemScopeService.OPENID_SCOPE);
548  }
549 
550  if (newClient.getGrantTypes().isEmpty()) {
551  // return an error, you need at least one grant type selected
552  throw new ValidationException("invalid_client_metadata", "Clients must register at least one grant type.", HttpStatus.BAD_REQUEST);
553  }
554  return newClient;
555  }
boolean isDualClient()
Definition: ConfigurationPropertiesBean.java:217
ConfigurationPropertiesBean config
Definition: DynamicClientRegistrationEndpoint.java:132

◆ validateRedirectUris()

ClientDetailsEntity org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.validateRedirectUris ( ClientDetailsEntity  newClient) throws ValidationException
inlineprivate
557  {
558  // check to make sure this client registered a redirect URI if using a redirect flow
559  if (newClient.getGrantTypes().contains("authorization_code") || newClient.getGrantTypes().contains("implicit")) {
560  if (newClient.getRedirectUris() == null || newClient.getRedirectUris().isEmpty()) {
561  // return an error
562  throw new ValidationException("invalid_redirect_uri", "Clients using a redirect-based grant type must register at least one redirect URI.", HttpStatus.BAD_REQUEST);
563  }
564 
565  for (String uri : newClient.getRedirectUris()) {
566  if (blacklistService.isBlacklisted(uri)) {
567  // return an error
568  throw new ValidationException("invalid_redirect_uri", "Redirect URI is not allowed: " + uri, HttpStatus.BAD_REQUEST);
569  }
570 
571  if (uri.contains("#")) {
572  // if it contains the hash symbol then it has a fragment, which isn't allowed
573  throw new ValidationException("invalid_redirect_uri", "Redirect URI can not have a fragment", HttpStatus.BAD_REQUEST);
574  }
575  }
576  }
577 
578  return newClient;
579  }
BlacklistedSiteService blacklistService
Definition: DynamicClientRegistrationEndpoint.java:129

◆ validateResponseTypes()

ClientDetailsEntity org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.validateResponseTypes ( ClientDetailsEntity  newClient) throws ValidationException
inlineprivate
455  {
456  if (newClient.getResponseTypes() == null) {
457  newClient.setResponseTypes(new HashSet<String>());
458  }
459  return newClient;
460  }

◆ validateScopes()

ClientDetailsEntity org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.validateScopes ( ClientDetailsEntity  newClient) throws ValidationException
inlineprivate
438  {
439  // scopes that the client is asking for
440  Set<SystemScope> requestedScopes = scopeService.fromStrings(newClient.getScope());
441 
442  // the scopes that the client can have must be a subset of the dynamically allowed scopes
443  Set<SystemScope> allowedScopes = scopeService.removeRestrictedAndReservedScopes(requestedScopes);
444 
445  // if the client didn't ask for any, give them the defaults
446  if (allowedScopes == null || allowedScopes.isEmpty()) {
447  allowedScopes = scopeService.getDefaults();
448  }
449 
450  newClient.setScope(scopeService.toStrings(allowedScopes));
451 
452  return newClient;
453  }
SystemScopeService scopeService
Definition: DynamicClientRegistrationEndpoint.java:126
Set< SystemScope > removeRestrictedAndReservedScopes(Set< SystemScope > scopes)
Set< SystemScope > fromStrings(Set< String > scope)
Set< String > toStrings(Set< SystemScope > scope)

◆ validateSoftwareStatement()

ClientDetailsEntity org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.validateSoftwareStatement ( ClientDetailsEntity  newClient) throws ValidationException
inlineprivate
引数
newClient
戻り値
例外
ValidationException
614  {
615  if (newClient.getSoftwareStatement() != null) {
616  if (assertionValidator.isValid(newClient.getSoftwareStatement())) {
617  // we have a software statement and its envelope passed all the checks from our validator
618 
619  // swap out all of the client's fields for the associated parts of the software statement
620  try {
621  JWTClaimsSet claimSet = newClient.getSoftwareStatement().getJWTClaimsSet();
622  for (String claim : claimSet.getClaims().keySet()) {
623  switch (claim) {
624  case SOFTWARE_STATEMENT:
625  throw new ValidationException("invalid_client_metadata", "Software statement can't include another software statement", HttpStatus.BAD_REQUEST);
626  case CLAIMS_REDIRECT_URIS:
627  newClient.setClaimsRedirectUris(Sets.newHashSet(claimSet.getStringListClaim(claim)));
628  break;
629  case CLIENT_SECRET_EXPIRES_AT:
630  throw new ValidationException("invalid_client_metadata", "Software statement can't include a client secret expiration time", HttpStatus.BAD_REQUEST);
631  case CLIENT_ID_ISSUED_AT:
632  throw new ValidationException("invalid_client_metadata", "Software statement can't include a client ID issuance time", HttpStatus.BAD_REQUEST);
633  case REGISTRATION_CLIENT_URI:
634  throw new ValidationException("invalid_client_metadata", "Software statement can't include a client configuration endpoint", HttpStatus.BAD_REQUEST);
635  case REGISTRATION_ACCESS_TOKEN:
636  throw new ValidationException("invalid_client_metadata", "Software statement can't include a client registration access token", HttpStatus.BAD_REQUEST);
637  case REQUEST_URIS:
638  newClient.setRequestUris(Sets.newHashSet(claimSet.getStringListClaim(claim)));
639  break;
640  case POST_LOGOUT_REDIRECT_URIS:
641  newClient.setPostLogoutRedirectUris(Sets.newHashSet(claimSet.getStringListClaim(claim)));
642  break;
643  case INITIATE_LOGIN_URI:
644  newClient.setInitiateLoginUri(claimSet.getStringClaim(claim));
645  break;
646  case DEFAULT_ACR_VALUES:
647  newClient.setDefaultACRvalues(Sets.newHashSet(claimSet.getStringListClaim(claim)));
648  break;
649  case REQUIRE_AUTH_TIME:
650  newClient.setRequireAuthTime(claimSet.getBooleanClaim(claim));
651  break;
652  case DEFAULT_MAX_AGE:
653  newClient.setDefaultMaxAge(claimSet.getIntegerClaim(claim));
654  break;
655  case TOKEN_ENDPOINT_AUTH_SIGNING_ALG:
656  newClient.setTokenEndpointAuthSigningAlg(JWSAlgorithm.parse(claimSet.getStringClaim(claim)));
657  break;
658  case ID_TOKEN_ENCRYPTED_RESPONSE_ENC:
659  newClient.setIdTokenEncryptedResponseEnc(EncryptionMethod.parse(claimSet.getStringClaim(claim)));
660  break;
661  case ID_TOKEN_ENCRYPTED_RESPONSE_ALG:
662  newClient.setIdTokenEncryptedResponseAlg(JWEAlgorithm.parse(claimSet.getStringClaim(claim)));
663  break;
664  case ID_TOKEN_SIGNED_RESPONSE_ALG:
665  newClient.setIdTokenSignedResponseAlg(JWSAlgorithm.parse(claimSet.getStringClaim(claim)));
666  break;
667  case USERINFO_ENCRYPTED_RESPONSE_ENC:
668  newClient.setUserInfoEncryptedResponseEnc(EncryptionMethod.parse(claimSet.getStringClaim(claim)));
669  break;
670  case USERINFO_ENCRYPTED_RESPONSE_ALG:
671  newClient.setUserInfoEncryptedResponseAlg(JWEAlgorithm.parse(claimSet.getStringClaim(claim)));
672  break;
673  case USERINFO_SIGNED_RESPONSE_ALG:
674  newClient.setUserInfoSignedResponseAlg(JWSAlgorithm.parse(claimSet.getStringClaim(claim)));
675  break;
676  case REQUEST_OBJECT_SIGNING_ALG:
677  newClient.setRequestObjectSigningAlg(JWSAlgorithm.parse(claimSet.getStringClaim(claim)));
678  break;
679  case SUBJECT_TYPE:
680  newClient.setSubjectType(SubjectType.getByValue(claimSet.getStringClaim(claim)));
681  break;
682  case SECTOR_IDENTIFIER_URI:
683  newClient.setSectorIdentifierUri(claimSet.getStringClaim(claim));
684  break;
685  case APPLICATION_TYPE:
686  newClient.setApplicationType(AppType.getByValue(claimSet.getStringClaim(claim)));
687  break;
688  case JWKS_URI:
689  newClient.setJwksUri(claimSet.getStringClaim(claim));
690  break;
691  case JWKS:
692  newClient.setJwks(JWKSet.parse(claimSet.getJSONObjectClaim(claim).toJSONString()));
693  break;
694  case POLICY_URI:
695  newClient.setPolicyUri(claimSet.getStringClaim(claim));
696  break;
697  case RESPONSE_TYPES:
698  newClient.setResponseTypes(Sets.newHashSet(claimSet.getStringListClaim(claim)));
699  break;
700  case GRANT_TYPES:
701  newClient.setGrantTypes(Sets.newHashSet(claimSet.getStringListClaim(claim)));
702  break;
703  case SCOPE:
704  newClient.setScope(OAuth2Utils.parseParameterList(claimSet.getStringClaim(claim)));
705  break;
706  case TOKEN_ENDPOINT_AUTH_METHOD:
707  newClient.setTokenEndpointAuthMethod(AuthMethod.getByValue(claimSet.getStringClaim(claim)));
708  break;
709  case TOS_URI:
710  newClient.setTosUri(claimSet.getStringClaim(claim));
711  break;
712  case CONTACTS:
713  newClient.setContacts(Sets.newHashSet(claimSet.getStringListClaim(claim)));
714  break;
715  case LOGO_URI:
716  newClient.setLogoUri(claimSet.getStringClaim(claim));
717  break;
718  case CLIENT_URI:
719  newClient.setClientUri(claimSet.getStringClaim(claim));
720  break;
721  case CLIENT_NAME:
722  newClient.setClientName(claimSet.getStringClaim(claim));
723  break;
724  case REDIRECT_URIS:
725  newClient.setRedirectUris(Sets.newHashSet(claimSet.getStringListClaim(claim)));
726  break;
727  case CLIENT_SECRET:
728  throw new ValidationException("invalid_client_metadata", "Software statement can't contain client secret", HttpStatus.BAD_REQUEST);
729  case CLIENT_ID:
730  throw new ValidationException("invalid_client_metadata", "Software statement can't contain client ID", HttpStatus.BAD_REQUEST);
731 
732  default:
733  logger.warn("Software statement contained unknown field: " + claim + " with value " + claimSet.getClaim(claim));
734  break;
735  }
736  }
737 
738  return newClient;
739  } catch (ParseException e) {
740  throw new ValidationException("invalid_client_metadata", "Software statement claims didn't parse", HttpStatus.BAD_REQUEST);
741  }
742  } else {
743  throw new ValidationException("invalid_client_metadata", "Software statement rejected by validator", HttpStatus.BAD_REQUEST);
744  }
745  } else {
746  // nothing to see here, carry on
747  return newClient;
748  }
749 
750  }
static final Logger logger
Definition: DynamicClientRegistrationEndpoint.java:144
AssertionValidator assertionValidator
Definition: DynamicClientRegistrationEndpoint.java:139

メンバ詳解

◆ assertionValidator

AssertionValidator org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.assertionValidator
private

◆ blacklistService

BlacklistedSiteService org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.blacklistService
private

◆ clientService

ClientDetailsEntityService org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.clientService
private

◆ config

ConfigurationPropertiesBean org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.config
private

◆ connectTokenService

OIDCTokenService org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.connectTokenService
private

◆ logger

final Logger org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.logger = LoggerFactory.getLogger(DynamicClientRegistrationEndpoint.class)
staticprivate

Logger for this class

◆ scopeService

SystemScopeService org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.scopeService
private

◆ tokenService

OAuth2TokenEntityService org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.tokenService
private

◆ URL

final String org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint.URL = "register"
static

このクラス詳解は次のファイルから抽出されました: