added check for HEART mode consistency
parent
028265faa6
commit
74ea42851b
|
@ -28,10 +28,12 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.http.MethodNotSupportedException;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.SystemScope;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
||||
import org.mitre.oauth2.repository.OAuth2ClientRepository;
|
||||
import org.mitre.oauth2.repository.OAuth2TokenRepository;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
|
@ -121,12 +123,15 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
|
|||
if (Strings.isNullOrEmpty(client.getClientId())) {
|
||||
client = generateClientId(client);
|
||||
}
|
||||
|
||||
|
||||
// make sure that clients with the "refresh_token" grant type have the "offline_access" scope, and vice versa
|
||||
ensureRefreshTokenConsistency(client);
|
||||
|
||||
// make sure we don't have both a JWKS and a JWKS URI
|
||||
ensureKeyConsistency(client);
|
||||
|
||||
// check consistency when using HEART mode
|
||||
checkHeartMode(client);
|
||||
|
||||
// timestamp this to right now
|
||||
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
|
||||
*/
|
||||
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) {
|
||||
// make sure a client doesn't get any special system scopes
|
||||
Set<SystemScope> requestedScope = scopeService.fromStrings(client.getScope());
|
||||
|
@ -164,6 +173,10 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
|
|||
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) {
|
||||
if (!Strings.isNullOrEmpty(client.getSectorIdentifierUri())) {
|
||||
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) {
|
||||
if (client.getAuthorizedGrantTypes().contains("refresh_token")
|
||||
|| 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
|
||||
*/
|
||||
|
@ -283,6 +376,9 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
|
|||
|
||||
// make sure we don't have both a JWKS and a JWKS URI
|
||||
ensureKeyConsistency(newClient);
|
||||
|
||||
// check consistency when using HEART mode
|
||||
checkHeartMode(newClient);
|
||||
|
||||
// check the sector URI
|
||||
checkSectorIdentifierUri(newClient);
|
||||
|
@ -317,7 +413,12 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
|
|||
*/
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue