예제 #1
0
  private void validateClient(ClientDetails client, boolean create) {
    final Set<String> VALID_GRANTS =
        new HashSet<String>(
            Arrays.asList(
                "implicit",
                "password",
                "client_credentials",
                "authorization_code",
                "refresh_token"));

    for (String grant : client.getAuthorizedGrantTypes()) {
      if (!VALID_GRANTS.contains(grant)) {
        throw new InvalidClientDetailsException(
            grant + " is not an allowed grant type. Must be one of: " + VALID_GRANTS.toString());
      }
    }

    if (create) {
      // Only check for missing secret if client is being created.
      if (client.getAuthorizedGrantTypes().size() == 1
          && client.getAuthorizedGrantTypes().contains("implicit")) {
        if (StringUtils.hasText(client.getClientSecret())) {
          throw new InvalidClientDetailsException(
              "implicit grant does not require a client_secret");
        }
      } else {
        if (!StringUtils.hasText(client.getClientSecret())) {
          throw new InvalidClientDetailsException(
              "client_secret is required for non-implicit grant types");
        }
      }
    }
  }
  public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
    System.out.println("loading client");

    ClientDetails client = jdbcClientService.loadClientByClientId(clientId);
    System.out.println(client.getClientId() + " " + client.getClientSecret());
    return client;
  }
예제 #3
0
 /**
  * Is a refresh token supported for this client (or the global setting if {@link
  * #setClientDetailsService(ClientDetailsService) clientDetailsService} is not set.
  *
  * @param authorizationRequest the current authorization request
  * @return boolean to indicate if refresh token is supported
  */
 protected boolean isSupportRefreshToken(OAuth2Request authorizationRequest) {
   if (clientDetailsService != null) {
     ClientDetails client =
         clientDetailsService.loadClientByClientId(authorizationRequest.getClientId());
     return client.getAuthorizedGrantTypes().contains("refresh_token");
   }
   return this.supportRefreshToken;
 }
 private HttpHeaders getHeaders(ClientDetails config) {
   HttpHeaders headers = new HttpHeaders();
   String token =
       new String(
           Base64.encode((config.getClientId() + ":" + config.getClientSecret()).getBytes()));
   headers.set("Authorization", "Basic " + token);
   return headers;
 }
  @Override
  public AuthorizationRequest createAuthorizationRequest(Map<String, String> parameters) {

    String clientId = parameters.get("client_id");
    if (clientId == null) {
      throw new InvalidClientException("A client id must be provided");
    }
    ClientDetails client = clientDetailsService.loadClientByClientId(clientId);

    String requestNonce = parameters.get("nonce");

    // Only process if the user is authenticated. If the user is not authenticated yet, this
    // code will be called a second time once the user is redirected from the login page back
    // to the auth endpoint.
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

    if (requestNonce != null && principal != null && principal instanceof User) {

      // Check request nonce for reuse
      Collection<Nonce> clientNonces = nonceService.getByClientId(client.getClientId());
      for (Nonce nonce : clientNonces) {
        String nonceVal = nonce.getValue();
        if (nonceVal.equals(requestNonce)) {
          throw new NonceReuseException(client.getClientId(), nonce);
        }
      }

      // Store nonce
      Nonce nonce = new Nonce();
      nonce.setClientId(client.getClientId());
      nonce.setValue(requestNonce);
      DateTime now = new DateTime(new Date());
      nonce.setUseDate(now.toDate());
      DateTime expDate = now.plus(nonceStorageDuration);
      Date expirationJdkDate = expDate.toDate();
      nonce.setExpireDate(expirationJdkDate);

      nonceService.save(nonce);
    }

    Set<String> scopes = OAuth2Utils.parseParameterList(parameters.get("scope"));
    if ((scopes == null || scopes.isEmpty())) {
      // TODO: do we want to allow default scoping at all?
      // If no scopes are specified in the incoming data, it is possible to default to the client's
      // registered scopes, but minus the "openid" scope. OpenID Connect requests MUST have the
      // "openid" scope.
      Set<String> clientScopes = client.getScope();
      if (clientScopes.contains("openid")) {
        clientScopes.remove("openid");
      }
      scopes = clientScopes;
    }
    DefaultAuthorizationRequest request =
        new DefaultAuthorizationRequest(
            parameters, Collections.<String, String>emptyMap(), clientId, scopes);
    request.addClientDetails(client);
    return request;
  }
