diff --git a/openid-connect-common/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java b/openid-connect-common/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java index 182f5d35d..dfbd3f5e7 100644 --- a/openid-connect-common/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java +++ b/openid-connect-common/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java @@ -64,8 +64,9 @@ public class ClientDetailsEntity implements ClientDetails { /** Our own fields **/ private String clientDescription = ""; // human-readable description private boolean allowMultipleAccessTokens = false; // do we allow multiple access tokens, or not? - private boolean reuseRefreshToken = false; // do we let someone reuse a refresh token? + private boolean reuseRefreshToken = true; // do we let someone reuse a refresh token? private boolean dynamicallyRegistered = false; // was this client dynamically registered? + private boolean allowIntrospection = false; // do we let this client call the introspection endpoint? private Integer idTokenValiditySeconds; //timeout for id tokens /** Fields from ClientDetails interface **/ @@ -301,6 +302,22 @@ public class ClientDetailsEntity implements ClientDetails { + /** + * @return the allowIntrospection + */ + @Basic + @Column(name="allow_introspection") + public boolean isAllowIntrospection() { + return allowIntrospection; + } + + /** + * @param allowIntrospection the allowIntrospection to set + */ + public void setAllowIntrospection(boolean allowIntrospection) { + this.allowIntrospection = allowIntrospection; + } + /** * If the clientSecret is not null, then it is always required. */ diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/token/ChainedTokenGranter.java b/openid-connect-server/src/main/java/org/mitre/oauth2/token/ChainedTokenGranter.java index 528fc7d70..3e8d5b62c 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/token/ChainedTokenGranter.java +++ b/openid-connect-server/src/main/java/org/mitre/oauth2/token/ChainedTokenGranter.java @@ -76,13 +76,6 @@ public class ChainedTokenGranter extends AbstractTokenGranter { requestedScopes = new HashSet(); } - // Check the incoming client id against the client that was issued the original token - // TODO: right now, this only lets a client chain a request, not a resource server. We need - // a way to let one client get a token chained from another client's token, securely. - if (!client.getClientId().equals(authorizationRequest.getClientId())) { - throw new InvalidClientException("Not the right client for this token"); - } - // if our scopes are a valid subset of what's allowed, we can continue if (approvedScopes.containsAll(requestedScopes)) { diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/IntrospectionEndpoint.java b/openid-connect-server/src/main/java/org/mitre/oauth2/web/IntrospectionEndpoint.java index 2bb7c9d7a..2762fc38f 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/IntrospectionEndpoint.java +++ b/openid-connect-server/src/main/java/org/mitre/oauth2/web/IntrospectionEndpoint.java @@ -26,6 +26,7 @@ import org.mitre.oauth2.service.OAuth2TokenEntityService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.oauth2.common.exceptions.InvalidClientException; +import org.springframework.security.oauth2.common.exceptions.InvalidScopeException; import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails; @@ -102,14 +103,20 @@ public class IntrospectionEndpoint { ClientDetailsEntity authClient = clientService.loadClientByClientId(clientId); if (tokenClient != null && authClient != null) { - if (Objects.equal(authClient, tokenClient)) { // TODO: this lets a client introspect but not an RS + if (authClient.isAllowIntrospection()) { - // if it's a valid token, we'll print out information on it - modelAndView.setViewName("tokenIntrospection"); - modelAndView.addObject("entity", token); - return modelAndView; + // if it's the same client that the token was issued to, or it at least has all the scopes the token was issued with + if (authClient.equals(tokenClient) || authClient.getScope().containsAll(token.getScope())) { + + // if it's a valid token, we'll print out information on it + modelAndView.setViewName("tokenIntrospection"); + modelAndView.addObject("entity", token); + return modelAndView; + } else { + throw new InvalidScopeException("Tried to introspect a token of different scope"); + } } else { - throw new InvalidClientException("Clients did not match."); + throw new InvalidClientException("Clients can't introspect."); } } else { throw new InvalidClientException("No client found."); diff --git a/openid-connect-server/src/main/resources/db/tables/hsql_database_tables.sql b/openid-connect-server/src/main/resources/db/tables/hsql_database_tables.sql index 7839c8169..e8e5e456d 100644 --- a/openid-connect-server/src/main/resources/db/tables/hsql_database_tables.sql +++ b/openid-connect-server/src/main/resources/db/tables/hsql_database_tables.sql @@ -72,6 +72,7 @@ CREATE TABLE IF NOT EXISTS client_details ( allow_multiple_access_tokens BOOLEAN NOT NULL DEFAULT true, reuse_refresh_tokens BOOLEAN NOT NULL DEFAULT true, dynamically_registered BOOLEAN NOT NULL DEFAULT false, + allow_introspection BOOLEAN NOT NULL DEFAULT false, id_token_validity_seconds BIGINT, client_id VARCHAR(256), diff --git a/openid-connect-server/src/main/resources/db/tables/mysql_database_tables.sql b/openid-connect-server/src/main/resources/db/tables/mysql_database_tables.sql index 33ea0e9c3..2ef6f1ff6 100644 --- a/openid-connect-server/src/main/resources/db/tables/mysql_database_tables.sql +++ b/openid-connect-server/src/main/resources/db/tables/mysql_database_tables.sql @@ -64,9 +64,10 @@ CREATE TABLE blacklisted_site ( CREATE TABLE client_details ( id BIGINT AUTO_INCREMENT PRIMARY KEY, client_description VARCHAR(256), - allow_multiple_access_tokens TINYINT NOT NULL DEFAULT 0, - reuse_refresh_tokens TINYINT NOT NULL DEFAULT 0, - dynamically_registered TINYINT NOT NULL DEFAULT 0, + allow_multiple_access_tokens BOOLEAN NOT NULL DEFAULT 0, + reuse_refresh_tokens BOOLEAN NOT NULL DEFAULT 1, + dynamically_registered BOOLEAN NOT NULL DEFAULT 0, + allow_introspection BOOLEAN NOT NULL DEFAULT 0, id_token_validity_seconds BIGINT, client_id VARCHAR(256), @@ -103,7 +104,7 @@ CREATE TABLE client_details ( id_token_encrypted_response_int VARCHAR(256), default_max_age BIGINT, - require_auth_time TINYINT NOT NULL DEFAULT 0, + require_auth_time BOOLEAN NOT NULL DEFAULT 0, default_acr VARCHAR(256) );