Skip to content

Commit

Permalink
tests for client secret policy
Browse files Browse the repository at this point in the history
  • Loading branch information
6palace committed Apr 18, 2017
1 parent 7303b5c commit 36312ad
Show file tree
Hide file tree
Showing 30 changed files with 1,138 additions and 103 deletions.
@@ -0,0 +1,130 @@
package org.cloudfoundry.identity.uaa.authentication;

import org.cloudfoundry.identity.uaa.provider.PasswordPolicy;

/**
* ****************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
* <p>
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
* <p>
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
* *****************************************************************************
*/
public abstract class GenericPasswordPolicy <T extends GenericPasswordPolicy<T>> {

private int minLength;
private int maxLength;
private int requireUpperCaseCharacter;
private int requireLowerCaseCharacter;
private int requireDigit;
private int requireSpecialCharacter;

public GenericPasswordPolicy() {
minLength = maxLength = requireUpperCaseCharacter = requireLowerCaseCharacter = requireDigit = requireSpecialCharacter = -1;
}

public GenericPasswordPolicy(int minLength,
int maxLength,
int requireUpperCaseCharacter,
int requireLowerCaseCharacter,
int requireDigit,
int requireSpecialCharacter) {
this.minLength = minLength;
this.maxLength = maxLength;
this.requireUpperCaseCharacter = requireUpperCaseCharacter;
this.requireLowerCaseCharacter = requireLowerCaseCharacter;
this.requireDigit = requireDigit;
this.requireSpecialCharacter = requireSpecialCharacter;
}

public int getMinLength() {
return minLength;
}

public int getMaxLength() {
return maxLength;
}

public int getRequireUpperCaseCharacter() {
return requireUpperCaseCharacter;
}

public int getRequireLowerCaseCharacter() {
return requireLowerCaseCharacter;
}

public int getRequireDigit() {
return requireDigit;
}

public T setMaxLength(int maxLength) {
this.maxLength = maxLength;
return (T)this;
}

public T setMinLength(int minLength) {
this.minLength = minLength;
return (T)this;
}

public T setRequireDigit(int requireDigit) {
this.requireDigit = requireDigit;
return (T)this;
}

public T setRequireLowerCaseCharacter(int requireLowerCaseCharacter) {
this.requireLowerCaseCharacter = requireLowerCaseCharacter;
return (T)this;
}

public T setRequireUpperCaseCharacter(int requireUpperCaseCharacter) {
this.requireUpperCaseCharacter = requireUpperCaseCharacter;
return (T)this;
}

public int getRequireSpecialCharacter() {
return requireSpecialCharacter;
}

public T setRequireSpecialCharacter(int requireSpecialCharacter) {
this.requireSpecialCharacter = requireSpecialCharacter;
return (T)this;
}

public boolean allPresentAndPositive() {
return minLength >= 0 && maxLength >= 0 && requireUpperCaseCharacter >= 0 && requireLowerCaseCharacter >= 0 && requireDigit >= 0 && requireSpecialCharacter >= 0;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

PasswordPolicy that = (PasswordPolicy) o;

if (getMinLength() != that.getMinLength()) return false;
if (getMaxLength() != that.getMaxLength()) return false;
if (getRequireUpperCaseCharacter() != that.getRequireUpperCaseCharacter()) return false;
if (getRequireLowerCaseCharacter() != that.getRequireLowerCaseCharacter()) return false;
if (getRequireDigit() != that.getRequireDigit()) return false;
if (getRequireSpecialCharacter() != that.getRequireSpecialCharacter()) return false;
return true;
}

@Override
public int hashCode() {
int result = getMinLength();
result = 31 * result + getMaxLength();
result = 31 * result + getRequireUpperCaseCharacter();
result = 31 * result + getRequireLowerCaseCharacter();
result = 31 * result + getRequireDigit();
result = 31 * result + getRequireSpecialCharacter();
return result;
}
}
Expand Up @@ -20,4 +20,5 @@ public class ClientConstants {
public static final String APPROVALS_DELETED = "approvals_deleted"; public static final String APPROVALS_DELETED = "approvals_deleted";
public static final String TOKEN_SALT = "token_salt"; public static final String TOKEN_SALT = "token_salt";
public static final String REQUIRED_USER_GROUPS = "required_user_groups"; public static final String REQUIRED_USER_GROUPS = "required_user_groups";
public static final String LAST_MODIFIED = "lastModified";
} }
@@ -0,0 +1,77 @@
package org.cloudfoundry.identity.uaa.zone;

import org.cloudfoundry.identity.uaa.authentication.GenericPasswordPolicy;