예제 #6
0
 @RequestMapping(value = "/oauth/clients", method = RequestMethod.GET)
 public ResponseEntity<Map<String, ClientDetails>> listClientDetails() throws Exception {
   List<ClientDetails> details = clientRegistrationService.listClientDetails();
   Map<String, ClientDetails> map = new LinkedHashMap<String, ClientDetails>();
   for (ClientDetails client : details) {
     map.put(client.getClientId(), removeSecret(client));
   }
   return new ResponseEntity<Map<String, ClientDetails>>(map, HttpStatus.OK);
 }
 private Object[] getFields(ClientDetails clientDetails) {
   Object[] fieldsForUpdate = getFieldsForUpdate(clientDetails);
   Object[] fields = new Object[fieldsForUpdate.length + 1];
   System.arraycopy(fieldsForUpdate, 0, fields, 1, fieldsForUpdate.length);
   fields[0] =
       clientDetails.getClientSecret() != null
           ? passwordEncoder.encode(clientDetails.getClientSecret())
           : null;
   return fields;
 }
예제 #8
0
 /**
  * The refresh token validity period in seconds
  *
  * @param authorizationRequest the current authorization request
  * @return the refresh token validity period in seconds
  */
 protected int getRefreshTokenValiditySeconds(OAuth2Request authorizationRequest) {
   if (clientDetailsService != null) {
     ClientDetails client =
         clientDetailsService.loadClientByClientId(authorizationRequest.getClientId());
     Integer validity = client.getRefreshTokenValiditySeconds();
     if (validity != null) {
       return validity;
     }
   }
   return refreshTokenValiditySeconds;
 }
 private String getAutoApproveScopes(ClientDetails clientDetails) {
   if (clientDetails.isAutoApprove("true")) {
     return "true"; // all scopes autoapproved
   }
   Set<String> scopes = new HashSet<String>();
   for (String scope : clientDetails.getScope()) {
     if (clientDetails.isAutoApprove(scope)) {
       scopes.add(scope);
     }
   }
   return StringUtils.collectionToCommaDelimitedString(scopes);
 }
 @Override
 public void validateParameters(Map<String, String> parameters, ClientDetails clientDetails) {
   if (parameters.containsKey("scope")) {
     if (clientDetails.isScoped()) {
       Set<String> validScope = clientDetails.getScope();
       for (String scope : OAuth2Utils.parseParameterList(parameters.get("scope"))) {
         if (!validScope.contains(scope)) {
           throw new InvalidScopeException("Invalid scope: " + scope, validScope);
         }
       }
     }
   }
 }
 @Test
 public void testEnvironmentalOverrides() {
   this.context = new AnnotationConfigEmbeddedWebApplicationContext();
   EnvironmentTestUtils.addEnvironment(
       this.context,
       "security.oauth2.client.clientId:myclientid",
       "security.oauth2.client.clientSecret:mysecret");
   this.context.register(
       AuthorizationAndResourceServerConfiguration.class, MinimalSecureWebApplication.class);
   this.context.refresh();
   ClientDetails config = this.context.getBean(ClientDetails.class);
   assertThat(config.getClientId(), equalTo("myclientid"));
   assertThat(config.getClientSecret(), equalTo("mysecret"));
   verifyAuthentication(config);
 }
  @Test
  public void verification_link() throws Exception {
    ScimUser joel = setUpScimUser();

    MockHttpServletRequestBuilder get = setUpVerificationLinkRequest(joel, scimCreateToken);

    MvcResult result = getMockMvc().perform(get).andExpect(status().isOk()).andReturn();

    VerificationResponse verificationResponse =
        JsonUtils.readValue(result.getResponse().getContentAsString(), VerificationResponse.class);
    assertThat(
        verificationResponse.getVerifyLink().toString(),
        startsWith("http://localhost/verify_user"));

    String query = verificationResponse.getVerifyLink().getQuery();

    String code = getQueryStringParam(query, "code");
    assertThat(code, is(notNullValue()));

    ExpiringCode expiringCode = codeStore.retrieveCode(code);
    assertThat(expiringCode.getExpiresAt().getTime(), is(greaterThan(System.currentTimeMillis())));
    assertThat(expiringCode.getIntent(), is(REGISTRATION.name()));
    Map<String, String> data =
        JsonUtils.readValue(expiringCode.getData(), new TypeReference<Map<String, String>>() {});
    assertThat(data.get(InvitationConstants.USER_ID), is(notNullValue()));
    assertThat(data.get(CLIENT_ID), is(clientDetails.getClientId()));
    assertThat(data.get(REDIRECT_URI), is(HTTP_REDIRECT_EXAMPLE_COM));
  }
 public void addClientDetails(ClientDetails clientDetails) throws ClientAlreadyExistsException {
   try {
     jdbcTemplate.update(insertClientDetailsSql, getFields(clientDetails));
   } catch (DuplicateKeyException e) {
     throw new ClientAlreadyExistsException(
         "Client already exists: " + clientDetails.getClientId(), e);
   }
 }
 /**
  * Apply UAA rules to validate the requested scope. For client credentials grants the valid scopes
  * are actually in the authorities of the client.
  *
  * @see
  *     org.springframework.security.oauth2.provider.endpoint.ParametersValidator#validateParameters(java.util.Map,
  *     org.springframework.security.oauth2.provider.ClientDetails)
  */
 @Override
 public void validateParameters(Map<String, String> parameters, ClientDetails clientDetails) {
   if (parameters.containsKey("scope")) {
     Set<String> validScope = clientDetails.getScope();
     if ("client_credentials".equals(parameters.get("grant_type"))) {
       validScope = AuthorityUtils.authorityListToSet(clientDetails.getAuthorities());
     }
     for (String scope : OAuth2Utils.parseParameterList(parameters.get("scope"))) {
       if (!validScope.contains(scope)) {
         throw new InvalidScopeException(
             "Invalid scope: "
                 + scope
                 + ". Did you know that you can get default scopes by simply sending no value?",
             validScope);
       }
     }
   }
 }
  public String resolveRedirect(String requestedRedirect, ClientDetails client)
      throws OAuth2Exception {
    Set<String> redirectUris = client.getRegisteredRedirectUri();

    if (redirectUris != null && !redirectUris.isEmpty()) {
      return obtainMatchingRedirect(redirectUris, requestedRedirect);
    } else if (StringUtils.hasText(requestedRedirect)) {
      return requestedRedirect;
    } else {
      throw new OAuth2Exception("A redirect_uri must be supplied.");
    }
  }
  /**
   * Add or remove scopes derived from the current authenticated user's authorities (if any)
   *
   * @param scopes the initial set of scopes from the client registration
   * @param clientDetails
   * @param collection the users authorities
   * @return modified scopes adapted according to the rules specified
   */
  private Set<String> checkUserScopes(
      Set<String> scopes,
      Collection<? extends GrantedAuthority> authorities,
      ClientDetails clientDetails) {

    Set<String> result = new LinkedHashSet<String>(scopes);
    Set<String> allowed = new LinkedHashSet<String>(AuthorityUtils.authorityListToSet(authorities));

    // Add in all default scopes
    allowed.addAll(defaultScopes);
    // Find intersection of user authorities, default scopes and client
    // scopes:
    for (Iterator<String> iter = allowed.iterator(); iter.hasNext(); ) {
      String scope = iter.next();
      if (!clientDetails.getScope().contains(scope)) {
        iter.remove();
      }
    }

    // Weed out disallowed scopes:
    for (Iterator<String> iter = result.iterator(); iter.hasNext(); ) {
      String scope = iter.next();
      if (!allowed.contains(scope)) {
        iter.remove();
      }
    }

    // Check that a token with empty scope is not going to be granted
    if (result.isEmpty() && !clientDetails.getScope().isEmpty()) {
      throw new InvalidScopeException(
          "Invalid scope (empty) - this user is not allowed any of the requested scopes: "
              + scopes
              + " (either you requested a scope that was not allowed or client '"
              + clientDetails.getClientId()
              + "' is not allowed to act on behalf of this user)",
          allowed);
    }

    return result;
  }
  public String resolveRedirect(String requestedRedirect, ClientDetails client)
      throws OAuth2Exception {

    Set<String> authorizedGrantTypes = client.getAuthorizedGrantTypes();
    if (authorizedGrantTypes.isEmpty()) {
      throw new InvalidGrantException("A client must have at least one authorized grant type.");
    }
    if (!containsRedirectGrantType(authorizedGrantTypes)) {
      throw new InvalidGrantException(
          "A redirect_uri can only be used by implicit or authorization_code grant types.");
    }

    Set<String> redirectUris = client.getRegisteredRedirectUri();

    if (redirectUris != null && !redirectUris.isEmpty()) {
      return obtainMatchingRedirect(redirectUris, requestedRedirect);
    } else if (StringUtils.hasText(requestedRedirect)) {
      return requestedRedirect;
    } else {
      throw new RedirectMismatchException("A redirect_uri must be supplied.");
    }
  }
