PageRenderTime 124ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/openid-connect-server/src/main/java/org/mitre/oauth2/web/IntrospectionEndpoint.java

https://gitlab.com/jslee1/OpenID-Connect-Java-Spring-Server
Java | 210 lines | 123 code | 49 blank | 38 comment | 12 complexity | cd00dbc104f3f7d217fcebff0d5ecece MD5 | raw file
  1. /*******************************************************************************
  2. * Copyright 2016 The MITRE Corporation
  3. * and the MIT Internet Trust Consortium
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *******************************************************************************/
  17. package org.mitre.oauth2.web;
  18. import java.util.Collection;
  19. import java.util.HashSet;
  20. import java.util.Map;
  21. import java.util.Set;
  22. import org.mitre.oauth2.model.ClientDetailsEntity;
  23. import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
  24. import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
  25. import org.mitre.oauth2.service.ClientDetailsEntityService;
  26. import org.mitre.oauth2.service.IntrospectionResultAssembler;
  27. import org.mitre.oauth2.service.OAuth2TokenEntityService;
  28. import org.mitre.oauth2.service.SystemScopeService;
  29. import org.mitre.openid.connect.model.UserInfo;
  30. import org.mitre.openid.connect.service.UserInfoService;
  31. import org.mitre.openid.connect.view.HttpCodeView;
  32. import org.mitre.openid.connect.view.JsonEntityView;
  33. import org.mitre.uma.model.ResourceSet;
  34. import org.mitre.uma.service.ResourceSetService;
  35. import org.slf4j.Logger;
  36. import org.slf4j.LoggerFactory;
  37. import org.springframework.beans.factory.annotation.Autowired;
  38. import org.springframework.http.HttpStatus;
  39. import org.springframework.security.core.Authentication;
  40. import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
  41. import org.springframework.security.oauth2.provider.OAuth2Authentication;
  42. import org.springframework.stereotype.Controller;
  43. import org.springframework.ui.Model;
  44. import org.springframework.web.bind.annotation.RequestMapping;
  45. import org.springframework.web.bind.annotation.RequestParam;
  46. import com.google.common.base.Strings;
  47. import com.google.common.collect.ImmutableMap;
  48. import static org.mitre.oauth2.web.AuthenticationUtilities.ensureOAuthScope;
  49. @Controller
  50. public class IntrospectionEndpoint {
  51. /**
  52. *
  53. */
  54. public static final String URL = "introspect";
  55. @Autowired
  56. private OAuth2TokenEntityService tokenServices;
  57. @Autowired
  58. private ClientDetailsEntityService clientService;
  59. @Autowired
  60. private IntrospectionResultAssembler introspectionResultAssembler;
  61. @Autowired
  62. private UserInfoService userInfoService;
  63. @Autowired
  64. private ResourceSetService resourceSetService;
  65. /**
  66. * Logger for this class
  67. */
  68. private static final Logger logger = LoggerFactory.getLogger(IntrospectionEndpoint.class);
  69. public IntrospectionEndpoint() {
  70. }
  71. public IntrospectionEndpoint(OAuth2TokenEntityService tokenServices) {
  72. this.tokenServices = tokenServices;
  73. }
  74. @RequestMapping("/" + URL)
  75. public String verify(@RequestParam("token") String tokenValue,
  76. @RequestParam(value = "token_type_hint", required = false) String tokenType,
  77. Authentication auth, Model model) {
  78. ClientDetailsEntity authClient = null;
  79. Set<String> authScopes = new HashSet<>();
  80. if (auth instanceof OAuth2Authentication) {
  81. // the client authenticated with OAuth, do our UMA checks
  82. ensureOAuthScope(auth, SystemScopeService.UMA_PROTECTION_SCOPE);
  83. // get out the client that was issued the access token (not the token being introspected)
  84. OAuth2Authentication o2a = (OAuth2Authentication) auth;
  85. String authClientId = o2a.getOAuth2Request().getClientId();
  86. authClient = clientService.loadClientByClientId(authClientId);
  87. // the owner is the user who authorized the token in the first place
  88. String ownerId = o2a.getUserAuthentication().getName();
  89. authScopes.addAll(authClient.getScope());
  90. // UMA style clients also get a subset of scopes of all the resource sets they've registered
  91. Collection<ResourceSet> resourceSets = resourceSetService.getAllForOwnerAndClient(ownerId, authClientId);
  92. // collect all the scopes
  93. for (ResourceSet rs : resourceSets) {
  94. authScopes.addAll(rs.getScopes());
  95. }
  96. } else {
  97. // the client authenticated directly, make sure it's got the right access
  98. String authClientId = auth.getName(); // direct authentication puts the client_id into the authentication's name field
  99. authClient = clientService.loadClientByClientId(authClientId);
  100. // directly authenticated clients get a subset of any scopes that they've registered for
  101. authScopes.addAll(authClient.getScope());
  102. if (!AuthenticationUtilities.hasRole(auth, "ROLE_CLIENT")
  103. || !authClient.isAllowIntrospection()) {
  104. // this client isn't allowed to do direct introspection
  105. logger.error("Client " + authClient.getClientId() + " is not allowed to call introspection endpoint");
  106. model.addAttribute("code", HttpStatus.FORBIDDEN);
  107. return HttpCodeView.VIEWNAME;
  108. }
  109. }
  110. // by here we're allowed to introspect, now we need to look up the token in our token stores
  111. // first make sure the token is there
  112. if (Strings.isNullOrEmpty(tokenValue)) {
  113. logger.error("Verify failed; token value is null");
  114. Map<String,Boolean> entity = ImmutableMap.of("active", Boolean.FALSE);
  115. model.addAttribute(JsonEntityView.ENTITY, entity);
  116. return JsonEntityView.VIEWNAME;
  117. }
  118. OAuth2AccessTokenEntity accessToken = null;
  119. OAuth2RefreshTokenEntity refreshToken = null;
  120. ClientDetailsEntity tokenClient;
  121. UserInfo user;
  122. try {
  123. // check access tokens first (includes ID tokens)
  124. accessToken = tokenServices.readAccessToken(tokenValue);
  125. tokenClient = accessToken.getClient();
  126. // get the user information of the user that authorized this token in the first place
  127. String userName = accessToken.getAuthenticationHolder().getAuthentication().getName();
  128. user = userInfoService.getByUsernameAndClientId(userName, tokenClient.getClientId());
  129. } catch (InvalidTokenException e) {
  130. logger.info("Invalid access token. Checking refresh token.");
  131. try {
  132. // check refresh tokens next
  133. refreshToken = tokenServices.getRefreshToken(tokenValue);
  134. tokenClient = refreshToken.getClient();
  135. // get the user information of the user that authorized this token in the first place
  136. String userName = refreshToken.getAuthenticationHolder().getAuthentication().getName();
  137. user = userInfoService.getByUsernameAndClientId(userName, tokenClient.getClientId());
  138. } catch (InvalidTokenException e2) {
  139. logger.error("Invalid refresh token");
  140. Map<String,Boolean> entity = ImmutableMap.of(IntrospectionResultAssembler.ACTIVE, Boolean.FALSE);
  141. model.addAttribute(JsonEntityView.ENTITY, entity);
  142. return JsonEntityView.VIEWNAME;
  143. }
  144. }
  145. // if it's a valid token, we'll print out information on it
  146. if (accessToken != null) {
  147. Map<String, Object> entity = introspectionResultAssembler.assembleFrom(accessToken, user, authScopes);
  148. model.addAttribute(JsonEntityView.ENTITY, entity);
  149. } else if (refreshToken != null) {
  150. Map<String, Object> entity = introspectionResultAssembler.assembleFrom(refreshToken, user, authScopes);
  151. model.addAttribute(JsonEntityView.ENTITY, entity);
  152. } else {
  153. // no tokens were found (we shouldn't get here)
  154. logger.error("Verify failed; Invalid access/refresh token");
  155. Map<String,Boolean> entity = ImmutableMap.of(IntrospectionResultAssembler.ACTIVE, Boolean.FALSE);
  156. model.addAttribute(JsonEntityView.ENTITY, entity);
  157. return JsonEntityView.VIEWNAME;
  158. }
  159. return JsonEntityView.VIEWNAME;
  160. }
  161. }