/**
* ****************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
* <p>
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
* <p>
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
* *****************************************************************************
*/
public class ClientSecretPolicy extends GenericPasswordPolicy<ClientSecretPolicy> {
public static final String CLIENT_SECRET_POLICY_FIELD = "clientSecretPolicy";

private int expireSecretInMonths;

public ClientSecretPolicy() {
super();
setExpireSecretInMonths(-1);
}

public ClientSecretPolicy(int minLength,
int maxLength,
int requireUpperCaseCharacter,
int requireLowerCaseCharacter,
int requireDigit,
int requireSpecialCharacter,
int expireSecretInMonths) {
super(minLength,
maxLength,
requireUpperCaseCharacter,
requireLowerCaseCharacter,
requireDigit,
requireSpecialCharacter);
this.setExpireSecretInMonths(expireSecretInMonths);
}

public int getExpireSecretInMonths() {
return expireSecretInMonths;
}

public ClientSecretPolicy setExpireSecretInMonths(int expireSecretInMonths) {
this.expireSecretInMonths = expireSecretInMonths;
return this;
}

@Override
public boolean allPresentAndPositive() {
return super.allPresentAndPositive() && expireSecretInMonths >= 0;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;

ClientSecretPolicy that = (ClientSecretPolicy) o;

return expireSecretInMonths == that.expireSecretInMonths;

}

@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + expireSecretInMonths;
return result;
}
}
Expand Up @@ -24,6 +24,7 @@
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class IdentityZoneConfiguration { public class IdentityZoneConfiguration {


private ClientSecretPolicy clientSecretPolicy = new ClientSecretPolicy();
private TokenPolicy tokenPolicy = new TokenPolicy(); private TokenPolicy tokenPolicy = new TokenPolicy();
private SamlConfig samlConfig = new SamlConfig(); private SamlConfig samlConfig = new SamlConfig();
private CorsPolicy corsPolicy = new CorsPolicy(); private CorsPolicy corsPolicy = new CorsPolicy();
Expand All @@ -43,6 +44,14 @@ public IdentityZoneConfiguration(TokenPolicy tokenPolicy) {
this.tokenPolicy = tokenPolicy; this.tokenPolicy = tokenPolicy;
} }


public ClientSecretPolicy getClientSecretPolicy() {
return clientSecretPolicy;
}

public void setClientSecretPolicy(ClientSecretPolicy clientSecretPolicy) {
this.clientSecretPolicy = clientSecretPolicy;
}

public TokenPolicy getTokenPolicy() { public TokenPolicy getTokenPolicy() {
return tokenPolicy; return tokenPolicy;
} }
Expand Down
Expand Up @@ -12,9 +12,16 @@
*******************************************************************************/ *******************************************************************************/
package org.cloudfoundry.identity.uaa.authentication; package org.cloudfoundry.identity.uaa.authentication;


import java.sql.Timestamp;
import java.util.Calendar;

import org.cloudfoundry.identity.uaa.oauth.client.ClientConstants;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.codec.Base64; import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;


Expand All @@ -32,6 +39,8 @@
*/ */
public class ClientBasicAuthenticationFilter extends BasicAuthenticationFilter { public class ClientBasicAuthenticationFilter extends BasicAuthenticationFilter {


protected ClientDetailsService clientDetailsService;

public ClientBasicAuthenticationFilter(AuthenticationManager authenticationManager, public ClientBasicAuthenticationFilter(AuthenticationManager authenticationManager,
AuthenticationEntryPoint authenticationEntryPoint) { AuthenticationEntryPoint authenticationEntryPoint) {


Expand All @@ -50,6 +59,7 @@ protected void doFilterInternal(HttpServletRequest request,
} }


String[] decodedHeader = extractAndDecodeHeader(header, request); String[] decodedHeader = extractAndDecodeHeader(header, request);
//Validate against client lockout policy
String clientId = decodedHeader[0]; String clientId = decodedHeader[0];
} catch(BadCredentialsException e) { } catch(BadCredentialsException e) {
super.getAuthenticationEntryPoint().commence(request, response, e); super.getAuthenticationEntryPoint().commence(request, response, e);
Expand All @@ -59,6 +69,14 @@ protected void doFilterInternal(HttpServletRequest request,
super.doFilterInternal(request, response, chain); super.doFilterInternal(request, response, chain);
} }


public ClientDetailsService getClientDetailsService() {
return clientDetailsService;
}

public void setClientDetailsService(ClientDetailsService clientDetailsService) {
this.clientDetailsService = clientDetailsService;
}

private String[] extractAndDecodeHeader(String header, HttpServletRequest request) private String[] extractAndDecodeHeader(String header, HttpServletRequest request)
throws IOException { throws IOException {


Expand Down
@@ -0,0 +1,10 @@
package org.cloudfoundry.identity.uaa.authentication;


import org.springframework.security.authentication.BadCredentialsException;

public class ClientSecretExpiredException extends BadCredentialsException {
public ClientSecretExpiredException(String msg) {
super(msg);
}
}
Expand Up @@ -19,6 +19,7 @@
import org.cloudfoundry.identity.uaa.security.DefaultSecurityContextAccessor; import org.cloudfoundry.identity.uaa.security.DefaultSecurityContextAccessor;
import org.cloudfoundry.identity.uaa.security.SecurityContextAccessor; import org.cloudfoundry.identity.uaa.security.SecurityContextAccessor;
import org.cloudfoundry.identity.uaa.util.UaaUrlUtils; import org.cloudfoundry.identity.uaa.util.UaaUrlUtils;
import org.cloudfoundry.identity.uaa.zone.ClientSecretValidator;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.ClientDetails;
Expand Down Expand Up @@ -57,6 +58,7 @@ public class ClientAdminEndpointsValidator implements InitializingBean, ClientDe


private static final Collection<String> NON_ADMIN_VALID_AUTHORITIES = new HashSet<>(Arrays.asList("uaa.none")); private static final Collection<String> NON_ADMIN_VALID_AUTHORITIES = new HashSet<>(Arrays.asList("uaa.none"));


private ClientSecretValidator clientSecretValidator;


private QueryableResourceManager<ClientDetails> clientDetailsService; private QueryableResourceManager<ClientDetails> clientDetailsService;


Expand All @@ -83,8 +85,8 @@ public void afterPropertiesSet() throws Exception {
} }


/* (non-Javadoc) /* (non-Javadoc)
* @see org.cloudfoundry.identity.uaa.oauth.ClientDetailsValidatorInterface#validate(org.springframework.security.oauth2.provider.ClientDetails, boolean) * @see org.cloudfoundry.identity.uaa.oauth.ClientDetailsValidatorInterface#validate(org.springframework.security.oauth2.provider.ClientDetails, boolean)
*/ */
@Override @Override
public ClientDetails validate(ClientDetails prototype, Mode mode) { public ClientDetails validate(ClientDetails prototype, Mode mode) {
return validate(prototype, mode == Mode.CREATE, true); return validate(prototype, mode == Mode.CREATE, true);
Expand Down Expand Up @@ -217,11 +219,13 @@ public ClientDetails validate(ClientDetails prototype, boolean create, boolean c
} }
if (create) { if (create) {
// Only check for missing secret if client is being created. // Only check for missing secret if client is being created.
if ((requestedGrantTypes.contains("client_credentials") || requestedGrantTypes if (requestedGrantTypes.contains("client_credentials") || requestedGrantTypes
.contains("authorization_code")) .contains("authorization_code")) {
&& !StringUtils.hasText(client.getClientSecret())) { if(!StringUtils.hasText(client.getClientSecret())) {
throw new InvalidClientDetailsException( throw new InvalidClientDetailsException(
"Client secret is required for client_credentials and authorization_code grant types"); "Client secret is required for client_credentials and authorization_code grant types");
}
clientSecretValidator.validate(client.getClientSecret());
} }
} }


Expand Down Expand Up @@ -261,4 +265,13 @@ public static void checkRequestedGrantTypes(Set<String> requestedGrantTypes) {
} }
} }
} }