예제 #18
0
 private ClientDetails removeSecret(ClientDetails client) {
   BaseClientDetails details = new BaseClientDetails();
   details.setClientId(client.getClientId());
   details.setScope(client.getScope());
   details.setResourceIds(client.getResourceIds());
   details.setAuthorizedGrantTypes(client.getAuthorizedGrantTypes());
   details.setRegisteredRedirectUri(client.getRegisteredRedirectUri());
   details.setAuthorities(client.getAuthorities());
   details.setAccessTokenValiditySeconds(client.getAccessTokenValiditySeconds());
   return details;
 }
 private Set<String> getResourceIds(ClientDetails clientDetails, Set<String> scopes) {
   Set<String> resourceIds = new LinkedHashSet<String>();
   for (String scope : scopes) {
     if (scopeToResource.containsKey(scope)) {
       resourceIds.add(scopeToResource.get(scope));
     } else if (scope.contains(scopeSeparator)
         && !scope.endsWith(scopeSeparator)
         && !scope.equals("uaa.none")) {
       String id = scope.substring(0, scope.lastIndexOf(scopeSeparator));
       resourceIds.add(id);
     }
   }
   return resourceIds.isEmpty() ? clientDetails.getResourceIds() : resourceIds;
 }
 @Test
 public void testDefaultConfiguration() {
   this.context = new AnnotationConfigEmbeddedWebApplicationContext();
   this.context.register(
       AuthorizationAndResourceServerConfiguration.class, MinimalSecureWebApplication.class);
   this.context.refresh();
   this.context.getBean(AUTHORIZATION_SERVER_CONFIG);
   this.context.getBean(RESOURCE_SERVER_CONFIG);
   this.context.getBean(OAuth2MethodSecurityConfiguration.class);
   ClientDetails config = this.context.getBean(BaseClientDetails.class);
   AuthorizationEndpoint endpoint = this.context.getBean(AuthorizationEndpoint.class);
   UserApprovalHandler handler =
       (UserApprovalHandler) ReflectionTestUtils.getField(endpoint, "userApprovalHandler");
   ClientDetailsService clientDetailsService = this.context.getBean(ClientDetailsService.class);
   ClientDetails clientDetails = clientDetailsService.loadClientByClientId(config.getClientId());
   assertThat(AopUtils.isJdkDynamicProxy(clientDetailsService), equalTo(true));
   assertThat(
       AopUtils.getTargetClass(clientDetailsService).getName(),
       equalTo(ClientDetailsService.class.getName()));
   assertThat(handler instanceof ApprovalStoreUserApprovalHandler, equalTo(true));
   assertThat(clientDetails, equalTo(config));
   verifyAuthentication(config);
 }
  @Override
  public UserDetails loadUserByUsername(String clientId)
      throws UsernameNotFoundException, DataAccessException {

    ClientDetails client = clientDetailsService.loadClientByClientId(clientId);

    String password = client.getClientSecret();
    boolean enabled = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    GrantedAuthority roleClient = new SimpleGrantedAuthority("ROLE_CLIENT");
    authorities.add(roleClient);

    return new User(
        clientId,
        password,
        enabled,
        accountNonExpired,
        credentialsNonExpired,
        accountNonLocked,
        authorities);
  }
