added check for HEART mode consistency

pull/1046/head
Justin Richer 2016-02-24 13:09:58 -05:00
parent 028265faa6
commit 74ea42851b
1 changed files with 103 additions and 2 deletions

View File

@ -28,10 +28,12 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.http.MethodNotSupportedException;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClientBuilder;
import org.mitre.oauth2.model.ClientDetailsEntity; import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.SystemScope; import org.mitre.oauth2.model.SystemScope;
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
import org.mitre.oauth2.repository.OAuth2ClientRepository; import org.mitre.oauth2.repository.OAuth2ClientRepository;
import org.mitre.oauth2.repository.OAuth2TokenRepository; import org.mitre.oauth2.repository.OAuth2TokenRepository;
import org.mitre.oauth2.service.ClientDetailsEntityService; import org.mitre.oauth2.service.ClientDetailsEntityService;
@ -128,6 +130,9 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
// make sure we don't have both a JWKS and a JWKS URI // make sure we don't have both a JWKS and a JWKS URI
ensureKeyConsistency(client); ensureKeyConsistency(client);
// check consistency when using HEART mode
checkHeartMode(client);
// timestamp this to right now // timestamp this to right now
client.setCreatedAt(new Date()); client.setCreatedAt(new Date());
@ -146,6 +151,7 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
} }
/** /**
* Make sure the client has only one type of key registered
* @param client * @param client
*/ */
private void ensureKeyConsistency(ClientDetailsEntity client) { private void ensureKeyConsistency(ClientDetailsEntity client) {
@ -155,6 +161,9 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
} }
} }
/**
* Make sure the client doesn't request any system reserved scopes
*/
private void ensureNoReservedScopes(ClientDetailsEntity client) { private void ensureNoReservedScopes(ClientDetailsEntity client) {
// make sure a client doesn't get any special system scopes // make sure a client doesn't get any special system scopes
Set<SystemScope> requestedScope = scopeService.fromStrings(client.getScope()); Set<SystemScope> requestedScope = scopeService.fromStrings(client.getScope());
@ -164,6 +173,10 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
client.setScope(scopeService.toStrings(requestedScope)); client.setScope(scopeService.toStrings(requestedScope));
} }
/**
* Load the sector identifier URI if it exists and check the redirect URIs against it
* @param client
*/
private void checkSectorIdentifierUri(ClientDetailsEntity client) { private void checkSectorIdentifierUri(ClientDetailsEntity client) {
if (!Strings.isNullOrEmpty(client.getSectorIdentifierUri())) { if (!Strings.isNullOrEmpty(client.getSectorIdentifierUri())) {
try { try {
@ -183,6 +196,10 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
} }
} }
/**
* Make sure the client has the appropriate scope and grant type.
* @param client
*/
private void ensureRefreshTokenConsistency(ClientDetailsEntity client) { private void ensureRefreshTokenConsistency(ClientDetailsEntity client) {
if (client.getAuthorizedGrantTypes().contains("refresh_token") if (client.getAuthorizedGrantTypes().contains("refresh_token")
|| client.getScope().contains(SystemScopeService.OFFLINE_ACCESS)) { || client.getScope().contains(SystemScopeService.OFFLINE_ACCESS)) {
@ -191,6 +208,82 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
} }
} }
/**
* If HEART mode is enabled, make sure the client meets the requirements:
* - Only one of authorization_code, implicit, or client_credentials can be used at a time
* - A redirect_uri must be registered with either authorization_code or implicit
* - A key must be registered
* - A client secret must not be generated
* - authorization_code and client_credentials must use the private_key authorization method
* @param client
*/
private void checkHeartMode(ClientDetailsEntity client) {
if (config.isHeartMode()) {
if (client.getGrantTypes().contains("authorization_code")) {
// make sure we don't have incompatible grant types
if (client.getGrantTypes().contains("implicit") || client.getGrantTypes().contains("client_credentials")) {
throw new IllegalArgumentException("[HEART mode] Incompatible grant types");
}
// make sure we've got the right authentication method
if (client.getTokenEndpointAuthMethod() == null || client.getTokenEndpointAuthMethod().equals(AuthMethod.PRIVATE_KEY)) {
throw new IllegalArgumentException("[HEART mode] Authorization code clients must use the private_key authentication method");
}
// make sure we've got a redirect URI
if (client.getRedirectUris().isEmpty()) {
throw new IllegalArgumentException("[HEART mode] Authorization code clients must register at least one redirect URI");
}
}
if (client.getGrantTypes().contains("implicit")) {
// make sure we don't have incompatible grant types
if (client.getGrantTypes().contains("authorization_code") || client.getGrantTypes().contains("client_credentials") || client.getGrantTypes().contains("refresh_token")) {
throw new IllegalArgumentException("[HEART mode] Incompatible grant types");
}
// make sure we've got the right authentication method
if (client.getTokenEndpointAuthMethod() == null || client.getTokenEndpointAuthMethod().equals(AuthMethod.NONE)) {
throw new IllegalArgumentException("[HEART mode] Implicit clients must use the none authentication method");
}
// make sure we've got a redirect URI
if (client.getRedirectUris().isEmpty()) {
throw new IllegalArgumentException("[HEART mode] Implicit clients must register at least one redirect URI");
}
}
if (client.getGrantTypes().contains("client_credentials")) {
// make sure we don't have incompatible grant types
if (client.getGrantTypes().contains("authorization_code") || client.getGrantTypes().contains("implicit") || client.getGrantTypes().contains("refresh_token")) {
throw new IllegalArgumentException("[HEART mode] Incompatible grant types");
}
// make sure we've got the right authentication method
if (client.getTokenEndpointAuthMethod() == null || client.getTokenEndpointAuthMethod().equals(AuthMethod.PRIVATE_KEY)) {
throw new IllegalArgumentException("[HEART mode] Client credentials clients must use the private_key authentication method");
}
// make sure we've got a redirect URI
if (!client.getRedirectUris().isEmpty()) {
throw new IllegalArgumentException("[HEART mode] Client credentials clients must not register a redirect URI");
}
}
// make sure we don't have a client secret
if (!Strings.isNullOrEmpty(client.getClientSecret())) {
throw new IllegalArgumentException("[HEART mode] Client secrets are not allowed");
}
// make sure we've got a key registered
if (client.getJwks() == null && Strings.isNullOrEmpty(client.getJwksUri())) {
throw new IllegalArgumentException("[HEART mode] All clients must have a key registered");
}
}
}
/** /**
* Get the client by its internal ID * Get the client by its internal ID
*/ */
@ -284,6 +377,9 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
// make sure we don't have both a JWKS and a JWKS URI // make sure we don't have both a JWKS and a JWKS URI
ensureKeyConsistency(newClient); ensureKeyConsistency(newClient);
// check consistency when using HEART mode
checkHeartMode(newClient);
// check the sector URI // check the sector URI
checkSectorIdentifierUri(newClient); checkSectorIdentifierUri(newClient);
@ -317,7 +413,12 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
*/ */
@Override @Override
public ClientDetailsEntity generateClientSecret(ClientDetailsEntity client) { public ClientDetailsEntity generateClientSecret(ClientDetailsEntity client) {
client.setClientSecret(Base64.encodeBase64URLSafeString(new BigInteger(512, new SecureRandom()).toByteArray()).replace("=", "")); if (config.isHeartMode()) {
logger.error("[HEART mode] Can't generate a client secret, skipping step; client won't be saved due to invalid configuration");
client.setClientSecret(null);
} else {
client.setClientSecret(Base64.encodeBase64URLSafeString(new BigInteger(512, new SecureRandom()).toByteArray()).replace("=", ""));
}
return client; return client;
} }