@Override
public ClientSecretValidator getClientSecretValidator() {
return this.clientSecretValidator;
}

public void setClientSecretValidator(ClientSecretValidator clientSecretValidator) {
this.clientSecretValidator = clientSecretValidator;
}
} }
Expand Up @@ -13,10 +13,17 @@


package org.cloudfoundry.identity.uaa.client; package org.cloudfoundry.identity.uaa.client;


import org.cloudfoundry.identity.uaa.zone.ClientSecretValidator;
import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.ClientDetails;


public interface ClientDetailsValidator { public interface ClientDetailsValidator {


/**
*
* @return Returns the configured client secret validator
*/
public ClientSecretValidator getClientSecretValidator();

/** /**
* *
* @param clientDetails * @param clientDetails
Expand Down
Expand Up @@ -15,6 +15,7 @@
package org.cloudfoundry.identity.uaa.client; package org.cloudfoundry.identity.uaa.client;




import org.cloudfoundry.identity.uaa.zone.ClientSecretValidator;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.ClientDetails;


Expand All @@ -29,6 +30,11 @@ public UaaScopes getUaaScopes() {
return uaaScopes; return uaaScopes;
} }


@Override
public ClientSecretValidator getClientSecretValidator() {
return null;
}

@Override @Override
public ClientDetails validate(ClientDetails clientDetails, Mode mode) throws InvalidClientDetailsException { public ClientDetails validate(ClientDetails clientDetails, Mode mode) throws InvalidClientDetailsException {
if (Mode.CREATE.equals(mode) || Mode.MODIFY.equals(mode)) { if (Mode.CREATE.equals(mode) || Mode.MODIFY.equals(mode)) {
Expand Down

0 comments on commit 36312ad

Please sign in to comment.