예제 #22
0
  private void checkPasswordChangeIsAllowed(ClientDetails clientDetails, String oldSecret) {

    if (!securityContextAccessor.isClient()) {
      // Trusted client (not acting on behalf of user)
      throw new IllegalStateException("Only a client can change client secret");
    }

    String clientId = clientDetails.getClientId();

    // Call is by client
    String currentClientId = securityContextAccessor.getClientId();

    if (securityContextAccessor.isAdmin()) {

      // even an admin needs to provide the old value to change password
      if (clientId.equals(currentClientId) && !StringUtils.hasText(oldSecret)) {
        throw new IllegalStateException("Previous secret is required even for admin");
      }

    } else {

      if (!clientId.equals(currentClientId)) {
        logger.warn(
            "Client with id "
                + currentClientId
                + " attempting to change password for client "
                + clientId);
        // TODO: This should be audited when we have non-authentication events in the log
        throw new IllegalStateException(
            "Bad request. Not permitted to change another client's secret");
      }

      // Client is changing their own secret, old password is required
      if (!StringUtils.hasText(oldSecret)) {
        throw new IllegalStateException("Previous secret is required");
      }
    }
  }
 public void updateClientDetails(ClientDetails clientDetails) throws NoSuchClientException {
   int count = jdbcTemplate.update(updateClientDetailsSql, getFieldsForUpdate(clientDetails));
   if (count != 1) {
     throw new NoSuchClientException("No client found with id = " + clientDetails.getClientId());
   }
 }
예제 #24
0
  @Override
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
      throws IOException, ServletException {

    final boolean debug = logger.isDebugEnabled();
    final HttpServletRequest request = (HttpServletRequest) req;
    final HttpServletResponse response = (HttpServletResponse) res;

    try {
      Authentication credentials = extractCredentials(request);

      if (credentials != null) {

        if (debug) {
          logger.debug("Authentication credentials found for '" + credentials.getName() + "'");
        }

        Authentication authResult = authenticationManager.authenticate(credentials);

        if (debug) {
          logger.debug("Authentication success: " + authResult.getName());
        }

        Authentication requestingPrincipal = SecurityContextHolder.getContext().getAuthentication();
        if (requestingPrincipal == null) {
          throw new BadCredentialsException(
              "No client authentication found. Remember to put a filter upstream of the LoginAuthenticationFilter.");
        }

        String clientId = request.getParameter("client_id");
        if (null == clientId) {
          logger.error("No client_id in the request");
          throw new BadCredentialsException("No client_id in the request");
        }

        // Check that the client exists
        ClientDetails authenticatingClient = clientDetailsService.loadClientByClientId(clientId);
        if (authenticatingClient == null) {
          throw new BadCredentialsException("No client " + clientId + " found");
        }

        DefaultAuthorizationRequest authorizationRequest =
            new DefaultAuthorizationRequest(
                getSingleValueMap(request),
                null,
                authenticatingClient.getClientId(),
                getScope(request));
        if (requestingPrincipal.isAuthenticated()) {
          // Ensure the OAuth2Authentication is authenticated
          authorizationRequest.setApproved(true);
        }

        SecurityContextHolder.getContext()
            .setAuthentication(new OAuth2Authentication(authorizationRequest, authResult));

        onSuccessfulAuthentication(request, response, authResult);
      }

    } catch (AuthenticationException failed) {
      SecurityContextHolder.clearContext();

      if (debug) {
        logger.debug("Authentication request for failed: " + failed);
      }

      onUnsuccessfulAuthentication(request, response, failed);

      authenticationEntryPoint.commence(request, response, failed);

      return;
    }

    chain.doFilter(request, response);
  }
 private Object[] getFieldsForUpdate(ClientDetails clientDetails) {
   String json = null;
   try {
     json = mapper.write(clientDetails.getAdditionalInformation());
   } catch (Exception e) {
     logger.warn("Could not serialize additional information: " + clientDetails, e);
   }
   return new Object[] {
     clientDetails.getResourceIds() != null
         ? StringUtils.collectionToCommaDelimitedString(clientDetails.getResourceIds())
         : null,
     clientDetails.getScope() != null
         ? StringUtils.collectionToCommaDelimitedString(clientDetails.getScope())
         : null,
     clientDetails.getAuthorizedGrantTypes() != null
         ? StringUtils.collectionToCommaDelimitedString(clientDetails.getAuthorizedGrantTypes())
         : null,
     clientDetails.getRegisteredRedirectUri() != null
         ? StringUtils.collectionToCommaDelimitedString(clientDetails.getRegisteredRedirectUri())
         : null,
     clientDetails.getAuthorities() != null
         ? StringUtils.collectionToCommaDelimitedString(clientDetails.getAuthorities())
         : null,
     clientDetails.getAccessTokenValiditySeconds(),
     clientDetails.getRefreshTokenValiditySeconds(),
     json,
     getAutoApproveScopes(clientDetails),
     clientDetails.getClientId()
   };
 }