whitespace, import, brace, annotation, and format cleanups
parent
b663cd5f8d
commit
8afab04544
|
@ -1,83 +1,85 @@
|
||||||
package org.mitre.oauth2.introspectingfilter;
|
package org.mitre.oauth2.introspectingfilter;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
public class AuthorizationRequestImpl implements AuthorizationRequest {
|
public class AuthorizationRequestImpl implements AuthorizationRequest {
|
||||||
|
|
||||||
private JsonObject token;
|
private JsonObject token;
|
||||||
private String clientId;
|
private String clientId;
|
||||||
private Set<String> scopes = null;
|
private Set<String> scopes = null;
|
||||||
|
|
||||||
public AuthorizationRequestImpl(JsonObject token) {
|
|
||||||
this.token = token;
|
|
||||||
clientId = token.get("client_id").getAsString();
|
|
||||||
scopes = new HashSet<String>();
|
|
||||||
for (JsonElement e : token.get("scope").getAsJsonArray()) {
|
|
||||||
scopes.add(e.getAsString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public AuthorizationRequestImpl(JsonObject token) {
|
||||||
public Map<String, String> getAuthorizationParameters() {
|
this.token = token;
|
||||||
return null;
|
clientId = token.get("client_id").getAsString();
|
||||||
}
|
scopes = new HashSet<String>();
|
||||||
|
for (JsonElement e : token.get("scope").getAsJsonArray()) {
|
||||||
|
scopes.add(e.getAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> getApprovalParameters() {
|
public Map<String, String> getAuthorizationParameters() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getClientId() {
|
public Map<String, String> getApprovalParameters() {
|
||||||
return clientId;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getScope() {
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
return scopes;
|
@Override
|
||||||
}
|
public Set<String> getScope() {
|
||||||
|
|
||||||
@Override
|
return scopes;
|
||||||
public Set<String> getResourceIds() {
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<GrantedAuthority> getAuthorities() {
|
public Set<String> getResourceIds() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isApproved() {
|
public Collection<GrantedAuthority> getAuthorities() {
|
||||||
return true;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDenied() {
|
public boolean isApproved() {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getState() {
|
public boolean isDenied() {
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRedirectUri() {
|
public String getState() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getResponseTypes() {
|
public String getRedirectUri() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getResponseTypes() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,14 @@
|
||||||
package org.mitre.oauth2.introspectingfilter;
|
package org.mitre.oauth2.introspectingfilter;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
|
||||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||||
|
@ -31,171 +18,175 @@ import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.web.client.RestClientException;
|
import org.springframework.web.client.RestClientException;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
public class IntrospectingTokenService implements ResourceServerTokenServices {
|
public class IntrospectingTokenService implements ResourceServerTokenServices {
|
||||||
|
|
||||||
|
|
||||||
private String clientId;
|
|
||||||
private String clientSecret;
|
|
||||||
private String introspectionUrl;
|
|
||||||
|
|
||||||
// Inner class to store in the hash map
|
|
||||||
private class TokenCacheObject { OAuth2AccessToken token; OAuth2Authentication auth;
|
|
||||||
private TokenCacheObject(OAuth2AccessToken token, OAuth2Authentication auth) {
|
|
||||||
this.token = token;
|
|
||||||
this.auth = auth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private Map<String, TokenCacheObject> authCache = new HashMap<String, TokenCacheObject>();
|
|
||||||
|
|
||||||
public String getIntrospectionUrl() {
|
private String clientId;
|
||||||
return introspectionUrl;
|
private String clientSecret;
|
||||||
}
|
private String introspectionUrl;
|
||||||
|
|
||||||
public void setIntrospectionUrl(String introspectionUrl) {
|
// Inner class to store in the hash map
|
||||||
this.introspectionUrl = introspectionUrl;
|
private class TokenCacheObject { OAuth2AccessToken token; OAuth2Authentication auth;
|
||||||
}
|
private TokenCacheObject(OAuth2AccessToken token, OAuth2Authentication auth) {
|
||||||
|
this.token = token;
|
||||||
|
this.auth = auth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Map<String, TokenCacheObject> authCache = new HashMap<String, TokenCacheObject>();
|
||||||
|
|
||||||
public String getClientId() {
|
public String getIntrospectionUrl() {
|
||||||
return clientId;
|
return introspectionUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClientId(String clientId) {
|
public void setIntrospectionUrl(String introspectionUrl) {
|
||||||
this.clientId = clientId;
|
this.introspectionUrl = introspectionUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getClientSecret() {
|
public String getClientId() {
|
||||||
return clientSecret;
|
return clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClientSecret(String clientSecret) {
|
public void setClientId(String clientId) {
|
||||||
this.clientSecret = clientSecret;
|
this.clientId = clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there is a token and authentication in the cache
|
|
||||||
// and check if it is not expired.
|
|
||||||
private TokenCacheObject checkCache(String key) {
|
|
||||||
if(authCache.containsKey(key)) {
|
|
||||||
TokenCacheObject tco = authCache.get(key);
|
|
||||||
if (tco.token.getExpiration().after(new Date())) {
|
|
||||||
return tco;
|
|
||||||
} else {
|
|
||||||
// if the token is expired, don't keep things around.
|
|
||||||
authCache.remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private AuthorizationRequest createAuthRequest(final JsonObject token) {
|
|
||||||
AuthorizationRequest authReq = new AuthorizationRequestImpl(token);
|
|
||||||
return authReq;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a default authentication object with authority ROLE_API
|
|
||||||
private Authentication createAuthentication(JsonObject token){
|
|
||||||
// TODO: make role/authority configurable somehow
|
|
||||||
return new PreAuthenticatedAuthenticationToken(token.get("subject").getAsString(), null, AuthorityUtils.createAuthorityList("ROLE_API"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private OAuth2AccessToken createAccessToken(final JsonObject token, final String tokenString){
|
|
||||||
OAuth2AccessToken accessToken = new OAuth2AccessTokenImpl(token, tokenString);
|
|
||||||
return accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate a token string against the introspection endpoint,
|
|
||||||
// then parse it and store it in the local cache. Return true on
|
|
||||||
// sucess, false otherwise.
|
|
||||||
private boolean parseToken(String accessToken) {
|
|
||||||
String validatedToken = null;
|
|
||||||
// Use the SpringFramework RestTemplate to send the request to the endpoint
|
|
||||||
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
|
||||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
|
||||||
form.add("token",accessToken);
|
|
||||||
form.add("client_id", this.clientId);
|
|
||||||
form.add("client_secret", this.clientSecret);
|
|
||||||
|
|
||||||
try {
|
|
||||||
validatedToken = restTemplate.postForObject(introspectionUrl, form, String.class);
|
|
||||||
} catch (RestClientException rce) {
|
|
||||||
// TODO: LOG THIS!?
|
|
||||||
LoggerFactory.getLogger(IntrospectingTokenService.class).error("validateToken", rce);
|
|
||||||
}
|
|
||||||
if (validatedToken != null) {
|
|
||||||
// parse the json
|
|
||||||
JsonElement jsonRoot = new JsonParser().parse(validatedToken);
|
|
||||||
if (!jsonRoot.isJsonObject()) {
|
|
||||||
return false; // didn't get a proper JSON object
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonObject tokenResponse = jsonRoot.getAsJsonObject();
|
|
||||||
|
|
||||||
if (tokenResponse.get("error") != null) {
|
|
||||||
// report an error?
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tokenResponse.get("valid").getAsBoolean()){
|
|
||||||
// non-valid token
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// create an OAuth2Authentication
|
|
||||||
OAuth2Authentication auth = new OAuth2Authentication(createAuthRequest(tokenResponse), createAuthentication(tokenResponse));
|
|
||||||
// create an OAuth2AccessToken
|
|
||||||
OAuth2AccessToken token = createAccessToken(tokenResponse, accessToken);
|
|
||||||
|
|
||||||
if (token.getExpiration().after(new Date())){
|
|
||||||
// Store them in the cache
|
|
||||||
authCache.put(accessToken, new TokenCacheObject(token,auth));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we never put a token and an authentication in the cache...
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException {
|
|
||||||
// First check if the in memory cache has an Authentication object, and that it is still valid
|
|
||||||
// If Valid, return it
|
|
||||||
TokenCacheObject cacheAuth = checkCache(accessToken);
|
|
||||||
if (cacheAuth != null) {
|
|
||||||
return cacheAuth.auth;
|
|
||||||
} else {
|
|
||||||
if (parseToken(accessToken)) {
|
|
||||||
cacheAuth = authCache.get(accessToken);
|
|
||||||
if (cacheAuth != null && (cacheAuth.token.getExpiration().after(new Date()))) {
|
|
||||||
return cacheAuth.auth;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public String getClientSecret() {
|
||||||
public OAuth2AccessToken readAccessToken(String accessToken) {
|
return clientSecret;
|
||||||
// First check if the in memory cache has a Token object, and that it is still valid
|
}
|
||||||
// If Valid, return it
|
|
||||||
TokenCacheObject cacheAuth = checkCache(accessToken);
|
public void setClientSecret(String clientSecret) {
|
||||||
if (cacheAuth != null) {
|
this.clientSecret = clientSecret;
|
||||||
return cacheAuth.token;
|
}
|
||||||
} else {
|
|
||||||
if (parseToken(accessToken)) {
|
// Check if there is a token and authentication in the cache
|
||||||
cacheAuth = authCache.get(accessToken);
|
// and check if it is not expired.
|
||||||
if (cacheAuth != null && (cacheAuth.token.getExpiration().after(new Date()))) {
|
private TokenCacheObject checkCache(String key) {
|
||||||
return cacheAuth.token;
|
if(authCache.containsKey(key)) {
|
||||||
} else {
|
TokenCacheObject tco = authCache.get(key);
|
||||||
return null;
|
if (tco.token.getExpiration().after(new Date())) {
|
||||||
}
|
return tco;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
// if the token is expired, don't keep things around.
|
||||||
}
|
authCache.remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthorizationRequest createAuthRequest(final JsonObject token) {
|
||||||
|
AuthorizationRequest authReq = new AuthorizationRequestImpl(token);
|
||||||
|
return authReq;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a default authentication object with authority ROLE_API
|
||||||
|
private Authentication createAuthentication(JsonObject token){
|
||||||
|
// TODO: make role/authority configurable somehow
|
||||||
|
return new PreAuthenticatedAuthenticationToken(token.get("subject").getAsString(), null, AuthorityUtils.createAuthorityList("ROLE_API"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private OAuth2AccessToken createAccessToken(final JsonObject token, final String tokenString){
|
||||||
|
OAuth2AccessToken accessToken = new OAuth2AccessTokenImpl(token, tokenString);
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate a token string against the introspection endpoint,
|
||||||
|
// then parse it and store it in the local cache. Return true on
|
||||||
|
// sucess, false otherwise.
|
||||||
|
private boolean parseToken(String accessToken) {
|
||||||
|
String validatedToken = null;
|
||||||
|
// Use the SpringFramework RestTemplate to send the request to the endpoint
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
||||||
|
form.add("token",accessToken);
|
||||||
|
form.add("client_id", this.clientId);
|
||||||
|
form.add("client_secret", this.clientSecret);
|
||||||
|
|
||||||
|
try {
|
||||||
|
validatedToken = restTemplate.postForObject(introspectionUrl, form, String.class);
|
||||||
|
} catch (RestClientException rce) {
|
||||||
|
// TODO: LOG THIS!?
|
||||||
|
LoggerFactory.getLogger(IntrospectingTokenService.class).error("validateToken", rce);
|
||||||
|
}
|
||||||
|
if (validatedToken != null) {
|
||||||
|
// parse the json
|
||||||
|
JsonElement jsonRoot = new JsonParser().parse(validatedToken);
|
||||||
|
if (!jsonRoot.isJsonObject()) {
|
||||||
|
return false; // didn't get a proper JSON object
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject tokenResponse = jsonRoot.getAsJsonObject();
|
||||||
|
|
||||||
|
if (tokenResponse.get("error") != null) {
|
||||||
|
// report an error?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tokenResponse.get("valid").getAsBoolean()){
|
||||||
|
// non-valid token
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// create an OAuth2Authentication
|
||||||
|
OAuth2Authentication auth = new OAuth2Authentication(createAuthRequest(tokenResponse), createAuthentication(tokenResponse));
|
||||||
|
// create an OAuth2AccessToken
|
||||||
|
OAuth2AccessToken token = createAccessToken(tokenResponse, accessToken);
|
||||||
|
|
||||||
|
if (token.getExpiration().after(new Date())){
|
||||||
|
// Store them in the cache
|
||||||
|
authCache.put(accessToken, new TokenCacheObject(token,auth));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we never put a token and an authentication in the cache...
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException {
|
||||||
|
// First check if the in memory cache has an Authentication object, and that it is still valid
|
||||||
|
// If Valid, return it
|
||||||
|
TokenCacheObject cacheAuth = checkCache(accessToken);
|
||||||
|
if (cacheAuth != null) {
|
||||||
|
return cacheAuth.auth;
|
||||||
|
} else {
|
||||||
|
if (parseToken(accessToken)) {
|
||||||
|
cacheAuth = authCache.get(accessToken);
|
||||||
|
if (cacheAuth != null && (cacheAuth.token.getExpiration().after(new Date()))) {
|
||||||
|
return cacheAuth.auth;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OAuth2AccessToken readAccessToken(String accessToken) {
|
||||||
|
// First check if the in memory cache has a Token object, and that it is still valid
|
||||||
|
// If Valid, return it
|
||||||
|
TokenCacheObject cacheAuth = checkCache(accessToken);
|
||||||
|
if (cacheAuth != null) {
|
||||||
|
return cacheAuth.token;
|
||||||
|
} else {
|
||||||
|
if (parseToken(accessToken)) {
|
||||||
|
cacheAuth = authCache.get(accessToken);
|
||||||
|
if (cacheAuth != null && (cacheAuth.token.getExpiration().after(new Date()))) {
|
||||||
|
return cacheAuth.token;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package org.mitre.oauth2.introspectingfilter;
|
package org.mitre.oauth2.introspectingfilter;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
@ -12,79 +10,83 @@ import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
|
||||||
public class OAuth2AccessTokenImpl implements OAuth2AccessToken {
|
public class OAuth2AccessTokenImpl implements OAuth2AccessToken {
|
||||||
|
|
||||||
private JsonObject token;
|
private JsonObject token;
|
||||||
private String tokenString;
|
private String tokenString;
|
||||||
private Set<String> scopes = null;
|
private Set<String> scopes = null;
|
||||||
private Date expireDate;
|
private Date expireDate;
|
||||||
|
|
||||||
|
|
||||||
public OAuth2AccessTokenImpl(JsonObject token, String tokenString) {
|
|
||||||
this.token = token;
|
|
||||||
this.tokenString = tokenString;
|
|
||||||
scopes = new HashSet<String>();
|
|
||||||
for (JsonElement e : token.get("scope").getAsJsonArray()) {
|
|
||||||
scopes.add(e.getAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
DateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
|
||||||
try {
|
|
||||||
expireDate = dateFormater.parse(token.get("expires_at").getAsString());
|
|
||||||
} catch (ParseException ex) {
|
|
||||||
Logger.getLogger(IntrospectingTokenService.class.getName()).log(Level.SEVERE, null, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
public OAuth2AccessTokenImpl(JsonObject token, String tokenString) {
|
||||||
public Map<String, Object> getAdditionalInformation() {
|
this.token = token;
|
||||||
return null;
|
this.tokenString = tokenString;
|
||||||
}
|
scopes = new HashSet<String>();
|
||||||
|
for (JsonElement e : token.get("scope").getAsJsonArray()) {
|
||||||
|
scopes.add(e.getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
DateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||||
public Set<String> getScope() {
|
try {
|
||||||
return scopes;
|
expireDate = dateFormater.parse(token.get("expires_at").getAsString());
|
||||||
}
|
} catch (ParseException ex) {
|
||||||
|
Logger.getLogger(IntrospectingTokenService.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public OAuth2RefreshToken getRefreshToken() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTokenType() {
|
public Map<String, Object> getAdditionalInformation() {
|
||||||
return BEARER_TYPE;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isExpired() {
|
public Set<String> getScope() {
|
||||||
if (expireDate != null && expireDate.before(new Date())) {
|
return scopes;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date getExpiration() {
|
public OAuth2RefreshToken getRefreshToken() {
|
||||||
return expireDate;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getExpiresIn() {
|
public String getTokenType() {
|
||||||
if (expireDate != null) {
|
return BEARER_TYPE;
|
||||||
return (int)TimeUnit.MILLISECONDS.toSeconds(expireDate.getTime() - (new Date()).getTime());
|
}
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValue() {
|
public boolean isExpired() {
|
||||||
return tokenString;
|
if (expireDate != null && expireDate.before(new Date())) {
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getExpiration() {
|
||||||
|
return expireDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getExpiresIn() {
|
||||||
|
if (expireDate != null) {
|
||||||
|
return (int)TimeUnit.MILLISECONDS.toSeconds(expireDate.getTime() - (new Date()).getTime());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue() {
|
||||||
|
return tokenString;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,8 @@
|
||||||
*/
|
*/
|
||||||
package org.mitre.openid.connect.client;
|
package org.mitre.openid.connect.client;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
@ -24,26 +22,26 @@ import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class NamedAdminAuthoritiesMapper implements GrantedAuthoritiesMapper {
|
public class NamedAdminAuthoritiesMapper implements GrantedAuthoritiesMapper {
|
||||||
|
|
||||||
private static final SimpleGrantedAuthority ROLE_ADMIN = new SimpleGrantedAuthority("ROLE_ADMIN");
|
private static final SimpleGrantedAuthority ROLE_ADMIN = new SimpleGrantedAuthority("ROLE_ADMIN");
|
||||||
private static final SimpleGrantedAuthority ROLE_USER = new SimpleGrantedAuthority("ROLE_USER");
|
private static final SimpleGrantedAuthority ROLE_USER = new SimpleGrantedAuthority("ROLE_USER");
|
||||||
|
|
||||||
private Set<SubjectIssuerGrantedAuthority> admins = new HashSet<SubjectIssuerGrantedAuthority>();
|
private Set<SubjectIssuerGrantedAuthority> admins = new HashSet<SubjectIssuerGrantedAuthority>();
|
||||||
|
|
||||||
private GrantedAuthoritiesMapper chain = new NullAuthoritiesMapper();
|
private GrantedAuthoritiesMapper chain = new NullAuthoritiesMapper();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||||
|
|
||||||
Set<GrantedAuthority> out = new HashSet<GrantedAuthority>();
|
Set<GrantedAuthority> out = new HashSet<GrantedAuthority>();
|
||||||
out.addAll(authorities);
|
out.addAll(authorities);
|
||||||
|
|
||||||
for (GrantedAuthority authority : authorities) {
|
for (GrantedAuthority authority : authorities) {
|
||||||
if (admins.contains(authority)) {
|
if (admins.contains(authority)) {
|
||||||
out.add(ROLE_ADMIN);
|
out.add(ROLE_ADMIN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// everybody's a user by default
|
// everybody's a user by default
|
||||||
out.add(ROLE_USER);
|
out.add(ROLE_USER);
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,6 @@ import java.math.BigInteger;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -29,8 +27,6 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.http.auth.AuthScope;
|
|
||||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||||
import org.mitre.jwt.signer.service.impl.JWKSetSigningAndValidationServiceCacheService;
|
import org.mitre.jwt.signer.service.impl.JWKSetSigningAndValidationServiceCacheService;
|
||||||
|
@ -74,7 +70,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
protected final static int HTTP_SOCKET_TIMEOUT = 30000;
|
protected final static int HTTP_SOCKET_TIMEOUT = 30000;
|
||||||
|
|
||||||
protected final static String FILTER_PROCESSES_URL = "/openid_connect_login";
|
protected final static String FILTER_PROCESSES_URL = "/openid_connect_login";
|
||||||
|
|
||||||
// Allow for time sync issues by having a window of X seconds.
|
// Allow for time sync issues by having a window of X seconds.
|
||||||
private int timeSkewAllowance = 300;
|
private int timeSkewAllowance = 300;
|
||||||
|
|
||||||
|
@ -86,7 +82,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
private ClientConfigurationService clients;
|
private ClientConfigurationService clients;
|
||||||
private IssuerService issuerService;
|
private IssuerService issuerService;
|
||||||
private AuthRequestUrlBuilder authRequestBuilder;
|
private AuthRequestUrlBuilder authRequestBuilder;
|
||||||
|
|
||||||
protected int httpSocketTimeout = HTTP_SOCKET_TIMEOUT;
|
protected int httpSocketTimeout = HTTP_SOCKET_TIMEOUT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,18 +115,18 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
// there's an error coming back from the server, need to handle this
|
// there's an error coming back from the server, need to handle this
|
||||||
handleError(request, response);
|
handleError(request, response);
|
||||||
return null; // no auth, response is sent to display page or something
|
return null; // no auth, response is sent to display page or something
|
||||||
|
|
||||||
} else if (!Strings.isNullOrEmpty(request.getParameter("code"))) {
|
} else if (!Strings.isNullOrEmpty(request.getParameter("code"))) {
|
||||||
|
|
||||||
// we got back the code, need to process this to get our tokens
|
// we got back the code, need to process this to get our tokens
|
||||||
Authentication auth = handleAuthorizationCodeResponse(request, response);
|
Authentication auth = handleAuthorizationCodeResponse(request, response);
|
||||||
return auth;
|
return auth;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// not an error, not a code, must be an initial login of some type
|
// not an error, not a code, must be an initial login of some type
|
||||||
handleAuthorizationRequest(request, response);
|
handleAuthorizationRequest(request, response);
|
||||||
|
|
||||||
return null; // no auth, response redirected to the server's Auth Endpoint (or possibly to the account chooser)
|
return null; // no auth, response redirected to the server's Auth Endpoint (or possibly to the account chooser)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,53 +145,53 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
protected void handleAuthorizationRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
protected void handleAuthorizationRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
|
||||||
HttpSession session = request.getSession();
|
HttpSession session = request.getSession();
|
||||||
|
|
||||||
IssuerServiceResponse issResp = issuerService.getIssuer(request);
|
IssuerServiceResponse issResp = issuerService.getIssuer(request);
|
||||||
|
|
||||||
if (issResp == null) {
|
if (issResp == null) {
|
||||||
logger.error("Null issuer response returned from service.");
|
logger.error("Null issuer response returned from service.");
|
||||||
throw new AuthenticationServiceException("No issuer found.");
|
throw new AuthenticationServiceException("No issuer found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (issResp.shouldRedirect()) {
|
if (issResp.shouldRedirect()) {
|
||||||
response.sendRedirect(issResp.getRedirectUrl());
|
response.sendRedirect(issResp.getRedirectUrl());
|
||||||
} else {
|
} else {
|
||||||
String issuer = issResp.getIssuer();
|
String issuer = issResp.getIssuer();
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(issuer)) {
|
if (Strings.isNullOrEmpty(issuer)) {
|
||||||
logger.error("No issuer found: " + issuer);
|
logger.error("No issuer found: " + issuer);
|
||||||
throw new AuthenticationServiceException("No issuer found: " + issuer);
|
throw new AuthenticationServiceException("No issuer found: " + issuer);
|
||||||
}
|
}
|
||||||
|
|
||||||
session.setAttribute(ISSUER_SESSION_VARIABLE, issuer);
|
session.setAttribute(ISSUER_SESSION_VARIABLE, issuer);
|
||||||
|
|
||||||
ServerConfiguration serverConfig = servers.getServerConfiguration(issuer);
|
ServerConfiguration serverConfig = servers.getServerConfiguration(issuer);
|
||||||
if (serverConfig == null) {
|
if (serverConfig == null) {
|
||||||
logger.error("No server configuration found for issuer: " + issuer);
|
logger.error("No server configuration found for issuer: " + issuer);
|
||||||
throw new AuthenticationServiceException("No server configuration found for issuer: " + issuer);
|
throw new AuthenticationServiceException("No server configuration found for issuer: " + issuer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ClientDetails clientConfig = clients.getClientConfiguration(serverConfig);
|
ClientDetails clientConfig = clients.getClientConfiguration(serverConfig);
|
||||||
if (clientConfig == null) {
|
if (clientConfig == null) {
|
||||||
logger.error("No client configuration found for issuer: " + issuer);
|
logger.error("No client configuration found for issuer: " + issuer);
|
||||||
throw new AuthenticationServiceException("No client configuration found for issuer: " + issuer);
|
throw new AuthenticationServiceException("No client configuration found for issuer: " + issuer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// our redirect URI is this current URL, with no query parameters
|
// our redirect URI is this current URL, with no query parameters
|
||||||
String redirectUri = request.getRequestURL().toString();
|
String redirectUri = request.getRequestURL().toString();
|
||||||
session.setAttribute(REDIRECT_URI_SESION_VARIABLE, redirectUri);
|
session.setAttribute(REDIRECT_URI_SESION_VARIABLE, redirectUri);
|
||||||
|
|
||||||
// this value comes back in the id token and is checked there
|
// this value comes back in the id token and is checked there
|
||||||
String nonce = createNonce(session);
|
String nonce = createNonce(session);
|
||||||
|
|
||||||
// this value comes back in the auth code response
|
// this value comes back in the auth code response
|
||||||
String state = createState(session);
|
String state = createState(session);
|
||||||
|
|
||||||
String authRequest = authRequestBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state);
|
String authRequest = authRequestBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state);
|
||||||
|
|
||||||
logger.debug("Auth Request: " + authRequest);
|
logger.debug("Auth Request: " + authRequest);
|
||||||
|
|
||||||
response.sendRedirect(authRequest);
|
response.sendRedirect(authRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,9 +206,9 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
protected Authentication handleAuthorizationCodeResponse(HttpServletRequest request, HttpServletResponse response) {
|
protected Authentication handleAuthorizationCodeResponse(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
|
||||||
String authorizationCode = request.getParameter("code");
|
String authorizationCode = request.getParameter("code");
|
||||||
|
|
||||||
HttpSession session = request.getSession();
|
HttpSession session = request.getSession();
|
||||||
|
|
||||||
// check for state, if it doesn't match we bail early
|
// check for state, if it doesn't match we bail early
|
||||||
String storedState = getStoredState(session);
|
String storedState = getStoredState(session);
|
||||||
if (!StringUtils.isBlank(storedState)) {
|
if (!StringUtils.isBlank(storedState)) {
|
||||||
|
@ -224,20 +220,20 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
|
|
||||||
// look up the issuer that we set out to talk to
|
// look up the issuer that we set out to talk to
|
||||||
String issuer = getStoredSessionString(session, ISSUER_SESSION_VARIABLE);
|
String issuer = getStoredSessionString(session, ISSUER_SESSION_VARIABLE);
|
||||||
|
|
||||||
// pull the configurations based on that issuer
|
// pull the configurations based on that issuer
|
||||||
ServerConfiguration serverConfig = servers.getServerConfiguration(issuer);
|
ServerConfiguration serverConfig = servers.getServerConfiguration(issuer);
|
||||||
ClientDetails clientConfig = clients.getClientConfiguration(serverConfig);
|
ClientDetails clientConfig = clients.getClientConfiguration(serverConfig);
|
||||||
|
|
||||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
||||||
form.add("grant_type", "authorization_code");
|
form.add("grant_type", "authorization_code");
|
||||||
form.add("code", authorizationCode);
|
form.add("code", authorizationCode);
|
||||||
|
|
||||||
String redirectUri = getStoredSessionString(session, REDIRECT_URI_SESION_VARIABLE);
|
String redirectUri = getStoredSessionString(session, REDIRECT_URI_SESION_VARIABLE);
|
||||||
if (redirectUri != null) {
|
if (redirectUri != null) {
|
||||||
form.add("redirect_uri", redirectUri);
|
form.add("redirect_uri", redirectUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Token Endpoint interaction
|
// Handle Token Endpoint interaction
|
||||||
DefaultHttpClient httpClient = new DefaultHttpClient();
|
DefaultHttpClient httpClient = new DefaultHttpClient();
|
||||||
|
|
||||||
|
@ -252,7 +248,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
*/
|
*/
|
||||||
form.add("client_id", clientConfig.getClientId());
|
form.add("client_id", clientConfig.getClientId());
|
||||||
form.add("client_secret", clientConfig.getClientSecret());
|
form.add("client_secret", clientConfig.getClientSecret());
|
||||||
/**/
|
/**/
|
||||||
|
|
||||||
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||||
|
|
||||||
|
@ -277,14 +273,14 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("from TokenEndpoint jsonString = " + jsonString);
|
logger.debug("from TokenEndpoint jsonString = " + jsonString);
|
||||||
|
|
||||||
JsonElement jsonRoot = new JsonParser().parse(jsonString);
|
JsonElement jsonRoot = new JsonParser().parse(jsonString);
|
||||||
if (!jsonRoot.isJsonObject()) {
|
if (!jsonRoot.isJsonObject()) {
|
||||||
throw new AuthenticationServiceException("Token Endpoint did not return a JSON object: " + jsonRoot);
|
throw new AuthenticationServiceException("Token Endpoint did not return a JSON object: " + jsonRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject tokenResponse = jsonRoot.getAsJsonObject();
|
JsonObject tokenResponse = jsonRoot.getAsJsonObject();
|
||||||
|
|
||||||
if (tokenResponse.get("error") != null) {
|
if (tokenResponse.get("error") != null) {
|
||||||
|
|
||||||
// Handle error
|
// Handle error
|
||||||
|
@ -299,125 +295,125 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
|
|
||||||
// Extract the id_token to insert into the
|
// Extract the id_token to insert into the
|
||||||
// OIDCAuthenticationToken
|
// OIDCAuthenticationToken
|
||||||
|
|
||||||
// get out all the token strings
|
// get out all the token strings
|
||||||
String accessTokenValue = null;
|
String accessTokenValue = null;
|
||||||
String idTokenValue = null;
|
String idTokenValue = null;
|
||||||
String refreshTokenValue = null;
|
String refreshTokenValue = null;
|
||||||
|
|
||||||
if (tokenResponse.has("access_token")) {
|
if (tokenResponse.has("access_token")) {
|
||||||
accessTokenValue = tokenResponse.get("access_token").getAsString();
|
accessTokenValue = tokenResponse.get("access_token").getAsString();
|
||||||
} else {
|
} else {
|
||||||
throw new AuthenticationServiceException("Token Endpoint did not return an access_token: " + jsonString);
|
throw new AuthenticationServiceException("Token Endpoint did not return an access_token: " + jsonString);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokenResponse.has("id_token")) {
|
if (tokenResponse.has("id_token")) {
|
||||||
idTokenValue = tokenResponse.get("id_token").getAsString();
|
idTokenValue = tokenResponse.get("id_token").getAsString();
|
||||||
} else {
|
} else {
|
||||||
logger.error("Token Endpoint did not return an id_token");
|
logger.error("Token Endpoint did not return an id_token");
|
||||||
throw new AuthenticationServiceException("Token Endpoint did not return an id_token");
|
throw new AuthenticationServiceException("Token Endpoint did not return an id_token");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokenResponse.has("refresh_token")) {
|
if (tokenResponse.has("refresh_token")) {
|
||||||
refreshTokenValue = tokenResponse.get("refresh_token").getAsString();
|
refreshTokenValue = tokenResponse.get("refresh_token").getAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SignedJWT idToken = SignedJWT.parse(idTokenValue);
|
SignedJWT idToken = SignedJWT.parse(idTokenValue);
|
||||||
|
|
||||||
// validate our ID Token over a number of tests
|
// validate our ID Token over a number of tests
|
||||||
ReadOnlyJWTClaimsSet idClaims = idToken.getJWTClaimsSet();
|
ReadOnlyJWTClaimsSet idClaims = idToken.getJWTClaimsSet();
|
||||||
|
|
||||||
// check the signature
|
|
||||||
JwtSigningAndValidationService jwtValidator = validationServices.get(serverConfig.getJwksUri());
|
|
||||||
if (jwtValidator != null) {
|
|
||||||
if(!jwtValidator.validateSignature(idToken)) {
|
|
||||||
throw new AuthenticationServiceException("Signature validation failed");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.info("No validation service found. Skipping signature validation");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the issuer
|
|
||||||
if (idClaims.getIssuer() == null) {
|
|
||||||
throw new AuthenticationServiceException("Id Token Issuer is null");
|
|
||||||
} else if (!idClaims.getIssuer().equals(serverConfig.getIssuer())){
|
|
||||||
throw new AuthenticationServiceException("Issuers do not match, expected " + serverConfig.getIssuer() + " got " + idClaims.getIssuer());
|
|
||||||
}
|
|
||||||
|
|
||||||
// check expiration
|
|
||||||
if (idClaims.getExpirationTime() == null) {
|
|
||||||
throw new AuthenticationServiceException("Id Token does not have required expiration claim");
|
|
||||||
} else {
|
|
||||||
// it's not null, see if it's expired
|
|
||||||
Date now = new Date(System.currentTimeMillis() - (timeSkewAllowance * 1000));
|
|
||||||
if (now.after(idClaims.getExpirationTime())) {
|
|
||||||
throw new AuthenticationServiceException("Id Token is expired: " + idClaims.getExpirationTime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check not before
|
|
||||||
if (idClaims.getNotBeforeTime() != null) {
|
|
||||||
Date now = new Date(System.currentTimeMillis() + (timeSkewAllowance * 1000));
|
|
||||||
if (now.before(idClaims.getNotBeforeTime())){
|
|
||||||
throw new AuthenticationServiceException("Id Token not valid untill: " + idClaims.getNotBeforeTime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check issued at
|
|
||||||
if (idClaims.getIssueTime() == null) {
|
|
||||||
throw new AuthenticationServiceException("Id Token does not have required issued-at claim");
|
|
||||||
} else {
|
|
||||||
// since it's not null, see if it was issued in the future
|
|
||||||
Date now = new Date(System.currentTimeMillis() + (timeSkewAllowance * 1000));
|
|
||||||
if (now.before(idClaims.getIssueTime())) {
|
|
||||||
throw new AuthenticationServiceException("Id Token was issued in the future: " + idClaims.getIssueTime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check audience
|
|
||||||
if (idClaims.getAudience() == null) {
|
|
||||||
throw new AuthenticationServiceException("Id token audience is null");
|
|
||||||
} else if (!idClaims.getAudience().contains(clientConfig.getClientId())) {
|
|
||||||
throw new AuthenticationServiceException("Audience does not match, expected " + clientConfig.getClientId() + " got " + idClaims.getAudience());
|
|
||||||
}
|
|
||||||
|
|
||||||
// compare the nonce to our stored claim
|
|
||||||
// FIXME: Nimbus claims as strings?
|
|
||||||
String nonce = (String) idClaims.getCustomClaim("nonce");
|
|
||||||
if (StringUtils.isBlank(nonce)) {
|
|
||||||
|
|
||||||
logger.error("ID token did not contain a nonce claim.");
|
|
||||||
|
|
||||||
throw new AuthenticationServiceException("ID token did not contain a nonce claim.");
|
// check the signature
|
||||||
}
|
JwtSigningAndValidationService jwtValidator = validationServices.get(serverConfig.getJwksUri());
|
||||||
|
if (jwtValidator != null) {
|
||||||
|
if(!jwtValidator.validateSignature(idToken)) {
|
||||||
|
throw new AuthenticationServiceException("Signature validation failed");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info("No validation service found. Skipping signature validation");
|
||||||
|
}
|
||||||
|
|
||||||
String storedNonce = getStoredNonce(session);
|
// check the issuer
|
||||||
if (!nonce.equals(storedNonce)) {
|
if (idClaims.getIssuer() == null) {
|
||||||
logger.error("Possible replay attack detected! The comparison of the nonce in the returned "
|
throw new AuthenticationServiceException("Id Token Issuer is null");
|
||||||
+ "ID Token to the session " + NONCE_SESSION_VARIABLE + " failed. Expected " + storedNonce + " got " + nonce + ".");
|
} else if (!idClaims.getIssuer().equals(serverConfig.getIssuer())){
|
||||||
|
throw new AuthenticationServiceException("Issuers do not match, expected " + serverConfig.getIssuer() + " got " + idClaims.getIssuer());
|
||||||
|
}
|
||||||
|
|
||||||
throw new AuthenticationServiceException(
|
// check expiration
|
||||||
"Possible replay attack detected! The comparison of the nonce in the returned "
|
if (idClaims.getExpirationTime() == null) {
|
||||||
+ "ID Token to the session " + NONCE_SESSION_VARIABLE + " failed. Expected " + storedNonce + " got " + nonce + ".");
|
throw new AuthenticationServiceException("Id Token does not have required expiration claim");
|
||||||
}
|
} else {
|
||||||
|
// it's not null, see if it's expired
|
||||||
|
Date now = new Date(System.currentTimeMillis() - (timeSkewAllowance * 1000));
|
||||||
|
if (now.after(idClaims.getExpirationTime())) {
|
||||||
|
throw new AuthenticationServiceException("Id Token is expired: " + idClaims.getExpirationTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pull the subject (user id) out as a claim on the id_token
|
// check not before
|
||||||
|
if (idClaims.getNotBeforeTime() != null) {
|
||||||
String userId = idClaims.getSubject();
|
Date now = new Date(System.currentTimeMillis() + (timeSkewAllowance * 1000));
|
||||||
|
if (now.before(idClaims.getNotBeforeTime())){
|
||||||
// construct an OIDCAuthenticationToken and return a Authentication object w/the userId and the idToken
|
throw new AuthenticationServiceException("Id Token not valid untill: " + idClaims.getNotBeforeTime());
|
||||||
|
}
|
||||||
OIDCAuthenticationToken token = new OIDCAuthenticationToken(userId, idClaims.getIssuer(), serverConfig, idTokenValue, accessTokenValue, refreshTokenValue);
|
}
|
||||||
|
|
||||||
Authentication authentication = this.getAuthenticationManager().authenticate(token);
|
// check issued at
|
||||||
|
if (idClaims.getIssueTime() == null) {
|
||||||
|
throw new AuthenticationServiceException("Id Token does not have required issued-at claim");
|
||||||
|
} else {
|
||||||
|
// since it's not null, see if it was issued in the future
|
||||||
|
Date now = new Date(System.currentTimeMillis() + (timeSkewAllowance * 1000));
|
||||||
|
if (now.before(idClaims.getIssueTime())) {
|
||||||
|
throw new AuthenticationServiceException("Id Token was issued in the future: " + idClaims.getIssueTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check audience
|
||||||
|
if (idClaims.getAudience() == null) {
|
||||||
|
throw new AuthenticationServiceException("Id token audience is null");
|
||||||
|
} else if (!idClaims.getAudience().contains(clientConfig.getClientId())) {
|
||||||
|
throw new AuthenticationServiceException("Audience does not match, expected " + clientConfig.getClientId() + " got " + idClaims.getAudience());
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare the nonce to our stored claim
|
||||||
|
// FIXME: Nimbus claims as strings?
|
||||||
|
String nonce = (String) idClaims.getCustomClaim("nonce");
|
||||||
|
if (StringUtils.isBlank(nonce)) {
|
||||||
|
|
||||||
|
logger.error("ID token did not contain a nonce claim.");
|
||||||
|
|
||||||
|
throw new AuthenticationServiceException("ID token did not contain a nonce claim.");
|
||||||
|
}
|
||||||
|
|
||||||
|
String storedNonce = getStoredNonce(session);
|
||||||
|
if (!nonce.equals(storedNonce)) {
|
||||||
|
logger.error("Possible replay attack detected! The comparison of the nonce in the returned "
|
||||||
|
+ "ID Token to the session " + NONCE_SESSION_VARIABLE + " failed. Expected " + storedNonce + " got " + nonce + ".");
|
||||||
|
|
||||||
|
throw new AuthenticationServiceException(
|
||||||
|
"Possible replay attack detected! The comparison of the nonce in the returned "
|
||||||
|
+ "ID Token to the session " + NONCE_SESSION_VARIABLE + " failed. Expected " + storedNonce + " got " + nonce + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull the subject (user id) out as a claim on the id_token
|
||||||
|
|
||||||
|
String userId = idClaims.getSubject();
|
||||||
|
|
||||||
|
// construct an OIDCAuthenticationToken and return a Authentication object w/the userId and the idToken
|
||||||
|
|
||||||
|
OIDCAuthenticationToken token = new OIDCAuthenticationToken(userId, idClaims.getIssuer(), serverConfig, idTokenValue, accessTokenValue, refreshTokenValue);
|
||||||
|
|
||||||
|
Authentication authentication = this.getAuthenticationManager().authenticate(token);
|
||||||
|
|
||||||
|
return authentication;
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new AuthenticationServiceException("Couldn't parse idToken: ", e);
|
||||||
|
}
|
||||||
|
|
||||||
return authentication;
|
|
||||||
} catch (ParseException e) {
|
|
||||||
throw new AuthenticationServiceException("Couldn't parse idToken: ", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -456,7 +452,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a cryptographically random nonce and store it in the session
|
* Create a cryptographically random nonce and store it in the session
|
||||||
* @param session
|
* @param session
|
||||||
|
@ -477,7 +473,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
protected static String getStoredNonce(HttpSession session) {
|
protected static String getStoredNonce(HttpSession session) {
|
||||||
return getStoredSessionString(session, NONCE_SESSION_VARIABLE);
|
return getStoredSessionString(session, NONCE_SESSION_VARIABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a cryptographically random state and store it in the session
|
* Create a cryptographically random state and store it in the session
|
||||||
* @param session
|
* @param session
|
||||||
|
@ -486,10 +482,10 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
protected static String createState(HttpSession session) {
|
protected static String createState(HttpSession session) {
|
||||||
String state = new BigInteger(50, new SecureRandom()).toString(16);
|
String state = new BigInteger(50, new SecureRandom()).toString(16);
|
||||||
session.setAttribute(STATE_SESSION_VARIABLE, state);
|
session.setAttribute(STATE_SESSION_VARIABLE, state);
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the state we stored in the session
|
* Get the state we stored in the session
|
||||||
* @param session
|
* @param session
|
||||||
|
@ -498,14 +494,14 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
protected static String getStoredState(HttpSession session) {
|
protected static String getStoredState(HttpSession session) {
|
||||||
return getStoredSessionString(session, STATE_SESSION_VARIABLE);
|
return getStoredSessionString(session, STATE_SESSION_VARIABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Getters and setters for configuration variables
|
// Getters and setters for configuration variables
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
public int getTimeSkewAllowance() {
|
public int getTimeSkewAllowance() {
|
||||||
return timeSkewAllowance;
|
return timeSkewAllowance;
|
||||||
}
|
}
|
||||||
|
@ -582,6 +578,6 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
*/
|
*/
|
||||||
public void setAuthRequestUrlBuilder(AuthRequestUrlBuilder authRequestBuilder) {
|
public void setAuthRequestUrlBuilder(AuthRequestUrlBuilder authRequestBuilder) {
|
||||||
this.authRequestBuilder = authRequestBuilder;
|
this.authRequestBuilder = authRequestBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,25 +22,21 @@ import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
||||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author nemonik
|
* @author nemonik
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class OIDCAuthenticationProvider implements
|
public class OIDCAuthenticationProvider implements
|
||||||
AuthenticationProvider, InitializingBean {
|
AuthenticationProvider, InitializingBean {
|
||||||
|
|
||||||
private UserInfoFetcher userInfoFetcher = new UserInfoFetcher();
|
private UserInfoFetcher userInfoFetcher = new UserInfoFetcher();
|
||||||
|
|
||||||
private GrantedAuthoritiesMapper authoritiesMapper = new NamedAdminAuthoritiesMapper();
|
private GrantedAuthoritiesMapper authoritiesMapper = new NamedAdminAuthoritiesMapper();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -69,24 +65,24 @@ public class OIDCAuthenticationProvider implements
|
||||||
|
|
||||||
if (authentication instanceof OIDCAuthenticationToken) {
|
if (authentication instanceof OIDCAuthenticationToken) {
|
||||||
|
|
||||||
|
|
||||||
OIDCAuthenticationToken token = (OIDCAuthenticationToken) authentication;
|
OIDCAuthenticationToken token = (OIDCAuthenticationToken) authentication;
|
||||||
|
|
||||||
Collection<SubjectIssuerGrantedAuthority> authorities = Lists.newArrayList(new SubjectIssuerGrantedAuthority(token.getSub(), token.getIssuer()));
|
Collection<SubjectIssuerGrantedAuthority> authorities = Lists.newArrayList(new SubjectIssuerGrantedAuthority(token.getSub(), token.getIssuer()));
|
||||||
|
|
||||||
UserInfo userInfo = userInfoFetcher.loadUserInfo(token);
|
UserInfo userInfo = userInfoFetcher.loadUserInfo(token);
|
||||||
|
|
||||||
if (userInfo == null) {
|
if (userInfo == null) {
|
||||||
// TODO: user Info not found -- error?
|
// TODO: user Info not found -- error?
|
||||||
} else {
|
} else {
|
||||||
if (!Strings.isNullOrEmpty(userInfo.getSub()) && !userInfo.getSub().equals(token.getSub())) {
|
if (!Strings.isNullOrEmpty(userInfo.getSub()) && !userInfo.getSub().equals(token.getSub())) {
|
||||||
// the userinfo came back and the user_id fields don't match what was in the id_token
|
// the userinfo came back and the user_id fields don't match what was in the id_token
|
||||||
throw new UsernameNotFoundException("user_id mismatch between id_token and user_info call: " + userInfo.getSub() + " / " + token.getSub());
|
throw new UsernameNotFoundException("user_id mismatch between id_token and user_info call: " + userInfo.getSub() + " / " + token.getSub());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new OIDCAuthenticationToken(token.getSub(),
|
return new OIDCAuthenticationToken(token.getSub(),
|
||||||
token.getIssuer(),
|
token.getIssuer(),
|
||||||
userInfo, authoritiesMapper.mapAuthorities(authorities),
|
userInfo, authoritiesMapper.mapAuthorities(authorities),
|
||||||
token.getIdTokenValue(), token.getAccessTokenValue(), token.getRefreshTokenValue());
|
token.getIdTokenValue(), token.getAccessTokenValue(), token.getRefreshTokenValue());
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,8 @@ import com.google.common.collect.ImmutableMap;
|
||||||
*/
|
*/
|
||||||
public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
|
|
||||||
private static final long serialVersionUID = 22100073066377804L;
|
private static final long serialVersionUID = 22100073066377804L;
|
||||||
|
|
||||||
private final Object principal;
|
private final Object principal;
|
||||||
private final String idTokenValue; // string representation of the id token
|
private final String idTokenValue; // string representation of the id token
|
||||||
private final String accessTokenValue; // string representation of the access token
|
private final String accessTokenValue; // string representation of the access token
|
||||||
|
@ -43,7 +43,7 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
|
|
||||||
private final transient ServerConfiguration serverConfiguration; // server configuration used to fulfill this token, don't serialize it
|
private final transient ServerConfiguration serverConfiguration; // server configuration used to fulfill this token, don't serialize it
|
||||||
private final transient UserInfo userInfo; // user info container, don't serialize it b/c it might be huge and can be re-fetched
|
private final transient UserInfo userInfo; // user info container, don't serialize it b/c it might be huge and can be re-fetched
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs OIDCAuthenticationToken with a full set of authorities, marking this as authenticated.
|
* Constructs OIDCAuthenticationToken with a full set of authorities, marking this as authenticated.
|
||||||
*
|
*
|
||||||
|
@ -55,7 +55,7 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
* @param principal
|
* @param principal
|
||||||
* @param idToken
|
* @param idToken
|
||||||
*/
|
*/
|
||||||
public OIDCAuthenticationToken(String subject, String issuer,
|
public OIDCAuthenticationToken(String subject, String issuer,
|
||||||
UserInfo userInfo, Collection<? extends GrantedAuthority> authorities,
|
UserInfo userInfo, Collection<? extends GrantedAuthority> authorities,
|
||||||
String idTokenValue, String accessTokenValue, String refreshTokenValue) {
|
String idTokenValue, String accessTokenValue, String refreshTokenValue) {
|
||||||
|
|
||||||
|
@ -70,12 +70,12 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
this.refreshTokenValue = refreshTokenValue;
|
this.refreshTokenValue = refreshTokenValue;
|
||||||
|
|
||||||
this.serverConfiguration = null; // we don't need a server config anymore
|
this.serverConfiguration = null; // we don't need a server config anymore
|
||||||
|
|
||||||
setAuthenticated(true);
|
setAuthenticated(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs OIDCAuthenticationToken for use as a data shuttle from the filter to the auth provider.
|
* Constructs OIDCAuthenticationToken for use as a data shuttle from the filter to the auth provider.
|
||||||
*
|
*
|
||||||
* Set to not-authenticated.
|
* Set to not-authenticated.
|
||||||
*
|
*
|
||||||
|
@ -83,8 +83,8 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
* @param sub
|
* @param sub
|
||||||
* @param idToken
|
* @param idToken
|
||||||
*/
|
*/
|
||||||
public OIDCAuthenticationToken(String subject, String issuer,
|
public OIDCAuthenticationToken(String subject, String issuer,
|
||||||
ServerConfiguration serverConfiguration,
|
ServerConfiguration serverConfiguration,
|
||||||
String idTokenValue, String accessTokenValue, String refreshTokenValue) {
|
String idTokenValue, String accessTokenValue, String refreshTokenValue) {
|
||||||
|
|
||||||
super(new ArrayList<GrantedAuthority>(0));
|
super(new ArrayList<GrantedAuthority>(0));
|
||||||
|
@ -97,10 +97,10 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
this.refreshTokenValue = refreshTokenValue;
|
this.refreshTokenValue = refreshTokenValue;
|
||||||
|
|
||||||
this.userInfo = null; // we don't have a UserInfo yet
|
this.userInfo = null; // we don't have a UserInfo yet
|
||||||
|
|
||||||
this.serverConfiguration = serverConfiguration;
|
this.serverConfiguration = serverConfiguration;
|
||||||
|
|
||||||
|
|
||||||
setAuthenticated(false);
|
setAuthenticated(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,46 +128,46 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the idTokenValue
|
* @return the idTokenValue
|
||||||
*/
|
*/
|
||||||
public String getIdTokenValue() {
|
public String getIdTokenValue() {
|
||||||
return idTokenValue;
|
return idTokenValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the accessTokenValue
|
* @return the accessTokenValue
|
||||||
*/
|
*/
|
||||||
public String getAccessTokenValue() {
|
public String getAccessTokenValue() {
|
||||||
return accessTokenValue;
|
return accessTokenValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the refreshTokenValue
|
* @return the refreshTokenValue
|
||||||
*/
|
*/
|
||||||
public String getRefreshTokenValue() {
|
public String getRefreshTokenValue() {
|
||||||
return refreshTokenValue;
|
return refreshTokenValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the serverConfiguration
|
* @return the serverConfiguration
|
||||||
*/
|
*/
|
||||||
public ServerConfiguration getServerConfiguration() {
|
public ServerConfiguration getServerConfiguration() {
|
||||||
return serverConfiguration;
|
return serverConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the issuer
|
* @return the issuer
|
||||||
*/
|
*/
|
||||||
public String getIssuer() {
|
public String getIssuer() {
|
||||||
return issuer;
|
return issuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the userInfo
|
* @return the userInfo
|
||||||
*/
|
*/
|
||||||
public UserInfo getUserInfo() {
|
public UserInfo getUserInfo() {
|
||||||
return userInfo;
|
return userInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -16,22 +16,22 @@ import com.google.common.base.Strings;
|
||||||
*/
|
*/
|
||||||
public class SubjectIssuerGrantedAuthority implements GrantedAuthority {
|
public class SubjectIssuerGrantedAuthority implements GrantedAuthority {
|
||||||
|
|
||||||
private static final long serialVersionUID = 5584978219226664794L;
|
private static final long serialVersionUID = 5584978219226664794L;
|
||||||
|
|
||||||
private final String subject;
|
private final String subject;
|
||||||
private final String issuer;
|
private final String issuer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param subject
|
* @param subject
|
||||||
* @param issuer
|
* @param issuer
|
||||||
*/
|
*/
|
||||||
public SubjectIssuerGrantedAuthority(String subject, String issuer) {
|
public SubjectIssuerGrantedAuthority(String subject, String issuer) {
|
||||||
if (Strings.isNullOrEmpty(subject) || Strings.isNullOrEmpty(issuer)) {
|
if (Strings.isNullOrEmpty(subject) || Strings.isNullOrEmpty(issuer)) {
|
||||||
throw new IllegalArgumentException("Neither subject nor issuer may be null or empty");
|
throw new IllegalArgumentException("Neither subject nor issuer may be null or empty");
|
||||||
}
|
}
|
||||||
this.subject = subject;
|
this.subject = subject;
|
||||||
this.issuer = issuer;
|
this.issuer = issuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a string formed by concatenating the subject with the issuer, separated by _ and prepended with OIDC_
|
* Returns a string formed by concatenating the subject with the issuer, separated by _ and prepended with OIDC_
|
||||||
|
@ -44,67 +44,67 @@ public class SubjectIssuerGrantedAuthority implements GrantedAuthority {
|
||||||
public String getAuthority() {
|
public String getAuthority() {
|
||||||
return "OIDC_" + subject + "_" + issuer;
|
return "OIDC_" + subject + "_" + issuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the subject
|
* @return the subject
|
||||||
*/
|
*/
|
||||||
public String getSubject() {
|
public String getSubject() {
|
||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the issuer
|
* @return the issuer
|
||||||
*/
|
*/
|
||||||
public String getIssuer() {
|
public String getIssuer() {
|
||||||
return issuer;
|
return issuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Object#hashCode()
|
* @see java.lang.Object#hashCode()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
|
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
|
||||||
result = prime * result + ((subject == null) ? 0 : subject.hashCode());
|
result = prime * result + ((subject == null) ? 0 : subject.hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Object#equals(java.lang.Object)
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(obj instanceof SubjectIssuerGrantedAuthority)) {
|
if (!(obj instanceof SubjectIssuerGrantedAuthority)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SubjectIssuerGrantedAuthority other = (SubjectIssuerGrantedAuthority) obj;
|
SubjectIssuerGrantedAuthority other = (SubjectIssuerGrantedAuthority) obj;
|
||||||
if (issuer == null) {
|
if (issuer == null) {
|
||||||
if (other.issuer != null) {
|
if (other.issuer != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!issuer.equals(other.issuer)) {
|
} else if (!issuer.equals(other.issuer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (subject == null) {
|
if (subject == null) {
|
||||||
if (other.subject != null) {
|
if (other.subject != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!subject.equals(other.subject)) {
|
} else if (!subject.equals(other.subject)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getAuthority();
|
return getAuthority();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import com.google.gson.JsonParser;
|
||||||
public class UserInfoFetcher {
|
public class UserInfoFetcher {
|
||||||
|
|
||||||
public UserInfo loadUserInfo(OIDCAuthenticationToken token) {
|
public UserInfo loadUserInfo(OIDCAuthenticationToken token) {
|
||||||
|
|
||||||
HttpClient httpClient = new DefaultHttpClient();
|
HttpClient httpClient = new DefaultHttpClient();
|
||||||
|
|
||||||
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||||
|
@ -25,15 +25,15 @@ public class UserInfoFetcher {
|
||||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
||||||
form.add("access_token", token.getAccessTokenValue());
|
form.add("access_token", token.getAccessTokenValue());
|
||||||
form.add("schema", "openid");
|
form.add("schema", "openid");
|
||||||
|
|
||||||
String userInfoString = restTemplate.postForObject(token.getServerConfiguration().getUserInfoUri(), form, String.class);
|
String userInfoString = restTemplate.postForObject(token.getServerConfiguration().getUserInfoUri(), form, String.class);
|
||||||
|
|
||||||
JsonObject userInfoJson = new JsonParser().parse(userInfoString).getAsJsonObject();
|
JsonObject userInfoJson = new JsonParser().parse(userInfoString).getAsJsonObject();
|
||||||
|
|
||||||
UserInfo userInfo = DefaultUserInfo.fromJson(userInfoJson);
|
UserInfo userInfo = DefaultUserInfo.fromJson(userInfoJson);
|
||||||
|
|
||||||
return userInfo;
|
return userInfo;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,16 +34,16 @@ public class ClientKeyPublisher implements BeanDefinitionRegistryPostProcessor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If either the jwkPublishUrl or x509PublishUrl fields are set on this bean, set up a listener on that URL to publish keys.
|
* If either the jwkPublishUrl or x509PublishUrl fields are set on this bean, set up a listener on that URL to publish keys.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||||
if (!Strings.isNullOrEmpty(getJwkPublishUrl())) {
|
if (!Strings.isNullOrEmpty(getJwkPublishUrl())) {
|
||||||
|
|
||||||
// add a mapping to this class
|
// add a mapping to this class
|
||||||
BeanDefinitionBuilder clientKeyMapping = BeanDefinitionBuilder.rootBeanDefinition(ClientKeyPublisherMapping.class);
|
BeanDefinitionBuilder clientKeyMapping = BeanDefinitionBuilder.rootBeanDefinition(ClientKeyPublisherMapping.class);
|
||||||
// custom view resolver
|
// custom view resolver
|
||||||
BeanDefinitionBuilder viewResolver = BeanDefinitionBuilder.rootBeanDefinition(JwkViewResolver.class);
|
BeanDefinitionBuilder viewResolver = BeanDefinitionBuilder.rootBeanDefinition(JwkViewResolver.class);
|
||||||
|
|
||||||
if (!Strings.isNullOrEmpty(getJwkPublishUrl())) {
|
if (!Strings.isNullOrEmpty(getJwkPublishUrl())) {
|
||||||
clientKeyMapping.addPropertyValue("jwkPublishUrl", getJwkPublishUrl());
|
clientKeyMapping.addPropertyValue("jwkPublishUrl", getJwkPublishUrl());
|
||||||
|
|
||||||
|
@ -56,49 +56,49 @@ public class ClientKeyPublisher implements BeanDefinitionRegistryPostProcessor {
|
||||||
registry.registerBeanDefinition("jwkKeyList", jwkView.getBeanDefinition());
|
registry.registerBeanDefinition("jwkKeyList", jwkView.getBeanDefinition());
|
||||||
viewResolver.addPropertyReference("jwk", "jwkKeyList");
|
viewResolver.addPropertyReference("jwk", "jwkKeyList");
|
||||||
}
|
}
|
||||||
|
|
||||||
registry.registerBeanDefinition("clientKeyMapping", clientKeyMapping.getBeanDefinition());
|
registry.registerBeanDefinition("clientKeyMapping", clientKeyMapping.getBeanDefinition());
|
||||||
registry.registerBeanDefinition("jwkViewResolver", viewResolver.getBeanDefinition());
|
registry.registerBeanDefinition("jwkViewResolver", viewResolver.getBeanDefinition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
* @see org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||||
this.registry = registry;
|
this.registry = registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a view to publish all keys in JWK format. Only used if jwkPublishUrl is set.
|
* Return a view to publish all keys in JWK format. Only used if jwkPublishUrl is set.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ModelAndView publishClientJwk() {
|
public ModelAndView publishClientJwk() {
|
||||||
|
|
||||||
// map from key id to key
|
// map from key id to key
|
||||||
Map<String, JWK> keys = signingAndValidationService.getAllPublicKeys();
|
Map<String, JWK> keys = signingAndValidationService.getAllPublicKeys();
|
||||||
|
|
||||||
// TODO: check if keys are empty, return a 404 here or just an empty list?
|
// TODO: check if keys are empty, return a 404 here or just an empty list?
|
||||||
|
|
||||||
return new ModelAndView(jwkViewName, "keys", keys);
|
return new ModelAndView(jwkViewName, "keys", keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the jwkPublishUrl
|
* @return the jwkPublishUrl
|
||||||
*/
|
*/
|
||||||
public String getJwkPublishUrl() {
|
public String getJwkPublishUrl() {
|
||||||
return jwkPublishUrl;
|
return jwkPublishUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param jwkPublishUrl the jwkPublishUrl to set
|
* @param jwkPublishUrl the jwkPublishUrl to set
|
||||||
*/
|
*/
|
||||||
public void setJwkPublishUrl(String jwkPublishUrl) {
|
public void setJwkPublishUrl(String jwkPublishUrl) {
|
||||||
this.jwkPublishUrl = jwkPublishUrl;
|
this.jwkPublishUrl = jwkPublishUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the signingAndValidationService
|
* @return the signingAndValidationService
|
||||||
|
|
|
@ -19,72 +19,72 @@ public class ClientKeyPublisherMapping extends RequestMappingInfoHandlerMapping
|
||||||
|
|
||||||
private String jwkPublishUrl;
|
private String jwkPublishUrl;
|
||||||
private String x509PublishUrl;
|
private String x509PublishUrl;
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#isHandler(java.lang.Class)
|
* @see org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#isHandler(java.lang.Class)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean isHandler(Class<?> beanType) {
|
protected boolean isHandler(Class<?> beanType) {
|
||||||
return beanType.equals(ClientKeyPublisher.class);
|
return beanType.equals(ClientKeyPublisher.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map the "jwkKeyPublish" method to our jwkPublishUrl.
|
* Map the "jwkKeyPublish" method to our jwkPublishUrl.
|
||||||
* Map the "x509KeyPublish" method to our x509PublishUrl.
|
* Map the "x509KeyPublish" method to our x509PublishUrl.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||||
|
|
||||||
if (method.getName().equals("publishClientJwk") && getJwkPublishUrl() != null) {
|
if (method.getName().equals("publishClientJwk") && getJwkPublishUrl() != null) {
|
||||||
return new RequestMappingInfo(
|
return new RequestMappingInfo(
|
||||||
new PatternsRequestCondition(new String[] {getJwkPublishUrl()}, getUrlPathHelper(), getPathMatcher(), false, false),
|
new PatternsRequestCondition(new String[] {getJwkPublishUrl()}, getUrlPathHelper(), getPathMatcher(), false, false),
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
} else if (method.getName().equals("publishClientx509") && getX509PublishUrl() != null) {
|
} else if (method.getName().equals("publishClientx509") && getX509PublishUrl() != null) {
|
||||||
return new RequestMappingInfo(
|
return new RequestMappingInfo(
|
||||||
new PatternsRequestCondition(new String[] {getX509PublishUrl()}, getUrlPathHelper(), getPathMatcher(), false, false),
|
new PatternsRequestCondition(new String[] {getX509PublishUrl()}, getUrlPathHelper(), getPathMatcher(), false, false),
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the jwkPublishUrl
|
* @return the jwkPublishUrl
|
||||||
*/
|
*/
|
||||||
public String getJwkPublishUrl() {
|
public String getJwkPublishUrl() {
|
||||||
return jwkPublishUrl;
|
return jwkPublishUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param jwkPublishUrl the jwkPublishUrl to set
|
* @param jwkPublishUrl the jwkPublishUrl to set
|
||||||
*/
|
*/
|
||||||
public void setJwkPublishUrl(String jwkPublishUrl) {
|
public void setJwkPublishUrl(String jwkPublishUrl) {
|
||||||
this.jwkPublishUrl = jwkPublishUrl;
|
this.jwkPublishUrl = jwkPublishUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the x509PublishUrl
|
* @return the x509PublishUrl
|
||||||
*/
|
*/
|
||||||
public String getX509PublishUrl() {
|
public String getX509PublishUrl() {
|
||||||
return x509PublishUrl;
|
return x509PublishUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param x509PublishUrl the x509PublishUrl to set
|
* @param x509PublishUrl the x509PublishUrl to set
|
||||||
*/
|
*/
|
||||||
public void setX509PublishUrl(String x509PublishUrl) {
|
public void setX509PublishUrl(String x509PublishUrl) {
|
||||||
this.x509PublishUrl = x509PublishUrl;
|
this.x509PublishUrl = x509PublishUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,12 @@ public class JwkViewResolver implements ViewResolver, Ordered {
|
||||||
|
|
||||||
private String jwkViewName = "jwkKeyList";
|
private String jwkViewName = "jwkKeyList";
|
||||||
private View jwk;
|
private View jwk;
|
||||||
|
|
||||||
private String x509ViewName = "x509certs";
|
private String x509ViewName = "x509certs";
|
||||||
private View x509;
|
private View x509;
|
||||||
|
|
||||||
private int order = HIGHEST_PRECEDENCE; // highest precedence, most specific -- avoids hitting the catch-all view resolvers
|
private int order = HIGHEST_PRECEDENCE; // highest precedence, most specific -- avoids hitting the catch-all view resolvers
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map "jwkKeyList" to the jwk property and "x509certs" to the x509 property on this bean.
|
* Map "jwkKeyList" to the jwk property and "x509certs" to the x509 property on this bean.
|
||||||
* Everything else returns null
|
* Everything else returns null
|
||||||
|
@ -46,74 +46,74 @@ public class JwkViewResolver implements ViewResolver, Ordered {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the x509
|
* @return the x509
|
||||||
*/
|
*/
|
||||||
public View getX509() {
|
public View getX509() {
|
||||||
return x509;
|
return x509;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param x509 the x509 to set
|
* @param x509 the x509 to set
|
||||||
*/
|
*/
|
||||||
public void setX509(View x509) {
|
public void setX509(View x509) {
|
||||||
this.x509 = x509;
|
this.x509 = x509;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the jwk
|
* @return the jwk
|
||||||
*/
|
*/
|
||||||
public View getJwk() {
|
public View getJwk() {
|
||||||
return jwk;
|
return jwk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param jwk the jwk to set
|
* @param jwk the jwk to set
|
||||||
*/
|
*/
|
||||||
public void setJwk(View jwk) {
|
public void setJwk(View jwk) {
|
||||||
this.jwk = jwk;
|
this.jwk = jwk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the order
|
* @return the order
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getOrder() {
|
public int getOrder() {
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param order the order to set
|
* @param order the order to set
|
||||||
*/
|
*/
|
||||||
public void setOrder(int order) {
|
public void setOrder(int order) {
|
||||||
this.order = order;
|
this.order = order;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the jwkViewName
|
* @return the jwkViewName
|
||||||
*/
|
*/
|
||||||
public String getJwkViewName() {
|
public String getJwkViewName() {
|
||||||
return jwkViewName;
|
return jwkViewName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param jwkViewName the jwkViewName to set
|
* @param jwkViewName the jwkViewName to set
|
||||||
*/
|
*/
|
||||||
public void setJwkViewName(String jwkViewName) {
|
public void setJwkViewName(String jwkViewName) {
|
||||||
this.jwkViewName = jwkViewName;
|
this.jwkViewName = jwkViewName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the x509ViewName
|
* @return the x509ViewName
|
||||||
*/
|
*/
|
||||||
public String getX509ViewName() {
|
public String getX509ViewName() {
|
||||||
return x509ViewName;
|
return x509ViewName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param x509ViewName the x509ViewName to set
|
* @param x509ViewName the x509ViewName to set
|
||||||
*/
|
*/
|
||||||
public void setX509ViewName(String x509ViewName) {
|
public void setX509ViewName(String x509ViewName) {
|
||||||
this.x509ViewName = x509ViewName;
|
this.x509ViewName = x509ViewName;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,24 +16,24 @@ public class IssuerServiceResponse {
|
||||||
private String loginHint;
|
private String loginHint;
|
||||||
private String targetLinkUri;
|
private String targetLinkUri;
|
||||||
private String redirectUrl;
|
private String redirectUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param issuer
|
* @param issuer
|
||||||
* @param loginHint
|
* @param loginHint
|
||||||
* @param targetLinkUri
|
* @param targetLinkUri
|
||||||
*/
|
*/
|
||||||
public IssuerServiceResponse(String issuer, String loginHint, String targetLinkUri) {
|
public IssuerServiceResponse(String issuer, String loginHint, String targetLinkUri) {
|
||||||
this.issuer = issuer;
|
this.issuer = issuer;
|
||||||
this.loginHint = loginHint;
|
this.loginHint = loginHint;
|
||||||
this.targetLinkUri = targetLinkUri;
|
this.targetLinkUri = targetLinkUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param redirectUrl
|
* @param redirectUrl
|
||||||
*/
|
*/
|
||||||
public IssuerServiceResponse(String redirectUrl) {
|
public IssuerServiceResponse(String redirectUrl) {
|
||||||
this.redirectUrl = redirectUrl;
|
this.redirectUrl = redirectUrl;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @return the issuer
|
* @return the issuer
|
||||||
*/
|
*/
|
||||||
|
@ -82,12 +82,12 @@ public class IssuerServiceResponse {
|
||||||
public void setRedirectUrl(String redirectUrl) {
|
public void setRedirectUrl(String redirectUrl) {
|
||||||
this.redirectUrl = redirectUrl;
|
this.redirectUrl = redirectUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the redirect url has been set, then we should send a redirect using it instead of processing things.
|
* If the redirect url has been set, then we should send a redirect using it instead of processing things.
|
||||||
*/
|
*/
|
||||||
public boolean shouldRedirect() {
|
public boolean shouldRedirect() {
|
||||||
return this.redirectUrl != null;
|
return this.redirectUrl != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,6 @@ public interface AuthRequestUrlBuilder {
|
||||||
* @param state
|
* @param state
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, ClientDetails clientConfig, String redirectUri, String nonce, String state);
|
public String buildAuthRequestUrl(ServerConfiguration serverConfig, ClientDetails clientConfig, String redirectUri, String nonce, String state);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,5 +13,5 @@ import org.springframework.security.oauth2.provider.ClientDetails;
|
||||||
public interface ClientConfigurationService {
|
public interface ClientConfigurationService {
|
||||||
|
|
||||||
public ClientDetails getClientConfiguration(ServerConfiguration issuer);
|
public ClientDetails getClientConfiguration(ServerConfiguration issuer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,5 +17,5 @@ import org.mitre.openid.connect.client.model.IssuerServiceResponse;
|
||||||
public interface IssuerService {
|
public interface IssuerService {
|
||||||
|
|
||||||
public IssuerServiceResponse getIssuer(HttpServletRequest request);
|
public IssuerServiceResponse getIssuer(HttpServletRequest request);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,5 +12,5 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
||||||
public interface ServerConfigurationService {
|
public interface ServerConfigurationService {
|
||||||
|
|
||||||
public ServerConfiguration getServerConfiguration(String issuer);
|
public ServerConfiguration getServerConfiguration(String issuer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.CacheLoader;
|
import com.google.common.cache.CacheLoader;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
|
@ -35,66 +34,66 @@ import com.google.gson.JsonParser;
|
||||||
public class DynamicRegistrationClientConfigurationService implements ClientConfigurationService {
|
public class DynamicRegistrationClientConfigurationService implements ClientConfigurationService {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
|
private static Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
|
||||||
|
|
||||||
private LoadingCache<ServerConfiguration, ClientDetailsEntity> clients;
|
private LoadingCache<ServerConfiguration, ClientDetailsEntity> clients;
|
||||||
|
|
||||||
private ClientDetailsEntity template;
|
private ClientDetailsEntity template;
|
||||||
|
|
||||||
public DynamicRegistrationClientConfigurationService() {
|
public DynamicRegistrationClientConfigurationService() {
|
||||||
clients = CacheBuilder.newBuilder().build(new DynamicClientRegistrationLoader());
|
clients = CacheBuilder.newBuilder().build(new DynamicClientRegistrationLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientDetails getClientConfiguration(ServerConfiguration issuer) {
|
public ClientDetails getClientConfiguration(ServerConfiguration issuer) {
|
||||||
try {
|
try {
|
||||||
return clients.get(issuer);
|
return clients.get(issuer);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
logger.warn("Unable to get client configuration", e);
|
logger.warn("Unable to get client configuration", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the template
|
* @return the template
|
||||||
*/
|
*/
|
||||||
public ClientDetailsEntity getTemplate() {
|
public ClientDetailsEntity getTemplate() {
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param template the template to set
|
* @param template the template to set
|
||||||
*/
|
*/
|
||||||
public void setTemplate(ClientDetailsEntity template) {
|
public void setTemplate(ClientDetailsEntity template) {
|
||||||
this.template = template;
|
this.template = template;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DynamicClientRegistrationLoader extends CacheLoader<ServerConfiguration, ClientDetailsEntity> {
|
public class DynamicClientRegistrationLoader extends CacheLoader<ServerConfiguration, ClientDetailsEntity> {
|
||||||
private HttpClient httpClient = new DefaultHttpClient();
|
private HttpClient httpClient = new DefaultHttpClient();
|
||||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||||
private JsonParser parser = new JsonParser();
|
private JsonParser parser = new JsonParser();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientDetailsEntity load(ServerConfiguration serverConfig) throws Exception {
|
public ClientDetailsEntity load(ServerConfiguration serverConfig) throws Exception {
|
||||||
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||||
|
|
||||||
// dynamically register this client
|
|
||||||
JsonObject jsonRequest = ClientDetailsEntityJsonProcessor.serialize(template, null, null);
|
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
headers.setAccept(Lists.newArrayList(MediaType.APPLICATION_JSON));
|
|
||||||
|
|
||||||
HttpEntity<String> entity = new HttpEntity<String>(jsonRequest.toString(), headers);
|
|
||||||
|
|
||||||
String registered = restTemplate.postForObject(serverConfig.getRegistrationEndpointUri(), entity, String.class);
|
|
||||||
// TODO: handle HTTP errors
|
|
||||||
|
|
||||||
// TODO: save registration token and other important bits
|
|
||||||
ClientDetailsEntity client = ClientDetailsEntityJsonProcessor.parse(registered);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
// dynamically register this client
|
||||||
|
JsonObject jsonRequest = ClientDetailsEntityJsonProcessor.serialize(template, null, null);
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
headers.setAccept(Lists.newArrayList(MediaType.APPLICATION_JSON));
|
||||||
|
|
||||||
|
HttpEntity<String> entity = new HttpEntity<String>(jsonRequest.toString(), headers);
|
||||||
|
|
||||||
|
String registered = restTemplate.postForObject(serverConfig.getRegistrationEndpointUri(), entity, String.class);
|
||||||
|
// TODO: handle HTTP errors
|
||||||
|
|
||||||
|
// TODO: save registration token and other important bits
|
||||||
|
ClientDetailsEntity client = ClientDetailsEntityJsonProcessor.parse(registered);
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,72 +31,72 @@ import com.google.gson.JsonParser;
|
||||||
public class DynamicServerConfigurationService implements ServerConfigurationService {
|
public class DynamicServerConfigurationService implements ServerConfigurationService {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
|
private static Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
|
||||||
|
|
||||||
// map of issuer -> server configuration, loaded dynamically from service discovery
|
// map of issuer -> server configuration, loaded dynamically from service discovery
|
||||||
private LoadingCache<String, ServerConfiguration> servers;
|
private LoadingCache<String, ServerConfiguration> servers;
|
||||||
|
|
||||||
public DynamicServerConfigurationService() {
|
public DynamicServerConfigurationService() {
|
||||||
// initialize the cache
|
// initialize the cache
|
||||||
servers = CacheBuilder.newBuilder().build(new OpenIDConnectServiceConfigurationFetcher());
|
servers = CacheBuilder.newBuilder().build(new OpenIDConnectServiceConfigurationFetcher());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServerConfiguration getServerConfiguration(String issuer) {
|
public ServerConfiguration getServerConfiguration(String issuer) {
|
||||||
try {
|
try {
|
||||||
return servers.get(issuer);
|
return servers.get(issuer);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
logger.warn("Couldn't load configuration for " + issuer, e);
|
logger.warn("Couldn't load configuration for " + issuer, e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jricher
|
* @author jricher
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private class OpenIDConnectServiceConfigurationFetcher extends CacheLoader<String, ServerConfiguration> {
|
private class OpenIDConnectServiceConfigurationFetcher extends CacheLoader<String, ServerConfiguration> {
|
||||||
private HttpClient httpClient = new DefaultHttpClient();
|
private HttpClient httpClient = new DefaultHttpClient();
|
||||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||||
private JsonParser parser = new JsonParser();
|
private JsonParser parser = new JsonParser();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServerConfiguration load(String issuer) throws Exception {
|
public ServerConfiguration load(String issuer) throws Exception {
|
||||||
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||||
|
|
||||||
// data holder
|
// data holder
|
||||||
ServerConfiguration conf = new ServerConfiguration();
|
ServerConfiguration conf = new ServerConfiguration();
|
||||||
|
|
||||||
// construct the well-known URI
|
|
||||||
String url = issuer + "/.well-known/openid-configuration";
|
|
||||||
|
|
||||||
// fetch the value
|
|
||||||
String jsonString = restTemplate.getForObject(url, String.class);
|
|
||||||
|
|
||||||
JsonElement parsed = parser.parse(jsonString);
|
// construct the well-known URI
|
||||||
if (parsed.isJsonObject()) {
|
String url = issuer + "/.well-known/openid-configuration";
|
||||||
|
|
||||||
JsonObject o = parsed.getAsJsonObject();
|
|
||||||
|
|
||||||
// sanity checks
|
|
||||||
if (!issuer.equals(o.get("issuer").getAsString())) {
|
|
||||||
throw new IllegalStateException("Discovered issuers didn't match, expected " + issuer + " got " + o.get("issuer").getAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
conf.setIssuer(o.get("issuer").getAsString());
|
|
||||||
conf.setAuthorizationEndpointUri(o.get("authorization_endpoint").getAsString());
|
|
||||||
conf.setTokenEndpointUri(o.get("token_endpoint").getAsString());
|
|
||||||
conf.setJwksUri(o.get("jwks_uri").getAsString());
|
|
||||||
conf.setUserInfoUri(o.get("userinfo_endpoint").getAsString());
|
|
||||||
conf.setRegistrationEndpointUri(o.get("registration_endpoint").getAsString());
|
|
||||||
|
|
||||||
return conf;
|
// fetch the value
|
||||||
} else {
|
String jsonString = restTemplate.getForObject(url, String.class);
|
||||||
throw new IllegalStateException("Couldn't parse server discovery results for " + url);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
JsonElement parsed = parser.parse(jsonString);
|
||||||
|
if (parsed.isJsonObject()) {
|
||||||
|
|
||||||
|
JsonObject o = parsed.getAsJsonObject();
|
||||||
|
|
||||||
|
// sanity checks
|
||||||
|
if (!issuer.equals(o.get("issuer").getAsString())) {
|
||||||
|
throw new IllegalStateException("Discovered issuers didn't match, expected " + issuer + " got " + o.get("issuer").getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
conf.setIssuer(o.get("issuer").getAsString());
|
||||||
|
conf.setAuthorizationEndpointUri(o.get("authorization_endpoint").getAsString());
|
||||||
|
conf.setTokenEndpointUri(o.get("token_endpoint").getAsString());
|
||||||
|
conf.setJwksUri(o.get("jwks_uri").getAsString());
|
||||||
|
conf.setUserInfoUri(o.get("userinfo_endpoint").getAsString());
|
||||||
|
conf.setRegistrationEndpointUri(o.get("registration_endpoint").getAsString());
|
||||||
|
|
||||||
|
return conf;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Couldn't parse server discovery results for " + url);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class PlainAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
||||||
@Override
|
@Override
|
||||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, ClientDetails clientConfig, String redirectUri, String nonce, String state) {
|
public String buildAuthRequestUrl(ServerConfiguration serverConfig, ClientDetails clientConfig, String redirectUri, String nonce, String state) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
||||||
uriBuilder.addParameter("response_type", "code");
|
uriBuilder.addParameter("response_type", "code");
|
||||||
uriBuilder.addParameter("client_id", clientConfig.getClientId());
|
uriBuilder.addParameter("client_id", clientConfig.getClientId());
|
||||||
|
@ -39,20 +39,20 @@ public class PlainAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
||||||
uriBuilder.addParameter("nonce", nonce);
|
uriBuilder.addParameter("nonce", nonce);
|
||||||
|
|
||||||
uriBuilder.addParameter("state", state);
|
uriBuilder.addParameter("state", state);
|
||||||
|
|
||||||
// Optional parameters:
|
// Optional parameters:
|
||||||
|
|
||||||
// TODO: display, prompt
|
// TODO: display, prompt
|
||||||
|
|
||||||
return uriBuilder.build().toString();
|
|
||||||
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
throw new AuthenticationServiceException("Malformed Authorization Endpoint Uri", e);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return uriBuilder.build().toString();
|
||||||
|
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw new AuthenticationServiceException("Malformed Authorization Endpoint Uri", e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,6 @@
|
||||||
package org.mitre.openid.connect.client.service.impl;
|
package org.mitre.openid.connect.client.service.impl;
|
||||||
|
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import javax.servlet.http.HttpSession;
|
|
||||||
|
|
||||||
import org.apache.http.client.utils.URIBuilder;
|
import org.apache.http.client.utils.URIBuilder;
|
||||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||||
|
@ -38,34 +33,34 @@ public class SignedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
||||||
|
|
||||||
// create our signed JWT for the request object
|
// create our signed JWT for the request object
|
||||||
JWTClaimsSet claims = new JWTClaimsSet();
|
JWTClaimsSet claims = new JWTClaimsSet();
|
||||||
|
|
||||||
//set parameters to JwtClaims
|
//set parameters to JwtClaims
|
||||||
claims.setCustomClaim("response_type", "code");
|
claims.setCustomClaim("response_type", "code");
|
||||||
claims.setCustomClaim("client_id", clientConfig.getClientId());
|
claims.setCustomClaim("client_id", clientConfig.getClientId());
|
||||||
claims.setCustomClaim("scope", Joiner.on(" ").join(clientConfig.getScope()));
|
claims.setCustomClaim("scope", Joiner.on(" ").join(clientConfig.getScope()));
|
||||||
|
|
||||||
// build our redirect URI
|
// build our redirect URI
|
||||||
claims.setCustomClaim("redirect_uri", redirectUri);
|
claims.setCustomClaim("redirect_uri", redirectUri);
|
||||||
|
|
||||||
// this comes back in the id token
|
// this comes back in the id token
|
||||||
claims.setCustomClaim("nonce", nonce);
|
claims.setCustomClaim("nonce", nonce);
|
||||||
|
|
||||||
// this comes back in the auth request return
|
// this comes back in the auth request return
|
||||||
claims.setCustomClaim("state", state);
|
claims.setCustomClaim("state", state);
|
||||||
|
|
||||||
SignedJWT jwt = new SignedJWT(new JWSHeader(signingAndValidationService.getDefaultSigningAlgorithm()), claims);
|
SignedJWT jwt = new SignedJWT(new JWSHeader(signingAndValidationService.getDefaultSigningAlgorithm()), claims);
|
||||||
|
|
||||||
signingAndValidationService.signJwt(jwt);
|
signingAndValidationService.signJwt(jwt);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
||||||
uriBuilder.addParameter("request", jwt.serialize());
|
uriBuilder.addParameter("request", jwt.serialize());
|
||||||
|
|
||||||
// build out the URI
|
// build out the URI
|
||||||
return uriBuilder.build().toString();
|
return uriBuilder.build().toString();
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
throw new AuthenticationServiceException("Malformed Authorization Endpoint Uri", e);
|
throw new AuthenticationServiceException("Malformed Authorization Endpoint Uri", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class StaticClientConfigurationService implements ClientConfigurationServ
|
||||||
|
|
||||||
// Map of issuer URL -> client configuration information
|
// Map of issuer URL -> client configuration information
|
||||||
private Map<String, ClientDetails> clients;
|
private Map<String, ClientDetails> clients;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the clients
|
* @return the clients
|
||||||
*/
|
*/
|
||||||
|
@ -44,19 +44,19 @@ public class StaticClientConfigurationService implements ClientConfigurationServ
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ClientDetails getClientConfiguration(ServerConfiguration issuer) {
|
public ClientDetails getClientConfiguration(ServerConfiguration issuer) {
|
||||||
|
|
||||||
return clients.get(issuer.getIssuer());
|
return clients.get(issuer.getIssuer());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
if (clients == null || clients.isEmpty()) {
|
if (clients == null || clients.isEmpty()) {
|
||||||
throw new IllegalArgumentException("Clients map cannot be null or empty");
|
throw new IllegalArgumentException("Clients map cannot be null or empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,12 +45,12 @@ public class StaticServerConfigurationService implements ServerConfigurationServ
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
if (servers == null || servers.isEmpty()) {
|
if (servers == null || servers.isEmpty()) {
|
||||||
throw new IllegalArgumentException("Servers map cannot be null or empty.");
|
throw new IllegalArgumentException("Servers map cannot be null or empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import com.google.common.base.Strings;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class StaticSingleIssuerService implements IssuerService, InitializingBean {
|
public class StaticSingleIssuerService implements IssuerService, InitializingBean {
|
||||||
|
|
||||||
private String issuer;
|
private String issuer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,13 +46,13 @@ public class StaticSingleIssuerService implements IssuerService, InitializingBea
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(issuer)) {
|
if (Strings.isNullOrEmpty(issuer)) {
|
||||||
throw new IllegalArgumentException("Issuer must not be null or empty.");
|
throw new IllegalArgumentException("Issuer must not be null or empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,34 +25,34 @@ import com.google.common.base.Strings;
|
||||||
public class ThirdPartyIssuerService implements IssuerService, InitializingBean {
|
public class ThirdPartyIssuerService implements IssuerService, InitializingBean {
|
||||||
|
|
||||||
private String accountChooserUrl;
|
private String accountChooserUrl;
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.openid.connect.client.service.IssuerService#getIssuer(javax.servlet.http.HttpServletRequest)
|
* @see org.mitre.openid.connect.client.service.IssuerService#getIssuer(javax.servlet.http.HttpServletRequest)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IssuerServiceResponse getIssuer(HttpServletRequest request) {
|
public IssuerServiceResponse getIssuer(HttpServletRequest request) {
|
||||||
|
|
||||||
// if the issuer is passed in, return that
|
// if the issuer is passed in, return that
|
||||||
if (!Strings.isNullOrEmpty(request.getParameter("iss"))) {
|
if (!Strings.isNullOrEmpty(request.getParameter("iss"))) {
|
||||||
return new IssuerServiceResponse(request.getParameter("iss"), request.getParameter("login_hint"), request.getParameter("target_link_uri"));
|
return new IssuerServiceResponse(request.getParameter("iss"), request.getParameter("login_hint"), request.getParameter("target_link_uri"));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// otherwise, need to forward to the account chooser
|
// otherwise, need to forward to the account chooser
|
||||||
String redirectUri = request.getRequestURL().toString();
|
String redirectUri = request.getRequestURL().toString();
|
||||||
URIBuilder builder = new URIBuilder(accountChooserUrl);
|
URIBuilder builder = new URIBuilder(accountChooserUrl);
|
||||||
|
|
||||||
builder.addParameter("redirect_uri", redirectUri);
|
builder.addParameter("redirect_uri", redirectUri);
|
||||||
|
|
||||||
return new IssuerServiceResponse(builder.build().toString());
|
return new IssuerServiceResponse(builder.build().toString());
|
||||||
|
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
throw new AuthenticationServiceException("Account Chooser URL is not valid", e);
|
throw new AuthenticationServiceException("Account Chooser URL is not valid", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,12 +72,12 @@ public class ThirdPartyIssuerService implements IssuerService, InitializingBean
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
if (Strings.isNullOrEmpty(this.accountChooserUrl)) {
|
if (Strings.isNullOrEmpty(this.accountChooserUrl)) {
|
||||||
throw new IllegalArgumentException("Account Chooser URL cannot be null or empty");
|
throw new IllegalArgumentException("Account Chooser URL cannot be null or empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ import com.google.gson.JsonParser;
|
||||||
public class WebfingerIssuerService implements IssuerService {
|
public class WebfingerIssuerService implements IssuerService {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(WebfingerIssuerService.class);
|
private static Logger logger = LoggerFactory.getLogger(WebfingerIssuerService.class);
|
||||||
|
|
||||||
// pattern used to parse user input; we can't use the built-in java URI parser
|
// pattern used to parse user input; we can't use the built-in java URI parser
|
||||||
private static final Pattern pattern = Pattern.compile("(https://|acct:|http://|mailto:)?(([^@]+)@)?([^\\?]+)(\\?([^#]+))?(#(.*))?");
|
private static final Pattern pattern = Pattern.compile("(https://|acct:|http://|mailto:)?(([^@]+)@)?([^\\?]+)(\\?([^#]+))?(#(.*))?");
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ public class WebfingerIssuerService implements IssuerService {
|
||||||
* Name of the incoming parameter to check for discovery purposes.
|
* Name of the incoming parameter to check for discovery purposes.
|
||||||
*/
|
*/
|
||||||
private String parameterName = "identifier";
|
private String parameterName = "identifier";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL of the page to forward to if no identifier is given.
|
* URL of the page to forward to if no identifier is given.
|
||||||
*/
|
*/
|
||||||
|
@ -56,53 +56,53 @@ public class WebfingerIssuerService implements IssuerService {
|
||||||
public WebfingerIssuerService() {
|
public WebfingerIssuerService() {
|
||||||
issuers = CacheBuilder.newBuilder().build(new WebfingerIssuerFetcher());
|
issuers = CacheBuilder.newBuilder().build(new WebfingerIssuerFetcher());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.openid.connect.client.service.IssuerService#getIssuer(javax.servlet.http.HttpServletRequest)
|
* @see org.mitre.openid.connect.client.service.IssuerService#getIssuer(javax.servlet.http.HttpServletRequest)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IssuerServiceResponse getIssuer(HttpServletRequest request) {
|
public IssuerServiceResponse getIssuer(HttpServletRequest request) {
|
||||||
|
|
||||||
String identifier = request.getParameter(parameterName);
|
String identifier = request.getParameter(parameterName);
|
||||||
if (!Strings.isNullOrEmpty(identifier)) {
|
if (!Strings.isNullOrEmpty(identifier)) {
|
||||||
try {
|
try {
|
||||||
String issuer = issuers.get(normalizeResource(identifier));
|
String issuer = issuers.get(normalizeResource(identifier));
|
||||||
return new IssuerServiceResponse(issuer, null, null);
|
return new IssuerServiceResponse(issuer, null, null);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
logger.warn("Issue fetching issuer for user input: " + identifier, e);
|
logger.warn("Issue fetching issuer for user input: " + identifier, e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logger.warn("No user input given, directing to login page: " + loginPageUrl);
|
logger.warn("No user input given, directing to login page: " + loginPageUrl);
|
||||||
return new IssuerServiceResponse(loginPageUrl);
|
return new IssuerServiceResponse(loginPageUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the resource string as per OIDC Discovery.
|
* Normalize the resource string as per OIDC Discovery.
|
||||||
* @param identifier
|
* @param identifier
|
||||||
* @return the normalized string, or null if the string can't be normalized
|
* @return the normalized string, or null if the string can't be normalized
|
||||||
*/
|
*/
|
||||||
private NormalizedURI normalizeResource(String identifier) {
|
private NormalizedURI normalizeResource(String identifier) {
|
||||||
// try to parse the URI
|
// try to parse the URI
|
||||||
// NOTE: we can't use the Java built-in URI class because it doesn't split the parts appropriately
|
// NOTE: we can't use the Java built-in URI class because it doesn't split the parts appropriately
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(identifier)) {
|
if (Strings.isNullOrEmpty(identifier)) {
|
||||||
logger.warn("Can't normalize null or empty URI: " + identifier);
|
logger.warn("Can't normalize null or empty URI: " + identifier);
|
||||||
return null; // nothing we can do
|
return null; // nothing we can do
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
NormalizedURI n = new NormalizedURI();
|
NormalizedURI n = new NormalizedURI();
|
||||||
Matcher m = pattern.matcher(identifier);
|
Matcher m = pattern.matcher(identifier);
|
||||||
|
|
||||||
if (m.matches()) {
|
if (m.matches()) {
|
||||||
n.scheme = m.group(1); // includes colon and maybe initial slashes
|
n.scheme = m.group(1); // includes colon and maybe initial slashes
|
||||||
n.user = m.group(2); // includes at sign
|
n.user = m.group(2); // includes at sign
|
||||||
n.hostportpath = m.group(4);
|
n.hostportpath = m.group(4);
|
||||||
n.query = m.group(5); // includes question mark
|
n.query = m.group(5); // includes question mark
|
||||||
n.hash = m.group(7); // includes hash mark
|
n.hash = m.group(7); // includes hash mark
|
||||||
|
|
||||||
// normalize scheme portion
|
// normalize scheme portion
|
||||||
if (Strings.isNullOrEmpty(n.scheme)) {
|
if (Strings.isNullOrEmpty(n.scheme)) {
|
||||||
if (!Strings.isNullOrEmpty(n.user)) {
|
if (!Strings.isNullOrEmpty(n.user)) {
|
||||||
|
@ -113,24 +113,24 @@ public class WebfingerIssuerService implements IssuerService {
|
||||||
n.scheme = "https://";
|
n.scheme = "https://";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n.source = Strings.nullToEmpty(n.scheme) +
|
n.source = Strings.nullToEmpty(n.scheme) +
|
||||||
Strings.nullToEmpty(n.user) +
|
Strings.nullToEmpty(n.user) +
|
||||||
Strings.nullToEmpty(n.hostportpath) +
|
Strings.nullToEmpty(n.hostportpath) +
|
||||||
Strings.nullToEmpty(n.query); // note: leave fragment off
|
Strings.nullToEmpty(n.query); // note: leave fragment off
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Parser couldn't match input: " + identifier);
|
logger.warn("Parser couldn't match input: " + identifier);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the parameterName
|
* @return the parameterName
|
||||||
*/
|
*/
|
||||||
|
@ -162,82 +162,82 @@ public class WebfingerIssuerService implements IssuerService {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jricher
|
* @author jricher
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private class WebfingerIssuerFetcher extends CacheLoader<NormalizedURI, String> {
|
private class WebfingerIssuerFetcher extends CacheLoader<NormalizedURI, String> {
|
||||||
private HttpClient httpClient = new DefaultHttpClient();
|
private HttpClient httpClient = new DefaultHttpClient();
|
||||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||||
private JsonParser parser = new JsonParser();
|
private JsonParser parser = new JsonParser();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String load(NormalizedURI key) throws Exception {
|
public String load(NormalizedURI key) throws Exception {
|
||||||
|
|
||||||
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||||
// construct the URL to go to
|
// construct the URL to go to
|
||||||
|
|
||||||
//String url = "https://" + key.hostportpath + "/.well-known/webfinger?resource="
|
|
||||||
String scheme = key.scheme;
|
|
||||||
if (!Strings.isNullOrEmpty(scheme) && !scheme.startsWith("http")) {
|
|
||||||
// do discovery on http or https URLs
|
|
||||||
scheme = "https://";
|
|
||||||
}
|
|
||||||
URIBuilder builder = new URIBuilder(scheme + key.hostportpath + "/.well-known/webfinger" + Strings.nullToEmpty(key.query));
|
|
||||||
builder.addParameter("resource", key.source);
|
|
||||||
builder.addParameter("rel", "http://openid.net/specs/connect/1.0/issuer");
|
|
||||||
|
|
||||||
// do the fetch
|
|
||||||
logger.info("Loading: " + builder.toString());
|
|
||||||
String webfingerResponse = restTemplate.getForObject(builder.build(), String.class);
|
|
||||||
|
|
||||||
// TODO: catch and handle HTTP errors
|
//String url = "https://" + key.hostportpath + "/.well-known/webfinger?resource="
|
||||||
|
String scheme = key.scheme;
|
||||||
JsonElement json = parser.parse(webfingerResponse);
|
if (!Strings.isNullOrEmpty(scheme) && !scheme.startsWith("http")) {
|
||||||
|
// do discovery on http or https URLs
|
||||||
// TODO: catch and handle JSON errors
|
scheme = "https://";
|
||||||
|
}
|
||||||
if (json != null && json.isJsonObject()) {
|
URIBuilder builder = new URIBuilder(scheme + key.hostportpath + "/.well-known/webfinger" + Strings.nullToEmpty(key.query));
|
||||||
// find the issuer
|
builder.addParameter("resource", key.source);
|
||||||
JsonArray links = json.getAsJsonObject().get("links").getAsJsonArray();
|
builder.addParameter("rel", "http://openid.net/specs/connect/1.0/issuer");
|
||||||
for (JsonElement link : links) {
|
|
||||||
if (link.isJsonObject()) {
|
|
||||||
JsonObject linkObj = link.getAsJsonObject();
|
|
||||||
if (linkObj.has("href")
|
|
||||||
&& linkObj.has("rel")
|
|
||||||
&& linkObj.get("rel").getAsString().equals("http://openid.net/specs/connect/1.0/issuer")) {
|
|
||||||
|
|
||||||
// we found the issuer, return it
|
|
||||||
return linkObj.get("href").getAsString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we couldn't find it
|
|
||||||
logger.warn("Couldn't find issuer");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
// do the fetch
|
||||||
|
logger.info("Loading: " + builder.toString());
|
||||||
|
String webfingerResponse = restTemplate.getForObject(builder.build(), String.class);
|
||||||
|
|
||||||
|
// TODO: catch and handle HTTP errors
|
||||||
|
|
||||||
|
JsonElement json = parser.parse(webfingerResponse);
|
||||||
|
|
||||||
|
// TODO: catch and handle JSON errors
|
||||||
|
|
||||||
|
if (json != null && json.isJsonObject()) {
|
||||||
|
// find the issuer
|
||||||
|
JsonArray links = json.getAsJsonObject().get("links").getAsJsonArray();
|
||||||
|
for (JsonElement link : links) {
|
||||||
|
if (link.isJsonObject()) {
|
||||||
|
JsonObject linkObj = link.getAsJsonObject();
|
||||||
|
if (linkObj.has("href")
|
||||||
|
&& linkObj.has("rel")
|
||||||
|
&& linkObj.get("rel").getAsString().equals("http://openid.net/specs/connect/1.0/issuer")) {
|
||||||
|
|
||||||
|
// we found the issuer, return it
|
||||||
|
return linkObj.get("href").getAsString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we couldn't find it
|
||||||
|
logger.warn("Couldn't find issuer");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple data shuttle class to represent the parsed components of a URI.
|
||||||
|
*
|
||||||
|
* @author jricher
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private class NormalizedURI {
|
||||||
|
|
||||||
|
public String scheme;
|
||||||
|
public String user;
|
||||||
|
public String hostportpath;
|
||||||
|
public String query;
|
||||||
|
public String hash;
|
||||||
|
public String source;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple data shuttle class to represent the parsed components of a URI.
|
|
||||||
*
|
|
||||||
* @author jricher
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private class NormalizedURI {
|
|
||||||
|
|
||||||
public String scheme;
|
|
||||||
public String user;
|
|
||||||
public String hostportpath;
|
|
||||||
public String query;
|
|
||||||
public String hash;
|
|
||||||
public String source;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
package org.mitre.openid.connect.client;
|
package org.mitre.openid.connect.client;
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit test for OIDCAuthenticationFilter
|
* Unit test for OIDCAuthenticationFilter
|
||||||
|
@ -18,10 +13,10 @@ public class AbstractOIDCAuthenticationFilterTest {
|
||||||
|
|
||||||
//@Autowired
|
//@Autowired
|
||||||
private OIDCAuthenticationFilter filter;
|
private OIDCAuthenticationFilter filter;
|
||||||
|
|
||||||
//@Test
|
//@Test
|
||||||
public void testUrlConstruction() {
|
public void testUrlConstruction() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +32,7 @@ public class AbstractOIDCAuthenticationFilterTest {
|
||||||
public void setFilter(OIDCAuthenticationFilter filter) {
|
public void setFilter(OIDCAuthenticationFilter filter) {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ package org.mitre.jose;
|
||||||
|
|
||||||
import javax.persistence.Basic;
|
import javax.persistence.Basic;
|
||||||
import javax.persistence.Embeddable;
|
import javax.persistence.Embeddable;
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
@ -22,16 +21,16 @@ import com.nimbusds.jose.JWEAlgorithm;
|
||||||
public class JWEAlgorithmEmbed {
|
public class JWEAlgorithmEmbed {
|
||||||
|
|
||||||
public static final JWEAlgorithmEmbed NONE = getForAlgorithmName("none");
|
public static final JWEAlgorithmEmbed NONE = getForAlgorithmName("none");
|
||||||
|
|
||||||
private JWEAlgorithm algorithm;
|
private JWEAlgorithm algorithm;
|
||||||
|
|
||||||
public JWEAlgorithmEmbed() {
|
public JWEAlgorithmEmbed() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JWEAlgorithmEmbed(JWEAlgorithm algorithm) {
|
public JWEAlgorithmEmbed(JWEAlgorithm algorithm) {
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JWEAlgorithmEmbed getForAlgorithmName (String algorithmName) {
|
public static JWEAlgorithmEmbed getForAlgorithmName (String algorithmName) {
|
||||||
JWEAlgorithmEmbed ent = new JWEAlgorithmEmbed();
|
JWEAlgorithmEmbed ent = new JWEAlgorithmEmbed();
|
||||||
|
@ -42,7 +41,7 @@ public class JWEAlgorithmEmbed {
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of this algorithm, return null if no algorithm set.
|
* Get the name of this algorithm, return null if no algorithm set.
|
||||||
* @return
|
* @return
|
||||||
|
@ -55,9 +54,9 @@ public class JWEAlgorithmEmbed {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the name of this algorithm.
|
* Set the name of this algorithm.
|
||||||
* Calls JWEAlgorithm.parse()
|
* Calls JWEAlgorithm.parse()
|
||||||
* @param algorithmName
|
* @param algorithmName
|
||||||
*/
|
*/
|
||||||
|
@ -72,15 +71,15 @@ public class JWEAlgorithmEmbed {
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Object#toString()
|
* @see java.lang.Object#toString()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "JWEAlgorithmEmbed [algorithm=" + algorithm + "]";
|
return "JWEAlgorithmEmbed [algorithm=" + algorithm + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the algorithm
|
* @return the algorithm
|
||||||
*/
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
public JWEAlgorithm getAlgorithm() {
|
public JWEAlgorithm getAlgorithm() {
|
||||||
return algorithm;
|
return algorithm;
|
||||||
}
|
}
|
||||||
|
@ -91,5 +90,5 @@ public class JWEAlgorithmEmbed {
|
||||||
public void setAlgorithm(JWEAlgorithm algorithm) {
|
public void setAlgorithm(JWEAlgorithm algorithm) {
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import javax.persistence.Transient;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.nimbusds.jose.EncryptionMethod;
|
import com.nimbusds.jose.EncryptionMethod;
|
||||||
import com.nimbusds.jose.JWEAlgorithm;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jricher
|
* @author jricher
|
||||||
|
@ -19,16 +18,16 @@ import com.nimbusds.jose.JWEAlgorithm;
|
||||||
public class JWEEncryptionMethodEmbed {
|
public class JWEEncryptionMethodEmbed {
|
||||||
|
|
||||||
public static final JWEEncryptionMethodEmbed NONE = getForAlgorithmName("none");
|
public static final JWEEncryptionMethodEmbed NONE = getForAlgorithmName("none");
|
||||||
|
|
||||||
private EncryptionMethod algorithm;
|
private EncryptionMethod algorithm;
|
||||||
|
|
||||||
public JWEEncryptionMethodEmbed() {
|
public JWEEncryptionMethodEmbed() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JWEEncryptionMethodEmbed(EncryptionMethod algorithm) {
|
public JWEEncryptionMethodEmbed(EncryptionMethod algorithm) {
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JWEEncryptionMethodEmbed getForAlgorithmName (String algorithmName) {
|
public static JWEEncryptionMethodEmbed getForAlgorithmName (String algorithmName) {
|
||||||
JWEEncryptionMethodEmbed ent = new JWEEncryptionMethodEmbed();
|
JWEEncryptionMethodEmbed ent = new JWEEncryptionMethodEmbed();
|
||||||
|
@ -39,7 +38,7 @@ public class JWEEncryptionMethodEmbed {
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of this algorithm, return null if no algorithm set.
|
* Get the name of this algorithm, return null if no algorithm set.
|
||||||
* @return
|
* @return
|
||||||
|
@ -52,9 +51,9 @@ public class JWEEncryptionMethodEmbed {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the name of this algorithm.
|
* Set the name of this algorithm.
|
||||||
* Calls EncryptionMethod.parse()
|
* Calls EncryptionMethod.parse()
|
||||||
* @param algorithmName
|
* @param algorithmName
|
||||||
*/
|
*/
|
||||||
|
@ -69,15 +68,15 @@ public class JWEEncryptionMethodEmbed {
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Object#toString()
|
* @see java.lang.Object#toString()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "JWEEncryptionMethodEmbed [algorithm=" + algorithm + "]";
|
return "JWEEncryptionMethodEmbed [algorithm=" + algorithm + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the algorithm
|
* @return the algorithm
|
||||||
*/
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
public EncryptionMethod getAlgorithm() {
|
public EncryptionMethod getAlgorithm() {
|
||||||
return algorithm;
|
return algorithm;
|
||||||
}
|
}
|
||||||
|
@ -88,6 +87,6 @@ public class JWEEncryptionMethodEmbed {
|
||||||
public void setAlgorithm(EncryptionMethod algorithm) {
|
public void setAlgorithm(EncryptionMethod algorithm) {
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ package org.mitre.jose;
|
||||||
|
|
||||||
import javax.persistence.Basic;
|
import javax.persistence.Basic;
|
||||||
import javax.persistence.Embeddable;
|
import javax.persistence.Embeddable;
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
@ -23,17 +21,17 @@ import com.nimbusds.jose.JWSAlgorithm;
|
||||||
public class JWSAlgorithmEmbed {
|
public class JWSAlgorithmEmbed {
|
||||||
|
|
||||||
public static final JWSAlgorithmEmbed NONE = getForAlgorithmName("none");
|
public static final JWSAlgorithmEmbed NONE = getForAlgorithmName("none");
|
||||||
|
|
||||||
private JWSAlgorithm algorithm;
|
private JWSAlgorithm algorithm;
|
||||||
|
|
||||||
public JWSAlgorithmEmbed() {
|
public JWSAlgorithmEmbed() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JWSAlgorithmEmbed(JWSAlgorithm algorithm) {
|
public JWSAlgorithmEmbed(JWSAlgorithm algorithm) {
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JWSAlgorithmEmbed getForAlgorithmName (String algorithmName) {
|
public static JWSAlgorithmEmbed getForAlgorithmName (String algorithmName) {
|
||||||
JWSAlgorithmEmbed ent = new JWSAlgorithmEmbed();
|
JWSAlgorithmEmbed ent = new JWSAlgorithmEmbed();
|
||||||
ent.setAlgorithmName(algorithmName);
|
ent.setAlgorithmName(algorithmName);
|
||||||
|
@ -56,9 +54,9 @@ public class JWSAlgorithmEmbed {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the name of this algorithm.
|
* Set the name of this algorithm.
|
||||||
* Calls JWSAlgorithm.parse()
|
* Calls JWSAlgorithm.parse()
|
||||||
* @param algorithmName
|
* @param algorithmName
|
||||||
*/
|
*/
|
||||||
|
@ -88,11 +86,11 @@ public class JWSAlgorithmEmbed {
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Object#toString()
|
* @see java.lang.Object#toString()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "JWSAlgorithmEmbed [algorithm=" + algorithm + "]";
|
return "JWSAlgorithmEmbed [algorithm=" + algorithm + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,26 +21,26 @@ import com.nimbusds.jose.jwk.JWKSet;
|
||||||
public class JWKSetKeyStore implements InitializingBean {
|
public class JWKSetKeyStore implements InitializingBean {
|
||||||
|
|
||||||
private JWKSet jwkSet;
|
private JWKSet jwkSet;
|
||||||
|
|
||||||
private Resource location;
|
private Resource location;
|
||||||
|
|
||||||
public JWKSetKeyStore() {
|
public JWKSetKeyStore() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JWKSetKeyStore(JWKSet jwkSet) {
|
public JWKSetKeyStore(JWKSet jwkSet) {
|
||||||
this.jwkSet = jwkSet;
|
this.jwkSet = jwkSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
|
||||||
if (jwkSet == null) {
|
if (jwkSet == null) {
|
||||||
if (location != null) {
|
if (location != null) {
|
||||||
|
|
||||||
if (location.exists() && location.isReadable()) {
|
if (location.exists() && location.isReadable()) {
|
||||||
|
|
||||||
// read in the file from disk
|
// read in the file from disk
|
||||||
|
@ -48,11 +48,11 @@ public class JWKSetKeyStore implements InitializingBean {
|
||||||
|
|
||||||
// parse it into a jwkSet object
|
// parse it into a jwkSet object
|
||||||
jwkSet = JWKSet.parse(s);
|
jwkSet = JWKSet.parse(s);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Key Set resource could not be read: " + location);
|
throw new IllegalArgumentException("Key Set resource could not be read: " + location);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Key store must be initialized with at least one of a jwkSet or a location.");
|
throw new IllegalArgumentException("Key store must be initialized with at least one of a jwkSet or a location.");
|
||||||
}
|
}
|
||||||
|
@ -90,10 +90,10 @@ public class JWKSetKeyStore implements InitializingBean {
|
||||||
/**
|
/**
|
||||||
* Get the list of keys in this keystore. This is a passthrough to the underlying JWK Set
|
* Get the list of keys in this keystore. This is a passthrough to the underlying JWK Set
|
||||||
*/
|
*/
|
||||||
public List<JWK> getKeys() {
|
public List<JWK> getKeys() {
|
||||||
return jwkSet.getKeys();
|
return jwkSet.getKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
package org.mitre.jwt.signer.service;
|
package org.mitre.jwt.signer.service;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ public interface JwtSigningAndValidationService {
|
||||||
* Get all public keys for this service, mapped by their Key ID
|
* Get all public keys for this service, mapped by their Key ID
|
||||||
*/
|
*/
|
||||||
public Map<String, JWK> getAllPublicKeys();
|
public Map<String, JWK> getAllPublicKeys();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the signature of the given JWT against all configured signers,
|
* Checks the signature of the given JWT against all configured signers,
|
||||||
* returns true if at least one of the signers validates it.
|
* returns true if at least one of the signers validates it.
|
||||||
|
@ -38,17 +37,17 @@ public interface JwtSigningAndValidationService {
|
||||||
* @param jwtString
|
* @param jwtString
|
||||||
* the string representation of the JWT as sent on the wire
|
* the string representation of the JWT as sent on the wire
|
||||||
* @return true if the signature is valid, false if not
|
* @return true if the signature is valid, false if not
|
||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
*/
|
*/
|
||||||
public boolean validateSignature(SignedJWT jwtString);
|
public boolean validateSignature(SignedJWT jwtString);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to sign a jwt in place for a client that hasn't registered a preferred signing algorithm.
|
* Called to sign a jwt in place for a client that hasn't registered a preferred signing algorithm.
|
||||||
* Use the default algorithm to sign.
|
* Use the default algorithm to sign.
|
||||||
*
|
*
|
||||||
* @param jwt the jwt to sign
|
* @param jwt the jwt to sign
|
||||||
* @return the signed jwt
|
* @return the signed jwt
|
||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
*/
|
*/
|
||||||
public void signJwt(SignedJWT jwt);
|
public void signJwt(SignedJWT jwt);
|
||||||
|
|
||||||
|
@ -56,13 +55,13 @@ public interface JwtSigningAndValidationService {
|
||||||
* Get the default signing algorithm for use when nothing else has been specified.
|
* Get the default signing algorithm for use when nothing else has been specified.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public JWSAlgorithm getDefaultSigningAlgorithm();
|
public JWSAlgorithm getDefaultSigningAlgorithm();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of all signing algorithms supported by this service.
|
* Get the list of all signing algorithms supported by this service.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Collection<JWSAlgorithm> getAllSigningAlgsSupported();
|
public Collection<JWSAlgorithm> getAllSigningAlgsSupported();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign a jwt using the selected algorithm. The algorithm is selected using the String parameter values specified
|
* Sign a jwt using the selected algorithm. The algorithm is selected using the String parameter values specified
|
||||||
|
@ -74,7 +73,7 @@ public interface JwtSigningAndValidationService {
|
||||||
*/
|
*/
|
||||||
//TODO: implement later; only need signJwt(Jwt jwt) for now
|
//TODO: implement later; only need signJwt(Jwt jwt) for now
|
||||||
//public Jwt signJwt(Jwt jwt, String alg);
|
//public Jwt signJwt(Jwt jwt, String alg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: method to sign a jwt using a specified algorithm and a key id
|
* TODO: method to sign a jwt using a specified algorithm and a key id
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -55,9 +55,9 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
||||||
private static Logger logger = LoggerFactory.getLogger(DefaultJwtSigningAndValidationService.class);
|
private static Logger logger = LoggerFactory.getLogger(DefaultJwtSigningAndValidationService.class);
|
||||||
|
|
||||||
private String defaultSignerKeyId;
|
private String defaultSignerKeyId;
|
||||||
|
|
||||||
private JWSAlgorithm defaultAlgorithm;
|
private JWSAlgorithm defaultAlgorithm;
|
||||||
|
|
||||||
// map of identifier to key
|
// map of identifier to key
|
||||||
private Map<String, JWK> keys = new HashMap<String, JWK>();
|
private Map<String, JWK> keys = new HashMap<String, JWK>();
|
||||||
|
|
||||||
|
@ -73,10 +73,10 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* If there is no appropriate algorithm to tie the keys to.
|
* If there is no appropriate algorithm to tie the keys to.
|
||||||
*/
|
*/
|
||||||
public DefaultJwtSigningAndValidationService(Map<String, JWK> keys) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
public DefaultJwtSigningAndValidationService(Map<String, JWK> keys) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||||
this.keys = keys;
|
this.keys = keys;
|
||||||
buildSignersAndVerifiers();
|
buildSignersAndVerifiers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build this service based on the given keystore. All keys must have a key
|
* Build this service based on the given keystore. All keys must have a key
|
||||||
|
@ -90,18 +90,18 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
||||||
* @throws NoSuchAlgorithmException
|
* @throws NoSuchAlgorithmException
|
||||||
* If there is no appropriate algorithm to tie the keys to.
|
* If there is no appropriate algorithm to tie the keys to.
|
||||||
*/
|
*/
|
||||||
public DefaultJwtSigningAndValidationService(JWKSetKeyStore keyStore) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
public DefaultJwtSigningAndValidationService(JWKSetKeyStore keyStore) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||||
// convert all keys in the keystore to a map based on key id
|
// convert all keys in the keystore to a map based on key id
|
||||||
for (JWK key : keyStore.getKeys()) {
|
for (JWK key : keyStore.getKeys()) {
|
||||||
if (!Strings.isNullOrEmpty(key.getKeyID())) {
|
if (!Strings.isNullOrEmpty(key.getKeyID())) {
|
||||||
this.keys.put(key.getKeyID(), key);
|
this.keys.put(key.getKeyID(), key);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Tried to load a key from a keystore without a 'kid' field: " + key);
|
throw new IllegalArgumentException("Tried to load a key from a keystore without a 'kid' field: " + key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buildSignersAndVerifiers();
|
buildSignersAndVerifiers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the defaultSignerKeyId
|
* @return the defaultSignerKeyId
|
||||||
*/
|
*/
|
||||||
|
@ -120,22 +120,22 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public JWSAlgorithm getDefaultSigningAlgorithm() {
|
public JWSAlgorithm getDefaultSigningAlgorithm() {
|
||||||
return defaultAlgorithm;
|
return defaultAlgorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDefaultSigningAlgorithmName(String algName) {
|
public void setDefaultSigningAlgorithmName(String algName) {
|
||||||
defaultAlgorithm = JWSAlgorithm.parse(algName);
|
defaultAlgorithm = JWSAlgorithm.parse(algName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDefaultSigningAlgorithmName() {
|
public String getDefaultSigningAlgorithmName() {
|
||||||
if (defaultAlgorithm != null) {
|
if (defaultAlgorithm != null) {
|
||||||
return defaultAlgorithm.getName();
|
return defaultAlgorithm.getName();
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
|
@ -148,9 +148,9 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
||||||
if (keys == null) {
|
if (keys == null) {
|
||||||
throw new IllegalArgumentException("Signing and validation service must have at least one key configured.");
|
throw new IllegalArgumentException("Signing and validation service must have at least one key configured.");
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSignersAndVerifiers();
|
buildSignersAndVerifiers();
|
||||||
|
|
||||||
logger.info("DefaultJwtSigningAndValidationService is ready: " + this.toString());
|
logger.info("DefaultJwtSigningAndValidationService is ready: " + this.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,45 +159,45 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
||||||
* @throws InvalidKeySpecException If the keys in the JWKs are not valid
|
* @throws InvalidKeySpecException If the keys in the JWKs are not valid
|
||||||
* @throws NoSuchAlgorithmException If there is no appropriate algorithm to tie the keys to.
|
* @throws NoSuchAlgorithmException If there is no appropriate algorithm to tie the keys to.
|
||||||
*/
|
*/
|
||||||
private void buildSignersAndVerifiers() throws NoSuchAlgorithmException, InvalidKeySpecException {
|
private void buildSignersAndVerifiers() throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||||
for (Map.Entry<String, JWK> jwkEntry : keys.entrySet()) {
|
for (Map.Entry<String, JWK> jwkEntry : keys.entrySet()) {
|
||||||
|
|
||||||
String id = jwkEntry.getKey();
|
String id = jwkEntry.getKey();
|
||||||
JWK jwk = jwkEntry.getValue();
|
JWK jwk = jwkEntry.getValue();
|
||||||
|
|
||||||
if (jwk instanceof RSAKey) {
|
if (jwk instanceof RSAKey) {
|
||||||
// build RSA signers & verifiers
|
// build RSA signers & verifiers
|
||||||
|
|
||||||
if (jwk.isPrivate()) { // only add the signer if there's a private key
|
if (jwk.isPrivate()) { // only add the signer if there's a private key
|
||||||
RSASSASigner signer = new RSASSASigner(((RSAKey) jwk).toRSAPrivateKey());
|
RSASSASigner signer = new RSASSASigner(((RSAKey) jwk).toRSAPrivateKey());
|
||||||
signers.put(id, signer);
|
signers.put(id, signer);
|
||||||
}
|
}
|
||||||
|
|
||||||
RSASSAVerifier verifier = new RSASSAVerifier(((RSAKey) jwk).toRSAPublicKey());
|
RSASSAVerifier verifier = new RSASSAVerifier(((RSAKey) jwk).toRSAPublicKey());
|
||||||
verifiers.put(id, verifier);
|
verifiers.put(id, verifier);
|
||||||
|
|
||||||
} else if (jwk instanceof ECKey) {
|
} else if (jwk instanceof ECKey) {
|
||||||
// build EC signers & verifiers
|
// build EC signers & verifiers
|
||||||
|
|
||||||
// TODO: add support for EC keys
|
// TODO: add support for EC keys
|
||||||
logger.warn("EC Keys are not yet supported.");
|
logger.warn("EC Keys are not yet supported.");
|
||||||
|
|
||||||
} else if (jwk instanceof OctetSequenceKey) {
|
} else if (jwk instanceof OctetSequenceKey) {
|
||||||
// build HMAC signers & verifiers
|
// build HMAC signers & verifiers
|
||||||
|
|
||||||
if (jwk.isPrivate()) { // technically redundant check because all HMAC keys are private
|
if (jwk.isPrivate()) { // technically redundant check because all HMAC keys are private
|
||||||
MACSigner signer = new MACSigner(((OctetSequenceKey) jwk).toByteArray());
|
MACSigner signer = new MACSigner(((OctetSequenceKey) jwk).toByteArray());
|
||||||
signers.put(id, signer);
|
signers.put(id, signer);
|
||||||
}
|
}
|
||||||
|
|
||||||
MACVerifier verifier = new MACVerifier(((OctetSequenceKey) jwk).toByteArray());
|
MACVerifier verifier = new MACVerifier(((OctetSequenceKey) jwk).toByteArray());
|
||||||
verifiers.put(id, verifier);
|
verifiers.put(id, verifier);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Unknown key type: " + jwk);
|
logger.warn("Unknown key type: " + jwk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign a jwt in place using the configured default signer.
|
* Sign a jwt in place using the configured default signer.
|
||||||
|
@ -207,18 +207,18 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
||||||
if (getDefaultSignerKeyId() == null) {
|
if (getDefaultSignerKeyId() == null) {
|
||||||
throw new IllegalStateException("Tried to call default signing with no default signer ID set");
|
throw new IllegalStateException("Tried to call default signing with no default signer ID set");
|
||||||
}
|
}
|
||||||
|
|
||||||
JWSSigner signer = signers.get(getDefaultSignerKeyId());
|
JWSSigner signer = signers.get(getDefaultSignerKeyId());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
jwt.sign(signer);
|
jwt.sign(signer);
|
||||||
} catch (JOSEException e) {
|
} catch (JOSEException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validateSignature(SignedJWT jwt) {
|
public boolean validateSignature(SignedJWT jwt) {
|
||||||
|
|
||||||
|
@ -228,9 +228,9 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (JOSEException e) {
|
} catch (JOSEException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -238,37 +238,37 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
||||||
@Override
|
@Override
|
||||||
public Map<String, JWK> getAllPublicKeys() {
|
public Map<String, JWK> getAllPublicKeys() {
|
||||||
Map<String, JWK> pubKeys = new HashMap<String, JWK>();
|
Map<String, JWK> pubKeys = new HashMap<String, JWK>();
|
||||||
|
|
||||||
// pull all keys out of the verifiers if we know how
|
// pull all keys out of the verifiers if we know how
|
||||||
for (String keyId : keys.keySet()) {
|
for (String keyId : keys.keySet()) {
|
||||||
JWK key = keys.get(keyId);
|
JWK key = keys.get(keyId);
|
||||||
JWK pub = key.toPublicJWK();
|
JWK pub = key.toPublicJWK();
|
||||||
if (pub != null) {
|
if (pub != null) {
|
||||||
pubKeys.put(keyId, pub);
|
pubKeys.put(keyId, pub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pubKeys;
|
return pubKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.jwt.signer.service.JwtSigningAndValidationService#getAllSigningAlgsSupported()
|
* @see org.mitre.jwt.signer.service.JwtSigningAndValidationService#getAllSigningAlgsSupported()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Collection<JWSAlgorithm> getAllSigningAlgsSupported() {
|
public Collection<JWSAlgorithm> getAllSigningAlgsSupported() {
|
||||||
|
|
||||||
Set<JWSAlgorithm> algs = new HashSet<JWSAlgorithm>();
|
Set<JWSAlgorithm> algs = new HashSet<JWSAlgorithm>();
|
||||||
|
|
||||||
for (JWSSigner signer : signers.values()) {
|
for (JWSSigner signer : signers.values()) {
|
||||||
algs.addAll(signer.supportedAlgorithms());
|
algs.addAll(signer.supportedAlgorithms());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (JWSVerifier verifier : verifiers.values()) {
|
||||||
|
algs.addAll(verifier.supportedAlgorithms());
|
||||||
|
}
|
||||||
|
|
||||||
|
return algs;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
for (JWSVerifier verifier : verifiers.values()) {
|
|
||||||
algs.addAll(verifier.supportedAlgorithms());
|
|
||||||
}
|
|
||||||
|
|
||||||
return algs;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,6 @@
|
||||||
*/
|
*/
|
||||||
package org.mitre.jwt.signer.service.impl;
|
package org.mitre.jwt.signer.service.impl;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.interfaces.RSAPublicKey;
|
|
||||||
import java.security.spec.RSAPublicKeySpec;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
|
@ -21,19 +15,14 @@ import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import com.google.common.cache.LoadingCache;
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.CacheLoader;
|
import com.google.common.cache.CacheLoader;
|
||||||
import com.nimbusds.jose.JWSVerifier;
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.nimbusds.jose.crypto.RSASSAVerifier;
|
|
||||||
import com.nimbusds.jose.jwk.JWK;
|
|
||||||
import com.nimbusds.jose.jwk.JWKSet;
|
import com.nimbusds.jose.jwk.JWKSet;
|
||||||
import com.nimbusds.jose.jwk.KeyType;
|
|
||||||
import com.nimbusds.jose.jwk.RSAKey;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Creates a caching map of JOSE signers and validators keyed on the JWK Set URI.
|
* Creates a caching map of JOSE signers and validators keyed on the JWK Set URI.
|
||||||
* Dynamically loads JWK Sets to create the signing and validation services.
|
* Dynamically loads JWK Sets to create the signing and validation services.
|
||||||
*
|
*
|
||||||
* @author jricher
|
* @author jricher
|
||||||
|
@ -43,7 +32,7 @@ import com.nimbusds.jose.jwk.RSAKey;
|
||||||
public class JWKSetSigningAndValidationServiceCacheService {
|
public class JWKSetSigningAndValidationServiceCacheService {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(JWKSetSigningAndValidationServiceCacheService.class);
|
private static Logger logger = LoggerFactory.getLogger(JWKSetSigningAndValidationServiceCacheService.class);
|
||||||
|
|
||||||
// map of jwk set uri -> signing/validation service built on the keys found in that jwk set
|
// map of jwk set uri -> signing/validation service built on the keys found in that jwk set
|
||||||
private LoadingCache<String, JwtSigningAndValidationService> cache;
|
private LoadingCache<String, JwtSigningAndValidationService> cache;
|
||||||
|
|
||||||
|
@ -52,48 +41,48 @@ public class JWKSetSigningAndValidationServiceCacheService {
|
||||||
.maximumSize(100)
|
.maximumSize(100)
|
||||||
.build(new JWKSetVerifierFetcher());
|
.build(new JWKSetVerifierFetcher());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param jwksUri
|
* @param jwksUri
|
||||||
* @return
|
* @return
|
||||||
* @throws ExecutionException
|
* @throws ExecutionException
|
||||||
* @see com.google.common.cache.Cache#get(java.lang.Object)
|
* @see com.google.common.cache.Cache#get(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
public JwtSigningAndValidationService get(String jwksUri) {
|
public JwtSigningAndValidationService get(String jwksUri) {
|
||||||
try {
|
try {
|
||||||
return cache.get(jwksUri);
|
return cache.get(jwksUri);
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
logger.warn("Couldn't load JWK Set from " + jwksUri, e);
|
logger.warn("Couldn't load JWK Set from " + jwksUri, e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jricher
|
* @author jricher
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private class JWKSetVerifierFetcher extends CacheLoader<String, JwtSigningAndValidationService> {
|
private class JWKSetVerifierFetcher extends CacheLoader<String, JwtSigningAndValidationService> {
|
||||||
private HttpClient httpClient = new DefaultHttpClient();
|
private HttpClient httpClient = new DefaultHttpClient();
|
||||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||||
private RestTemplate restTemplate = new RestTemplate(httpFactory);
|
private RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the JWK Set and build the appropriate signing service.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public JwtSigningAndValidationService load(String key) throws Exception {
|
|
||||||
|
|
||||||
String jsonString = restTemplate.getForObject(key, String.class);
|
/**
|
||||||
JWKSet jwkSet = JWKSet.parse(jsonString);
|
* Load the JWK Set and build the appropriate signing service.
|
||||||
|
*/
|
||||||
JWKSetKeyStore keyStore = new JWKSetKeyStore(jwkSet);
|
@Override
|
||||||
|
public JwtSigningAndValidationService load(String key) throws Exception {
|
||||||
JwtSigningAndValidationService service = new DefaultJwtSigningAndValidationService(keyStore);
|
|
||||||
|
|
||||||
return service;
|
String jsonString = restTemplate.getForObject(key, String.class);
|
||||||
|
JWKSet jwkSet = JWKSet.parse(jsonString);
|
||||||
}
|
|
||||||
|
|
||||||
}
|
JWKSetKeyStore keyStore = new JWKSetKeyStore(jwkSet);
|
||||||
|
|
||||||
|
JwtSigningAndValidationService service = new DefaultJwtSigningAndValidationService(keyStore);
|
||||||
|
|
||||||
|
return service;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,13 @@ import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
public class AuthenticationHolderEntity {
|
public class AuthenticationHolderEntity {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
private Long ownerId;
|
private Long ownerId;
|
||||||
|
|
||||||
private OAuth2Authentication authentication;
|
private OAuth2Authentication authentication;
|
||||||
|
|
||||||
public AuthenticationHolderEntity() {
|
public AuthenticationHolderEntity() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
@ -60,7 +60,7 @@ public class AuthenticationHolderEntity {
|
||||||
public void setAuthentication(OAuth2Authentication authentication) {
|
public void setAuthentication(OAuth2Authentication authentication) {
|
||||||
this.authentication = authentication;
|
this.authentication = authentication;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,18 +28,18 @@ import org.springframework.security.oauth2.provider.code.AuthorizationRequestHol
|
||||||
public class AuthorizationCodeEntity {
|
public class AuthorizationCodeEntity {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
private String code;
|
private String code;
|
||||||
|
|
||||||
private AuthorizationRequestHolder authorizationRequestHolder;
|
private AuthorizationRequestHolder authorizationRequestHolder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
public AuthorizationCodeEntity() {
|
public AuthorizationCodeEntity() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new AuthorizationCodeEntity with the given code and AuthorizationRequestHolder.
|
* Create a new AuthorizationCodeEntity with the given code and AuthorizationRequestHolder.
|
||||||
*
|
*
|
||||||
|
@ -50,12 +50,12 @@ public class AuthorizationCodeEntity {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.authorizationRequestHolder = authRequest;
|
this.authorizationRequestHolder = authRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -98,5 +98,5 @@ public class AuthorizationCodeEntity {
|
||||||
public void setAuthorizationRequestHolder(AuthorizationRequestHolder authorizationRequestHolder) {
|
public void setAuthorizationRequestHolder(AuthorizationRequestHolder authorizationRequestHolder) {
|
||||||
this.authorizationRequestHolder = authorizationRequestHolder;
|
this.authorizationRequestHolder = authorizationRequestHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
private static final long serialVersionUID = -1617727085733786296L;
|
private static final long serialVersionUID = -1617727085733786296L;
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/** Fields from the OAuth2 Dynamic Registration Specification */
|
/** Fields from the OAuth2 Dynamic Registration Specification */
|
||||||
private String clientId = null; // client_id
|
private String clientId = null; // client_id
|
||||||
private String clientSecret = null; // client_secret
|
private String clientSecret = null; // client_secret
|
||||||
|
@ -75,7 +75,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
private String clientName; // client_name
|
private String clientName; // client_name
|
||||||
private String clientUri; // client_uri
|
private String clientUri; // client_uri
|
||||||
private String logoUri; // logo_uri
|
private String logoUri; // logo_uri
|
||||||
private Set<String> contacts; // contacts
|
private Set<String> contacts; // contacts
|
||||||
private String tosUri; // tos_uri
|
private String tosUri; // tos_uri
|
||||||
private AuthMethod tokenEndpointAuthMethod = AuthMethod.SECRET_BASIC; // token_endpoint_auth_method
|
private AuthMethod tokenEndpointAuthMethod = AuthMethod.SECRET_BASIC; // token_endpoint_auth_method
|
||||||
private Set<String> scope = new HashSet<String>(); // scope
|
private Set<String> scope = new HashSet<String>(); // scope
|
||||||
|
@ -83,38 +83,38 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
private Set<String> responseTypes = new HashSet<String>(); // response_types
|
private Set<String> responseTypes = new HashSet<String>(); // response_types
|
||||||
private String policyUri;
|
private String policyUri;
|
||||||
private String jwksUri;
|
private String jwksUri;
|
||||||
|
|
||||||
/** Fields from OIDC Client Registration Specification **/
|
/** Fields from OIDC Client Registration Specification **/
|
||||||
private AppType applicationType; // application_type
|
private AppType applicationType; // application_type
|
||||||
private String sectorIdentifierUri; // sector_identifier_uri
|
private String sectorIdentifierUri; // sector_identifier_uri
|
||||||
private SubjectType subjectType; // subject_type
|
private SubjectType subjectType; // subject_type
|
||||||
|
|
||||||
private JWSAlgorithmEmbed requestObjectSigningAlg = JWSAlgorithmEmbed.NONE; // request_object_signing_alg
|
private JWSAlgorithmEmbed requestObjectSigningAlg = JWSAlgorithmEmbed.NONE; // request_object_signing_alg
|
||||||
|
|
||||||
private JWSAlgorithmEmbed userInfoSignedResponseAlg = JWSAlgorithmEmbed.NONE; // user_info_signed_response_alg
|
private JWSAlgorithmEmbed userInfoSignedResponseAlg = JWSAlgorithmEmbed.NONE; // user_info_signed_response_alg
|
||||||
private JWEAlgorithmEmbed userInfoEncryptedResponseAlg = JWEAlgorithmEmbed.NONE; // user_info_encrypted_response_alg
|
private JWEAlgorithmEmbed userInfoEncryptedResponseAlg = JWEAlgorithmEmbed.NONE; // user_info_encrypted_response_alg
|
||||||
private JWEEncryptionMethodEmbed userInfoEncryptedResponseEnc = JWEEncryptionMethodEmbed.NONE; // user_info_encrypted_response_enc
|
private JWEEncryptionMethodEmbed userInfoEncryptedResponseEnc = JWEEncryptionMethodEmbed.NONE; // user_info_encrypted_response_enc
|
||||||
|
|
||||||
private JWSAlgorithmEmbed idTokenSignedResponseAlg = JWSAlgorithmEmbed.NONE; // id_token_signed_response_alg
|
private JWSAlgorithmEmbed idTokenSignedResponseAlg = JWSAlgorithmEmbed.NONE; // id_token_signed_response_alg
|
||||||
private JWEAlgorithmEmbed idTokenEncryptedResponseAlg = JWEAlgorithmEmbed.NONE; // id_token_encrypted_response_alg
|
private JWEAlgorithmEmbed idTokenEncryptedResponseAlg = JWEAlgorithmEmbed.NONE; // id_token_encrypted_response_alg
|
||||||
private JWEEncryptionMethodEmbed idTokenEncryptedResponseEnc = JWEEncryptionMethodEmbed.NONE; // id_token_encrypted_response_enc
|
private JWEEncryptionMethodEmbed idTokenEncryptedResponseEnc = JWEEncryptionMethodEmbed.NONE; // id_token_encrypted_response_enc
|
||||||
|
|
||||||
private Integer defaultMaxAge; // default_max_age
|
private Integer defaultMaxAge; // default_max_age
|
||||||
private Boolean requireAuthTime; // require_auth_time
|
private Boolean requireAuthTime; // require_auth_time
|
||||||
private Set<String> defaultACRvalues; // default_acr_values
|
private Set<String> defaultACRvalues; // default_acr_values
|
||||||
|
|
||||||
private String initiateLoginUri; // initiate_login_uri
|
private String initiateLoginUri; // initiate_login_uri
|
||||||
private String postLogoutRedirectUri; // post_logout_redirect_uri
|
private String postLogoutRedirectUri; // post_logout_redirect_uri
|
||||||
|
|
||||||
private Set<String> requestUris; // request_uris
|
private Set<String> requestUris; // request_uris
|
||||||
|
|
||||||
/** Fields to support the ClientDetails interface **/
|
/** Fields to support the ClientDetails interface **/
|
||||||
private Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
|
private Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
|
||||||
private Integer accessTokenValiditySeconds = 0; // in seconds
|
private Integer accessTokenValiditySeconds = 0; // in seconds
|
||||||
private Integer refreshTokenValiditySeconds = 0; // in seconds
|
private Integer refreshTokenValiditySeconds = 0; // in seconds
|
||||||
private Set<String> resourceIds = new HashSet<String>();
|
private Set<String> resourceIds = new HashSet<String>();
|
||||||
private Map<String, Object> additionalInformation = new HashMap<String, Object>();
|
private Map<String, Object> additionalInformation = new HashMap<String, Object>();
|
||||||
|
|
||||||
/** Our own fields **/
|
/** Our own fields **/
|
||||||
private String clientDescription = ""; // human-readable description
|
private String clientDescription = ""; // human-readable description
|
||||||
private boolean reuseRefreshToken = true; // do we let someone reuse a refresh token?
|
private boolean reuseRefreshToken = true; // do we let someone reuse a refresh token?
|
||||||
|
@ -122,16 +122,16 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
private boolean allowIntrospection = false; // do we let this client call the introspection endpoint?
|
private boolean allowIntrospection = false; // do we let this client call the introspection endpoint?
|
||||||
private Integer idTokenValiditySeconds; //timeout for id tokens
|
private Integer idTokenValiditySeconds; //timeout for id tokens
|
||||||
private Date createdAt; // time the client was created
|
private Date createdAt; // time the client was created
|
||||||
|
|
||||||
public enum AuthMethod {
|
public enum AuthMethod {
|
||||||
SECRET_POST("client_secret_post"),
|
SECRET_POST("client_secret_post"),
|
||||||
SECRET_BASIC("client_secret_basic"),
|
SECRET_BASIC("client_secret_basic"),
|
||||||
SECRET_JWT("client_secret_jwt"),
|
SECRET_JWT("client_secret_jwt"),
|
||||||
PRIVATE_KEY("private_key_jwt"),
|
PRIVATE_KEY("private_key_jwt"),
|
||||||
NONE("none");
|
NONE("none");
|
||||||
|
|
||||||
private final String value;
|
private final String value;
|
||||||
|
|
||||||
// map to aid reverse lookup
|
// map to aid reverse lookup
|
||||||
private static final Map<String, AuthMethod> lookup = new HashMap<String, AuthMethod>();
|
private static final Map<String, AuthMethod> lookup = new HashMap<String, AuthMethod>();
|
||||||
static {
|
static {
|
||||||
|
@ -139,77 +139,77 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
lookup.put(a.getValue(), a);
|
lookup.put(a.getValue(), a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthMethod(String value) {
|
AuthMethod(String value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AuthMethod getByValue(String value) {
|
public static AuthMethod getByValue(String value) {
|
||||||
return lookup.get(value);
|
return lookup.get(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum AppType {
|
public enum AppType {
|
||||||
WEB("web"), NATIVE("native");
|
WEB("web"), NATIVE("native");
|
||||||
|
|
||||||
private final String value;
|
private final String value;
|
||||||
|
|
||||||
// map to aid reverse lookup
|
// map to aid reverse lookup
|
||||||
private static final Map<String, AppType> lookup = new HashMap<String, AppType>();
|
private static final Map<String, AppType> lookup = new HashMap<String, AppType>();
|
||||||
static {
|
static {
|
||||||
for (AppType a : AppType.values()) {
|
for (AppType a : AppType.values()) {
|
||||||
lookup.put(a.getValue(), a);
|
lookup.put(a.getValue(), a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AppType(String value) {
|
AppType(String value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AppType getByValue(String value) {
|
public static AppType getByValue(String value) {
|
||||||
return lookup.get(value);
|
return lookup.get(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SubjectType {
|
public enum SubjectType {
|
||||||
PAIRWISE("pairwise"), PUBLIC("public");
|
PAIRWISE("pairwise"), PUBLIC("public");
|
||||||
|
|
||||||
private final String value;
|
private final String value;
|
||||||
|
|
||||||
// map to aid reverse lookup
|
// map to aid reverse lookup
|
||||||
private static final Map<String, SubjectType> lookup = new HashMap<String, SubjectType>();
|
private static final Map<String, SubjectType> lookup = new HashMap<String, SubjectType>();
|
||||||
static {
|
static {
|
||||||
for (SubjectType u : SubjectType.values()) {
|
for (SubjectType u : SubjectType.values()) {
|
||||||
lookup.put(u.getValue(), u);
|
lookup.put(u.getValue(), u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SubjectType(String value) {
|
SubjectType(String value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SubjectType getByValue(String value) {
|
public static SubjectType getByValue(String value) {
|
||||||
return lookup.get(value);
|
return lookup.get(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a blank ClientDetailsEntity
|
* Create a blank ClientDetailsEntity
|
||||||
*/
|
*/
|
||||||
public ClientDetailsEntity() {
|
public ClientDetailsEntity() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -228,34 +228,34 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the clientDescription
|
* @return the clientDescription
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="client_description")
|
@Column(name="client_description")
|
||||||
public String getClientDescription() {
|
public String getClientDescription() {
|
||||||
return clientDescription;
|
return clientDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param clientDescription Human-readable long description of the client (optional)
|
* @param clientDescription Human-readable long description of the client (optional)
|
||||||
*/
|
*/
|
||||||
public void setClientDescription(String clientDescription) {
|
public void setClientDescription(String clientDescription) {
|
||||||
this.clientDescription = clientDescription;
|
this.clientDescription = clientDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the allowRefresh
|
* @return the allowRefresh
|
||||||
*/
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
public boolean isAllowRefresh() {
|
public boolean isAllowRefresh() {
|
||||||
if (grantTypes != null) {
|
if (grantTypes != null) {
|
||||||
return getAuthorizedGrantTypes().contains("refresh_token");
|
return getAuthorizedGrantTypes().contains("refresh_token");
|
||||||
} else {
|
} else {
|
||||||
return false; // if there are no grants, we can't be refreshing them, can we?
|
return false; // if there are no grants, we can't be refreshing them, can we?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="reuse_refresh_tokens")
|
@Column(name="reuse_refresh_tokens")
|
||||||
|
@ -266,7 +266,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
public void setReuseRefreshToken(boolean reuseRefreshToken) {
|
public void setReuseRefreshToken(boolean reuseRefreshToken) {
|
||||||
this.reuseRefreshToken = reuseRefreshToken;
|
this.reuseRefreshToken = reuseRefreshToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the idTokenValiditySeconds
|
* @return the idTokenValiditySeconds
|
||||||
*/
|
*/
|
||||||
|
@ -282,7 +282,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
public void setIdTokenValiditySeconds(Integer idTokenValiditySeconds) {
|
public void setIdTokenValiditySeconds(Integer idTokenValiditySeconds) {
|
||||||
this.idTokenValiditySeconds = idTokenValiditySeconds;
|
this.idTokenValiditySeconds = idTokenValiditySeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the dynamicallyRegistered
|
* @return the dynamicallyRegistered
|
||||||
*/
|
*/
|
||||||
|
@ -298,148 +298,149 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
public void setDynamicallyRegistered(boolean dynamicallyRegistered) {
|
public void setDynamicallyRegistered(boolean dynamicallyRegistered) {
|
||||||
this.dynamicallyRegistered = dynamicallyRegistered;
|
this.dynamicallyRegistered = dynamicallyRegistered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the allowIntrospection
|
* @return the allowIntrospection
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="allow_introspection")
|
@Column(name="allow_introspection")
|
||||||
public boolean isAllowIntrospection() {
|
public boolean isAllowIntrospection() {
|
||||||
return allowIntrospection;
|
return allowIntrospection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param allowIntrospection the allowIntrospection to set
|
* @param allowIntrospection the allowIntrospection to set
|
||||||
*/
|
*/
|
||||||
public void setAllowIntrospection(boolean allowIntrospection) {
|
public void setAllowIntrospection(boolean allowIntrospection) {
|
||||||
this.allowIntrospection = allowIntrospection;
|
this.allowIntrospection = allowIntrospection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transient
|
@Transient
|
||||||
public boolean isSecretRequired() {
|
public boolean isSecretRequired() {
|
||||||
// TODO: this should check the auth method field instead
|
// TODO: this should check the auth method field instead
|
||||||
return getClientSecret() != null;
|
return getClientSecret() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the scope list is not null or empty, then this client has been scoped.
|
* If the scope list is not null or empty, then this client has been scoped.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transient
|
@Transient
|
||||||
public boolean isScoped() {
|
public boolean isScoped() {
|
||||||
return getScope() != null && !getScope().isEmpty();
|
return getScope() != null && !getScope().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the clientId
|
* @return the clientId
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Override
|
@Override
|
||||||
@Column(name="client_id")
|
@Column(name="client_id")
|
||||||
public String getClientId() {
|
public String getClientId() {
|
||||||
return clientId;
|
return clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param clientId The OAuth2 client_id, must be unique to this client
|
* @param clientId The OAuth2 client_id, must be unique to this client
|
||||||
*/
|
*/
|
||||||
public void setClientId(String clientId) {
|
public void setClientId(String clientId) {
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the clientSecret
|
* @return the clientSecret
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Override
|
@Override
|
||||||
@Column(name="client_secret")
|
@Column(name="client_secret")
|
||||||
public String getClientSecret() {
|
public String getClientSecret() {
|
||||||
return clientSecret;
|
return clientSecret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param clientSecret the OAuth2 client_secret (optional)
|
* @param clientSecret the OAuth2 client_secret (optional)
|
||||||
*/
|
*/
|
||||||
public void setClientSecret(String clientSecret) {
|
public void setClientSecret(String clientSecret) {
|
||||||
this.clientSecret = clientSecret;
|
this.clientSecret = clientSecret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the scope
|
* @return the scope
|
||||||
*/
|
*/
|
||||||
@ElementCollection(fetch = FetchType.EAGER)
|
@ElementCollection(fetch = FetchType.EAGER)
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="client_scope",
|
name="client_scope",
|
||||||
joinColumns=@JoinColumn(name="owner_id")
|
joinColumns=@JoinColumn(name="owner_id")
|
||||||
)
|
)
|
||||||
@Override
|
@Override
|
||||||
@Column(name="scope")
|
@Column(name="scope")
|
||||||
public Set<String> getScope() {
|
public Set<String> getScope() {
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param scope the set of scopes allowed to be issued to this client
|
* @param scope the set of scopes allowed to be issued to this client
|
||||||
*/
|
*/
|
||||||
public void setScope(Set<String> scope) {
|
public void setScope(Set<String> scope) {
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the authorizedGrantTypes
|
* @return the authorizedGrantTypes
|
||||||
*/
|
*/
|
||||||
@ElementCollection(fetch = FetchType.EAGER)
|
@ElementCollection(fetch = FetchType.EAGER)
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="client_grant_type",
|
name="client_grant_type",
|
||||||
joinColumns=@JoinColumn(name="owner_id")
|
joinColumns=@JoinColumn(name="owner_id")
|
||||||
)
|
)
|
||||||
@Column(name="grant_type")
|
@Column(name="grant_type")
|
||||||
public Set<String> getGrantTypes() {
|
public Set<String> getGrantTypes() {
|
||||||
return grantTypes;
|
return grantTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param authorizedGrantTypes the OAuth2 grant types that this client is allowed to use
|
* @param authorizedGrantTypes the OAuth2 grant types that this client is allowed to use
|
||||||
*/
|
*/
|
||||||
public void setGrantTypes(Set<String> grantTypes) {
|
public void setGrantTypes(Set<String> grantTypes) {
|
||||||
this.grantTypes = grantTypes;
|
this.grantTypes = grantTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* passthrough for SECOAUTH api
|
|
||||||
*/
|
|
||||||
public Set<String> getAuthorizedGrantTypes() {
|
|
||||||
return getGrantTypes();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the authorities
|
* passthrough for SECOAUTH api
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
|
public Set<String> getAuthorizedGrantTypes() {
|
||||||
|
return getGrantTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the authorities
|
||||||
|
*/
|
||||||
@ElementCollection(fetch = FetchType.EAGER)
|
@ElementCollection(fetch = FetchType.EAGER)
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="client_authority",
|
name="client_authority",
|
||||||
joinColumns=@JoinColumn(name="owner_id")
|
joinColumns=@JoinColumn(name="owner_id")
|
||||||
)
|
)
|
||||||
@Override
|
@Override
|
||||||
@Column(name="authority")
|
@Column(name="authority")
|
||||||
public Set<GrantedAuthority> getAuthorities() {
|
public Set<GrantedAuthority> getAuthorities() {
|
||||||
return authorities;
|
return authorities;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param authorities the Spring Security authorities this client is given
|
* @param authorities the Spring Security authorities this client is given
|
||||||
*/
|
*/
|
||||||
public void setAuthorities(Set<GrantedAuthority> authorities) {
|
public void setAuthorities(Set<GrantedAuthority> authorities) {
|
||||||
this.authorities = authorities;
|
this.authorities = authorities;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Basic
|
@Basic
|
||||||
|
@ -447,13 +448,13 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
public Integer getAccessTokenValiditySeconds() {
|
public Integer getAccessTokenValiditySeconds() {
|
||||||
return accessTokenValiditySeconds;
|
return accessTokenValiditySeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param accessTokenTimeout the accessTokenTimeout to set
|
* @param accessTokenTimeout the accessTokenTimeout to set
|
||||||
*/
|
*/
|
||||||
public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) {
|
public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) {
|
||||||
this.accessTokenValiditySeconds = accessTokenValiditySeconds;
|
this.accessTokenValiditySeconds = accessTokenValiditySeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Basic
|
@Basic
|
||||||
|
@ -461,64 +462,65 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
public Integer getRefreshTokenValiditySeconds() {
|
public Integer getRefreshTokenValiditySeconds() {
|
||||||
return refreshTokenValiditySeconds;
|
return refreshTokenValiditySeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param refreshTokenTimeout Lifetime of refresh tokens, in seconds (optional - leave null for no timeout)
|
* @param refreshTokenTimeout Lifetime of refresh tokens, in seconds (optional - leave null for no timeout)
|
||||||
*/
|
*/
|
||||||
public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) {
|
public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) {
|
||||||
this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
|
this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the registeredRedirectUri
|
* @return the registeredRedirectUri
|
||||||
*/
|
*/
|
||||||
@ElementCollection(fetch = FetchType.EAGER)
|
@ElementCollection(fetch = FetchType.EAGER)
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="client_redirect_uri",
|
name="client_redirect_uri",
|
||||||
joinColumns=@JoinColumn(name="owner_id")
|
joinColumns=@JoinColumn(name="owner_id")
|
||||||
)
|
)
|
||||||
@Column(name="redirect_uri")
|
@Column(name="redirect_uri")
|
||||||
public Set<String> getRedirectUris() {
|
public Set<String> getRedirectUris() {
|
||||||
return redirectUris;
|
return redirectUris;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param registeredRedirectUri the registeredRedirectUri to set
|
* @param registeredRedirectUri the registeredRedirectUri to set
|
||||||
*/
|
*/
|
||||||
public void setRedirectUris(Set<String> redirectUris) {
|
public void setRedirectUris(Set<String> redirectUris) {
|
||||||
this.redirectUris = redirectUris;
|
this.redirectUris = redirectUris;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Pass-through method to fulfill the ClientDetails interface with a bad name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Transient
|
|
||||||
public Set<String> getRegisteredRedirectUri() {
|
|
||||||
return getRedirectUris();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the resourceIds
|
* Pass-through method to fulfill the ClientDetails interface with a bad name
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
|
@Transient
|
||||||
|
public Set<String> getRegisteredRedirectUri() {
|
||||||
|
return getRedirectUris();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the resourceIds
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
@ElementCollection(fetch = FetchType.EAGER)
|
@ElementCollection(fetch = FetchType.EAGER)
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="client_resource",
|
name="client_resource",
|
||||||
joinColumns=@JoinColumn(name="owner_id")
|
joinColumns=@JoinColumn(name="owner_id")
|
||||||
)
|
)
|
||||||
@Column(name="resource_id")
|
@Column(name="resource_id")
|
||||||
public Set<String> getResourceIds() {
|
public Set<String> getResourceIds() {
|
||||||
return resourceIds;
|
return resourceIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param resourceIds the resourceIds to set
|
* @param resourceIds the resourceIds to set
|
||||||
*/
|
*/
|
||||||
public void setResourceIds(Set<String> resourceIds) {
|
public void setResourceIds(Set<String> resourceIds) {
|
||||||
this.resourceIds = resourceIds;
|
this.resourceIds = resourceIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This library does not make use of this field, so it is not
|
* This library does not make use of this field, so it is not
|
||||||
* stored using our persistence layer.
|
* stored using our persistence layer.
|
||||||
|
@ -533,7 +535,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
return this.additionalInformation;
|
return this.additionalInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
|
@ -580,7 +582,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="client_contact",
|
name="client_contact",
|
||||||
joinColumns=@JoinColumn(name="owner_id")
|
joinColumns=@JoinColumn(name="owner_id")
|
||||||
)
|
)
|
||||||
@Column(name="contact")
|
@Column(name="contact")
|
||||||
public Set<String> getContacts() {
|
public Set<String> getContacts() {
|
||||||
return contacts;
|
return contacts;
|
||||||
|
@ -599,7 +601,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
public void setLogoUri(String logoUri) {
|
public void setLogoUri(String logoUri) {
|
||||||
this.logoUri = logoUri;
|
this.logoUri = logoUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="policy_uri")
|
@Column(name="policy_uri")
|
||||||
public String getPolicyUri() {
|
public String getPolicyUri() {
|
||||||
|
@ -611,36 +613,36 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the clientUrl
|
* @return the clientUrl
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="client_uri")
|
@Column(name="client_uri")
|
||||||
public String getClientUri() {
|
public String getClientUri() {
|
||||||
return clientUri;
|
return clientUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param clientUrl the clientUrl to set
|
* @param clientUrl the clientUrl to set
|
||||||
*/
|
*/
|
||||||
public void setClientUri(String clientUri) {
|
public void setClientUri(String clientUri) {
|
||||||
this.clientUri = clientUri;
|
this.clientUri = clientUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the tosUrl
|
* @return the tosUrl
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="tos_uri")
|
@Column(name="tos_uri")
|
||||||
public String getTosUri() {
|
public String getTosUri() {
|
||||||
return tosUri;
|
return tosUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tosUrl the tosUrl to set
|
* @param tosUrl the tosUrl to set
|
||||||
*/
|
*/
|
||||||
public void setTosUri(String tosUri) {
|
public void setTosUri(String tosUri) {
|
||||||
this.tosUri = tosUri;
|
this.tosUri = tosUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="jwks_uri")
|
@Column(name="jwks_uri")
|
||||||
|
@ -708,7 +710,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
|
|
||||||
public void setUserInfoEncryptedResponseEnc(JWEEncryptionMethodEmbed userInfoEncryptedResponseEnc) {
|
public void setUserInfoEncryptedResponseEnc(JWEEncryptionMethodEmbed userInfoEncryptedResponseEnc) {
|
||||||
this.userInfoEncryptedResponseEnc = userInfoEncryptedResponseEnc;
|
this.userInfoEncryptedResponseEnc = userInfoEncryptedResponseEnc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Embedded
|
@Embedded
|
||||||
@AttributeOverrides({
|
@AttributeOverrides({
|
||||||
|
@ -773,7 +775,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="client_response_type",
|
name="client_response_type",
|
||||||
joinColumns=@JoinColumn(name="response_type")
|
joinColumns=@JoinColumn(name="response_type")
|
||||||
)
|
)
|
||||||
@Column(name="response_type")
|
@Column(name="response_type")
|
||||||
public Set<String> getResponseTypes() {
|
public Set<String> getResponseTypes() {
|
||||||
return responseTypes;
|
return responseTypes;
|
||||||
|
@ -793,7 +795,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="client_default_acr_value",
|
name="client_default_acr_value",
|
||||||
joinColumns=@JoinColumn(name="owner_id")
|
joinColumns=@JoinColumn(name="owner_id")
|
||||||
)
|
)
|
||||||
@Column(name="default_acr_value")
|
@Column(name="default_acr_value")
|
||||||
public Set<String> getDefaultACRvalues() {
|
public Set<String> getDefaultACRvalues() {
|
||||||
return defaultACRvalues;
|
return defaultACRvalues;
|
||||||
|
@ -845,7 +847,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="client_request_uri",
|
name="client_request_uri",
|
||||||
joinColumns=@JoinColumn(name="owner_id")
|
joinColumns=@JoinColumn(name="owner_id")
|
||||||
)
|
)
|
||||||
@Column(name="request_uri")
|
@Column(name="request_uri")
|
||||||
public Set<String> getRequestUris() {
|
public Set<String> getRequestUris() {
|
||||||
return requestUris;
|
return requestUris;
|
||||||
|
@ -863,15 +865,15 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
*/
|
*/
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
@Column(name="created_at")
|
@Column(name="created_at")
|
||||||
public Date getCreatedAt() {
|
public Date getCreatedAt() {
|
||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param createdAt the createdAt to set
|
* @param createdAt the createdAt to set
|
||||||
*/
|
*/
|
||||||
public void setCreatedAt(Date createdAt) {
|
public void setCreatedAt(Date createdAt) {
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,9 +47,7 @@ import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||||
|
|
||||||
import com.nimbusds.jwt.JWT;
|
import com.nimbusds.jwt.JWT;
|
||||||
import com.nimbusds.jwt.JWTClaimsSet;
|
|
||||||
import com.nimbusds.jwt.JWTParser;
|
import com.nimbusds.jwt.JWTParser;
|
||||||
import com.nimbusds.jwt.PlainJWT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jricher
|
* @author jricher
|
||||||
|
@ -73,17 +71,17 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
||||||
public static final String REGISTRATION_TOKEN_SCOPE = "registration-token";
|
public static final String REGISTRATION_TOKEN_SCOPE = "registration-token";
|
||||||
|
|
||||||
public static String ID_TOKEN = "id_token";
|
public static String ID_TOKEN = "id_token";
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
private ClientDetailsEntity client;
|
private ClientDetailsEntity client;
|
||||||
|
|
||||||
private AuthenticationHolderEntity authenticationHolder; // the authentication that made this access
|
private AuthenticationHolderEntity authenticationHolder; // the authentication that made this access
|
||||||
|
|
||||||
private JWT jwtValue; // JWT-encoded access token value
|
private JWT jwtValue; // JWT-encoded access token value
|
||||||
|
|
||||||
private OAuth2AccessTokenEntity idToken; // JWT-encoded OpenID Connect IdToken
|
private OAuth2AccessTokenEntity idToken; // JWT-encoded OpenID Connect IdToken
|
||||||
|
|
||||||
private Date expiration;
|
private Date expiration;
|
||||||
|
|
||||||
private String tokenType = OAuth2AccessToken.BEARER_TYPE;
|
private String tokenType = OAuth2AccessToken.BEARER_TYPE;
|
||||||
|
@ -91,14 +89,14 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
||||||
private OAuth2RefreshTokenEntity refreshToken;
|
private OAuth2RefreshTokenEntity refreshToken;
|
||||||
|
|
||||||
private Set<String> scope;
|
private Set<String> scope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new, blank access token
|
* Create a new, blank access token
|
||||||
*/
|
*/
|
||||||
public OAuth2AccessTokenEntity() {
|
public OAuth2AccessTokenEntity() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
|
@ -116,8 +114,9 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all additional information to be sent to the serializer. Inserts a copy of the IdToken (in JWT String form).
|
* Get all additional information to be sent to the serializer. Inserts a copy of the IdToken (in JWT String form).
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
@Transient
|
@Transient
|
||||||
public Map<String, Object> getAdditionalInformation() {
|
public Map<String, Object> getAdditionalInformation() {
|
||||||
Map<String, Object> map = new HashMap<String, Object>(); //super.getAdditionalInformation();
|
Map<String, Object> map = new HashMap<String, Object>(); //super.getAdditionalInformation();
|
||||||
|
@ -126,121 +125,127 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The authentication in place when this token was created.
|
* The authentication in place when this token was created.
|
||||||
* @return the authentication
|
* @return the authentication
|
||||||
*/
|
*/
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "auth_holder_id")
|
@JoinColumn(name = "auth_holder_id")
|
||||||
public AuthenticationHolderEntity getAuthenticationHolder() {
|
public AuthenticationHolderEntity getAuthenticationHolder() {
|
||||||
return authenticationHolder;
|
return authenticationHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param authentication the authentication to set
|
* @param authentication the authentication to set
|
||||||
*/
|
*/
|
||||||
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
|
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
|
||||||
this.authenticationHolder = authenticationHolder;
|
this.authenticationHolder = authenticationHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the client
|
* @return the client
|
||||||
*/
|
*/
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "client_id")
|
@JoinColumn(name = "client_id")
|
||||||
public ClientDetailsEntity getClient() {
|
public ClientDetailsEntity getClient() {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param client the client to set
|
* @param client the client to set
|
||||||
*/
|
*/
|
||||||
public void setClient(ClientDetailsEntity client) {
|
public void setClient(ClientDetailsEntity client) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the string-encoded value of this access token.
|
|
||||||
*/
|
|
||||||
@Basic
|
|
||||||
@Column(name="token_value")
|
|
||||||
public String getValue() {
|
|
||||||
return jwtValue.serialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the "value" of this Access Token
|
* Get the string-encoded value of this access token.
|
||||||
*
|
*/
|
||||||
* @param value the JWT string
|
@Override
|
||||||
* @throws ParseException if "value" is not a properly formatted JWT string
|
@Basic
|
||||||
*/
|
@Column(name="token_value")
|
||||||
public void setValue(String value) throws ParseException {
|
public String getValue() {
|
||||||
setJwt(JWTParser.parse(value));
|
return jwtValue.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Basic
|
/**
|
||||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
* Set the "value" of this Access Token
|
||||||
public Date getExpiration() {
|
*
|
||||||
return expiration;
|
* @param value the JWT string
|
||||||
}
|
* @throws ParseException if "value" is not a properly formatted JWT string
|
||||||
|
*/
|
||||||
|
public void setValue(String value) throws ParseException {
|
||||||
|
setJwt(JWTParser.parse(value));
|
||||||
|
}
|
||||||
|
|
||||||
public void setExpiration(Date expiration) {
|
@Override
|
||||||
this.expiration = expiration;
|
@Basic
|
||||||
}
|
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||||
|
public Date getExpiration() {
|
||||||
|
return expiration;
|
||||||
|
}
|
||||||
|
|
||||||
@Basic
|
public void setExpiration(Date expiration) {
|
||||||
@Column(name="token_type")
|
this.expiration = expiration;
|
||||||
public String getTokenType() {
|
}
|
||||||
return tokenType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTokenType(String tokenType) {
|
@Override
|
||||||
this.tokenType = tokenType;
|
@Basic
|
||||||
}
|
@Column(name="token_type")
|
||||||
|
public String getTokenType() {
|
||||||
|
return tokenType;
|
||||||
|
}
|
||||||
|
|
||||||
@ManyToOne
|
public void setTokenType(String tokenType) {
|
||||||
@JoinColumn(name="refresh_token_id")
|
this.tokenType = tokenType;
|
||||||
public OAuth2RefreshTokenEntity getRefreshToken() {
|
}
|
||||||
return refreshToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
@Override
|
||||||
this.refreshToken = refreshToken;
|
@ManyToOne
|
||||||
}
|
@JoinColumn(name="refresh_token_id")
|
||||||
|
public OAuth2RefreshTokenEntity getRefreshToken() {
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
public void setRefreshToken(OAuth2RefreshToken refreshToken) {
|
public void setRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||||
if (!(refreshToken instanceof OAuth2RefreshTokenEntity)) {
|
this.refreshToken = refreshToken;
|
||||||
// TODO: make a copy constructor instead....
|
}
|
||||||
throw new IllegalArgumentException("Not a storable refresh token entity!");
|
|
||||||
}
|
|
||||||
// force a pass through to the entity version
|
|
||||||
setRefreshToken((OAuth2RefreshTokenEntity)refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ElementCollection(fetch=FetchType.EAGER)
|
|
||||||
@CollectionTable(
|
|
||||||
joinColumns=@JoinColumn(name="owner_id"),
|
|
||||||
name="token_scope"
|
|
||||||
)
|
|
||||||
public Set<String> getScope() {
|
|
||||||
return scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setScope(Set<String> scope) {
|
public void setRefreshToken(OAuth2RefreshToken refreshToken) {
|
||||||
this.scope = scope;
|
if (!(refreshToken instanceof OAuth2RefreshTokenEntity)) {
|
||||||
}
|
// TODO: make a copy constructor instead....
|
||||||
|
throw new IllegalArgumentException("Not a storable refresh token entity!");
|
||||||
|
}
|
||||||
|
// force a pass through to the entity version
|
||||||
|
setRefreshToken((OAuth2RefreshTokenEntity)refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
@Transient
|
@Override
|
||||||
|
@ElementCollection(fetch=FetchType.EAGER)
|
||||||
|
@CollectionTable(
|
||||||
|
joinColumns=@JoinColumn(name="owner_id"),
|
||||||
|
name="token_scope"
|
||||||
|
)
|
||||||
|
public Set<String> getScope() {
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScope(Set<String> scope) {
|
||||||
|
this.scope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transient
|
||||||
public boolean isExpired() {
|
public boolean isExpired() {
|
||||||
return getExpiration() == null ? false : System.currentTimeMillis() > getExpiration().getTime();
|
return getExpiration() == null ? false : System.currentTimeMillis() > getExpiration().getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the idToken
|
* @return the idToken
|
||||||
*/
|
*/
|
||||||
@OneToOne(cascade=CascadeType.ALL) // one-to-one mapping for now
|
@OneToOne(cascade=CascadeType.ALL) // one-to-one mapping for now
|
||||||
@JoinColumn(name = "id_token_id")
|
@JoinColumn(name = "id_token_id")
|
||||||
public OAuth2AccessTokenEntity getIdToken() {
|
public OAuth2AccessTokenEntity getIdToken() {
|
||||||
return idToken;
|
return idToken;
|
||||||
}
|
}
|
||||||
|
@ -251,7 +256,7 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
||||||
public void setIdToken(OAuth2AccessTokenEntity idToken) {
|
public void setIdToken(OAuth2AccessTokenEntity idToken) {
|
||||||
this.idToken = idToken;
|
this.idToken = idToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the idTokenString
|
* @return the idTokenString
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -39,9 +39,7 @@ import javax.persistence.Transient;
|
||||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||||
|
|
||||||
import com.nimbusds.jwt.JWT;
|
import com.nimbusds.jwt.JWT;
|
||||||
import com.nimbusds.jwt.JWTClaimsSet;
|
|
||||||
import com.nimbusds.jwt.JWTParser;
|
import com.nimbusds.jwt.JWTParser;
|
||||||
import com.nimbusds.jwt.PlainJWT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jricher
|
* @author jricher
|
||||||
|
@ -58,14 +56,14 @@ import com.nimbusds.jwt.PlainJWT;
|
||||||
public class OAuth2RefreshTokenEntity implements OAuth2RefreshToken {
|
public class OAuth2RefreshTokenEntity implements OAuth2RefreshToken {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
private AuthenticationHolderEntity authenticationHolder;
|
private AuthenticationHolderEntity authenticationHolder;
|
||||||
|
|
||||||
private ClientDetailsEntity client;
|
private ClientDetailsEntity client;
|
||||||
|
|
||||||
//JWT-encoded representation of this access token entity
|
//JWT-encoded representation of this access token entity
|
||||||
private JWT jwt;
|
private JWT jwt;
|
||||||
|
|
||||||
// our refresh tokens might expire
|
// our refresh tokens might expire
|
||||||
private Date expiration;
|
private Date expiration;
|
||||||
|
|
||||||
|
@ -91,97 +89,98 @@ public class OAuth2RefreshTokenEntity implements OAuth2RefreshToken {
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The authentication in place when the original access token was
|
|
||||||
* created
|
|
||||||
*
|
|
||||||
* @return the authentication
|
|
||||||
*/
|
|
||||||
@ManyToOne
|
|
||||||
@JoinColumn(name = "auth_holder_id")
|
|
||||||
public AuthenticationHolderEntity getAuthenticationHolder() {
|
|
||||||
return authenticationHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param authentication the authentication to set
|
* The authentication in place when the original access token was
|
||||||
*/
|
* created
|
||||||
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
|
*
|
||||||
this.authenticationHolder = authenticationHolder;
|
* @return the authentication
|
||||||
}
|
*/
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "auth_holder_id")
|
||||||
|
public AuthenticationHolderEntity getAuthenticationHolder() {
|
||||||
|
return authenticationHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param authentication the authentication to set
|
||||||
|
*/
|
||||||
|
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
|
||||||
|
this.authenticationHolder = authenticationHolder;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the JWT-encoded value of this token
|
* Get the JWT-encoded value of this token
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Override
|
||||||
@Column(name="token_value")
|
@Basic
|
||||||
public String getValue() {
|
@Column(name="token_value")
|
||||||
return jwt.serialize();
|
public String getValue() {
|
||||||
}
|
return jwt.serialize();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the value of this token as a string. Parses the string into a JWT.
|
* Set the value of this token as a string. Parses the string into a JWT.
|
||||||
* @param value
|
* @param value
|
||||||
* @throws ParseException if the value is not a valid JWT string
|
* @throws ParseException if the value is not a valid JWT string
|
||||||
*/
|
*/
|
||||||
public void setValue(String value) throws ParseException {
|
public void setValue(String value) throws ParseException {
|
||||||
setJwt(JWTParser.parse(value));
|
setJwt(JWTParser.parse(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Basic
|
@Basic
|
||||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||||
public Date getExpiration() {
|
public Date getExpiration() {
|
||||||
return expiration;
|
return expiration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken#setExpiration(java.util.Date)
|
* @see org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken#setExpiration(java.util.Date)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void setExpiration(Date expiration) {
|
|
||||||
this.expiration = expiration;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public void setExpiration(Date expiration) {
|
||||||
* Has this token expired?
|
this.expiration = expiration;
|
||||||
* @return true if it has a timeout set and the timeout has passed
|
}
|
||||||
*/
|
|
||||||
@Transient
|
/**
|
||||||
|
* Has this token expired?
|
||||||
|
* @return true if it has a timeout set and the timeout has passed
|
||||||
|
*/
|
||||||
|
@Transient
|
||||||
public boolean isExpired() {
|
public boolean isExpired() {
|
||||||
return getExpiration() == null ? false : System.currentTimeMillis() > getExpiration().getTime();
|
return getExpiration() == null ? false : System.currentTimeMillis() > getExpiration().getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the client
|
* @return the client
|
||||||
*/
|
*/
|
||||||
@ManyToOne(fetch = FetchType.EAGER)
|
@ManyToOne(fetch = FetchType.EAGER)
|
||||||
@JoinColumn(name = "client_id")
|
@JoinColumn(name = "client_id")
|
||||||
public ClientDetailsEntity getClient() {
|
public ClientDetailsEntity getClient() {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param client the client to set
|
* @param client the client to set
|
||||||
*/
|
*/
|
||||||
public void setClient(ClientDetailsEntity client) {
|
public void setClient(ClientDetailsEntity client) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the JWT object directly
|
||||||
|
* @return the jwt
|
||||||
|
*/
|
||||||
|
@Transient
|
||||||
|
public JWT getJwt() {
|
||||||
|
return jwt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param jwt the jwt to set
|
||||||
|
*/
|
||||||
|
public void setJwt(JWT jwt) {
|
||||||
|
this.jwt = jwt;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the JWT object directly
|
|
||||||
* @return the jwt
|
|
||||||
*/
|
|
||||||
@Transient
|
|
||||||
public JWT getJwt() {
|
|
||||||
return jwt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param jwt the jwt to set
|
|
||||||
*/
|
|
||||||
public void setJwt(JWT jwt) {
|
|
||||||
this.jwt = jwt;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class SystemScope {
|
||||||
private Long id;
|
private Long id;
|
||||||
private String value; // scope value
|
private String value; // scope value
|
||||||
private String description; // human-readable description
|
private String description; // human-readable description
|
||||||
private String icon; // class of the icon to display on the auth page
|
private String icon; // class of the icon to display on the auth page
|
||||||
private boolean allowDynReg = false; // can a dynamically registered client ask for this scope?
|
private boolean allowDynReg = false; // can a dynamically registered client ask for this scope?
|
||||||
private boolean defaultScope = false; // is this a default scope for newly-registered clients?
|
private boolean defaultScope = false; // is this a default scope for newly-registered clients?
|
||||||
|
|
||||||
|
@ -36,16 +36,16 @@ public class SystemScope {
|
||||||
* Make a blank system scope with no value
|
* Make a blank system scope with no value
|
||||||
*/
|
*/
|
||||||
public SystemScope() {
|
public SystemScope() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a system scope with the given scope value
|
* Make a system scope with the given scope value
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
public SystemScope(String value) {
|
public SystemScope(String value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
|
@ -117,7 +117,7 @@ public class SystemScope {
|
||||||
public void setAllowDynReg(boolean allowDynReg) {
|
public void setAllowDynReg(boolean allowDynReg) {
|
||||||
this.allowDynReg = allowDynReg;
|
this.allowDynReg = allowDynReg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the defaultScope
|
* @return the defaultScope
|
||||||
*/
|
*/
|
||||||
|
@ -136,76 +136,76 @@ public class SystemScope {
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Object#hashCode()
|
* @see java.lang.Object#hashCode()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + (allowDynReg ? 1231 : 1237);
|
result = prime * result + (allowDynReg ? 1231 : 1237);
|
||||||
result = prime * result + (defaultScope ? 1231 : 1237);
|
result = prime * result + (defaultScope ? 1231 : 1237);
|
||||||
result = prime * result + ((description == null) ? 0 : description.hashCode());
|
result = prime * result + ((description == null) ? 0 : description.hashCode());
|
||||||
result = prime * result + ((icon == null) ? 0 : icon.hashCode());
|
result = prime * result + ((icon == null) ? 0 : icon.hashCode());
|
||||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||||
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Object#equals(java.lang.Object)
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (getClass() != obj.getClass()) {
|
if (getClass() != obj.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SystemScope other = (SystemScope) obj;
|
SystemScope other = (SystemScope) obj;
|
||||||
if (allowDynReg != other.allowDynReg) {
|
if (allowDynReg != other.allowDynReg) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (defaultScope != other.defaultScope) {
|
if (defaultScope != other.defaultScope) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (description == null) {
|
if (description == null) {
|
||||||
if (other.description != null) {
|
if (other.description != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!description.equals(other.description)) {
|
} else if (!description.equals(other.description)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (icon == null) {
|
if (icon == null) {
|
||||||
if (other.icon != null) {
|
if (other.icon != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!icon.equals(other.icon)) {
|
} else if (!icon.equals(other.icon)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
if (other.id != null) {
|
if (other.id != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!id.equals(other.id)) {
|
} else if (!id.equals(other.id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
if (other.value != null) {
|
if (other.value != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!value.equals(other.value)) {
|
} else if (!value.equals(other.value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SystemScope [value=" + value + ", description=" + description + ", icon=" + icon + ", allowDynReg=" + allowDynReg + ", defaultScope=" + defaultScope + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "SystemScope [value=" + value + ", description=" + description + ", icon=" + icon + ", allowDynReg=" + allowDynReg + ", defaultScope=" + defaultScope + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,13 @@ import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
public interface AuthenticationHolderRepository {
|
public interface AuthenticationHolderRepository {
|
||||||
|
|
||||||
public AuthenticationHolderEntity getById(Long id);
|
public AuthenticationHolderEntity getById(Long id);
|
||||||
|
|
||||||
public AuthenticationHolderEntity getByAuthentication(OAuth2Authentication a);
|
public AuthenticationHolderEntity getByAuthentication(OAuth2Authentication a);
|
||||||
|
|
||||||
public void removeById(Long id);
|
public void removeById(Long id);
|
||||||
|
|
||||||
public void remove(AuthenticationHolderEntity a);
|
public void remove(AuthenticationHolderEntity a);
|
||||||
|
|
||||||
public AuthenticationHolderEntity save(AuthenticationHolderEntity a);
|
public AuthenticationHolderEntity save(AuthenticationHolderEntity a);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import org.springframework.security.oauth2.common.exceptions.InvalidGrantExcepti
|
||||||
import org.springframework.security.oauth2.provider.code.AuthorizationRequestHolder;
|
import org.springframework.security.oauth2.provider.code.AuthorizationRequestHolder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for saving and consuming OAuth2 authorization codes as AuthorizationCodeEntitys.
|
* Interface for saving and consuming OAuth2 authorization codes as AuthorizationCodeEntitys.
|
||||||
*
|
*
|
||||||
* @author aanganes
|
* @author aanganes
|
||||||
*
|
*
|
||||||
|
@ -19,14 +19,14 @@ public interface AuthorizationCodeRepository {
|
||||||
* @return the saved AuthorizationCodeEntity
|
* @return the saved AuthorizationCodeEntity
|
||||||
*/
|
*/
|
||||||
public AuthorizationCodeEntity save(AuthorizationCodeEntity authorizationCode);
|
public AuthorizationCodeEntity save(AuthorizationCodeEntity authorizationCode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Consume an authorization code.
|
* Consume an authorization code.
|
||||||
*
|
*
|
||||||
* @param code the authorization code value
|
* @param code the authorization code value
|
||||||
* @return the authentication associated with the code
|
* @return the authentication associated with the code
|
||||||
* @throws InvalidGrantException if no AuthorizationCodeEntity is found with the given value
|
* @throws InvalidGrantException if no AuthorizationCodeEntity is found with the given value
|
||||||
*/
|
*/
|
||||||
public AuthorizationRequestHolder consume(String code) throws InvalidGrantException;
|
public AuthorizationRequestHolder consume(String code) throws InvalidGrantException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Collection;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||||
|
|
||||||
public interface OAuth2ClientRepository {
|
public interface OAuth2ClientRepository {
|
||||||
|
|
||||||
public ClientDetailsEntity getById(Long id);
|
public ClientDetailsEntity getById(Long id);
|
||||||
|
|
||||||
public ClientDetailsEntity getClientByClientId(String clientId);
|
public ClientDetailsEntity getClientByClientId(String clientId);
|
||||||
|
|
|
@ -27,17 +27,17 @@ public interface OAuth2TokenRepository {
|
||||||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity token);
|
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity token);
|
||||||
|
|
||||||
public OAuth2RefreshTokenEntity getRefreshTokenByValue(String refreshTokenValue);
|
public OAuth2RefreshTokenEntity getRefreshTokenByValue(String refreshTokenValue);
|
||||||
|
|
||||||
public OAuth2RefreshTokenEntity getRefreshTokenById(Long Id);
|
public OAuth2RefreshTokenEntity getRefreshTokenById(Long Id);
|
||||||
|
|
||||||
public void clearAccessTokensForRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
public void clearAccessTokensForRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||||
|
|
||||||
public void removeRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
public void removeRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||||
|
|
||||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||||
|
|
||||||
public OAuth2AccessTokenEntity getAccessTokenByValue(String accessTokenValue);
|
public OAuth2AccessTokenEntity getAccessTokenByValue(String accessTokenValue);
|
||||||
|
|
||||||
public OAuth2AccessTokenEntity getAccessTokenById(Long id);
|
public OAuth2AccessTokenEntity getAccessTokenById(Long id);
|
||||||
|
|
||||||
public void removeAccessToken(OAuth2AccessTokenEntity accessToken);
|
public void removeAccessToken(OAuth2AccessTokenEntity accessToken);
|
||||||
|
@ -55,8 +55,8 @@ public interface OAuth2TokenRepository {
|
||||||
public OAuth2AccessTokenEntity getByAuthentication(OAuth2Authentication auth);
|
public OAuth2AccessTokenEntity getByAuthentication(OAuth2Authentication auth);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken);
|
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,13 @@ import org.mitre.oauth2.model.SystemScope;
|
||||||
public interface SystemScopeRepository {
|
public interface SystemScopeRepository {
|
||||||
|
|
||||||
public Set<SystemScope> getAll();
|
public Set<SystemScope> getAll();
|
||||||
|
|
||||||
public SystemScope getById(Long id);
|
public SystemScope getById(Long id);
|
||||||
|
|
||||||
public SystemScope getByValue(String value);
|
public SystemScope getByValue(String value);
|
||||||
|
|
||||||
public void remove(SystemScope scope);
|
public void remove(SystemScope scope);
|
||||||
|
|
||||||
public SystemScope save(SystemScope scope);
|
public SystemScope save(SystemScope scope);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,19 +24,20 @@ import org.springframework.security.oauth2.provider.ClientDetailsService;
|
||||||
public interface ClientDetailsEntityService extends ClientDetailsService {
|
public interface ClientDetailsEntityService extends ClientDetailsService {
|
||||||
|
|
||||||
public ClientDetailsEntity saveNewClient(ClientDetailsEntity client);
|
public ClientDetailsEntity saveNewClient(ClientDetailsEntity client);
|
||||||
|
|
||||||
public ClientDetailsEntity getClientById(Long id);
|
public ClientDetailsEntity getClientById(Long id);
|
||||||
|
|
||||||
|
@Override
|
||||||
public ClientDetailsEntity loadClientByClientId(String clientId) throws OAuth2Exception;
|
public ClientDetailsEntity loadClientByClientId(String clientId) throws OAuth2Exception;
|
||||||
|
|
||||||
public void deleteClient(ClientDetailsEntity client);
|
public void deleteClient(ClientDetailsEntity client);
|
||||||
|
|
||||||
public ClientDetailsEntity updateClient(ClientDetailsEntity oldClient, ClientDetailsEntity newClient);
|
public ClientDetailsEntity updateClient(ClientDetailsEntity oldClient, ClientDetailsEntity newClient);
|
||||||
|
|
||||||
public Collection<ClientDetailsEntity> getAllClients();
|
public Collection<ClientDetailsEntity> getAllClients();
|
||||||
|
|
||||||
public ClientDetailsEntity generateClientId(ClientDetailsEntity client);
|
public ClientDetailsEntity generateClientId(ClientDetailsEntity client);
|
||||||
|
|
||||||
public ClientDetailsEntity generateClientSecret(ClientDetailsEntity client);
|
public ClientDetailsEntity generateClientSecret(ClientDetailsEntity client);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,30 +26,32 @@ import org.springframework.security.oauth2.provider.token.ResourceServerTokenSer
|
||||||
|
|
||||||
public interface OAuth2TokenEntityService extends AuthorizationServerTokenServices, ResourceServerTokenServices {
|
public interface OAuth2TokenEntityService extends AuthorizationServerTokenServices, ResourceServerTokenServices {
|
||||||
|
|
||||||
|
@Override
|
||||||
public OAuth2AccessTokenEntity readAccessToken(String accessTokenValue);
|
public OAuth2AccessTokenEntity readAccessToken(String accessTokenValue);
|
||||||
|
|
||||||
public OAuth2RefreshTokenEntity getRefreshToken(String refreshTokenValue);
|
public OAuth2RefreshTokenEntity getRefreshToken(String refreshTokenValue);
|
||||||
|
|
||||||
public void revokeRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
public void revokeRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||||
|
|
||||||
public void revokeAccessToken(OAuth2AccessTokenEntity accessToken);
|
public void revokeAccessToken(OAuth2AccessTokenEntity accessToken);
|
||||||
|
|
||||||
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client);
|
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client);
|
||||||
|
|
||||||
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client);
|
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client);
|
||||||
|
|
||||||
public void clearExpiredTokens();
|
public void clearExpiredTokens();
|
||||||
|
|
||||||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity accessToken);
|
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity accessToken);
|
||||||
|
|
||||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||||
|
|
||||||
|
@Override
|
||||||
public OAuth2AccessTokenEntity getAccessToken(OAuth2Authentication authentication);
|
public OAuth2AccessTokenEntity getAccessToken(OAuth2Authentication authentication);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param incomingToken
|
* @param incomingToken
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken);
|
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,15 +12,15 @@ import org.mitre.oauth2.model.SystemScope;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface SystemScopeService {
|
public interface SystemScopeService {
|
||||||
|
|
||||||
public Set<SystemScope> getAll();
|
public Set<SystemScope> getAll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all scopes that are defaulted to new clients on this system
|
* Get all scopes that are defaulted to new clients on this system
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Set<SystemScope> getDefaults();
|
public Set<SystemScope> getDefaults();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all scopes that are allowed for dynamic registration on this system
|
* Get all scopes that are allowed for dynamic registration on this system
|
||||||
* @return
|
* @return
|
||||||
|
@ -28,20 +28,20 @@ public interface SystemScopeService {
|
||||||
public Set<SystemScope> getDynReg();
|
public Set<SystemScope> getDynReg();
|
||||||
|
|
||||||
public SystemScope getById(Long id);
|
public SystemScope getById(Long id);
|
||||||
|
|
||||||
public SystemScope getByValue(String value);
|
public SystemScope getByValue(String value);
|
||||||
|
|
||||||
public void remove(SystemScope scope);
|
public void remove(SystemScope scope);
|
||||||
|
|
||||||
public SystemScope save(SystemScope scope);
|
public SystemScope save(SystemScope scope);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate the set of scope strings into a set of SystemScope objects.
|
* Translate the set of scope strings into a set of SystemScope objects.
|
||||||
* @param scope
|
* @param scope
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Set<SystemScope> fromStrings(Set<String> scope);
|
public Set<SystemScope> fromStrings(Set<String> scope);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pluck the scope values from the set of SystemScope objects and return a list of strings
|
* Pluck the scope values from the set of SystemScope objects and return a list of strings
|
||||||
* @param scope
|
* @param scope
|
||||||
|
|
|
@ -17,7 +17,6 @@ package org.mitre.oauth2.service.impl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
|
@ -44,32 +43,32 @@ public class DefaultClientUserDetailsService implements UserDetailsService {
|
||||||
private ClientDetailsService clientDetailsService;
|
private ClientDetailsService clientDetailsService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(String clientId) throws UsernameNotFoundException, DataAccessException {
|
public UserDetails loadUserByUsername(String clientId) throws UsernameNotFoundException, DataAccessException {
|
||||||
|
|
||||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
|
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
|
||||||
|
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
|
|
||||||
String password = client.getClientSecret();
|
String password = client.getClientSecret();
|
||||||
boolean enabled = true;
|
boolean enabled = true;
|
||||||
boolean accountNonExpired = true;
|
boolean accountNonExpired = true;
|
||||||
boolean credentialsNonExpired = true;
|
boolean credentialsNonExpired = true;
|
||||||
boolean accountNonLocked = true;
|
boolean accountNonLocked = true;
|
||||||
Collection<GrantedAuthority> authorities = client.getAuthorities();
|
Collection<GrantedAuthority> authorities = client.getAuthorities();
|
||||||
if (authorities == null || authorities.isEmpty()) {
|
if (authorities == null || authorities.isEmpty()) {
|
||||||
// automatically inject ROLE_CLIENT if none exists ...
|
// automatically inject ROLE_CLIENT if none exists ...
|
||||||
// TODO: this should probably happen on the client service side instead to keep it in the real data model
|
// TODO: this should probably happen on the client service side instead to keep it in the real data model
|
||||||
authorities = new ArrayList<GrantedAuthority>();
|
authorities = new ArrayList<GrantedAuthority>();
|
||||||
GrantedAuthority roleClient = new SimpleGrantedAuthority("ROLE_CLIENT");
|
GrantedAuthority roleClient = new SimpleGrantedAuthority("ROLE_CLIENT");
|
||||||
authorities.add(roleClient);
|
authorities.add(roleClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new User(clientId, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
return new User(clientId, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
||||||
} else {
|
} else {
|
||||||
throw new UsernameNotFoundException("Client not found: " + clientId);
|
throw new UsernameNotFoundException("Client not found: " + clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientDetailsService getClientDetailsService() {
|
public ClientDetailsService getClientDetailsService() {
|
||||||
return clientDetailsService;
|
return clientDetailsService;
|
||||||
|
@ -78,5 +77,5 @@ public class DefaultClientUserDetailsService implements UserDetailsService {
|
||||||
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
|
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
|
||||||
this.clientDetailsService = clientDetailsService;
|
this.clientDetailsService = clientDetailsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ import com.google.gson.reflect.TypeToken;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ClientDetailsEntityJsonProcessor {
|
public class ClientDetailsEntityJsonProcessor {
|
||||||
|
|
||||||
private static Gson gson = new Gson();
|
private static Gson gson = new Gson();
|
||||||
private static JsonParser parser = new JsonParser();
|
private static JsonParser parser = new JsonParser();
|
||||||
|
|
||||||
|
@ -43,16 +43,16 @@ public class ClientDetailsEntityJsonProcessor {
|
||||||
public static ClientDetailsEntity parse(String jsonString) {
|
public static ClientDetailsEntity parse(String jsonString) {
|
||||||
JsonElement jsonEl = parser.parse(jsonString);
|
JsonElement jsonEl = parser.parse(jsonString);
|
||||||
if (jsonEl.isJsonObject()) {
|
if (jsonEl.isJsonObject()) {
|
||||||
|
|
||||||
JsonObject o = jsonEl.getAsJsonObject();
|
JsonObject o = jsonEl.getAsJsonObject();
|
||||||
ClientDetailsEntity c = new ClientDetailsEntity();
|
ClientDetailsEntity c = new ClientDetailsEntity();
|
||||||
|
|
||||||
// TODO: make these field names into constants
|
// TODO: make these field names into constants
|
||||||
|
|
||||||
// these two fields should only be sent in the update request, and MUST match existing values
|
// these two fields should only be sent in the update request, and MUST match existing values
|
||||||
c.setClientId(getAsString(o, "client_id"));
|
c.setClientId(getAsString(o, "client_id"));
|
||||||
c.setClientSecret(getAsString(o, "client_secret"));
|
c.setClientSecret(getAsString(o, "client_secret"));
|
||||||
|
|
||||||
// OAuth DynReg
|
// OAuth DynReg
|
||||||
c.setRedirectUris(getAsStringSet(o, "redirect_uris"));
|
c.setRedirectUris(getAsStringSet(o, "redirect_uris"));
|
||||||
c.setClientName(getAsString(o, "client_name"));
|
c.setClientName(getAsString(o, "client_name"));
|
||||||
|
@ -60,66 +60,66 @@ public class ClientDetailsEntityJsonProcessor {
|
||||||
c.setLogoUri(getAsString(o, "logo_uri"));
|
c.setLogoUri(getAsString(o, "logo_uri"));
|
||||||
c.setContacts(getAsStringSet(o, "contacts"));
|
c.setContacts(getAsStringSet(o, "contacts"));
|
||||||
c.setTosUri(getAsString(o, "tos_uri"));
|
c.setTosUri(getAsString(o, "tos_uri"));
|
||||||
|
|
||||||
String authMethod = getAsString(o, "token_endpoint_auth_method");
|
String authMethod = getAsString(o, "token_endpoint_auth_method");
|
||||||
if (authMethod != null) {
|
if (authMethod != null) {
|
||||||
c.setTokenEndpointAuthMethod(AuthMethod.getByValue(authMethod));
|
c.setTokenEndpointAuthMethod(AuthMethod.getByValue(authMethod));
|
||||||
}
|
}
|
||||||
|
|
||||||
// scope is a space-separated string
|
// scope is a space-separated string
|
||||||
String scope = getAsString(o, "scope");
|
String scope = getAsString(o, "scope");
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
c.setScope(Sets.newHashSet(Splitter.on(" ").split(scope)));
|
c.setScope(Sets.newHashSet(Splitter.on(" ").split(scope)));
|
||||||
}
|
}
|
||||||
|
|
||||||
c.setGrantTypes(getAsStringSet(o, "grant_types"));
|
c.setGrantTypes(getAsStringSet(o, "grant_types"));
|
||||||
c.setPolicyUri(getAsString(o, "policy_uri"));
|
c.setPolicyUri(getAsString(o, "policy_uri"));
|
||||||
c.setJwksUri(getAsString(o, "jwks_uri"));
|
c.setJwksUri(getAsString(o, "jwks_uri"));
|
||||||
|
|
||||||
|
|
||||||
// OIDC Additions
|
// OIDC Additions
|
||||||
String appType = getAsString(o, "application_type");
|
String appType = getAsString(o, "application_type");
|
||||||
if (appType != null) {
|
if (appType != null) {
|
||||||
c.setApplicationType(AppType.getByValue(appType));
|
c.setApplicationType(AppType.getByValue(appType));
|
||||||
}
|
}
|
||||||
|
|
||||||
c.setSectorIdentifierUri(getAsString(o, "sector_identifier_uri"));
|
c.setSectorIdentifierUri(getAsString(o, "sector_identifier_uri"));
|
||||||
|
|
||||||
String subjectType = getAsString(o, "subject_type");
|
String subjectType = getAsString(o, "subject_type");
|
||||||
if (subjectType != null) {
|
if (subjectType != null) {
|
||||||
c.setSubjectType(SubjectType.getByValue(subjectType));
|
c.setSubjectType(SubjectType.getByValue(subjectType));
|
||||||
}
|
}
|
||||||
|
|
||||||
c.setRequestObjectSigningAlg(getAsJwsAlgorithm(o, "request_object_signing_alg"));
|
c.setRequestObjectSigningAlg(getAsJwsAlgorithm(o, "request_object_signing_alg"));
|
||||||
|
|
||||||
c.setUserInfoSignedResponseAlg(getAsJwsAlgorithm(o, "userinfo_signed_response_alg"));
|
c.setUserInfoSignedResponseAlg(getAsJwsAlgorithm(o, "userinfo_signed_response_alg"));
|
||||||
c.setUserInfoEncryptedResponseAlg(getAsJweAlgorithm(o, "userinfo_encrypted_response_alg"));
|
c.setUserInfoEncryptedResponseAlg(getAsJweAlgorithm(o, "userinfo_encrypted_response_alg"));
|
||||||
c.setUserInfoEncryptedResponseEnc(getAsJweEncryptionMethod(o, "userinfo_encrypted_response_enc"));
|
c.setUserInfoEncryptedResponseEnc(getAsJweEncryptionMethod(o, "userinfo_encrypted_response_enc"));
|
||||||
|
|
||||||
c.setIdTokenSignedResponseAlg(getAsJwsAlgorithm(o, "id_token_signed_response_alg"));
|
c.setIdTokenSignedResponseAlg(getAsJwsAlgorithm(o, "id_token_signed_response_alg"));
|
||||||
c.setIdTokenEncryptedResponseAlg(getAsJweAlgorithm(o, "id_token_encrypted_response_alg"));
|
c.setIdTokenEncryptedResponseAlg(getAsJweAlgorithm(o, "id_token_encrypted_response_alg"));
|
||||||
c.setIdTokenEncryptedResponseEnc(getAsJweEncryptionMethod(o, "id_token_encrypted_response_enc"));
|
c.setIdTokenEncryptedResponseEnc(getAsJweEncryptionMethod(o, "id_token_encrypted_response_enc"));
|
||||||
|
|
||||||
if (o.has("default_max_age")) {
|
if (o.has("default_max_age")) {
|
||||||
if (o.get("default_max_age").isJsonPrimitive()) {
|
if (o.get("default_max_age").isJsonPrimitive()) {
|
||||||
c.setDefaultMaxAge(o.get("default_max_age").getAsInt());
|
c.setDefaultMaxAge(o.get("default_max_age").getAsInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o.has("require_auth_time")) {
|
if (o.has("require_auth_time")) {
|
||||||
if (o.get("require_auth_time").isJsonPrimitive()) {
|
if (o.get("require_auth_time").isJsonPrimitive()) {
|
||||||
c.setRequireAuthTime(o.get("require_auth_time").getAsBoolean());
|
c.setRequireAuthTime(o.get("require_auth_time").getAsBoolean());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.setDefaultACRvalues(getAsStringSet(o, "default_acr_values"));
|
c.setDefaultACRvalues(getAsStringSet(o, "default_acr_values"));
|
||||||
c.setInitiateLoginUri(getAsString(o, "initiate_login_uri"));
|
c.setInitiateLoginUri(getAsString(o, "initiate_login_uri"));
|
||||||
c.setPostLogoutRedirectUri(getAsString(o, "post_logout_redirect_uri"));
|
c.setPostLogoutRedirectUri(getAsString(o, "post_logout_redirect_uri"));
|
||||||
c.setRequestUris(getAsStringSet(o, "request_uris"));
|
c.setRequestUris(getAsStringSet(o, "request_uris"));
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,28 +134,28 @@ public class ClientDetailsEntityJsonProcessor {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static JsonObject serialize(ClientDetailsEntity c, OAuth2AccessTokenEntity token, String registrationUri) {
|
public static JsonObject serialize(ClientDetailsEntity c, OAuth2AccessTokenEntity token, String registrationUri) {
|
||||||
JsonObject o = new JsonObject();
|
JsonObject o = new JsonObject();
|
||||||
|
|
||||||
o.addProperty("client_id", c.getClientId());
|
o.addProperty("client_id", c.getClientId());
|
||||||
if (c.getClientSecret() != null) {
|
if (c.getClientSecret() != null) {
|
||||||
o.addProperty("client_secret", c.getClientSecret());
|
o.addProperty("client_secret", c.getClientSecret());
|
||||||
o.addProperty("expires_at", 0); // TODO: do we want to let secrets expire?
|
o.addProperty("expires_at", 0); // TODO: do we want to let secrets expire?
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c.getCreatedAt() != null) {
|
if (c.getCreatedAt() != null) {
|
||||||
o.addProperty("issued_at", c.getCreatedAt().getTime());
|
o.addProperty("issued_at", c.getCreatedAt().getTime());
|
||||||
}
|
}
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
o.addProperty("registration_access_token", token.getValue());
|
o.addProperty("registration_access_token", token.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (registrationUri != null) {
|
if (registrationUri != null) {
|
||||||
o.addProperty("registration_client_uri", registrationUri);
|
o.addProperty("registration_client_uri", registrationUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// add in all other client properties
|
// add in all other client properties
|
||||||
|
|
||||||
// OAuth DynReg
|
// OAuth DynReg
|
||||||
o.add("redirect_uris", getAsArray(c.getRedirectUris()));
|
o.add("redirect_uris", getAsArray(c.getRedirectUris()));
|
||||||
o.addProperty("client_name", c.getClientName());
|
o.addProperty("client_name", c.getClientName());
|
||||||
|
@ -168,7 +168,7 @@ public class ClientDetailsEntityJsonProcessor {
|
||||||
o.add("grant_types", getAsArray(c.getGrantTypes()));
|
o.add("grant_types", getAsArray(c.getGrantTypes()));
|
||||||
o.addProperty("policy_uri", c.getPolicyUri());
|
o.addProperty("policy_uri", c.getPolicyUri());
|
||||||
o.addProperty("jwks_uri", c.getJwksUri());
|
o.addProperty("jwks_uri", c.getJwksUri());
|
||||||
|
|
||||||
// OIDC Registration
|
// OIDC Registration
|
||||||
o.addProperty("application_type", c.getApplicationType() != null ? c.getApplicationType().getValue() : null);
|
o.addProperty("application_type", c.getApplicationType() != null ? c.getApplicationType().getValue() : null);
|
||||||
o.addProperty("sector_identifier_uri", c.getSectorIdentifierUri());
|
o.addProperty("sector_identifier_uri", c.getSectorIdentifierUri());
|
||||||
|
@ -186,7 +186,7 @@ public class ClientDetailsEntityJsonProcessor {
|
||||||
o.addProperty("initiate_login_uri", c.getInitiateLoginUri());
|
o.addProperty("initiate_login_uri", c.getInitiateLoginUri());
|
||||||
o.addProperty("post_logout_redirect_uri", c.getPostLogoutRedirectUri());
|
o.addProperty("post_logout_redirect_uri", c.getPostLogoutRedirectUri());
|
||||||
o.add("request_uris", getAsArray(c.getRequestUris()));
|
o.add("request_uris", getAsArray(c.getRequestUris()));
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,7 +20,7 @@ package org.mitre.openid.connect.config;
|
||||||
/**
|
/**
|
||||||
* Bean to hold configuration information that must be injected into various parts
|
* Bean to hold configuration information that must be injected into various parts
|
||||||
* of our application. Set all of the properties here, and autowire a reference
|
* of our application. Set all of the properties here, and autowire a reference
|
||||||
* to this bean if you need access to any configuration properties.
|
* to this bean if you need access to any configuration properties.
|
||||||
*
|
*
|
||||||
* @author AANGANES
|
* @author AANGANES
|
||||||
*
|
*
|
||||||
|
@ -28,22 +28,22 @@ package org.mitre.openid.connect.config;
|
||||||
public class ConfigurationPropertiesBean {
|
public class ConfigurationPropertiesBean {
|
||||||
|
|
||||||
private String issuer;
|
private String issuer;
|
||||||
|
|
||||||
private String topbarTitle;
|
private String topbarTitle;
|
||||||
|
|
||||||
private String logoImageUrl;
|
private String logoImageUrl;
|
||||||
|
|
||||||
public ConfigurationPropertiesBean() {
|
public ConfigurationPropertiesBean() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the issuer baseUrl
|
* @return the issuer baseUrl
|
||||||
*/
|
*/
|
||||||
public String getIssuer() {
|
public String getIssuer() {
|
||||||
return issuer;
|
return issuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param iss the issuer to set
|
* @param iss the issuer to set
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -29,13 +29,13 @@ public class ServerConfiguration {
|
||||||
private String authorizationEndpointUri;
|
private String authorizationEndpointUri;
|
||||||
|
|
||||||
private String tokenEndpointUri;
|
private String tokenEndpointUri;
|
||||||
|
|
||||||
private String registrationEndpointUri;
|
private String registrationEndpointUri;
|
||||||
|
|
||||||
private String issuer;
|
private String issuer;
|
||||||
|
|
||||||
private String jwksUri;
|
private String jwksUri;
|
||||||
|
|
||||||
private String userInfoUri;
|
private String userInfoUri;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -125,78 +125,78 @@ public class ServerConfiguration {
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Object#hashCode()
|
* @see java.lang.Object#hashCode()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + ((authorizationEndpointUri == null) ? 0 : authorizationEndpointUri.hashCode());
|
result = prime * result + ((authorizationEndpointUri == null) ? 0 : authorizationEndpointUri.hashCode());
|
||||||
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
|
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
|
||||||
result = prime * result + ((jwksUri == null) ? 0 : jwksUri.hashCode());
|
result = prime * result + ((jwksUri == null) ? 0 : jwksUri.hashCode());
|
||||||
result = prime * result + ((registrationEndpointUri == null) ? 0 : registrationEndpointUri.hashCode());
|
result = prime * result + ((registrationEndpointUri == null) ? 0 : registrationEndpointUri.hashCode());
|
||||||
result = prime * result + ((tokenEndpointUri == null) ? 0 : tokenEndpointUri.hashCode());
|
result = prime * result + ((tokenEndpointUri == null) ? 0 : tokenEndpointUri.hashCode());
|
||||||
result = prime * result + ((userInfoUri == null) ? 0 : userInfoUri.hashCode());
|
result = prime * result + ((userInfoUri == null) ? 0 : userInfoUri.hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Object#equals(java.lang.Object)
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (getClass() != obj.getClass()) {
|
if (getClass() != obj.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ServerConfiguration other = (ServerConfiguration) obj;
|
ServerConfiguration other = (ServerConfiguration) obj;
|
||||||
if (authorizationEndpointUri == null) {
|
if (authorizationEndpointUri == null) {
|
||||||
if (other.authorizationEndpointUri != null) {
|
if (other.authorizationEndpointUri != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!authorizationEndpointUri.equals(other.authorizationEndpointUri)) {
|
} else if (!authorizationEndpointUri.equals(other.authorizationEndpointUri)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (issuer == null) {
|
if (issuer == null) {
|
||||||
if (other.issuer != null) {
|
if (other.issuer != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!issuer.equals(other.issuer)) {
|
} else if (!issuer.equals(other.issuer)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (jwksUri == null) {
|
if (jwksUri == null) {
|
||||||
if (other.jwksUri != null) {
|
if (other.jwksUri != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!jwksUri.equals(other.jwksUri)) {
|
} else if (!jwksUri.equals(other.jwksUri)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (registrationEndpointUri == null) {
|
if (registrationEndpointUri == null) {
|
||||||
if (other.registrationEndpointUri != null) {
|
if (other.registrationEndpointUri != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!registrationEndpointUri.equals(other.registrationEndpointUri)) {
|
} else if (!registrationEndpointUri.equals(other.registrationEndpointUri)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (tokenEndpointUri == null) {
|
if (tokenEndpointUri == null) {
|
||||||
if (other.tokenEndpointUri != null) {
|
if (other.tokenEndpointUri != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!tokenEndpointUri.equals(other.tokenEndpointUri)) {
|
} else if (!tokenEndpointUri.equals(other.tokenEndpointUri)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (userInfoUri == null) {
|
if (userInfoUri == null) {
|
||||||
if (other.userInfoUri != null) {
|
if (other.userInfoUri != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!userInfoUri.equals(other.userInfoUri)) {
|
} else if (!userInfoUri.equals(other.userInfoUri)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -27,7 +27,7 @@ import javax.persistence.Table;
|
||||||
@Table(name="address")
|
@Table(name="address")
|
||||||
public class Address {
|
public class Address {
|
||||||
|
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String formatted;
|
private String formatted;
|
||||||
private String streetAddress;
|
private String streetAddress;
|
||||||
|
@ -35,14 +35,14 @@ public class Address {
|
||||||
private String region;
|
private String region;
|
||||||
private String postalCode;
|
private String postalCode;
|
||||||
private String country;
|
private String country;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Empty constructor
|
* Empty constructor
|
||||||
*/
|
*/
|
||||||
public Address() {
|
public Address() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the formatted address string
|
* @return the formatted address string
|
||||||
*/
|
*/
|
||||||
|
@ -125,19 +125,19 @@ public class Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param id the id to set
|
* @param id the id to set
|
||||||
*/
|
*/
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,164 +45,164 @@ import javax.persistence.Transient;
|
||||||
})
|
})
|
||||||
public class ApprovedSite {
|
public class ApprovedSite {
|
||||||
|
|
||||||
// unique id
|
// unique id
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
// which user made the approval
|
// which user made the approval
|
||||||
private String userId;
|
private String userId;
|
||||||
|
|
||||||
// which OAuth2 client is this tied to
|
// which OAuth2 client is this tied to
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
|
||||||
// when was this first approved?
|
// when was this first approved?
|
||||||
private Date creationDate;
|
private Date creationDate;
|
||||||
|
|
||||||
// when was this last accessed?
|
// when was this last accessed?
|
||||||
private Date accessDate;
|
private Date accessDate;
|
||||||
|
|
||||||
// if this is a time-limited access, when does it run out?
|
// if this is a time-limited access, when does it run out?
|
||||||
private Date timeoutDate;
|
private Date timeoutDate;
|
||||||
|
|
||||||
// what scopes have been allowed
|
// what scopes have been allowed
|
||||||
// this should include all information for what data to access
|
// this should include all information for what data to access
|
||||||
private Set<String> allowedScopes;
|
private Set<String> allowedScopes;
|
||||||
|
|
||||||
// If this AP is a WS, link to the WS
|
// If this AP is a WS, link to the WS
|
||||||
private WhitelistedSite whitelistedSite;
|
private WhitelistedSite whitelistedSite;
|
||||||
|
|
||||||
// TODO: should we store the OAuth2 tokens and IdTokens here?
|
// TODO: should we store the OAuth2 tokens and IdTokens here?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Empty constructor
|
* Empty constructor
|
||||||
*/
|
*/
|
||||||
public ApprovedSite() {
|
public ApprovedSite() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param id the id to set
|
* @param id the id to set
|
||||||
*/
|
*/
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the userInfo
|
* @return the userInfo
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="user_id")
|
@Column(name="user_id")
|
||||||
public String getUserId() {
|
public String getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param userInfo the userInfo to set
|
* @param userInfo the userInfo to set
|
||||||
*/
|
*/
|
||||||
public void setUserId(String userId) {
|
public void setUserId(String userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the clientId
|
* @return the clientId
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="client_id")
|
@Column(name="client_id")
|
||||||
public String getClientId() {
|
public String getClientId() {
|
||||||
return clientId;
|
return clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param clientId the clientId to set
|
* @param clientId the clientId to set
|
||||||
*/
|
*/
|
||||||
public void setClientId(String clientId) {
|
public void setClientId(String clientId) {
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the creationDate
|
* @return the creationDate
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||||
@Column(name="creation_date")
|
@Column(name="creation_date")
|
||||||
public Date getCreationDate() {
|
public Date getCreationDate() {
|
||||||
return creationDate;
|
return creationDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param creationDate the creationDate to set
|
* @param creationDate the creationDate to set
|
||||||
*/
|
*/
|
||||||
public void setCreationDate(Date creationDate) {
|
public void setCreationDate(Date creationDate) {
|
||||||
this.creationDate = creationDate;
|
this.creationDate = creationDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the accessDate
|
* @return the accessDate
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||||
@Column(name="access_date")
|
@Column(name="access_date")
|
||||||
public Date getAccessDate() {
|
public Date getAccessDate() {
|
||||||
return accessDate;
|
return accessDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param accessDate the accessDate to set
|
* @param accessDate the accessDate to set
|
||||||
*/
|
*/
|
||||||
public void setAccessDate(Date accessDate) {
|
public void setAccessDate(Date accessDate) {
|
||||||
this.accessDate = accessDate;
|
this.accessDate = accessDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the allowedScopes
|
* @return the allowedScopes
|
||||||
*/
|
*/
|
||||||
@ElementCollection(fetch = FetchType.EAGER)
|
@ElementCollection(fetch = FetchType.EAGER)
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="approved_site_scope",
|
name="approved_site_scope",
|
||||||
joinColumns=@JoinColumn(name="owner_id")
|
joinColumns=@JoinColumn(name="owner_id")
|
||||||
)
|
)
|
||||||
@Column(name="scope")
|
@Column(name="scope")
|
||||||
public Set<String> getAllowedScopes() {
|
public Set<String> getAllowedScopes() {
|
||||||
return allowedScopes;
|
return allowedScopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param allowedScopes the allowedScopes to set
|
* @param allowedScopes the allowedScopes to set
|
||||||
*/
|
*/
|
||||||
public void setAllowedScopes(Set<String> allowedScopes) {
|
public void setAllowedScopes(Set<String> allowedScopes) {
|
||||||
this.allowedScopes = allowedScopes;
|
this.allowedScopes = allowedScopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the timeoutDate
|
* @return the timeoutDate
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||||
@Column(name="timeout_date")
|
@Column(name="timeout_date")
|
||||||
public Date getTimeoutDate() {
|
public Date getTimeoutDate() {
|
||||||
return timeoutDate;
|
return timeoutDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param timeoutDate the timeoutDate to set
|
* @param timeoutDate the timeoutDate to set
|
||||||
*/
|
*/
|
||||||
public void setTimeoutDate(Date timeoutDate) {
|
public void setTimeoutDate(Date timeoutDate) {
|
||||||
this.timeoutDate = timeoutDate;
|
this.timeoutDate = timeoutDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this AP entry correspond to a WS?
|
* Does this AP entry correspond to a WS?
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
public Boolean getIsWhitelisted() {
|
public Boolean getIsWhitelisted() {
|
||||||
return (whitelistedSite != null);
|
return (whitelistedSite != null);
|
||||||
}
|
}
|
||||||
|
@ -220,10 +220,10 @@ public class ApprovedSite {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Has this approval expired?
|
* Has this approval expired?
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Transient
|
@Transient
|
||||||
public boolean isExpired() {
|
public boolean isExpired() {
|
||||||
if (getTimeoutDate() != null) {
|
if (getTimeoutDate() != null) {
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
if (now.after(getTimeoutDate())) {
|
if (now.after(getTimeoutDate())) {
|
||||||
|
@ -234,6 +234,6 @@ public class ApprovedSite {
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,41 +24,41 @@ import javax.persistence.Table;
|
||||||
})
|
})
|
||||||
public class BlacklistedSite {
|
public class BlacklistedSite {
|
||||||
|
|
||||||
// unique id
|
// unique id
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
// URI pattern to black list
|
// URI pattern to black list
|
||||||
private String uri;
|
private String uri;
|
||||||
|
|
||||||
public BlacklistedSite() {
|
public BlacklistedSite() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param id the id to set
|
* @param id the id to set
|
||||||
*/
|
*/
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="uri")
|
@Column(name="uri")
|
||||||
public String getUri() {
|
public String getUri() {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUri(String uri) {
|
||||||
|
this.uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
public void setUri(String uri) {
|
|
||||||
this.uri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,21 +33,21 @@ import com.google.gson.JsonObject;
|
||||||
@Table(name="user_info")
|
@Table(name="user_info")
|
||||||
@NamedQueries({
|
@NamedQueries({
|
||||||
@NamedQuery(name="DefaultUserInfo.getAll", query = "select u from DefaultUserInfo u"),
|
@NamedQuery(name="DefaultUserInfo.getAll", query = "select u from DefaultUserInfo u"),
|
||||||
@NamedQuery(name="DefaultUserInfo.getByUsername", query = "select u from DefaultUserInfo u WHERE u.preferredUsername = :username"),
|
@NamedQuery(name="DefaultUserInfo.getByUsername", query = "select u from DefaultUserInfo u WHERE u.preferredUsername = :username"),
|
||||||
@NamedQuery(name="DefaultUserInfo.getBySubject", query = "select u from DefaultUserInfo u WHERE u.sub = :sub")
|
@NamedQuery(name="DefaultUserInfo.getBySubject", query = "select u from DefaultUserInfo u WHERE u.sub = :sub")
|
||||||
})
|
})
|
||||||
public class DefaultUserInfo implements UserInfo {
|
public class DefaultUserInfo implements UserInfo {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String sub;
|
private String sub;
|
||||||
private String preferredUsername;
|
private String preferredUsername;
|
||||||
private String name;
|
private String name;
|
||||||
private String givenName;
|
private String givenName;
|
||||||
private String familyName;
|
private String familyName;
|
||||||
private String middleName;
|
private String middleName;
|
||||||
private String nickname;
|
private String nickname;
|
||||||
private String profile;
|
private String profile;
|
||||||
private String picture;
|
private String picture;
|
||||||
private String website;
|
private String website;
|
||||||
private String email;
|
private String email;
|
||||||
private Boolean emailVerified;
|
private Boolean emailVerified;
|
||||||
|
@ -58,8 +58,8 @@ public class DefaultUserInfo implements UserInfo {
|
||||||
private Address address;
|
private Address address;
|
||||||
private String updatedTime;
|
private String updatedTime;
|
||||||
private String birthdate;
|
private String birthdate;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
|
@ -356,21 +356,23 @@ public class DefaultUserInfo implements UserInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the birthdate
|
* @return the birthdate
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
@Basic
|
@Basic
|
||||||
@Column(name="birthdate")
|
@Column(name="birthdate")
|
||||||
public String getBirthdate() {
|
public String getBirthdate() {
|
||||||
return birthdate;
|
return birthdate;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param birthdate the birthdate to set
|
* @param birthdate the birthdate to set
|
||||||
*/
|
*/
|
||||||
public void setBirthdate(String birthdate) {
|
@Override
|
||||||
this.birthdate = birthdate;
|
public void setBirthdate(String birthdate) {
|
||||||
}
|
this.birthdate = birthdate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a JsonObject into a UserInfo.
|
* Parse a JsonObject into a UserInfo.
|
||||||
* @param o
|
* @param o
|
||||||
* @return
|
* @return
|
||||||
|
@ -379,7 +381,7 @@ public class DefaultUserInfo implements UserInfo {
|
||||||
DefaultUserInfo ui = new DefaultUserInfo();
|
DefaultUserInfo ui = new DefaultUserInfo();
|
||||||
|
|
||||||
ui.setSub(obj.has("sub") ? obj.get("sub").getAsString() : null);
|
ui.setSub(obj.has("sub") ? obj.get("sub").getAsString() : null);
|
||||||
|
|
||||||
ui.setName(obj.has("name") ? obj.get("name").getAsString() : null);
|
ui.setName(obj.has("name") ? obj.get("name").getAsString() : null);
|
||||||
ui.setPreferredUsername(obj.has("preferred_username") ? obj.get("preferred_username").getAsString() : null);
|
ui.setPreferredUsername(obj.has("preferred_username") ? obj.get("preferred_username").getAsString() : null);
|
||||||
ui.setGivenName(obj.has("given_name") ? obj.get("given_name").getAsString() : null);
|
ui.setGivenName(obj.has("given_name") ? obj.get("given_name").getAsString() : null);
|
||||||
|
@ -394,29 +396,29 @@ public class DefaultUserInfo implements UserInfo {
|
||||||
ui.setLocale(obj.has("locale") ? obj.get("locale").getAsString() : null);
|
ui.setLocale(obj.has("locale") ? obj.get("locale").getAsString() : null);
|
||||||
ui.setUpdatedTime(obj.has("updated_time") ? obj.get("updated_time").getAsString() : null);
|
ui.setUpdatedTime(obj.has("updated_time") ? obj.get("updated_time").getAsString() : null);
|
||||||
ui.setBirthdate(obj.has("birthdate") ? obj.get("birthdate").getAsString() : null);
|
ui.setBirthdate(obj.has("birthdate") ? obj.get("birthdate").getAsString() : null);
|
||||||
|
|
||||||
ui.setEmail(obj.has("email") ? obj.get("email").getAsString() : null);
|
ui.setEmail(obj.has("email") ? obj.get("email").getAsString() : null);
|
||||||
ui.setEmailVerified(obj.has("email_verified") ? obj.get("email_verified").getAsBoolean() : null);
|
ui.setEmailVerified(obj.has("email_verified") ? obj.get("email_verified").getAsBoolean() : null);
|
||||||
|
|
||||||
ui.setPhoneNumber(obj.has("phone_number") ? obj.get("phone_number").getAsString() : null);
|
ui.setPhoneNumber(obj.has("phone_number") ? obj.get("phone_number").getAsString() : null);
|
||||||
|
|
||||||
|
|
||||||
if (obj.has("address") && obj.get("address").isJsonObject()) {
|
if (obj.has("address") && obj.get("address").isJsonObject()) {
|
||||||
JsonObject addr = obj.get("address").getAsJsonObject();
|
JsonObject addr = obj.get("address").getAsJsonObject();
|
||||||
ui.setAddress(new Address());
|
ui.setAddress(new Address());
|
||||||
|
|
||||||
ui.getAddress().setFormatted(addr.has("formatted") ? addr.get("formatted").getAsString() : null);
|
ui.getAddress().setFormatted(addr.has("formatted") ? addr.get("formatted").getAsString() : null);
|
||||||
ui.getAddress().setStreetAddress(addr.has("street_address") ? addr.get("street_address").getAsString() : null);
|
ui.getAddress().setStreetAddress(addr.has("street_address") ? addr.get("street_address").getAsString() : null);
|
||||||
ui.getAddress().setLocality(addr.has("locality") ? addr.get("locality").getAsString() : null);
|
ui.getAddress().setLocality(addr.has("locality") ? addr.get("locality").getAsString() : null);
|
||||||
ui.getAddress().setRegion(addr.has("region") ? addr.get("region").getAsString() : null);
|
ui.getAddress().setRegion(addr.has("region") ? addr.get("region").getAsString() : null);
|
||||||
ui.getAddress().setPostalCode(addr.has("postal_code") ? addr.get("postal_code").getAsString() : null);
|
ui.getAddress().setPostalCode(addr.has("postal_code") ? addr.get("postal_code").getAsString() : null);
|
||||||
ui.getAddress().setCountry(addr.has("country") ? addr.get("country").getAsString() : null);
|
ui.getAddress().setCountry(addr.has("country") ? addr.get("country").getAsString() : null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return ui;
|
return ui;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,50 +37,50 @@ import javax.persistence.Temporal;
|
||||||
public class Event {
|
public class Event {
|
||||||
|
|
||||||
public static enum EventType { LOGIN, AUTHORIZATION, ACCESS }
|
public static enum EventType { LOGIN, AUTHORIZATION, ACCESS }
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private EventType type;
|
private EventType type;
|
||||||
private Date timestamp;
|
private Date timestamp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param id the id to set
|
* @param id the id to set
|
||||||
*/
|
*/
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @return the type
|
* @return the type
|
||||||
*/
|
*/
|
||||||
public EventType getType() {
|
public EventType getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param type the type to set
|
* @param type the type to set
|
||||||
*/
|
*/
|
||||||
public void setType(EventType type) {
|
public void setType(EventType type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @return the timestamp
|
* @return the timestamp
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||||
public Date getTimestamp() {
|
public Date getTimestamp() {
|
||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @param timestamp the timestamp to set
|
* @param timestamp the timestamp to set
|
||||||
*/
|
*/
|
||||||
public void setTimestamp(Date timestamp) {
|
public void setTimestamp(Date timestamp) {
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,16 +23,16 @@ import javax.persistence.Temporal;
|
||||||
})
|
})
|
||||||
public class Nonce {
|
public class Nonce {
|
||||||
|
|
||||||
|
|
||||||
private Long id; //the ID of this Nonce
|
private Long id; //the ID of this Nonce
|
||||||
|
|
||||||
private String value; //the value of this Nonce
|
private String value; //the value of this Nonce
|
||||||
|
|
||||||
private String clientId;//The id of the client who used this Nonce
|
private String clientId;//The id of the client who used this Nonce
|
||||||
|
|
||||||
private Date useDate; //the date this Nonce was used
|
private Date useDate; //the date this Nonce was used
|
||||||
|
|
||||||
private Date expireDate; //the date after which this Nonce should be removed from the database
|
private Date expireDate; //the date after which this Nonce should be removed from the database
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the id
|
* @return the id
|
||||||
|
@ -86,7 +86,7 @@ public class Nonce {
|
||||||
* @return the useDate
|
* @return the useDate
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||||
@Column(name="use_date")
|
@Column(name="use_date")
|
||||||
public Date getUseDate() {
|
public Date getUseDate() {
|
||||||
return useDate;
|
return useDate;
|
||||||
|
@ -103,7 +103,7 @@ public class Nonce {
|
||||||
* @return the expireDate
|
* @return the expireDate
|
||||||
*/
|
*/
|
||||||
@Basic
|
@Basic
|
||||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||||
@Column(name="expire_date")
|
@Column(name="expire_date")
|
||||||
public Date getExpireDate() {
|
public Date getExpireDate() {
|
||||||
return expireDate;
|
return expireDate;
|
||||||
|
@ -115,8 +115,8 @@ public class Nonce {
|
||||||
public void setExpireDate(Date expireDate) {
|
public void setExpireDate(Date expireDate) {
|
||||||
this.expireDate = expireDate;
|
this.expireDate = expireDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,12 @@ public interface UserInfo {
|
||||||
* @param sub the userId to set
|
* @param sub the userId to set
|
||||||
*/
|
*/
|
||||||
public abstract void setSub(String sub);
|
public abstract void setSub(String sub);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the preferred username
|
* @return the preferred username
|
||||||
*/
|
*/
|
||||||
public abstract String getPreferredUsername();
|
public abstract String getPreferredUsername();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param preferredUsername the preferredUsername to set
|
* @param preferredUsername the preferredUsername to set
|
||||||
*/
|
*/
|
||||||
|
@ -189,7 +189,7 @@ public interface UserInfo {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public abstract String getBirthdate();
|
public abstract String getBirthdate();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param birthdate
|
* @param birthdate
|
||||||
|
|
|
@ -32,7 +32,7 @@ import javax.persistence.NamedQuery;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicator that login to a site should be automatically granted
|
* Indicator that login to a site should be automatically granted
|
||||||
* without user interaction.
|
* without user interaction.
|
||||||
* @author jricher, aanganes
|
* @author jricher, aanganes
|
||||||
*
|
*
|
||||||
|
@ -40,21 +40,21 @@ import javax.persistence.Table;
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name="whitelisted_site")
|
@Table(name="whitelisted_site")
|
||||||
@NamedQueries({
|
@NamedQueries({
|
||||||
@NamedQuery(name = "WhitelistedSite.getAll", query = "select w from WhitelistedSite w"),
|
@NamedQuery(name = "WhitelistedSite.getAll", query = "select w from WhitelistedSite w"),
|
||||||
@NamedQuery(name = "WhitelistedSite.getByClientId", query = "select w from WhitelistedSite w where w.clientId = :clientId"),
|
@NamedQuery(name = "WhitelistedSite.getByClientId", query = "select w from WhitelistedSite w where w.clientId = :clientId"),
|
||||||
@NamedQuery(name = "WhitelistedSite.getByCreatoruserId", query = "select w from WhitelistedSite w where w.creatorUserId = :userId")
|
@NamedQuery(name = "WhitelistedSite.getByCreatoruserId", query = "select w from WhitelistedSite w where w.creatorUserId = :userId")
|
||||||
})
|
})
|
||||||
public class WhitelistedSite {
|
public class WhitelistedSite {
|
||||||
|
|
||||||
// unique id
|
// unique id
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
// Reference to the admin user who created this entry
|
// Reference to the admin user who created this entry
|
||||||
private String creatorUserId;
|
private String creatorUserId;
|
||||||
|
|
||||||
// which OAuth2 client is this tied to
|
// which OAuth2 client is this tied to
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
|
||||||
// what scopes be allowed by default
|
// what scopes be allowed by default
|
||||||
// this should include all information for what data to access
|
// this should include all information for what data to access
|
||||||
private Set<String> allowedScopes;
|
private Set<String> allowedScopes;
|
||||||
|
@ -63,14 +63,14 @@ public class WhitelistedSite {
|
||||||
* Empty constructor
|
* Empty constructor
|
||||||
*/
|
*/
|
||||||
public WhitelistedSite() {
|
public WhitelistedSite() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -103,9 +103,9 @@ public class WhitelistedSite {
|
||||||
*/
|
*/
|
||||||
@ElementCollection(fetch = FetchType.EAGER)
|
@ElementCollection(fetch = FetchType.EAGER)
|
||||||
@CollectionTable(
|
@CollectionTable(
|
||||||
name="whitelisted_site_scope",
|
name="whitelisted_site_scope",
|
||||||
joinColumns=@JoinColumn(name="owner_id")
|
joinColumns=@JoinColumn(name="owner_id")
|
||||||
)
|
)
|
||||||
@Column(name="scope")
|
@Column(name="scope")
|
||||||
public Set<String> getAllowedScopes() {
|
public Set<String> getAllowedScopes() {
|
||||||
return allowedScopes;
|
return allowedScopes;
|
||||||
|
|
|
@ -50,7 +50,7 @@ public interface ApprovedSiteRepository {
|
||||||
* @param clientId
|
* @param clientId
|
||||||
* @param userId
|
* @param userId
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Collection<ApprovedSite> getByClientIdAndUserId(String clientId, String userId);
|
public Collection<ApprovedSite> getByClientIdAndUserId(String clientId, String userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,14 +69,14 @@ public interface ApprovedSiteRepository {
|
||||||
* @return the persisted entity
|
* @return the persisted entity
|
||||||
*/
|
*/
|
||||||
public ApprovedSite save(ApprovedSite approvedSite);
|
public ApprovedSite save(ApprovedSite approvedSite);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all sites approved by this user
|
* Get all sites approved by this user
|
||||||
* @param userId
|
* @param userId
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Collection<ApprovedSite> getByUserId(String userId);
|
public Collection<ApprovedSite> getByUserId(String userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all sites associated with this client
|
* Get all sites associated with this client
|
||||||
* @param clientId
|
* @param clientId
|
||||||
|
|
|
@ -14,13 +14,13 @@ import org.mitre.openid.connect.model.BlacklistedSite;
|
||||||
public interface BlacklistedSiteRepository {
|
public interface BlacklistedSiteRepository {
|
||||||
|
|
||||||
public Collection<BlacklistedSite> getAll();
|
public Collection<BlacklistedSite> getAll();
|
||||||
|
|
||||||
public BlacklistedSite getById(Long id);
|
public BlacklistedSite getById(Long id);
|
||||||
|
|
||||||
public void remove(BlacklistedSite blacklistedSite);
|
public void remove(BlacklistedSite blacklistedSite);
|
||||||
|
|
||||||
public BlacklistedSite save(BlacklistedSite blacklistedSite);
|
public BlacklistedSite save(BlacklistedSite blacklistedSite);
|
||||||
|
|
||||||
public BlacklistedSite update(BlacklistedSite oldBlacklistedSite, BlacklistedSite blacklistedSite);
|
public BlacklistedSite update(BlacklistedSite oldBlacklistedSite, BlacklistedSite blacklistedSite);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,8 @@ public interface EventRepository {
|
||||||
* @param startChunk
|
* @param startChunk
|
||||||
* the start chuck of a list you desire
|
* the start chuck of a list you desire
|
||||||
* @param chunkSize
|
* @param chunkSize
|
||||||
* the size of the chunk you desire
|
* the size of the chunk you desire
|
||||||
*
|
*
|
||||||
* @return a Collection of Events
|
* @return a Collection of Events
|
||||||
*/
|
*/
|
||||||
public Collection<Event> getEventsDuringPeriod(Date start, Date end, int startChunk, int chunkSize);
|
public Collection<Event> getEventsDuringPeriod(Date start, Date end, int startChunk, int chunkSize);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.mitre.openid.connect.repository;
|
package org.mitre.openid.connect.repository;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.mitre.openid.connect.model.Nonce;
|
import org.mitre.openid.connect.model.Nonce;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,14 +20,14 @@ public interface NonceRepository {
|
||||||
* @return the nonce, if found
|
* @return the nonce, if found
|
||||||
*/
|
*/
|
||||||
public Nonce getById(Long id);
|
public Nonce getById(Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the given Nonce from the database
|
* Remove the given Nonce from the database
|
||||||
*
|
*
|
||||||
* @param nonce the Nonce to remove
|
* @param nonce the Nonce to remove
|
||||||
*/
|
*/
|
||||||
public void remove(Nonce nonce);
|
public void remove(Nonce nonce);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a new Nonce in the database
|
* Save a new Nonce in the database
|
||||||
*
|
*
|
||||||
|
@ -34,21 +35,21 @@ public interface NonceRepository {
|
||||||
* @return the saved Nonce
|
* @return the saved Nonce
|
||||||
*/
|
*/
|
||||||
public Nonce save(Nonce nonce);
|
public Nonce save(Nonce nonce);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all nonces stored in the database
|
* Return all nonces stored in the database
|
||||||
*
|
*
|
||||||
* @return the set of nonces
|
* @return the set of nonces
|
||||||
*/
|
*/
|
||||||
public Collection<Nonce> getAll();
|
public Collection<Nonce> getAll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all expired nonces stored in the database
|
* Return all expired nonces stored in the database
|
||||||
*
|
*
|
||||||
* @return the set of expired nonces
|
* @return the set of expired nonces
|
||||||
*/
|
*/
|
||||||
public Collection<Nonce> getExpired();
|
public Collection<Nonce> getExpired();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the set of nonces registered to the given client ID
|
* Return the set of nonces registered to the given client ID
|
||||||
*
|
*
|
||||||
|
@ -56,5 +57,5 @@ public interface NonceRepository {
|
||||||
* @return the set of nonces registered to the client
|
* @return the set of nonces registered to the client
|
||||||
*/
|
*/
|
||||||
public Collection<Nonce> getByClientId(String clientId);
|
public Collection<Nonce> getByClientId(String clientId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,24 +26,24 @@ import org.mitre.openid.connect.model.UserInfo;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface UserInfoRepository {
|
public interface UserInfoRepository {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the UserInfo for the given subject
|
* Returns the UserInfo for the given subject
|
||||||
*
|
*
|
||||||
* @param sub
|
* @param sub
|
||||||
* the subject of the UserInfo
|
* the subject of the UserInfo
|
||||||
* @return a valid UserInfo if it exists, null otherwise
|
* @return a valid UserInfo if it exists, null otherwise
|
||||||
*/
|
*/
|
||||||
public UserInfo getBySubject(String sub);
|
public UserInfo getBySubject(String sub);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Persists a UserInfo
|
* Persists a UserInfo
|
||||||
*
|
*
|
||||||
* @param user
|
* @param user
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public UserInfo save(UserInfo userInfo);
|
public UserInfo save(UserInfo userInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the given UserInfo from the repository
|
* Removes the given UserInfo from the repository
|
||||||
*
|
*
|
||||||
|
@ -64,6 +64,6 @@ public interface UserInfoRepository {
|
||||||
* @param username
|
* @param username
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public UserInfo getByUsername(String username);
|
public UserInfo getByUsername(String username);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public interface WhitelistedSiteRepository {
|
||||||
* @return a valid WhitelistedSite if it exists, null otherwise
|
* @return a valid WhitelistedSite if it exists, null otherwise
|
||||||
*/
|
*/
|
||||||
public WhitelistedSite getById(Long id);
|
public WhitelistedSite getById(Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a WhitelistedSite by its associated ClientDetails reference
|
* Find a WhitelistedSite by its associated ClientDetails reference
|
||||||
*
|
*
|
||||||
|
@ -50,7 +50,7 @@ public interface WhitelistedSiteRepository {
|
||||||
* @return the corresponding WhitelistedSite if one exists for the RP, or null
|
* @return the corresponding WhitelistedSite if one exists for the RP, or null
|
||||||
*/
|
*/
|
||||||
public WhitelistedSite getByClientId(String clientId);
|
public WhitelistedSite getByClientId(String clientId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a collection of the WhitelistedSites created by a given user
|
* Return a collection of the WhitelistedSites created by a given user
|
||||||
*
|
*
|
||||||
|
@ -77,10 +77,10 @@ public interface WhitelistedSiteRepository {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Persist changes to a whitelistedSite. The ID of oldWhitelistedSite is retained.
|
* Persist changes to a whitelistedSite. The ID of oldWhitelistedSite is retained.
|
||||||
* @param oldWhitelistedSite
|
* @param oldWhitelistedSite
|
||||||
* @param whitelistedSite
|
* @param whitelistedSite
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public WhitelistedSite update(WhitelistedSite oldWhitelistedSite, WhitelistedSite whitelistedSite);
|
public WhitelistedSite update(WhitelistedSite oldWhitelistedSite, WhitelistedSite whitelistedSite);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,17 +30,17 @@ import org.springframework.security.oauth2.provider.ClientDetails;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface ApprovedSiteService {
|
public interface ApprovedSiteService {
|
||||||
|
|
||||||
|
|
||||||
public ApprovedSite createApprovedSite(String clientId, String userId, Date timeoutDate, Set<String> allowedScopes, WhitelistedSite whitelistedSite);
|
public ApprovedSite createApprovedSite(String clientId, String userId, Date timeoutDate, Set<String> allowedScopes, WhitelistedSite whitelistedSite);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a collection of all ApprovedSites
|
* Return a collection of all ApprovedSites
|
||||||
*
|
*
|
||||||
* @return the ApprovedSite collection, or null
|
* @return the ApprovedSite collection, or null
|
||||||
*/
|
*/
|
||||||
public Collection<ApprovedSite> getAll();
|
public Collection<ApprovedSite> getAll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a collection of ApprovedSite managed by this repository matching the
|
* Return a collection of ApprovedSite managed by this repository matching the
|
||||||
* provided client ID and user ID
|
* provided client ID and user ID
|
||||||
|
@ -48,9 +48,9 @@ public interface ApprovedSiteService {
|
||||||
* @param clientId
|
* @param clientId
|
||||||
* @param userId
|
* @param userId
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Collection<ApprovedSite> getByClientIdAndUserId(String clientId, String userId);
|
public Collection<ApprovedSite> getByClientIdAndUserId(String clientId, String userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save an ApprovedSite
|
* Save an ApprovedSite
|
||||||
*
|
*
|
||||||
|
@ -82,14 +82,14 @@ public interface ApprovedSiteService {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Collection<ApprovedSite> getByUserId(String userId);
|
public Collection<ApprovedSite> getByUserId(String userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all sites associated with this client
|
* Get all sites associated with this client
|
||||||
* @param clientId
|
* @param clientId
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Collection<ApprovedSite> getByClientId(String clientId);
|
public Collection<ApprovedSite> getByClientId(String clientId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear out any approved sites for a given client.
|
* Clear out any approved sites for a given client.
|
||||||
* @param client
|
* @param client
|
||||||
|
|
|
@ -14,15 +14,15 @@ import org.mitre.openid.connect.model.BlacklistedSite;
|
||||||
public interface BlacklistedSiteService {
|
public interface BlacklistedSiteService {
|
||||||
|
|
||||||
public Collection<BlacklistedSite> getAll();
|
public Collection<BlacklistedSite> getAll();
|
||||||
|
|
||||||
public BlacklistedSite getById(Long id);
|
public BlacklistedSite getById(Long id);
|
||||||
|
|
||||||
public void remove(BlacklistedSite blacklistedSite);
|
public void remove(BlacklistedSite blacklistedSite);
|
||||||
|
|
||||||
public BlacklistedSite saveNew(BlacklistedSite blacklistedSite);
|
public BlacklistedSite saveNew(BlacklistedSite blacklistedSite);
|
||||||
|
|
||||||
public BlacklistedSite update(BlacklistedSite oldBlacklistedSite, BlacklistedSite blacklistedSite);
|
public BlacklistedSite update(BlacklistedSite oldBlacklistedSite, BlacklistedSite blacklistedSite);
|
||||||
|
|
||||||
public boolean isBlacklisted(String uri);
|
public boolean isBlacklisted(String uri);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,24 +15,24 @@ import org.mitre.openid.connect.model.Nonce;
|
||||||
public interface NonceService {
|
public interface NonceService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new nonce.
|
* Create a new nonce.
|
||||||
*
|
*
|
||||||
* @param clientId the ID of the client
|
* @param clientId the ID of the client
|
||||||
* @param value the value of the Nonce
|
* @param value the value of the Nonce
|
||||||
* @return the saved Nonce
|
* @return the saved Nonce
|
||||||
*/
|
*/
|
||||||
public Nonce create(String clientId, String value);
|
public Nonce create(String clientId, String value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether a given nonce value has been previously used and stored
|
* Check whether a given nonce value has been previously used and stored
|
||||||
* by the client.
|
* by the client.
|
||||||
*
|
*
|
||||||
* @param clientId the ID of the client
|
* @param clientId the ID of the client
|
||||||
* @param value the value of the nonce
|
* @param value the value of the nonce
|
||||||
* @return true if the nonce has already been used, false otherwise
|
* @return true if the nonce has already been used, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean alreadyUsed(String clientId, String value);
|
public boolean alreadyUsed(String clientId, String value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the nonce with the given ID
|
* Return the nonce with the given ID
|
||||||
*
|
*
|
||||||
|
@ -40,14 +40,14 @@ public interface NonceService {
|
||||||
* @return the nonce, if found
|
* @return the nonce, if found
|
||||||
*/
|
*/
|
||||||
public Nonce getById(Long id);
|
public Nonce getById(Long id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the given Nonce from the database
|
* Remove the given Nonce from the database
|
||||||
*
|
*
|
||||||
* @param nonce the Nonce to remove
|
* @param nonce the Nonce to remove
|
||||||
*/
|
*/
|
||||||
public void remove(Nonce nonce);
|
public void remove(Nonce nonce);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a new Nonce in the database
|
* Save a new Nonce in the database
|
||||||
*
|
*
|
||||||
|
@ -55,21 +55,21 @@ public interface NonceService {
|
||||||
* @return the saved Nonce
|
* @return the saved Nonce
|
||||||
*/
|
*/
|
||||||
public Nonce save(Nonce nonce);
|
public Nonce save(Nonce nonce);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all nonces stored in the database
|
* Return all nonces stored in the database
|
||||||
*
|
*
|
||||||
* @return the set of nonces
|
* @return the set of nonces
|
||||||
*/
|
*/
|
||||||
public Collection<Nonce> getAll();
|
public Collection<Nonce> getAll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all expired nonces stored in the database
|
* Return all expired nonces stored in the database
|
||||||
*
|
*
|
||||||
* @return the set of expired nonces
|
* @return the set of expired nonces
|
||||||
*/
|
*/
|
||||||
public Collection<Nonce> getExpired();
|
public Collection<Nonce> getExpired();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the set of nonces registered to the given client ID
|
* Return the set of nonces registered to the given client ID
|
||||||
*
|
*
|
||||||
|
@ -82,5 +82,5 @@ public interface NonceService {
|
||||||
* Clear expired nonces from the database
|
* Clear expired nonces from the database
|
||||||
*/
|
*/
|
||||||
void clearExpiredNonces();
|
void clearExpiredNonces();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ public interface StatsService {
|
||||||
/**
|
/**
|
||||||
* Calculate summary statistics
|
* Calculate summary statistics
|
||||||
* approvalCount: total approved sites
|
* approvalCount: total approved sites
|
||||||
* userCount: unique users
|
* userCount: unique users
|
||||||
* clientCount: unique clients
|
* clientCount: unique clients
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Map<String, Integer> calculateSummaryStats();
|
public Map<String, Integer> calculateSummaryStats();
|
||||||
|
|
|
@ -41,7 +41,7 @@ public interface UserInfoService {
|
||||||
* @return UserInfo for sub, or null
|
* @return UserInfo for sub, or null
|
||||||
*/
|
*/
|
||||||
public UserInfo getBySubject(String userId);
|
public UserInfo getBySubject(String userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the UserInfo
|
* Remove the UserInfo
|
||||||
*
|
*
|
||||||
|
|
|
@ -33,7 +33,7 @@ public interface WhitelistedSiteService {
|
||||||
* @return the WhitelistedSite collection, or null
|
* @return the WhitelistedSite collection, or null
|
||||||
*/
|
*/
|
||||||
public Collection<WhitelistedSite> getAll();
|
public Collection<WhitelistedSite> getAll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the WhitelistedSite for the given id
|
* Returns the WhitelistedSite for the given id
|
||||||
*
|
*
|
||||||
|
@ -50,7 +50,7 @@ public interface WhitelistedSiteService {
|
||||||
* @return the corresponding WhitelistedSite if one exists for the RP, or null
|
* @return the corresponding WhitelistedSite if one exists for the RP, or null
|
||||||
*/
|
*/
|
||||||
public WhitelistedSite getByClientId(String clientId);
|
public WhitelistedSite getByClientId(String clientId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a collection of the WhitelistedSites created by a given user
|
* Return a collection of the WhitelistedSites created by a given user
|
||||||
*
|
*
|
||||||
|
@ -58,7 +58,7 @@ public interface WhitelistedSiteService {
|
||||||
* @return the collection of corresponding WhitelistedSites, if any, or null
|
* @return the collection of corresponding WhitelistedSites, if any, or null
|
||||||
*/
|
*/
|
||||||
public Collection<WhitelistedSite> getByCreator(String creatorId);
|
public Collection<WhitelistedSite> getByCreator(String creatorId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the given WhitelistedSite from the repository
|
* Removes the given WhitelistedSite from the repository
|
||||||
*
|
*
|
||||||
|
@ -75,10 +75,10 @@ public interface WhitelistedSiteService {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public WhitelistedSite saveNew(WhitelistedSite whitelistedSite);
|
public WhitelistedSite saveNew(WhitelistedSite whitelistedSite);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates an existing whitelisted site
|
* Updates an existing whitelisted site
|
||||||
*/
|
*/
|
||||||
public WhitelistedSite update(WhitelistedSite oldWhitelistedSite, WhitelistedSite whitelistedSite);
|
public WhitelistedSite update(WhitelistedSite oldWhitelistedSite, WhitelistedSite whitelistedSite);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,27 +42,27 @@ import com.nimbusds.jose.jwk.JWKSet;
|
||||||
public class JwkKeyListView extends AbstractView {
|
public class JwkKeyListView extends AbstractView {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(JwkKeyListView.class);
|
private static Logger logger = LoggerFactory.getLogger(JwkKeyListView.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
|
||||||
response.setContentType("application/json");
|
response.setContentType("application/json");
|
||||||
|
|
||||||
|
|
||||||
//BiMap<String, PublicKey> keyMap = (BiMap<String, PublicKey>) model.get("keys");
|
//BiMap<String, PublicKey> keyMap = (BiMap<String, PublicKey>) model.get("keys");
|
||||||
Map<String, JWK> keys = (Map<String, JWK>) model.get("keys");
|
Map<String, JWK> keys = (Map<String, JWK>) model.get("keys");
|
||||||
|
|
||||||
JWKSet jwkSet = new JWKSet(new ArrayList<JWK>(keys.values()));
|
JWKSet jwkSet = new JWKSet(new ArrayList<JWK>(keys.values()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Writer out = response.getWriter();
|
Writer out = response.getWriter();
|
||||||
out.write(jwkSet.toString());
|
out.write(jwkSet.toString());
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
||||||
logger.error("IOException in JwkKeyListView.java: ", e);
|
logger.error("IOException in JwkKeyListView.java: ", e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,26 +27,26 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||||
* Time: 2:13 PM
|
* Time: 2:13 PM
|
||||||
*/
|
*/
|
||||||
public class JpaUtil {
|
public class JpaUtil {
|
||||||
public static <T> T getSingleResult(List<T> list) {
|
public static <T> T getSingleResult(List<T> list) {
|
||||||
switch(list.size()) {
|
switch(list.size()) {
|
||||||
case 0:
|
case 0:
|
||||||
return null;
|
return null;
|
||||||
case 1:
|
case 1:
|
||||||
return list.get(0);
|
return list.get(0);
|
||||||
default:
|
default:
|
||||||
throw new IncorrectResultSizeDataAccessException(1);
|
throw new IncorrectResultSizeDataAccessException(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T, I> T saveOrUpdate(I id, EntityManager entityManager, T entity) {
|
public static <T, I> T saveOrUpdate(I id, EntityManager entityManager, T entity) {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
entityManager.persist(entity);
|
entityManager.persist(entity);
|
||||||
entityManager.flush();
|
entityManager.flush();
|
||||||
return entity;
|
return entity;
|
||||||
} else {
|
} else {
|
||||||
T tmp = entityManager.merge(entity);
|
T tmp = entityManager.merge(entity);
|
||||||
entityManager.flush();
|
entityManager.flush();
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import java.util.Map;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.mitre.openid.connect.view.JsonEntityView;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
@ -35,63 +34,66 @@ public class WebfingerView extends AbstractView {
|
||||||
private static Logger logger = LoggerFactory.getLogger(WebfingerView.class);
|
private static Logger logger = LoggerFactory.getLogger(WebfingerView.class);
|
||||||
|
|
||||||
private Gson gson = new GsonBuilder()
|
private Gson gson = new GsonBuilder()
|
||||||
.setExclusionStrategies(new ExclusionStrategy() {
|
.setExclusionStrategies(new ExclusionStrategy() {
|
||||||
|
|
||||||
public boolean shouldSkipField(FieldAttributes f) {
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldSkipClass(Class<?> clazz) {
|
|
||||||
// skip the JPA binding wrapper
|
|
||||||
if (clazz.equals(BeanPropertyBindingResult.class)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
.serializeNulls()
|
|
||||||
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldSkipField(FieldAttributes f) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldSkipClass(Class<?> clazz) {
|
||||||
|
// skip the JPA binding wrapper
|
||||||
|
if (clazz.equals(BeanPropertyBindingResult.class)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.serializeNulls()
|
||||||
|
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
|
||||||
response.setContentType("application/jrd+json");
|
response.setContentType("application/jrd+json");
|
||||||
|
|
||||||
|
|
||||||
HttpStatus code = (HttpStatus) model.get("code");
|
HttpStatus code = (HttpStatus) model.get("code");
|
||||||
if (code == null) {
|
if (code == null) {
|
||||||
code = HttpStatus.OK; // default to 200
|
code = HttpStatus.OK; // default to 200
|
||||||
}
|
}
|
||||||
|
|
||||||
response.setStatus(code.value());
|
response.setStatus(code.value());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
String resource = (String)model.get("resource");
|
String resource = (String)model.get("resource");
|
||||||
String issuer = (String)model.get("issuer");
|
String issuer = (String)model.get("issuer");
|
||||||
|
|
||||||
JsonObject obj = new JsonObject();
|
JsonObject obj = new JsonObject();
|
||||||
obj.addProperty("subject", resource);
|
obj.addProperty("subject", resource);
|
||||||
|
|
||||||
JsonArray links = new JsonArray();
|
JsonArray links = new JsonArray();
|
||||||
JsonObject link = new JsonObject();
|
JsonObject link = new JsonObject();
|
||||||
link.addProperty("rel", "http://openid.net/specs/connect/1.0/issuer");
|
link.addProperty("rel", "http://openid.net/specs/connect/1.0/issuer");
|
||||||
link.addProperty("href", issuer);
|
link.addProperty("href", issuer);
|
||||||
links.add(link);
|
links.add(link);
|
||||||
|
|
||||||
obj.add("links", links);
|
obj.add("links", links);
|
||||||
|
|
||||||
Writer out = response.getWriter();
|
Writer out = response.getWriter();
|
||||||
gson.toJson(obj, out);
|
gson.toJson(obj, out);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
||||||
//TODO: Error Handling
|
//TODO: Error Handling
|
||||||
logger.error("IOException in JsonEntityView.java: ", e);
|
logger.error("IOException in JsonEntityView.java: ", e);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ package org.mitre.discovery.web;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -53,20 +52,20 @@ import com.nimbusds.jose.Algorithm;
|
||||||
public class DiscoveryEndpoint {
|
public class DiscoveryEndpoint {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(DiscoveryEndpoint.class);
|
private static Logger logger = LoggerFactory.getLogger(DiscoveryEndpoint.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ConfigurationPropertiesBean config;
|
private ConfigurationPropertiesBean config;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SystemScopeService scopeService;
|
private SystemScopeService scopeService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JwtSigningAndValidationService jwtService;
|
private JwtSigningAndValidationService jwtService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserInfoService userService;
|
private UserInfoService userService;
|
||||||
|
|
||||||
|
|
||||||
// used to map JWA algorithms objects to strings
|
// used to map JWA algorithms objects to strings
|
||||||
private Function<Algorithm, String> toAlgorithmName = new Function<Algorithm, String>() {
|
private Function<Algorithm, String> toAlgorithmName = new Function<Algorithm, String>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -78,7 +77,7 @@ public class DiscoveryEndpoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@RequestMapping(value={"/.well-known/webfinger"},
|
@RequestMapping(value={"/.well-known/webfinger"},
|
||||||
params={"resource", "rel=http://openid.net/specs/connect/1.0/issuer"}, produces = "application/json")
|
params={"resource", "rel=http://openid.net/specs/connect/1.0/issuer"}, produces = "application/json")
|
||||||
public String webfinger(@RequestParam("resource") String resource, Model model) {
|
public String webfinger(@RequestParam("resource") String resource, Model model) {
|
||||||
|
@ -89,10 +88,10 @@ public class DiscoveryEndpoint {
|
||||||
try {
|
try {
|
||||||
URI resourceUri = new URI(resource);
|
URI resourceUri = new URI(resource);
|
||||||
if (resourceUri != null
|
if (resourceUri != null
|
||||||
&& resourceUri.getScheme() != null
|
&& resourceUri.getScheme() != null
|
||||||
&& resourceUri.getScheme().equals("acct")) {
|
&& resourceUri.getScheme().equals("acct")) {
|
||||||
// acct: URI
|
// acct: URI
|
||||||
|
|
||||||
// split out the user and host parts
|
// split out the user and host parts
|
||||||
List<String> parts = Lists.newArrayList(Splitter.on("@").split(resourceUri.getSchemeSpecificPart()));
|
List<String> parts = Lists.newArrayList(Splitter.on("@").split(resourceUri.getSchemeSpecificPart()));
|
||||||
|
|
||||||
|
@ -100,14 +99,14 @@ public class DiscoveryEndpoint {
|
||||||
if (parts.size() > 0) {
|
if (parts.size() > 0) {
|
||||||
user = userService.getByUsername(parts.get(0)); // first part is the username
|
user = userService.getByUsername(parts.get(0)); // first part is the username
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
logger.info("User not found: " + resource);
|
logger.info("User not found: " + resource);
|
||||||
model.addAttribute("code", HttpStatus.NOT_FOUND);
|
model.addAttribute("code", HttpStatus.NOT_FOUND);
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
}
|
}
|
||||||
// TODO: check the "host" part against our issuer
|
// TODO: check the "host" part against our issuer
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logger.info("Unknown URI format: " + resource);
|
logger.info("Unknown URI format: " + resource);
|
||||||
model.addAttribute("code", HttpStatus.NOT_FOUND);
|
model.addAttribute("code", HttpStatus.NOT_FOUND);
|
||||||
|
@ -119,96 +118,96 @@ public class DiscoveryEndpoint {
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we got here, then we're good
|
// if we got here, then we're good
|
||||||
model.addAttribute("resource", resource);
|
model.addAttribute("resource", resource);
|
||||||
model.addAttribute("issuer", config.getIssuer());
|
model.addAttribute("issuer", config.getIssuer());
|
||||||
|
|
||||||
return "webfingerView";
|
return "webfingerView";
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/.well-known/openid-configuration")
|
@RequestMapping("/.well-known/openid-configuration")
|
||||||
public String providerConfiguration(Model model) {
|
public String providerConfiguration(Model model) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
version
|
version
|
||||||
REQUIRED. Version string of the provider response. "3.0" is the expected value.
|
REQUIRED. Version string of the provider response. "3.0" is the expected value.
|
||||||
issuer
|
issuer
|
||||||
REQUIRED. URL using the https scheme with no query or fragment component that the OP asserts as its Issuer Identifier.
|
REQUIRED. URL using the https scheme with no query or fragment component that the OP asserts as its Issuer Identifier.
|
||||||
authorization_endpoint
|
authorization_endpoint
|
||||||
OPTIONAL. URL of the OP's Authentication and Authorization Endpoint [OpenID.Messages].
|
OPTIONAL. URL of the OP's Authentication and Authorization Endpoint [OpenID.Messages].
|
||||||
token_endpoint
|
token_endpoint
|
||||||
OPTIONAL. URL of the OP's OAuth 2.0 Token Endpoint [OpenID.Messages].
|
OPTIONAL. URL of the OP's OAuth 2.0 Token Endpoint [OpenID.Messages].
|
||||||
userinfo_endpoint
|
userinfo_endpoint
|
||||||
RECOMMENDED. URL of the OP's UserInfo Endpoint [OpenID.Messages]. This URL MUST use the https scheme and MAY contain port, path, and query parameter components.
|
RECOMMENDED. URL of the OP's UserInfo Endpoint [OpenID.Messages]. This URL MUST use the https scheme and MAY contain port, path, and query parameter components.
|
||||||
check_session_iframe
|
check_session_iframe
|
||||||
OPTIONAL. URL of an OP endpoint that provides a page to support cross-origin communications for session state information with the RP Client, using the HTML5 postMessage API. The page is loaded from an invisible iframe embedded in an RP page so that it can run in the OP's security context.[OpenID.Session]
|
OPTIONAL. URL of an OP endpoint that provides a page to support cross-origin communications for session state information with the RP Client, using the HTML5 postMessage API. The page is loaded from an invisible iframe embedded in an RP page so that it can run in the OP's security context.[OpenID.Session]
|
||||||
end_session_endpoint
|
end_session_endpoint
|
||||||
OPTIONAL. URL of the OP's endpoint that initiates the user logout [OpenID.Session].
|
OPTIONAL. URL of the OP's endpoint that initiates the user logout [OpenID.Session].
|
||||||
jwks_uri
|
jwks_uri
|
||||||
OPTIONAL. URL of the OP's JSON Web Key Set [JWK] document that contains the Server's signing key(s) that are used for signing responses to the Client. The JWK Set MAY also contain the Server's encryption key(s) that are used by the Client to encrypt requests to the Server. When both signing and encryption keys are made available, a use (Key Use) parameter value is REQUIRED for all keys in the document to indicate each key's intended usage.
|
OPTIONAL. URL of the OP's JSON Web Key Set [JWK] document that contains the Server's signing key(s) that are used for signing responses to the Client. The JWK Set MAY also contain the Server's encryption key(s) that are used by the Client to encrypt requests to the Server. When both signing and encryption keys are made available, a use (Key Use) parameter value is REQUIRED for all keys in the document to indicate each key's intended usage.
|
||||||
registration_endpoint
|
registration_endpoint
|
||||||
RECOMMENDED. URL of the OP's Dynamic Client Registration Endpoint [OpenID.Registration].
|
RECOMMENDED. URL of the OP's Dynamic Client Registration Endpoint [OpenID.Registration].
|
||||||
scopes_supported
|
scopes_supported
|
||||||
RECOMMENDED. JSON array containing a list of the OAuth 2.0 [RFC6749] scope values that this server supports. The server MUST support the openid scope value.
|
RECOMMENDED. JSON array containing a list of the OAuth 2.0 [RFC6749] scope values that this server supports. The server MUST support the openid scope value.
|
||||||
response_types_supported
|
response_types_supported
|
||||||
REQUIRED. JSON array containing a list of the OAuth 2.0 response_type values that this server supports. The server MUST support the code, id_token, and the token id_token response type values.
|
REQUIRED. JSON array containing a list of the OAuth 2.0 response_type values that this server supports. The server MUST support the code, id_token, and the token id_token response type values.
|
||||||
grant_types_supported
|
grant_types_supported
|
||||||
OPTIONAL. JSON array containing a list of the OAuth 2.0 grant type values that this server supports. The server MUST support the authorization_code and implicit grant type values and MAY support the urn:ietf:params:oauth:grant-type:jwt-bearer grant type defined in OAuth JWT Bearer Token Profiles [OAuth.JWT]. If omitted, the default value is ["authorization_code", "implicit"].
|
OPTIONAL. JSON array containing a list of the OAuth 2.0 grant type values that this server supports. The server MUST support the authorization_code and implicit grant type values and MAY support the urn:ietf:params:oauth:grant-type:jwt-bearer grant type defined in OAuth JWT Bearer Token Profiles [OAuth.JWT]. If omitted, the default value is ["authorization_code", "implicit"].
|
||||||
acr_values_supported
|
acr_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the Authentication Context Class References that this server supports.
|
OPTIONAL. JSON array containing a list of the Authentication Context Class References that this server supports.
|
||||||
subject_types_supported
|
subject_types_supported
|
||||||
REQUIRED. JSON array containing a list of the subject identifier types that this server supports. Valid types include pairwise and public.
|
REQUIRED. JSON array containing a list of the subject identifier types that this server supports. Valid types include pairwise and public.
|
||||||
userinfo_signing_alg_values_supported
|
userinfo_signing_alg_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the JWS [JWS] signing algorithms (alg values) [JWA] supported by the UserInfo Endpoint to encode the Claims in a JWT [JWT].
|
OPTIONAL. JSON array containing a list of the JWS [JWS] signing algorithms (alg values) [JWA] supported by the UserInfo Endpoint to encode the Claims in a JWT [JWT].
|
||||||
userinfo_encryption_alg_values_supported
|
userinfo_encryption_alg_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the JWE [JWE] encryption algorithms (alg values) [JWA] supported by the UserInfo Endpoint to encode the Claims in a JWT [JWT].
|
OPTIONAL. JSON array containing a list of the JWE [JWE] encryption algorithms (alg values) [JWA] supported by the UserInfo Endpoint to encode the Claims in a JWT [JWT].
|
||||||
userinfo_encryption_enc_values_supported
|
userinfo_encryption_enc_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the JWE encryption algorithms (enc values) [JWA] supported by the UserInfo Endpoint to encode the Claims in a JWT [JWT].
|
OPTIONAL. JSON array containing a list of the JWE encryption algorithms (enc values) [JWA] supported by the UserInfo Endpoint to encode the Claims in a JWT [JWT].
|
||||||
id_token_signing_alg_values_supported
|
id_token_signing_alg_values_supported
|
||||||
REQUIRED. JSON array containing a list of the JWS signing algorithms (alg values) supported by the Authorization Server for the ID Token to encode the Claims in a JWT [JWT].
|
REQUIRED. JSON array containing a list of the JWS signing algorithms (alg values) supported by the Authorization Server for the ID Token to encode the Claims in a JWT [JWT].
|
||||||
id_token_encryption_alg_values_supported
|
id_token_encryption_alg_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the JWE encryption algorithms (alg values) supported by the Authorization Server for the ID Token to encode the Claims in a JWT [JWT].
|
OPTIONAL. JSON array containing a list of the JWE encryption algorithms (alg values) supported by the Authorization Server for the ID Token to encode the Claims in a JWT [JWT].
|
||||||
id_token_encryption_enc_values_supported
|
id_token_encryption_enc_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the JWE encryption algorithms (enc values) supported by the Authorization Server for the ID Token to encode the Claims in a JWT [JWT].
|
OPTIONAL. JSON array containing a list of the JWE encryption algorithms (enc values) supported by the Authorization Server for the ID Token to encode the Claims in a JWT [JWT].
|
||||||
request_object_signing_alg_values_supported
|
request_object_signing_alg_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the JWS signing algorithms (alg values) supported by the Authorization Server for the Request Object described in Section 2.9 of OpenID Connect Messages 1.0 [OpenID.Messages]. These algorithms are used both when the Request Object is passed by value (using the request parameter) and when it is passed by reference (using the request_uri parameter). Servers SHOULD support none and RS256.
|
OPTIONAL. JSON array containing a list of the JWS signing algorithms (alg values) supported by the Authorization Server for the Request Object described in Section 2.9 of OpenID Connect Messages 1.0 [OpenID.Messages]. These algorithms are used both when the Request Object is passed by value (using the request parameter) and when it is passed by reference (using the request_uri parameter). Servers SHOULD support none and RS256.
|
||||||
request_object_encryption_alg_values_supported
|
request_object_encryption_alg_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the JWE encryption algorithms (alg values) supported by the Authorization Server for the Request Object described in Section 2.9 of OpenID Connect Messages 1.0 [OpenID.Messages]. These algorithms are used both when the Request Object is passed by value and when it is passed by reference.
|
OPTIONAL. JSON array containing a list of the JWE encryption algorithms (alg values) supported by the Authorization Server for the Request Object described in Section 2.9 of OpenID Connect Messages 1.0 [OpenID.Messages]. These algorithms are used both when the Request Object is passed by value and when it is passed by reference.
|
||||||
request_object_encryption_enc_values_supported
|
request_object_encryption_enc_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the JWE encryption algorithms (enc values) supported by the Authorization Server for the Request Object described in Section 2.9 of OpenID Connect Messages 1.0 [OpenID.Messages]. These algorithms are used both when the Request Object is passed by value and when it is passed by reference.
|
OPTIONAL. JSON array containing a list of the JWE encryption algorithms (enc values) supported by the Authorization Server for the Request Object described in Section 2.9 of OpenID Connect Messages 1.0 [OpenID.Messages]. These algorithms are used both when the Request Object is passed by value and when it is passed by reference.
|
||||||
token_endpoint_auth_methods_supported
|
token_endpoint_auth_methods_supported
|
||||||
OPTIONAL. JSON array containing a list of authentication methods supported by this Token Endpoint. The options are client_secret_post, client_secret_basic, client_secret_jwt, and private_key_jwt, as described in Section 2.2.1 of OpenID Connect Messages 1.0 [OpenID.Messages]. Other authentication methods may be defined by extensions. If omitted, the default is client_secret_basic -- the HTTP Basic Authentication Scheme as specified in Section 2.3.1 of OAuth 2.0 [RFC6749].
|
OPTIONAL. JSON array containing a list of authentication methods supported by this Token Endpoint. The options are client_secret_post, client_secret_basic, client_secret_jwt, and private_key_jwt, as described in Section 2.2.1 of OpenID Connect Messages 1.0 [OpenID.Messages]. Other authentication methods may be defined by extensions. If omitted, the default is client_secret_basic -- the HTTP Basic Authentication Scheme as specified in Section 2.3.1 of OAuth 2.0 [RFC6749].
|
||||||
token_endpoint_auth_signing_alg_values_supported
|
token_endpoint_auth_signing_alg_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the JWS signing algorithms (alg values) supported by the Token Endpoint for the private_key_jwt and client_secret_jwt methods to encode the JWT [JWT]. Servers SHOULD support RS256.
|
OPTIONAL. JSON array containing a list of the JWS signing algorithms (alg values) supported by the Token Endpoint for the private_key_jwt and client_secret_jwt methods to encode the JWT [JWT]. Servers SHOULD support RS256.
|
||||||
display_values_supported
|
display_values_supported
|
||||||
OPTIONAL. JSON array containing a list of the display parameter values that the OpenID Provider supports. These values are described in Section 2.1.1 of OpenID Connect Messages 1.0 [OpenID.Messages].
|
OPTIONAL. JSON array containing a list of the display parameter values that the OpenID Provider supports. These values are described in Section 2.1.1 of OpenID Connect Messages 1.0 [OpenID.Messages].
|
||||||
claim_types_supported
|
claim_types_supported
|
||||||
OPTIONAL. JSON array containing a list of the Claim Types that the OpenID Provider supports. These Claim Types are described in Section 2.6 of OpenID Connect Messages 1.0 [OpenID.Messages]. Values defined by this specification are normal, aggregated, and distributed. If not specified, the implementation supports only normal Claims.
|
OPTIONAL. JSON array containing a list of the Claim Types that the OpenID Provider supports. These Claim Types are described in Section 2.6 of OpenID Connect Messages 1.0 [OpenID.Messages]. Values defined by this specification are normal, aggregated, and distributed. If not specified, the implementation supports only normal Claims.
|
||||||
claims_supported
|
claims_supported
|
||||||
RECOMMENDED. JSON array containing a list of the Claim Names of the Claims that the OpenID Provider may be able to supply values for. Note that for privacy or other reasons, this may not be an exhaustive list.
|
RECOMMENDED. JSON array containing a list of the Claim Names of the Claims that the OpenID Provider may be able to supply values for. Note that for privacy or other reasons, this may not be an exhaustive list.
|
||||||
service_documentation
|
service_documentation
|
||||||
OPTIONAL. URL of a page containing human-readable information that developers might want or need to know when using the OpenID Provider. In particular, if the OpenID Provider does not support Dynamic Client Registration, then information on how to register Clients should be provided in this documentation.
|
OPTIONAL. URL of a page containing human-readable information that developers might want or need to know when using the OpenID Provider. In particular, if the OpenID Provider does not support Dynamic Client Registration, then information on how to register Clients should be provided in this documentation.
|
||||||
claims_locales_supported
|
claims_locales_supported
|
||||||
OPTIONAL. Languages and scripts supported for values in Claims being returned, represented as a JSON array of BCP47 [RFC5646] language tag values. Not all languages and scripts may be supported for all Claim values.
|
OPTIONAL. Languages and scripts supported for values in Claims being returned, represented as a JSON array of BCP47 [RFC5646] language tag values. Not all languages and scripts may be supported for all Claim values.
|
||||||
ui_locales_supported
|
ui_locales_supported
|
||||||
OPTIONAL. Languages and scripts supported for the user interface, represented as a JSON array of BCP47 [RFC5646] language tag values.
|
OPTIONAL. Languages and scripts supported for the user interface, represented as a JSON array of BCP47 [RFC5646] language tag values.
|
||||||
claims_parameter_supported
|
claims_parameter_supported
|
||||||
OPTIONAL. Boolean value specifying whether the OP supports use of the claims parameter, with true indicating support. If omitted, the default value is false.
|
OPTIONAL. Boolean value specifying whether the OP supports use of the claims parameter, with true indicating support. If omitted, the default value is false.
|
||||||
request_parameter_supported
|
request_parameter_supported
|
||||||
OPTIONAL. Boolean value specifying whether the OP supports use of the request parameter, with true indicating support. If omitted, the default value is false.
|
OPTIONAL. Boolean value specifying whether the OP supports use of the request parameter, with true indicating support. If omitted, the default value is false.
|
||||||
request_uri_parameter_supported
|
request_uri_parameter_supported
|
||||||
OPTIONAL. Boolean value specifying whether the OP supports use of the request_uri parameter, with true indicating support. If omitted, the default value is true.
|
OPTIONAL. Boolean value specifying whether the OP supports use of the request_uri parameter, with true indicating support. If omitted, the default value is true.
|
||||||
require_request_uri_registration
|
require_request_uri_registration
|
||||||
OPTIONAL. Boolean value specifying whether the OP requires any request_uri values used to be pre-registered using the request_uris registration parameter. Pre-registration is REQUIRED when the value is true.
|
OPTIONAL. Boolean value specifying whether the OP requires any request_uri values used to be pre-registered using the request_uris registration parameter. Pre-registration is REQUIRED when the value is true.
|
||||||
op_policy_uri
|
op_policy_uri
|
||||||
OPTIONAL. URL that the OpenID Provider provides to the person registering the Client to read about the OP's requirements on how the Relying Party may use the data provided by the OP. The registration process SHOULD display this URL to the person registering the Client if it is given.
|
OPTIONAL. URL that the OpenID Provider provides to the person registering the Client to read about the OP's requirements on how the Relying Party may use the data provided by the OP. The registration process SHOULD display this URL to the person registering the Client if it is given.
|
||||||
op_tos_uri
|
op_tos_uri
|
||||||
OPTIONAL. URL that the OpenID Provider provides to the person registering the Client to read about OpenID Provider's terms of service. The registration process SHOULD display this URL to the person registering the Client if it is given. *
|
OPTIONAL. URL that the OpenID Provider provides to the person registering the Client to read about OpenID Provider's terms of service. The registration process SHOULD display this URL to the person registering the Client if it is given. *
|
||||||
*/
|
*/
|
||||||
String baseUrl = config.getIssuer();
|
String baseUrl = config.getIssuer();
|
||||||
|
|
||||||
if (!baseUrl.endsWith("/")) {
|
if (!baseUrl.endsWith("/")) {
|
||||||
logger.warn("Configured issuer doesn't end in /, adding for discovery: " + baseUrl);
|
logger.warn("Configured issuer doesn't end in /, adding for discovery: " + baseUrl);
|
||||||
baseUrl = baseUrl.concat("/");
|
baseUrl = baseUrl.concat("/");
|
||||||
|
@ -242,25 +241,25 @@ public class DiscoveryEndpoint {
|
||||||
//display_types_supported
|
//display_types_supported
|
||||||
m.put("claim_types_supported", Lists.newArrayList("normal" /*, "aggregated", "distributed"*/));
|
m.put("claim_types_supported", Lists.newArrayList("normal" /*, "aggregated", "distributed"*/));
|
||||||
m.put("claims_supported", Lists.newArrayList(
|
m.put("claims_supported", Lists.newArrayList(
|
||||||
"sub",
|
"sub",
|
||||||
"name",
|
"name",
|
||||||
"preferred_username",
|
"preferred_username",
|
||||||
"given_name",
|
"given_name",
|
||||||
"family_name",
|
"family_name",
|
||||||
"middle_name",
|
"middle_name",
|
||||||
"nickname",
|
"nickname",
|
||||||
"profile",
|
"profile",
|
||||||
"picture",
|
"picture",
|
||||||
"website",
|
"website",
|
||||||
"gender",
|
"gender",
|
||||||
"zone_info",
|
"zone_info",
|
||||||
"locale",
|
"locale",
|
||||||
"updated_time",
|
"updated_time",
|
||||||
"birthdate",
|
"birthdate",
|
||||||
"email",
|
"email",
|
||||||
"email_verified",
|
"email_verified",
|
||||||
"phone_number",
|
"phone_number",
|
||||||
"address"
|
"address"
|
||||||
));
|
));
|
||||||
m.put("service_documentation", baseUrl + "about");
|
m.put("service_documentation", baseUrl + "about");
|
||||||
//claims_locales_supported
|
//claims_locales_supported
|
||||||
|
@ -271,11 +270,11 @@ public class DiscoveryEndpoint {
|
||||||
m.put("require_request_uri_registration", false);
|
m.put("require_request_uri_registration", false);
|
||||||
m.put("op_policy_uri", baseUrl + "about");
|
m.put("op_policy_uri", baseUrl + "about");
|
||||||
m.put("op_tos_uri", baseUrl + "about");
|
m.put("op_tos_uri", baseUrl + "about");
|
||||||
|
|
||||||
|
|
||||||
model.addAttribute("entity", m);
|
model.addAttribute("entity", m);
|
||||||
|
|
||||||
return "jsonEntityView";
|
return "jsonEntityView";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,13 +18,13 @@ package org.mitre.oauth2.exception;
|
||||||
public class DuplicateClientIdException extends RuntimeException {
|
public class DuplicateClientIdException extends RuntimeException {
|
||||||
|
|
||||||
public DuplicateClientIdException(String clientId) {
|
public DuplicateClientIdException(String clientId) {
|
||||||
super("Duplicate client id: " + clientId);
|
super("Duplicate client id: " + clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class JpaAuthenticationHolderRepository implements AuthenticationHolderRe
|
||||||
|
|
||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
private EntityManager manager;
|
private EntityManager manager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthenticationHolderEntity getById(Long id) {
|
public AuthenticationHolderEntity getById(Long id) {
|
||||||
return manager.find(AuthenticationHolderEntity.class, id);
|
return manager.find(AuthenticationHolderEntity.class, id);
|
||||||
|
|
|
@ -27,16 +27,16 @@ public class JpaAuthorizationCodeRepository implements AuthorizationCodeReposito
|
||||||
|
|
||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
EntityManager manager;
|
EntityManager manager;
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.repository.AuthorizationCodeRepository#save(org.mitre.oauth2.model.AuthorizationCodeEntity)
|
* @see org.mitre.oauth2.repository.AuthorizationCodeRepository#save(org.mitre.oauth2.model.AuthorizationCodeEntity)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public AuthorizationCodeEntity save(AuthorizationCodeEntity authorizationCode) {
|
public AuthorizationCodeEntity save(AuthorizationCodeEntity authorizationCode) {
|
||||||
|
|
||||||
return JpaUtil.saveOrUpdate(authorizationCode.getId(), manager, authorizationCode);
|
return JpaUtil.saveOrUpdate(authorizationCode.getId(), manager, authorizationCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
@ -45,20 +45,20 @@ public class JpaAuthorizationCodeRepository implements AuthorizationCodeReposito
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public AuthorizationRequestHolder consume(String code) throws InvalidGrantException {
|
public AuthorizationRequestHolder consume(String code) throws InvalidGrantException {
|
||||||
|
|
||||||
TypedQuery<AuthorizationCodeEntity> query = manager.createNamedQuery("AuthorizationCodeEntity.getByValue", AuthorizationCodeEntity.class);
|
TypedQuery<AuthorizationCodeEntity> query = manager.createNamedQuery("AuthorizationCodeEntity.getByValue", AuthorizationCodeEntity.class);
|
||||||
query.setParameter("code", code);
|
query.setParameter("code", code);
|
||||||
|
|
||||||
AuthorizationCodeEntity result = JpaUtil.getSingleResult(query.getResultList());
|
AuthorizationCodeEntity result = JpaUtil.getSingleResult(query.getResultList());
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new InvalidGrantException("JpaAuthorizationCodeRepository: no authorization code found for value " + code);
|
throw new InvalidGrantException("JpaAuthorizationCodeRepository: no authorization code found for value " + code);
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthorizationRequestHolder authRequest = result.getAuthorizationRequestHolder();
|
AuthorizationRequestHolder authRequest = result.getAuthorizationRequestHolder();
|
||||||
|
|
||||||
manager.remove(result);
|
manager.remove(result);
|
||||||
|
|
||||||
return authRequest;
|
return authRequest;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,15 +37,16 @@ public class JpaOAuth2ClientRepository implements OAuth2ClientRepository {
|
||||||
|
|
||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
private EntityManager manager;
|
private EntityManager manager;
|
||||||
|
|
||||||
public JpaOAuth2ClientRepository() {
|
public JpaOAuth2ClientRepository() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JpaOAuth2ClientRepository(EntityManager manager) {
|
public JpaOAuth2ClientRepository(EntityManager manager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ClientDetailsEntity getById(Long id) {
|
public ClientDetailsEntity getById(Long id) {
|
||||||
return manager.find(ClientDetailsEntity.class, id);
|
return manager.find(ClientDetailsEntity.class, id);
|
||||||
}
|
}
|
||||||
|
@ -82,17 +83,17 @@ public class JpaOAuth2ClientRepository implements OAuth2ClientRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientDetailsEntity updateClient(Long id, ClientDetailsEntity client) {
|
public ClientDetailsEntity updateClient(Long id, ClientDetailsEntity client) {
|
||||||
// sanity check
|
// sanity check
|
||||||
client.setId(id);
|
client.setId(id);
|
||||||
|
|
||||||
return JpaUtil.saveOrUpdate(id, manager, client);
|
return JpaUtil.saveOrUpdate(id, manager, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ClientDetailsEntity> getAllClients() {
|
public Collection<ClientDetailsEntity> getAllClients() {
|
||||||
TypedQuery<ClientDetailsEntity> query = manager.createNamedQuery("ClientDetailsEntity.findAll", ClientDetailsEntity.class);
|
TypedQuery<ClientDetailsEntity> query = manager.createNamedQuery("ClientDetailsEntity.findAll", ClientDetailsEntity.class);
|
||||||
return query.getResultList();
|
return query.getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,18 +42,18 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
|
||||||
query.setParameter("tokenValue", accessTokenValue);
|
query.setParameter("tokenValue", accessTokenValue);
|
||||||
return JpaUtil.getSingleResult(query.getResultList());
|
return JpaUtil.getSingleResult(query.getResultList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenEntity getAccessTokenById(Long id) {
|
public OAuth2AccessTokenEntity getAccessTokenById(Long id) {
|
||||||
return manager.find(OAuth2AccessTokenEntity.class, id);
|
return manager.find(OAuth2AccessTokenEntity.class, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity token) {
|
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity token) {
|
||||||
return JpaUtil.saveOrUpdate(token.getId(), manager, token);
|
return JpaUtil.saveOrUpdate(token.getId(), manager, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void removeAccessToken(OAuth2AccessTokenEntity accessToken) {
|
public void removeAccessToken(OAuth2AccessTokenEntity accessToken) {
|
||||||
|
@ -64,17 +64,17 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
|
||||||
throw new IllegalArgumentException("Access token not found: " + accessToken);
|
throw new IllegalArgumentException("Access token not found: " + accessToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void clearAccessTokensForRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
public void clearAccessTokensForRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||||
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery("OAuth2AccessTokenEntity.getByRefreshToken", OAuth2AccessTokenEntity.class);
|
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery("OAuth2AccessTokenEntity.getByRefreshToken", OAuth2AccessTokenEntity.class);
|
||||||
query.setParameter("refreshToken", refreshToken);
|
query.setParameter("refreshToken", refreshToken);
|
||||||
List<OAuth2AccessTokenEntity> accessTokens = query.getResultList();
|
List<OAuth2AccessTokenEntity> accessTokens = query.getResultList();
|
||||||
for (OAuth2AccessTokenEntity accessToken : accessTokens) {
|
for (OAuth2AccessTokenEntity accessToken : accessTokens) {
|
||||||
removeAccessToken(accessToken);
|
removeAccessToken(accessToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2RefreshTokenEntity getRefreshTokenByValue(String refreshTokenValue) {
|
public OAuth2RefreshTokenEntity getRefreshTokenByValue(String refreshTokenValue) {
|
||||||
|
@ -82,105 +82,105 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
|
||||||
query.setParameter("tokenValue", refreshTokenValue);
|
query.setParameter("tokenValue", refreshTokenValue);
|
||||||
return JpaUtil.getSingleResult(query.getResultList());
|
return JpaUtil.getSingleResult(query.getResultList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2RefreshTokenEntity getRefreshTokenById(Long id) {
|
public OAuth2RefreshTokenEntity getRefreshTokenById(Long id) {
|
||||||
return manager.find(OAuth2RefreshTokenEntity.class, id);
|
return manager.find(OAuth2RefreshTokenEntity.class, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||||
return JpaUtil.saveOrUpdate(refreshToken.getId(), manager, refreshToken);
|
return JpaUtil.saveOrUpdate(refreshToken.getId(), manager, refreshToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void removeRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
public void removeRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||||
OAuth2RefreshTokenEntity found = getRefreshTokenByValue(refreshToken.getValue());
|
OAuth2RefreshTokenEntity found = getRefreshTokenByValue(refreshToken.getValue());
|
||||||
if (found != null) {
|
if (found != null) {
|
||||||
manager.remove(found);
|
manager.remove(found);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Refresh token not found: " + refreshToken);
|
throw new IllegalArgumentException("Refresh token not found: " + refreshToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void clearTokensForClient(ClientDetailsEntity client) {
|
public void clearTokensForClient(ClientDetailsEntity client) {
|
||||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByClient", OAuth2AccessTokenEntity.class);
|
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByClient", OAuth2AccessTokenEntity.class);
|
||||||
queryA.setParameter("client", client);
|
queryA.setParameter("client", client);
|
||||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||||
for (OAuth2AccessTokenEntity accessToken : accessTokens) {
|
for (OAuth2AccessTokenEntity accessToken : accessTokens) {
|
||||||
removeAccessToken(accessToken);
|
removeAccessToken(accessToken);
|
||||||
}
|
}
|
||||||
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getByClient", OAuth2RefreshTokenEntity.class);
|
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getByClient", OAuth2RefreshTokenEntity.class);
|
||||||
queryR.setParameter("client", client);
|
queryR.setParameter("client", client);
|
||||||
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
||||||
for (OAuth2RefreshTokenEntity refreshToken : refreshTokens) {
|
for (OAuth2RefreshTokenEntity refreshToken : refreshTokens) {
|
||||||
removeRefreshToken(refreshToken);
|
removeRefreshToken(refreshToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getAccessTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getAccessTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client) {
|
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client) {
|
||||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByClient", OAuth2AccessTokenEntity.class);
|
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByClient", OAuth2AccessTokenEntity.class);
|
||||||
queryA.setParameter("client", client);
|
queryA.setParameter("client", client);
|
||||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||||
return accessTokens;
|
return accessTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getRefreshTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getRefreshTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client) {
|
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client) {
|
||||||
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getByClient", OAuth2RefreshTokenEntity.class);
|
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getByClient", OAuth2RefreshTokenEntity.class);
|
||||||
queryR.setParameter("client", client);
|
queryR.setParameter("client", client);
|
||||||
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
||||||
return refreshTokens;
|
return refreshTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getExpiredAccessTokens()
|
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getExpiredAccessTokens()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<OAuth2AccessTokenEntity> getExpiredAccessTokens() {
|
public List<OAuth2AccessTokenEntity> getExpiredAccessTokens() {
|
||||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getExpired", OAuth2AccessTokenEntity.class);
|
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getExpired", OAuth2AccessTokenEntity.class);
|
||||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||||
return accessTokens;
|
return accessTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getExpiredRefreshTokens()
|
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getExpiredRefreshTokens()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<OAuth2RefreshTokenEntity> getExpiredRefreshTokens() {
|
public List<OAuth2RefreshTokenEntity> getExpiredRefreshTokens() {
|
||||||
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getExpired", OAuth2RefreshTokenEntity.class);
|
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getExpired", OAuth2RefreshTokenEntity.class);
|
||||||
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
||||||
return refreshTokens;
|
return refreshTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenEntity getByAuthentication(OAuth2Authentication auth) {
|
public OAuth2AccessTokenEntity getByAuthentication(OAuth2Authentication auth) {
|
||||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByAuthentication", OAuth2AccessTokenEntity.class);
|
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByAuthentication", OAuth2AccessTokenEntity.class);
|
||||||
queryA.setParameter("authentication", auth);
|
queryA.setParameter("authentication", auth);
|
||||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||||
return JpaUtil.getSingleResult(accessTokens);
|
return JpaUtil.getSingleResult(accessTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getAccessTokenForIdToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getAccessTokenForIdToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
|
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
|
||||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByIdToken", OAuth2AccessTokenEntity.class);
|
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByIdToken", OAuth2AccessTokenEntity.class);
|
||||||
queryA.setParameter("idToken", idToken);
|
queryA.setParameter("idToken", idToken);
|
||||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||||
return JpaUtil.getSingleResult(accessTokens);
|
return JpaUtil.getSingleResult(accessTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class JpaSystemScopeRepository implements SystemScopeRepository {
|
||||||
|
|
||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
private EntityManager em;
|
private EntityManager em;
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.repository.SystemScopeRepository#getAll()
|
* @see org.mitre.oauth2.repository.SystemScopeRepository#getAll()
|
||||||
*/
|
*/
|
||||||
|
@ -35,7 +35,7 @@ public class JpaSystemScopeRepository implements SystemScopeRepository {
|
||||||
@Transactional
|
@Transactional
|
||||||
public Set<SystemScope> getAll() {
|
public Set<SystemScope> getAll() {
|
||||||
TypedQuery<SystemScope> query = em.createNamedQuery("SystemScope.findAll", SystemScope.class);
|
TypedQuery<SystemScope> query = em.createNamedQuery("SystemScope.findAll", SystemScope.class);
|
||||||
|
|
||||||
return new LinkedHashSet<SystemScope>(query.getResultList());
|
return new LinkedHashSet<SystemScope>(query.getResultList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ public class JpaSystemScopeRepository implements SystemScopeRepository {
|
||||||
@Transactional
|
@Transactional
|
||||||
public void remove(SystemScope scope) {
|
public void remove(SystemScope scope) {
|
||||||
SystemScope found = getById(scope.getId());
|
SystemScope found = getById(scope.getId());
|
||||||
|
|
||||||
if (found != null) {
|
if (found != null) {
|
||||||
em.remove(found);
|
em.remove(found);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@ public class DefaultOAuth2AuthorizationCodeService implements AuthorizationCodeS
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthorizationCodeRepository repository;
|
private AuthorizationCodeRepository repository;
|
||||||
|
|
||||||
private RandomValueStringGenerator generator = new RandomValueStringGenerator();
|
private RandomValueStringGenerator generator = new RandomValueStringGenerator();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a random authorization code and create an AuthorizationCodeEntity,
|
* Generate a random authorization code and create an AuthorizationCodeEntity,
|
||||||
* which will be stored in the repository.
|
* which will be stored in the repository.
|
||||||
|
@ -37,16 +37,16 @@ public class DefaultOAuth2AuthorizationCodeService implements AuthorizationCodeS
|
||||||
@Override
|
@Override
|
||||||
public String createAuthorizationCode(AuthorizationRequestHolder authentication) {
|
public String createAuthorizationCode(AuthorizationRequestHolder authentication) {
|
||||||
String code = generator.generate();
|
String code = generator.generate();
|
||||||
|
|
||||||
AuthorizationCodeEntity entity = new AuthorizationCodeEntity(code, authentication);
|
AuthorizationCodeEntity entity = new AuthorizationCodeEntity(code, authentication);
|
||||||
repository.save(entity);
|
repository.save(entity);
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Consume a given authorization code.
|
* Consume a given authorization code.
|
||||||
* Match the provided string to an AuthorizationCodeEntity. If one is found, return
|
* Match the provided string to an AuthorizationCodeEntity. If one is found, return
|
||||||
* the authentication associated with the code. If one is not found, throw an
|
* the authentication associated with the code. If one is not found, throw an
|
||||||
* InvalidGrantException.
|
* InvalidGrantException.
|
||||||
*
|
*
|
||||||
|
@ -56,7 +56,7 @@ public class DefaultOAuth2AuthorizationCodeService implements AuthorizationCodeS
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AuthorizationRequestHolder consumeAuthorizationCode(String code) throws InvalidGrantException {
|
public AuthorizationRequestHolder consumeAuthorizationCode(String code) throws InvalidGrantException {
|
||||||
|
|
||||||
AuthorizationRequestHolder auth = repository.consume(code);
|
AuthorizationRequestHolder auth = repository.consume(code);
|
||||||
return auth;
|
return auth;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,32 +39,32 @@ import com.google.common.base.Strings;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEntityService {
|
public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEntityService {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private OAuth2ClientRepository clientRepository;
|
private OAuth2ClientRepository clientRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private OAuth2TokenRepository tokenRepository;
|
private OAuth2TokenRepository tokenRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ApprovedSiteService approvedSiteService;
|
private ApprovedSiteService approvedSiteService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private WhitelistedSiteService whitelistedSiteService;
|
private WhitelistedSiteService whitelistedSiteService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private BlacklistedSiteService blacklistedSiteService;
|
private BlacklistedSiteService blacklistedSiteService;
|
||||||
|
|
||||||
public DefaultOAuth2ClientDetailsEntityService() {
|
public DefaultOAuth2ClientDetailsEntityService() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultOAuth2ClientDetailsEntityService(OAuth2ClientRepository clientRepository,
|
public DefaultOAuth2ClientDetailsEntityService(OAuth2ClientRepository clientRepository,
|
||||||
OAuth2TokenRepository tokenRepository) {
|
OAuth2TokenRepository tokenRepository) {
|
||||||
this.clientRepository = clientRepository;
|
this.clientRepository = clientRepository;
|
||||||
this.tokenRepository = tokenRepository;
|
this.tokenRepository = tokenRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientDetailsEntity saveNewClient(ClientDetailsEntity client) {
|
public ClientDetailsEntity saveNewClient(ClientDetailsEntity client) {
|
||||||
if (client.getId() != null) { // if it's not null, it's already been saved, this is an error
|
if (client.getId() != null) { // if it's not null, it's already been saved, this is an error
|
||||||
|
@ -76,37 +76,38 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
|
||||||
if (blacklistedSiteService.isBlacklisted(uri)) {
|
if (blacklistedSiteService.isBlacklisted(uri)) {
|
||||||
throw new IllegalArgumentException("Client URI is blacklisted: " + uri);
|
throw new IllegalArgumentException("Client URI is blacklisted: " + uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign a random clientid if it's empty
|
// assign a random clientid if it's empty
|
||||||
// NOTE: don't assign a random client secret without asking, since public clients have no secret
|
// NOTE: don't assign a random client secret without asking, since public clients have no secret
|
||||||
if (Strings.isNullOrEmpty(client.getClientId())) {
|
if (Strings.isNullOrEmpty(client.getClientId())) {
|
||||||
client = generateClientId(client);
|
client = generateClientId(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the client is flagged to allow for refresh tokens, make sure it's got the right granted scopes
|
// if the client is flagged to allow for refresh tokens, make sure it's got the right granted scopes
|
||||||
if (client.isAllowRefresh()) {
|
if (client.isAllowRefresh()) {
|
||||||
client.getScope().add("offline_access");
|
client.getScope().add("offline_access");
|
||||||
} else {
|
} else {
|
||||||
client.getScope().remove("offline_access");
|
client.getScope().remove("offline_access");
|
||||||
}
|
}
|
||||||
|
|
||||||
// timestamp this to right now
|
// timestamp this to right now
|
||||||
client.setCreatedAt(new Date());
|
client.setCreatedAt(new Date());
|
||||||
|
|
||||||
return clientRepository.saveClient(client);
|
return clientRepository.saveClient(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the client by its internal ID
|
* Get the client by its internal ID
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public ClientDetailsEntity getClientById(Long id) {
|
public ClientDetailsEntity getClientById(Long id) {
|
||||||
ClientDetailsEntity client = clientRepository.getById(id);
|
ClientDetailsEntity client = clientRepository.getById(id);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the client for the given ClientID
|
* Get the client for the given ClientID
|
||||||
*/
|
*/
|
||||||
|
@ -121,87 +122,87 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException("Client id must not be empty!");
|
throw new IllegalArgumentException("Client id must not be empty!");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a client and all its associated tokens
|
* Delete a client and all its associated tokens
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void deleteClient(ClientDetailsEntity client) throws InvalidClientException {
|
public void deleteClient(ClientDetailsEntity client) throws InvalidClientException {
|
||||||
|
|
||||||
if (clientRepository.getById(client.getId()) == null) {
|
if (clientRepository.getById(client.getId()) == null) {
|
||||||
throw new InvalidClientException("Client with id " + client.getClientId() + " was not found");
|
throw new InvalidClientException("Client with id " + client.getClientId() + " was not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean out any tokens that this client had issued
|
// clean out any tokens that this client had issued
|
||||||
tokenRepository.clearTokensForClient(client);
|
tokenRepository.clearTokensForClient(client);
|
||||||
|
|
||||||
// clean out any approved sites for this client
|
// clean out any approved sites for this client
|
||||||
approvedSiteService.clearApprovedSitesForClient(client);
|
approvedSiteService.clearApprovedSitesForClient(client);
|
||||||
|
|
||||||
// clear out any whitelisted sites for this client
|
// clear out any whitelisted sites for this client
|
||||||
WhitelistedSite whitelistedSite = whitelistedSiteService.getByClientId(client.getClientId());
|
WhitelistedSite whitelistedSite = whitelistedSiteService.getByClientId(client.getClientId());
|
||||||
if (whitelistedSite != null) {
|
if (whitelistedSite != null) {
|
||||||
whitelistedSiteService.remove(whitelistedSite);
|
whitelistedSiteService.remove(whitelistedSite);
|
||||||
}
|
}
|
||||||
|
|
||||||
// take care of the client itself
|
// take care of the client itself
|
||||||
clientRepository.deleteClient(client);
|
clientRepository.deleteClient(client);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the oldClient with information from the newClient. The
|
* Update the oldClient with information from the newClient. The
|
||||||
* id from oldClient is retained.
|
* id from oldClient is retained.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ClientDetailsEntity updateClient(ClientDetailsEntity oldClient, ClientDetailsEntity newClient) throws IllegalArgumentException {
|
public ClientDetailsEntity updateClient(ClientDetailsEntity oldClient, ClientDetailsEntity newClient) throws IllegalArgumentException {
|
||||||
if (oldClient != null && newClient != null) {
|
if (oldClient != null && newClient != null) {
|
||||||
|
|
||||||
for (String uri : newClient.getRegisteredRedirectUri()) {
|
for (String uri : newClient.getRegisteredRedirectUri()) {
|
||||||
if (blacklistedSiteService.isBlacklisted(uri)) {
|
if (blacklistedSiteService.isBlacklisted(uri)) {
|
||||||
throw new IllegalArgumentException("Client URI is blacklisted: " + uri);
|
throw new IllegalArgumentException("Client URI is blacklisted: " + uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the client is flagged to allow for refresh tokens, make sure it's got the right scope
|
|
||||||
if (newClient.isAllowRefresh()) {
|
|
||||||
newClient.getScope().add("offline_access");
|
|
||||||
} else {
|
|
||||||
newClient.getScope().remove("offline_access");
|
|
||||||
}
|
|
||||||
|
|
||||||
return clientRepository.updateClient(oldClient.getId(), newClient);
|
// if the client is flagged to allow for refresh tokens, make sure it's got the right scope
|
||||||
|
if (newClient.isAllowRefresh()) {
|
||||||
|
newClient.getScope().add("offline_access");
|
||||||
|
} else {
|
||||||
|
newClient.getScope().remove("offline_access");
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientRepository.updateClient(oldClient.getId(), newClient);
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("Neither old client or new client can be null!");
|
throw new IllegalArgumentException("Neither old client or new client can be null!");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all clients in the system
|
* Get all clients in the system
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Collection<ClientDetailsEntity> getAllClients() {
|
public Collection<ClientDetailsEntity> getAllClients() {
|
||||||
return clientRepository.getAllClients();
|
return clientRepository.getAllClients();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a clientId for the given client and sets it to the client's clientId field. Returns the client that was passed in, now with id set.
|
* Generates a clientId for the given client and sets it to the client's clientId field. Returns the client that was passed in, now with id set.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ClientDetailsEntity generateClientId(ClientDetailsEntity client) {
|
public ClientDetailsEntity generateClientId(ClientDetailsEntity client) {
|
||||||
client.setClientId(UUID.randomUUID().toString());
|
client.setClientId(UUID.randomUUID().toString());
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a new clientSecret for the given client and sets it to the client's clientSecret field. Returns the client that was passed in, now with secret set.
|
* Generates a new clientSecret for the given client and sets it to the client's clientSecret field. Returns the client that was passed in, now with secret set.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ClientDetailsEntity generateClientSecret(ClientDetailsEntity client) {
|
public ClientDetailsEntity generateClientSecret(ClientDetailsEntity client) {
|
||||||
client.setClientSecret(Base64.encodeBase64URLSafeString(new BigInteger(512, new SecureRandom()).toByteArray()).replace("=", ""));
|
client.setClientSecret(Base64.encodeBase64URLSafeString(new BigInteger(512, new SecureRandom()).toByteArray()).replace("=", ""));
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,16 +18,12 @@
|
||||||
*/
|
*/
|
||||||
package org.mitre.oauth2.service.impl;
|
package org.mitre.oauth2.service.impl;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.joda.time.Period;
|
|
||||||
import org.mitre.oauth2.exception.NonceReuseException;
|
|
||||||
import org.mitre.oauth2.model.AuthenticationHolderEntity;
|
import org.mitre.oauth2.model.AuthenticationHolderEntity;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||||
|
@ -36,8 +32,6 @@ import org.mitre.oauth2.repository.AuthenticationHolderRepository;
|
||||||
import org.mitre.oauth2.repository.OAuth2TokenRepository;
|
import org.mitre.oauth2.repository.OAuth2TokenRepository;
|
||||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||||
import org.mitre.openid.connect.model.Nonce;
|
|
||||||
import org.mitre.openid.connect.service.NonceService;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -62,142 +56,142 @@ import com.nimbusds.jwt.PlainJWT;
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityService {
|
public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityService {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(DefaultOAuth2ProviderTokenService.class);
|
private static Logger logger = LoggerFactory.getLogger(DefaultOAuth2ProviderTokenService.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private OAuth2TokenRepository tokenRepository;
|
private OAuth2TokenRepository tokenRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthenticationHolderRepository authenticationHolderRepository;
|
private AuthenticationHolderRepository authenticationHolderRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ClientDetailsEntityService clientDetailsService;
|
private ClientDetailsEntityService clientDetailsService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TokenEnhancer tokenEnhancer;
|
private TokenEnhancer tokenEnhancer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenEntity createAccessToken(OAuth2Authentication authentication) throws AuthenticationException, InvalidClientException {
|
public OAuth2AccessTokenEntity createAccessToken(OAuth2Authentication authentication) throws AuthenticationException, InvalidClientException {
|
||||||
if (authentication != null && authentication.getAuthorizationRequest() != null) {
|
if (authentication != null && authentication.getAuthorizationRequest() != null) {
|
||||||
// look up our client
|
// look up our client
|
||||||
AuthorizationRequest clientAuth = authentication.getAuthorizationRequest();
|
AuthorizationRequest clientAuth = authentication.getAuthorizationRequest();
|
||||||
|
|
||||||
ClientDetailsEntity client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
ClientDetailsEntity client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
||||||
|
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
throw new InvalidClientException("Client not found: " + clientAuth.getClientId());
|
throw new InvalidClientException("Client not found: " + clientAuth.getClientId());
|
||||||
}
|
}
|
||||||
|
|
||||||
OAuth2AccessTokenEntity token = new OAuth2AccessTokenEntity();//accessTokenFactory.createNewAccessToken();
|
OAuth2AccessTokenEntity token = new OAuth2AccessTokenEntity();//accessTokenFactory.createNewAccessToken();
|
||||||
|
|
||||||
// attach the client
|
|
||||||
token.setClient(client);
|
|
||||||
|
|
||||||
// inherit the scope from the auth, but make a new set so it is
|
|
||||||
//not unmodifiable. Unmodifiables don't play nicely with Eclipselink, which
|
|
||||||
//wants to use the clone operation.
|
|
||||||
Set<String> scopes = Sets.newHashSet(clientAuth.getScope());
|
|
||||||
token.setScope(scopes);
|
|
||||||
|
|
||||||
// make it expire if necessary
|
// attach the client
|
||||||
if (client.getAccessTokenValiditySeconds() != null && client.getAccessTokenValiditySeconds() > 0) {
|
token.setClient(client);
|
||||||
Date expiration = new Date(System.currentTimeMillis() + (client.getAccessTokenValiditySeconds() * 1000L));
|
|
||||||
token.setExpiration(expiration);
|
|
||||||
}
|
|
||||||
|
|
||||||
// attach the authorization so that we can look it up later
|
|
||||||
AuthenticationHolderEntity authHolder = new AuthenticationHolderEntity();
|
|
||||||
authHolder.setAuthentication(authentication);
|
|
||||||
authHolder = authenticationHolderRepository.save(authHolder);
|
|
||||||
|
|
||||||
token.setAuthenticationHolder(authHolder);
|
|
||||||
|
|
||||||
// attach a refresh token, if this client is allowed to request them and the user gets the offline scope
|
|
||||||
// TODO: tie this to some kind of scope service
|
|
||||||
if (client.isAllowRefresh() && scopes.contains("offline_access")) {
|
|
||||||
OAuth2RefreshTokenEntity refreshToken = new OAuth2RefreshTokenEntity(); //refreshTokenFactory.createNewRefreshToken();
|
|
||||||
JWTClaimsSet refreshClaims = new JWTClaimsSet();
|
|
||||||
|
|
||||||
|
// inherit the scope from the auth, but make a new set so it is
|
||||||
// make it expire if necessary
|
//not unmodifiable. Unmodifiables don't play nicely with Eclipselink, which
|
||||||
if (client.getRefreshTokenValiditySeconds() != null) {
|
//wants to use the clone operation.
|
||||||
Date expiration = new Date(System.currentTimeMillis() + (client.getRefreshTokenValiditySeconds() * 1000L));
|
Set<String> scopes = Sets.newHashSet(clientAuth.getScope());
|
||||||
refreshToken.setExpiration(expiration);
|
token.setScope(scopes);
|
||||||
refreshClaims.setExpirationTime(expiration);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set a random identifier
|
|
||||||
refreshClaims.setJWTID(UUID.randomUUID().toString());
|
|
||||||
|
|
||||||
// TODO: add issuer fields, signature to JWT
|
// make it expire if necessary
|
||||||
|
if (client.getAccessTokenValiditySeconds() != null && client.getAccessTokenValiditySeconds() > 0) {
|
||||||
PlainJWT refreshJwt = new PlainJWT(refreshClaims);
|
Date expiration = new Date(System.currentTimeMillis() + (client.getAccessTokenValiditySeconds() * 1000L));
|
||||||
refreshToken.setJwt(refreshJwt);
|
token.setExpiration(expiration);
|
||||||
|
}
|
||||||
//Add the authentication
|
|
||||||
refreshToken.setAuthenticationHolder(authHolder);
|
|
||||||
refreshToken.setClient(client);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// save the token first so that we can set it to a member of the access token (NOTE: is this step necessary?)
|
|
||||||
tokenRepository.saveRefreshToken(refreshToken);
|
|
||||||
|
|
||||||
token.setRefreshToken(refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenEnhancer.enhance(token, authentication);
|
// attach the authorization so that we can look it up later
|
||||||
|
AuthenticationHolderEntity authHolder = new AuthenticationHolderEntity();
|
||||||
tokenRepository.saveAccessToken(token);
|
authHolder.setAuthentication(authentication);
|
||||||
|
authHolder = authenticationHolderRepository.save(authHolder);
|
||||||
if (token.getRefreshToken() != null) {
|
|
||||||
tokenRepository.saveRefreshToken(token.getRefreshToken()); // make sure we save any changes that might have been enhanced
|
token.setAuthenticationHolder(authHolder);
|
||||||
}
|
|
||||||
|
// attach a refresh token, if this client is allowed to request them and the user gets the offline scope
|
||||||
return token;
|
// TODO: tie this to some kind of scope service
|
||||||
|
if (client.isAllowRefresh() && scopes.contains("offline_access")) {
|
||||||
|
OAuth2RefreshTokenEntity refreshToken = new OAuth2RefreshTokenEntity(); //refreshTokenFactory.createNewRefreshToken();
|
||||||
|
JWTClaimsSet refreshClaims = new JWTClaimsSet();
|
||||||
|
|
||||||
|
|
||||||
|
// make it expire if necessary
|
||||||
|
if (client.getRefreshTokenValiditySeconds() != null) {
|
||||||
|
Date expiration = new Date(System.currentTimeMillis() + (client.getRefreshTokenValiditySeconds() * 1000L));
|
||||||
|
refreshToken.setExpiration(expiration);
|
||||||
|
refreshClaims.setExpirationTime(expiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set a random identifier
|
||||||
|
refreshClaims.setJWTID(UUID.randomUUID().toString());
|
||||||
|
|
||||||
|
// TODO: add issuer fields, signature to JWT
|
||||||
|
|
||||||
|
PlainJWT refreshJwt = new PlainJWT(refreshClaims);
|
||||||
|
refreshToken.setJwt(refreshJwt);
|
||||||
|
|
||||||
|
//Add the authentication
|
||||||
|
refreshToken.setAuthenticationHolder(authHolder);
|
||||||
|
refreshToken.setClient(client);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// save the token first so that we can set it to a member of the access token (NOTE: is this step necessary?)
|
||||||
|
tokenRepository.saveRefreshToken(refreshToken);
|
||||||
|
|
||||||
|
token.setRefreshToken(refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenEnhancer.enhance(token, authentication);
|
||||||
|
|
||||||
|
tokenRepository.saveAccessToken(token);
|
||||||
|
|
||||||
|
if (token.getRefreshToken() != null) {
|
||||||
|
tokenRepository.saveRefreshToken(token.getRefreshToken()); // make sure we save any changes that might have been enhanced
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new AuthenticationCredentialsNotFoundException("No authentication credentials found");
|
throw new AuthenticationCredentialsNotFoundException("No authentication credentials found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenEntity refreshAccessToken(String refreshTokenValue, AuthorizationRequest authRequest) throws AuthenticationException {
|
public OAuth2AccessTokenEntity refreshAccessToken(String refreshTokenValue, AuthorizationRequest authRequest) throws AuthenticationException {
|
||||||
|
|
||||||
OAuth2RefreshTokenEntity refreshToken = tokenRepository.getRefreshTokenByValue(refreshTokenValue);
|
OAuth2RefreshTokenEntity refreshToken = tokenRepository.getRefreshTokenByValue(refreshTokenValue);
|
||||||
|
|
||||||
if (refreshToken == null) {
|
if (refreshToken == null) {
|
||||||
throw new InvalidTokenException("Invalid refresh token: " + refreshTokenValue);
|
throw new InvalidTokenException("Invalid refresh token: " + refreshTokenValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientDetailsEntity client = refreshToken.getClient();
|
ClientDetailsEntity client = refreshToken.getClient();
|
||||||
|
|
||||||
AuthenticationHolderEntity authHolder = refreshToken.getAuthenticationHolder();
|
AuthenticationHolderEntity authHolder = refreshToken.getAuthenticationHolder();
|
||||||
|
|
||||||
//Make sure this client allows access token refreshing
|
//Make sure this client allows access token refreshing
|
||||||
if (!client.isAllowRefresh()) {
|
if (!client.isAllowRefresh()) {
|
||||||
throw new InvalidClientException("Client does not allow refreshing access token!");
|
throw new InvalidClientException("Client does not allow refreshing access token!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear out any access tokens
|
// clear out any access tokens
|
||||||
// TODO: make this a configurable option
|
// TODO: make this a configurable option
|
||||||
tokenRepository.clearAccessTokensForRefreshToken(refreshToken);
|
tokenRepository.clearAccessTokensForRefreshToken(refreshToken);
|
||||||
|
|
||||||
if (refreshToken.isExpired()) {
|
if (refreshToken.isExpired()) {
|
||||||
tokenRepository.removeRefreshToken(refreshToken);
|
tokenRepository.removeRefreshToken(refreshToken);
|
||||||
throw new InvalidTokenException("Expired refresh token: " + refreshTokenValue);
|
throw new InvalidTokenException("Expired refresh token: " + refreshTokenValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: have the option to recycle the refresh token here, too
|
// TODO: have the option to recycle the refresh token here, too
|
||||||
// for now, we just reuse it as long as it's valid, which is the original intent
|
// for now, we just reuse it as long as it's valid, which is the original intent
|
||||||
|
|
||||||
OAuth2AccessTokenEntity token = new OAuth2AccessTokenEntity();
|
OAuth2AccessTokenEntity token = new OAuth2AccessTokenEntity();
|
||||||
|
|
||||||
// get the stored scopes from the authentication holder's authorization request; these are the scopes associated with the refresh token
|
// get the stored scopes from the authentication holder's authorization request; these are the scopes associated with the refresh token
|
||||||
Set<String> refreshScopes = new HashSet<String>(refreshToken.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getScope());
|
Set<String> refreshScopes = new HashSet<String>(refreshToken.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getScope());
|
||||||
|
|
||||||
Set<String> scope = new HashSet<String>(authRequest.getScope());
|
Set<String> scope = new HashSet<String>(authRequest.getScope());
|
||||||
if (scope != null && !scope.isEmpty()) {
|
if (scope != null && !scope.isEmpty()) {
|
||||||
// ensure a proper subset of scopes
|
// ensure a proper subset of scopes
|
||||||
if (refreshScopes != null && refreshScopes.containsAll(scope)) {
|
if (refreshScopes != null && refreshScopes.containsAll(scope)) {
|
||||||
// set the scope of the new access token if requested
|
// set the scope of the new access token if requested
|
||||||
|
@ -211,189 +205,189 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
|
||||||
// otherwise inherit the scope of the refresh token (if it's there -- this can return a null scope set)
|
// otherwise inherit the scope of the refresh token (if it's there -- this can return a null scope set)
|
||||||
token.setScope(refreshScopes);
|
token.setScope(refreshScopes);
|
||||||
}
|
}
|
||||||
|
|
||||||
token.setClient(client);
|
|
||||||
|
|
||||||
if (client.getAccessTokenValiditySeconds() != null) {
|
|
||||||
Date expiration = new Date(System.currentTimeMillis() + (client.getAccessTokenValiditySeconds() * 1000L));
|
|
||||||
token.setExpiration(expiration);
|
|
||||||
}
|
|
||||||
|
|
||||||
token.setRefreshToken(refreshToken);
|
|
||||||
|
|
||||||
token.setAuthenticationHolder(authHolder);
|
|
||||||
|
|
||||||
tokenEnhancer.enhance(token, authHolder.getAuthentication());
|
token.setClient(client);
|
||||||
|
|
||||||
tokenRepository.saveAccessToken(token);
|
if (client.getAccessTokenValiditySeconds() != null) {
|
||||||
|
Date expiration = new Date(System.currentTimeMillis() + (client.getAccessTokenValiditySeconds() * 1000L));
|
||||||
return token;
|
token.setExpiration(expiration);
|
||||||
|
}
|
||||||
}
|
|
||||||
|
token.setRefreshToken(refreshToken);
|
||||||
|
|
||||||
|
token.setAuthenticationHolder(authHolder);
|
||||||
|
|
||||||
|
tokenEnhancer.enhance(token, authHolder.getAuthentication());
|
||||||
|
|
||||||
|
tokenRepository.saveAccessToken(token);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException {
|
public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException {
|
||||||
|
|
||||||
OAuth2AccessTokenEntity accessToken = tokenRepository.getAccessTokenByValue(accessTokenValue);
|
OAuth2AccessTokenEntity accessToken = tokenRepository.getAccessTokenByValue(accessTokenValue);
|
||||||
|
|
||||||
if (accessToken == null) {
|
if (accessToken == null) {
|
||||||
throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
|
throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessToken.isExpired()) {
|
if (accessToken.isExpired()) {
|
||||||
//tokenRepository.removeAccessToken(accessToken);
|
//tokenRepository.removeAccessToken(accessToken);
|
||||||
revokeAccessToken(accessToken);
|
revokeAccessToken(accessToken);
|
||||||
throw new InvalidTokenException("Expired access token: " + accessTokenValue);
|
throw new InvalidTokenException("Expired access token: " + accessTokenValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return accessToken.getAuthenticationHolder().getAuthentication();
|
return accessToken.getAuthenticationHolder().getAuthentication();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an access token from its token value.
|
* Get an access token from its token value.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenEntity readAccessToken(String accessTokenValue) throws AuthenticationException {
|
public OAuth2AccessTokenEntity readAccessToken(String accessTokenValue) throws AuthenticationException {
|
||||||
OAuth2AccessTokenEntity accessToken = tokenRepository.getAccessTokenByValue(accessTokenValue);
|
OAuth2AccessTokenEntity accessToken = tokenRepository.getAccessTokenByValue(accessTokenValue);
|
||||||
if (accessToken == null) {
|
if (accessToken == null) {
|
||||||
throw new InvalidTokenException("Access token for value " + accessTokenValue + " was not found");
|
throw new InvalidTokenException("Access token for value " + accessTokenValue + " was not found");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return accessToken;
|
return accessToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an access token by its authentication object.
|
* Get an access token by its authentication object.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenEntity getAccessToken(OAuth2Authentication authentication) {
|
public OAuth2AccessTokenEntity getAccessToken(OAuth2Authentication authentication) {
|
||||||
|
|
||||||
OAuth2AccessTokenEntity accessToken = tokenRepository.getByAuthentication(authentication);
|
OAuth2AccessTokenEntity accessToken = tokenRepository.getByAuthentication(authentication);
|
||||||
|
|
||||||
return accessToken;
|
return accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a refresh token by its token value.
|
* Get a refresh token by its token value.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public OAuth2RefreshTokenEntity getRefreshToken(String refreshTokenValue) throws AuthenticationException {
|
public OAuth2RefreshTokenEntity getRefreshToken(String refreshTokenValue) throws AuthenticationException {
|
||||||
OAuth2RefreshTokenEntity refreshToken = tokenRepository.getRefreshTokenByValue(refreshTokenValue);
|
OAuth2RefreshTokenEntity refreshToken = tokenRepository.getRefreshTokenByValue(refreshTokenValue);
|
||||||
if (refreshToken == null) {
|
if (refreshToken == null) {
|
||||||
throw new InvalidTokenException("Refresh token for value " + refreshTokenValue + " was not found");
|
throw new InvalidTokenException("Refresh token for value " + refreshTokenValue + " was not found");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return refreshToken;
|
return refreshToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revoke a refresh token and all access tokens issued to it.
|
* Revoke a refresh token and all access tokens issued to it.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void revokeRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
public void revokeRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||||
tokenRepository.clearAccessTokensForRefreshToken(refreshToken);
|
tokenRepository.clearAccessTokensForRefreshToken(refreshToken);
|
||||||
tokenRepository.removeRefreshToken(refreshToken);
|
tokenRepository.removeRefreshToken(refreshToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revoke an access token.
|
* Revoke an access token.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void revokeAccessToken(OAuth2AccessTokenEntity accessToken) {
|
public void revokeAccessToken(OAuth2AccessTokenEntity accessToken) {
|
||||||
tokenRepository.removeAccessToken(accessToken);
|
tokenRepository.removeAccessToken(accessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getAccessTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getAccessTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client) {
|
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client) {
|
||||||
return tokenRepository.getAccessTokensForClient(client);
|
return tokenRepository.getAccessTokensForClient(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getRefreshTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getRefreshTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client) {
|
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client) {
|
||||||
return tokenRepository.getRefreshTokensForClient(client);
|
return tokenRepository.getRefreshTokensForClient(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Scheduled(fixedRate = 5 * 60 * 1000) // schedule this task every five minutes
|
@Scheduled(fixedRate = 5 * 60 * 1000) // schedule this task every five minutes
|
||||||
public void clearExpiredTokens() {
|
public void clearExpiredTokens() {
|
||||||
logger.info("Cleaning out all expired tokens");
|
logger.info("Cleaning out all expired tokens");
|
||||||
|
|
||||||
List<OAuth2AccessTokenEntity> accessTokens = tokenRepository.getExpiredAccessTokens();
|
List<OAuth2AccessTokenEntity> accessTokens = tokenRepository.getExpiredAccessTokens();
|
||||||
logger.info("Found " + accessTokens.size() + " expired access tokens");
|
logger.info("Found " + accessTokens.size() + " expired access tokens");
|
||||||
for (OAuth2AccessTokenEntity oAuth2AccessTokenEntity : accessTokens) {
|
for (OAuth2AccessTokenEntity oAuth2AccessTokenEntity : accessTokens) {
|
||||||
revokeAccessToken(oAuth2AccessTokenEntity);
|
revokeAccessToken(oAuth2AccessTokenEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<OAuth2RefreshTokenEntity> refreshTokens = tokenRepository.getExpiredRefreshTokens();
|
List<OAuth2RefreshTokenEntity> refreshTokens = tokenRepository.getExpiredRefreshTokens();
|
||||||
logger.info("Found " + refreshTokens.size() + " expired refresh tokens");
|
logger.info("Found " + refreshTokens.size() + " expired refresh tokens");
|
||||||
for (OAuth2RefreshTokenEntity oAuth2RefreshTokenEntity : refreshTokens) {
|
for (OAuth2RefreshTokenEntity oAuth2RefreshTokenEntity : refreshTokens) {
|
||||||
revokeRefreshToken(oAuth2RefreshTokenEntity);
|
revokeRefreshToken(oAuth2RefreshTokenEntity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a builder object for this class (for tests)
|
* Get a builder object for this class (for tests)
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static DefaultOAuth2ProviderTokenServicesBuilder makeBuilder() {
|
public static DefaultOAuth2ProviderTokenServicesBuilder makeBuilder() {
|
||||||
return new DefaultOAuth2ProviderTokenServicesBuilder();
|
return new DefaultOAuth2ProviderTokenServicesBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder class for test harnesses.
|
* Builder class for test harnesses.
|
||||||
*/
|
*/
|
||||||
public static class DefaultOAuth2ProviderTokenServicesBuilder {
|
public static class DefaultOAuth2ProviderTokenServicesBuilder {
|
||||||
private DefaultOAuth2ProviderTokenService instance;
|
private DefaultOAuth2ProviderTokenService instance;
|
||||||
|
|
||||||
private DefaultOAuth2ProviderTokenServicesBuilder() {
|
private DefaultOAuth2ProviderTokenServicesBuilder() {
|
||||||
instance = new DefaultOAuth2ProviderTokenService();
|
instance = new DefaultOAuth2ProviderTokenService();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultOAuth2ProviderTokenServicesBuilder setTokenRepository(OAuth2TokenRepository tokenRepository) {
|
public DefaultOAuth2ProviderTokenServicesBuilder setTokenRepository(OAuth2TokenRepository tokenRepository) {
|
||||||
instance.tokenRepository = tokenRepository;
|
instance.tokenRepository = tokenRepository;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultOAuth2ProviderTokenServicesBuilder setClientDetailsService(ClientDetailsEntityService clientDetailsService) {
|
public DefaultOAuth2ProviderTokenServicesBuilder setClientDetailsService(ClientDetailsEntityService clientDetailsService) {
|
||||||
instance.clientDetailsService = clientDetailsService;
|
instance.clientDetailsService = clientDetailsService;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultOAuth2ProviderTokenServicesBuilder setTokenEnhancer(TokenEnhancer tokenEnhancer) {
|
public DefaultOAuth2ProviderTokenServicesBuilder setTokenEnhancer(TokenEnhancer tokenEnhancer) {
|
||||||
instance.tokenEnhancer = tokenEnhancer;
|
instance.tokenEnhancer = tokenEnhancer;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OAuth2TokenEntityService finish() {
|
public OAuth2TokenEntityService finish() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveAccessToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveAccessToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity accessToken) {
|
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity accessToken) {
|
||||||
return tokenRepository.saveAccessToken(accessToken);
|
return tokenRepository.saveAccessToken(accessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveRefreshToken(org.mitre.oauth2.model.OAuth2RefreshTokenEntity)
|
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveRefreshToken(org.mitre.oauth2.model.OAuth2RefreshTokenEntity)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||||
return tokenRepository.saveRefreshToken(refreshToken);
|
return tokenRepository.saveRefreshToken(refreshToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the tokenEnhancer
|
* @return the tokenEnhancer
|
||||||
|
@ -410,11 +404,11 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getAccessTokenForIdToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getAccessTokenForIdToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
|
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
|
||||||
return tokenRepository.getAccessTokenForIdToken(idToken);
|
return tokenRepository.getAccessTokenForIdToken(idToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,132 +27,132 @@ public class DefaultSystemScopeService implements SystemScopeService {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SystemScopeRepository repository;
|
private SystemScopeRepository repository;
|
||||||
|
|
||||||
private Predicate<SystemScope> isDefault = new Predicate<SystemScope>() {
|
private Predicate<SystemScope> isDefault = new Predicate<SystemScope>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(SystemScope input) {
|
public boolean apply(SystemScope input) {
|
||||||
return (input != null && input.isDefaultScope());
|
return (input != null && input.isDefaultScope());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private Predicate<SystemScope> isDynReg = new Predicate<SystemScope>() {
|
private Predicate<SystemScope> isDynReg = new Predicate<SystemScope>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(SystemScope input) {
|
public boolean apply(SystemScope input) {
|
||||||
return (input != null && input.isAllowDynReg());
|
return (input != null && input.isAllowDynReg());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private Function<String, SystemScope> stringToSystemScope = new Function<String, SystemScope>() {
|
private Function<String, SystemScope> stringToSystemScope = new Function<String, SystemScope>() {
|
||||||
@Override
|
@Override
|
||||||
public SystemScope apply(String input) {
|
public SystemScope apply(String input) {
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
SystemScope s = getByValue(input);
|
SystemScope s = getByValue(input);
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
// get the real scope if it's available
|
// get the real scope if it's available
|
||||||
return s;
|
return s;
|
||||||
} else {
|
} else {
|
||||||
// make a fake one otherwise
|
// make a fake one otherwise
|
||||||
return new SystemScope(input);
|
return new SystemScope(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private Function<SystemScope, String> systemScopeToString = new Function<SystemScope, String>() {
|
private Function<SystemScope, String> systemScopeToString = new Function<SystemScope, String>() {
|
||||||
@Override
|
@Override
|
||||||
public String apply(SystemScope input) {
|
public String apply(SystemScope input) {
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return input.getValue();
|
return input.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.SystemScopeService#getAll()
|
* @see org.mitre.oauth2.service.SystemScopeService#getAll()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<SystemScope> getAll() {
|
public Set<SystemScope> getAll() {
|
||||||
return repository.getAll();
|
return repository.getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.SystemScopeService#getDefaults()
|
* @see org.mitre.oauth2.service.SystemScopeService#getDefaults()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<SystemScope> getDefaults() {
|
public Set<SystemScope> getDefaults() {
|
||||||
return Sets.filter(getAll(), isDefault);
|
return Sets.filter(getAll(), isDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.SystemScopeService#getDynReg()
|
* @see org.mitre.oauth2.service.SystemScopeService#getDynReg()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<SystemScope> getDynReg() {
|
public Set<SystemScope> getDynReg() {
|
||||||
return Sets.filter(getAll(), isDynReg);
|
return Sets.filter(getAll(), isDynReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.SystemScopeService#getById(java.lang.Long)
|
* @see org.mitre.oauth2.service.SystemScopeService#getById(java.lang.Long)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SystemScope getById(Long id) {
|
public SystemScope getById(Long id) {
|
||||||
return repository.getById(id);
|
return repository.getById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.SystemScopeService#getByValue(java.lang.String)
|
* @see org.mitre.oauth2.service.SystemScopeService#getByValue(java.lang.String)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SystemScope getByValue(String value) {
|
public SystemScope getByValue(String value) {
|
||||||
return repository.getByValue(value);
|
return repository.getByValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.SystemScopeService#remove(org.mitre.oauth2.model.SystemScope)
|
* @see org.mitre.oauth2.service.SystemScopeService#remove(org.mitre.oauth2.model.SystemScope)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void remove(SystemScope scope) {
|
public void remove(SystemScope scope) {
|
||||||
repository.remove(scope);
|
repository.remove(scope);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.SystemScopeService#save(org.mitre.oauth2.model.SystemScope)
|
* @see org.mitre.oauth2.service.SystemScopeService#save(org.mitre.oauth2.model.SystemScope)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SystemScope save(SystemScope scope) {
|
public SystemScope save(SystemScope scope) {
|
||||||
return repository.save(scope);
|
return repository.save(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.SystemScopeService#fromStrings(java.util.Set)
|
* @see org.mitre.oauth2.service.SystemScopeService#fromStrings(java.util.Set)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<SystemScope> fromStrings(Set<String> scope) {
|
public Set<SystemScope> fromStrings(Set<String> scope) {
|
||||||
if (scope == null) {
|
if (scope == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return new LinkedHashSet<SystemScope>(Collections2.filter(Collections2.transform(scope, stringToSystemScope), Predicates.notNull()));
|
return new LinkedHashSet<SystemScope>(Collections2.filter(Collections2.transform(scope, stringToSystemScope), Predicates.notNull()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.SystemScopeService#toStrings(java.util.Set)
|
* @see org.mitre.oauth2.service.SystemScopeService#toStrings(java.util.Set)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> toStrings(Set<SystemScope> scope) {
|
public Set<String> toStrings(Set<SystemScope> scope) {
|
||||||
if (scope == null) {
|
if (scope == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return new LinkedHashSet<String>(Collections2.filter(Collections2.transform(scope, systemScopeToString), Predicates.notNull()));
|
return new LinkedHashSet<String>(Collections2.filter(Collections2.transform(scope, systemScopeToString), Predicates.notNull()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class ChainedTokenGranter extends AbstractTokenGranter {
|
||||||
|
|
||||||
// keep down-cast versions so we can get to the right queries
|
// keep down-cast versions so we can get to the right queries
|
||||||
private OAuth2TokenEntityService tokenServices;
|
private OAuth2TokenEntityService tokenServices;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tokenServices
|
* @param tokenServices
|
||||||
* @param clientDetailsService
|
* @param clientDetailsService
|
||||||
|
@ -46,55 +46,55 @@ public class ChainedTokenGranter extends AbstractTokenGranter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest authorizationRequest) throws AuthenticationException, InvalidTokenException {
|
protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest authorizationRequest) throws AuthenticationException, InvalidTokenException {
|
||||||
// read and load up the existing token
|
// read and load up the existing token
|
||||||
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("token");
|
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("token");
|
||||||
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
||||||
|
|
||||||
// check for scoping in the request, can't up-scope with a chained request
|
|
||||||
Set<String> approvedScopes = incomingToken.getScope();
|
|
||||||
Set<String> requestedScopes = authorizationRequest.getScope();
|
|
||||||
|
|
||||||
if (requestedScopes == null) {
|
|
||||||
requestedScopes = new HashSet<String>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// do a check on the requested scopes -- if they exactly match the client scopes, they were probably shadowed by the token granter
|
|
||||||
// FIXME: bug in SECOAUTH functionality
|
|
||||||
ClientDetailsEntity client = incomingToken.getClient();
|
|
||||||
if (client.getScope().equals(requestedScopes)) {
|
|
||||||
requestedScopes = new HashSet<String>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if our scopes are a valid subset of what's allowed, we can continue
|
|
||||||
if (approvedScopes.containsAll(requestedScopes)) {
|
|
||||||
|
|
||||||
// build an appropriate auth request to hand to the token services layer
|
// check for scoping in the request, can't up-scope with a chained request
|
||||||
DefaultAuthorizationRequest outgoingAuthRequest = new DefaultAuthorizationRequest(authorizationRequest);
|
Set<String> approvedScopes = incomingToken.getScope();
|
||||||
outgoingAuthRequest.setApproved(true);
|
Set<String> requestedScopes = authorizationRequest.getScope();
|
||||||
if (requestedScopes.isEmpty()) {
|
|
||||||
// if there are no scopes, inherit the original scopes from the token
|
if (requestedScopes == null) {
|
||||||
outgoingAuthRequest.setScope(approvedScopes);
|
requestedScopes = new HashSet<String>();
|
||||||
} else {
|
}
|
||||||
// if scopes were asked for, give only the subset of scopes requested
|
|
||||||
// this allows safe downscoping
|
// do a check on the requested scopes -- if they exactly match the client scopes, they were probably shadowed by the token granter
|
||||||
outgoingAuthRequest.setScope(Sets.intersection(requestedScopes, approvedScopes));
|
// FIXME: bug in SECOAUTH functionality
|
||||||
}
|
ClientDetailsEntity client = incomingToken.getClient();
|
||||||
|
if (client.getScope().equals(requestedScopes)) {
|
||||||
// NOTE: don't revoke the existing access token
|
requestedScopes = new HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if our scopes are a valid subset of what's allowed, we can continue
|
||||||
|
if (approvedScopes.containsAll(requestedScopes)) {
|
||||||
|
|
||||||
|
// build an appropriate auth request to hand to the token services layer
|
||||||
|
DefaultAuthorizationRequest outgoingAuthRequest = new DefaultAuthorizationRequest(authorizationRequest);
|
||||||
|
outgoingAuthRequest.setApproved(true);
|
||||||
|
if (requestedScopes.isEmpty()) {
|
||||||
|
// if there are no scopes, inherit the original scopes from the token
|
||||||
|
outgoingAuthRequest.setScope(approvedScopes);
|
||||||
|
} else {
|
||||||
|
// if scopes were asked for, give only the subset of scopes requested
|
||||||
|
// this allows safe downscoping
|
||||||
|
outgoingAuthRequest.setScope(Sets.intersection(requestedScopes, approvedScopes));
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: don't revoke the existing access token
|
||||||
|
|
||||||
|
// create a new access token
|
||||||
|
OAuth2Authentication authentication = new OAuth2Authentication(outgoingAuthRequest, incomingToken.getAuthenticationHolder().getAuthentication().getUserAuthentication());
|
||||||
|
|
||||||
|
return authentication;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new InvalidScopeException("Invalid scope requested in chained request", approvedScopes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// create a new access token
|
|
||||||
OAuth2Authentication authentication = new OAuth2Authentication(outgoingAuthRequest, incomingToken.getAuthenticationHolder().getAuthentication().getUserAuthentication());
|
|
||||||
|
|
||||||
return authentication;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new InvalidScopeException("Invalid scope requested in chained request", approvedScopes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
*/
|
*/
|
||||||
package org.mitre.oauth2.token;
|
package org.mitre.oauth2.token;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
@ -39,118 +38,118 @@ public class JwtAssertionTokenGranter extends AbstractTokenGranter {
|
||||||
|
|
||||||
// keep down-cast versions so we can get to the right queries
|
// keep down-cast versions so we can get to the right queries
|
||||||
private OAuth2TokenEntityService tokenServices;
|
private OAuth2TokenEntityService tokenServices;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JwtSigningAndValidationService jwtService;
|
private JwtSigningAndValidationService jwtService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ConfigurationPropertiesBean config;
|
private ConfigurationPropertiesBean config;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public JwtAssertionTokenGranter(OAuth2TokenEntityService tokenServices, ClientDetailsEntityService clientDetailsService) {
|
public JwtAssertionTokenGranter(OAuth2TokenEntityService tokenServices, ClientDetailsEntityService clientDetailsService) {
|
||||||
super(tokenServices, clientDetailsService, grantType);
|
super(tokenServices, clientDetailsService, grantType);
|
||||||
this.tokenServices = tokenServices;
|
this.tokenServices = tokenServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected OAuth2AccessToken getAccessToken(AuthorizationRequest authorizationRequest) throws AuthenticationException, InvalidTokenException {
|
protected OAuth2AccessToken getAccessToken(AuthorizationRequest authorizationRequest) throws AuthenticationException, InvalidTokenException {
|
||||||
// read and load up the existing token
|
// read and load up the existing token
|
||||||
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("assertion");
|
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("assertion");
|
||||||
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
||||||
|
|
||||||
ClientDetailsEntity client = incomingToken.getClient();
|
|
||||||
|
|
||||||
|
ClientDetailsEntity client = incomingToken.getClient();
|
||||||
if (incomingToken.getScope().contains(OAuth2AccessTokenEntity.ID_TOKEN_SCOPE)) {
|
|
||||||
|
|
||||||
if (!client.getClientId().equals(authorizationRequest.getClientId())) {
|
|
||||||
throw new InvalidClientException("Not the right client for this token");
|
|
||||||
}
|
|
||||||
|
|
||||||
// it's an ID token, process it accordingly
|
|
||||||
|
if (incomingToken.getScope().contains(OAuth2AccessTokenEntity.ID_TOKEN_SCOPE)) {
|
||||||
try {
|
|
||||||
|
if (!client.getClientId().equals(authorizationRequest.getClientId())) {
|
||||||
// TODO: make this use a more specific idtoken class
|
throw new InvalidClientException("Not the right client for this token");
|
||||||
JWT idToken = JWTParser.parse(incomingTokenValue);
|
}
|
||||||
|
|
||||||
OAuth2AccessTokenEntity accessToken = tokenServices.getAccessTokenForIdToken(incomingToken);
|
// it's an ID token, process it accordingly
|
||||||
|
|
||||||
if (accessToken != null) {
|
try {
|
||||||
|
|
||||||
//OAuth2AccessTokenEntity newIdToken = tokenServices.get
|
// TODO: make this use a more specific idtoken class
|
||||||
|
JWT idToken = JWTParser.parse(incomingTokenValue);
|
||||||
OAuth2AccessTokenEntity newIdTokenEntity = new OAuth2AccessTokenEntity();
|
|
||||||
|
OAuth2AccessTokenEntity accessToken = tokenServices.getAccessTokenForIdToken(incomingToken);
|
||||||
// copy over all existing claims
|
|
||||||
JWTClaimsSet claims = new JWTClaimsSet(idToken.getJWTClaimsSet());
|
if (accessToken != null) {
|
||||||
|
|
||||||
// update expiration and issued-at claims
|
//OAuth2AccessTokenEntity newIdToken = tokenServices.get
|
||||||
|
|
||||||
|
OAuth2AccessTokenEntity newIdTokenEntity = new OAuth2AccessTokenEntity();
|
||||||
|
|
||||||
|
// copy over all existing claims
|
||||||
|
JWTClaimsSet claims = new JWTClaimsSet(idToken.getJWTClaimsSet());
|
||||||
|
|
||||||
|
// update expiration and issued-at claims
|
||||||
if (client.getIdTokenValiditySeconds() != null) {
|
if (client.getIdTokenValiditySeconds() != null) {
|
||||||
Date expiration = new Date(System.currentTimeMillis() + (client.getIdTokenValiditySeconds() * 1000L));
|
Date expiration = new Date(System.currentTimeMillis() + (client.getIdTokenValiditySeconds() * 1000L));
|
||||||
claims.setExpirationTime(expiration);
|
claims.setExpirationTime(expiration);
|
||||||
newIdTokenEntity.setExpiration(expiration);
|
newIdTokenEntity.setExpiration(expiration);
|
||||||
}
|
}
|
||||||
claims.setIssueTime(new Date());
|
claims.setIssueTime(new Date());
|
||||||
|
|
||||||
|
|
||||||
SignedJWT newIdToken = new SignedJWT((JWSHeader) idToken.getHeader(), claims);
|
SignedJWT newIdToken = new SignedJWT((JWSHeader) idToken.getHeader(), claims);
|
||||||
jwtService.signJwt(newIdToken);
|
jwtService.signJwt(newIdToken);
|
||||||
|
|
||||||
newIdTokenEntity.setJwt(newIdToken);
|
newIdTokenEntity.setJwt(newIdToken);
|
||||||
newIdTokenEntity.setAuthenticationHolder(incomingToken.getAuthenticationHolder());
|
newIdTokenEntity.setAuthenticationHolder(incomingToken.getAuthenticationHolder());
|
||||||
newIdTokenEntity.setScope(incomingToken.getScope());
|
newIdTokenEntity.setScope(incomingToken.getScope());
|
||||||
newIdTokenEntity.setClient(incomingToken.getClient());
|
newIdTokenEntity.setClient(incomingToken.getClient());
|
||||||
|
|
||||||
newIdTokenEntity = tokenServices.saveAccessToken(newIdTokenEntity);
|
newIdTokenEntity = tokenServices.saveAccessToken(newIdTokenEntity);
|
||||||
|
|
||||||
// attach the ID token to the access token entity
|
// attach the ID token to the access token entity
|
||||||
accessToken.setIdToken(newIdTokenEntity);
|
accessToken.setIdToken(newIdTokenEntity);
|
||||||
accessToken = tokenServices.saveAccessToken(accessToken);
|
accessToken = tokenServices.saveAccessToken(accessToken);
|
||||||
|
|
||||||
// delete the old ID token
|
// delete the old ID token
|
||||||
tokenServices.revokeAccessToken(incomingToken);
|
tokenServices.revokeAccessToken(incomingToken);
|
||||||
|
|
||||||
return newIdTokenEntity;
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (ParseException e) {
|
|
||||||
logger.warn("Couldn't parse id token", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we got down here, we didn't actually create any tokens, so return null
|
|
||||||
|
|
||||||
return null;
|
|
||||||
|
|
||||||
/*
|
return newIdTokenEntity;
|
||||||
* Otherwise, process it like an access token assertion ... which we don't support yet so this is all commented out
|
|
||||||
* /
|
}
|
||||||
|
} catch (ParseException e) {
|
||||||
|
logger.warn("Couldn't parse id token", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we got down here, we didn't actually create any tokens, so return null
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Otherwise, process it like an access token assertion ... which we don't support yet so this is all commented out
|
||||||
|
* /
|
||||||
if (jwtService.validateSignature(incomingTokenValue)) {
|
if (jwtService.validateSignature(incomingTokenValue)) {
|
||||||
|
|
||||||
Jwt jwt = Jwt.parse(incomingTokenValue);
|
Jwt jwt = Jwt.parse(incomingTokenValue);
|
||||||
|
|
||||||
|
|
||||||
if (oldToken.getScope().contains("id-token")) {
|
if (oldToken.getScope().contains("id-token")) {
|
||||||
// TODO: things
|
// TODO: things
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should any of these throw an exception instead of returning null?
|
// TODO: should any of these throw an exception instead of returning null?
|
||||||
JwtClaims claims = jwt.getClaims();
|
JwtClaims claims = jwt.getClaims();
|
||||||
if (!config.getIssuer().equals(claims.getIssuer())) {
|
if (!config.getIssuer().equals(claims.getIssuer())) {
|
||||||
// issuer isn't us
|
// issuer isn't us
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!authorizationRequest.getClientId().equals(claims.getAudience())) {
|
if (!authorizationRequest.getClientId().equals(claims.getAudience())) {
|
||||||
// audience isn't the client
|
// audience isn't the client
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
if (!now.after(claims.getExpiration())) {
|
if (!now.after(claims.getExpiration())) {
|
||||||
// token is expired
|
// token is expired
|
||||||
|
@ -164,14 +163,14 @@ public class JwtAssertionTokenGranter extends AbstractTokenGranter {
|
||||||
// we might need new calls on the token services layer to handle this, and we might
|
// we might need new calls on the token services layer to handle this, and we might
|
||||||
// need to handle id tokens separately.
|
// need to handle id tokens separately.
|
||||||
return new OAuth2Authentication(authorizationRequest, null);
|
return new OAuth2Authentication(authorizationRequest, null);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return null; // throw error??
|
return null; // throw error??
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,11 +43,11 @@ import com.google.gson.JsonSerializer;
|
||||||
|
|
||||||
@Component("tokenIntrospection")
|
@Component("tokenIntrospection")
|
||||||
public class TokenIntrospectionView extends AbstractView {
|
public class TokenIntrospectionView extends AbstractView {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(TokenIntrospectionView.class);
|
private static Logger logger = LoggerFactory.getLogger(TokenIntrospectionView.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
|
||||||
Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
|
Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ public class TokenIntrospectionView extends AbstractView {
|
||||||
// serialize other classes without filter (lists and sets and things)
|
// serialize other classes without filter (lists and sets and things)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,28 +84,29 @@ public class TokenIntrospectionView extends AbstractView {
|
||||||
|
|
||||||
})
|
})
|
||||||
.registerTypeAdapter(OAuth2AccessTokenEntity.class, new JsonSerializer<OAuth2AccessTokenEntity>() {
|
.registerTypeAdapter(OAuth2AccessTokenEntity.class, new JsonSerializer<OAuth2AccessTokenEntity>() {
|
||||||
public JsonElement serialize(OAuth2AccessTokenEntity src, Type typeOfSrc, JsonSerializationContext context) {
|
@Override
|
||||||
JsonObject token = new JsonObject();
|
public JsonElement serialize(OAuth2AccessTokenEntity src, Type typeOfSrc, JsonSerializationContext context) {
|
||||||
|
JsonObject token = new JsonObject();
|
||||||
token.addProperty("valid", true);
|
|
||||||
|
token.addProperty("valid", true);
|
||||||
JsonArray scopes = new JsonArray();
|
|
||||||
for (String scope : src.getScope()) {
|
JsonArray scopes = new JsonArray();
|
||||||
scopes.add(new JsonPrimitive(scope));
|
for (String scope : src.getScope()) {
|
||||||
}
|
scopes.add(new JsonPrimitive(scope));
|
||||||
token.add("scope", scopes);
|
}
|
||||||
|
token.add("scope", scopes);
|
||||||
token.add("expires_at", context.serialize(src.getExpiration()));
|
|
||||||
|
token.add("expires_at", context.serialize(src.getExpiration()));
|
||||||
//token.addProperty("audience", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
|
|
||||||
|
//token.addProperty("audience", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
|
||||||
token.addProperty("subject", src.getAuthenticationHolder().getAuthentication().getName());
|
|
||||||
|
token.addProperty("subject", src.getAuthenticationHolder().getAuthentication().getName());
|
||||||
token.addProperty("client_id", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
|
|
||||||
|
token.addProperty("client_id", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
|
||||||
return token;
|
|
||||||
}
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||||
.create();
|
.create();
|
||||||
|
@ -113,9 +114,9 @@ public class TokenIntrospectionView extends AbstractView {
|
||||||
response.setContentType("application/json");
|
response.setContentType("application/json");
|
||||||
|
|
||||||
Writer out;
|
Writer out;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
out = response.getWriter();
|
out = response.getWriter();
|
||||||
Object obj = model.get("entity");
|
Object obj = model.get("entity");
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
|
@ -123,13 +124,13 @@ public class TokenIntrospectionView extends AbstractView {
|
||||||
}
|
}
|
||||||
|
|
||||||
gson.toJson(obj, out);
|
gson.toJson(obj, out);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
||||||
logger.error("IOException occurred in TokenIntrospectionView.java: ", e);
|
logger.error("IOException occurred in TokenIntrospectionView.java: ", e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
package org.mitre.oauth2.web;
|
package org.mitre.oauth2.web;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||||
|
@ -28,14 +27,11 @@ import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -45,53 +41,53 @@ public class IntrospectionEndpoint {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private OAuth2TokenEntityService tokenServices;
|
private OAuth2TokenEntityService tokenServices;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ClientDetailsEntityService clientService;
|
private ClientDetailsEntityService clientService;
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(IntrospectionEndpoint.class);
|
private static Logger logger = LoggerFactory.getLogger(IntrospectionEndpoint.class);
|
||||||
|
|
||||||
public IntrospectionEndpoint() {
|
public IntrospectionEndpoint() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntrospectionEndpoint(OAuth2TokenEntityService tokenServices) {
|
public IntrospectionEndpoint(OAuth2TokenEntityService tokenServices) {
|
||||||
this.tokenServices = tokenServices;
|
this.tokenServices = tokenServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasRole('ROLE_CLIENT')")
|
@PreAuthorize("hasRole('ROLE_CLIENT')")
|
||||||
@RequestMapping("/introspect")
|
@RequestMapping("/introspect")
|
||||||
public String verify(@RequestParam("token") String tokenValue, Principal p, Model model) {
|
public String verify(@RequestParam("token") String tokenValue, Principal p, Model model) {
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(tokenValue)) {
|
if (Strings.isNullOrEmpty(tokenValue)) {
|
||||||
logger.error("Verify failed; token value is null");
|
logger.error("Verify failed; token value is null");
|
||||||
Map<String,Boolean> entity = ImmutableMap.of("valid", Boolean.FALSE);
|
Map<String,Boolean> entity = ImmutableMap.of("valid", Boolean.FALSE);
|
||||||
model.addAttribute("entity", entity);
|
model.addAttribute("entity", entity);
|
||||||
return "jsonEntityView";
|
return "jsonEntityView";
|
||||||
}
|
}
|
||||||
|
|
||||||
OAuth2AccessTokenEntity token = null;
|
OAuth2AccessTokenEntity token = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
token = tokenServices.readAccessToken(tokenValue);
|
token = tokenServices.readAccessToken(tokenValue);
|
||||||
} catch (InvalidTokenException e) {
|
} catch (InvalidTokenException e) {
|
||||||
logger.error("Verify failed; AuthenticationException: " + e.getStackTrace().toString());
|
logger.error("Verify failed; AuthenticationException: " + e.getStackTrace().toString());
|
||||||
Map<String,Boolean> entity = ImmutableMap.of("valid", Boolean.FALSE);
|
Map<String,Boolean> entity = ImmutableMap.of("valid", Boolean.FALSE);
|
||||||
model.addAttribute("entity", entity);
|
model.addAttribute("entity", entity);
|
||||||
return "jsonEntityView";
|
return "jsonEntityView";
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientDetailsEntity tokenClient = token.getClient();
|
ClientDetailsEntity tokenClient = token.getClient();
|
||||||
// clientID is the principal name in the authentication
|
// clientID is the principal name in the authentication
|
||||||
String clientId = p.getName();
|
String clientId = p.getName();
|
||||||
ClientDetailsEntity authClient = clientService.loadClientByClientId(clientId);
|
ClientDetailsEntity authClient = clientService.loadClientByClientId(clientId);
|
||||||
|
|
||||||
if (tokenClient != null && authClient != null) {
|
if (tokenClient != null && authClient != null) {
|
||||||
if (authClient.isAllowIntrospection()) {
|
if (authClient.isAllowIntrospection()) {
|
||||||
|
|
||||||
// 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 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 (authClient.equals(tokenClient) || authClient.getScope().containsAll(token.getScope())) {
|
||||||
|
|
||||||
// if it's a valid token, we'll print out information on it
|
// if it's a valid token, we'll print out information on it
|
||||||
model.addAttribute("entity", token);
|
model.addAttribute("entity", token);
|
||||||
return "tokenIntrospection";
|
return "tokenIntrospection";
|
||||||
|
@ -111,7 +107,7 @@ public class IntrospectionEndpoint {
|
||||||
model.addAttribute("code", HttpStatus.NOT_FOUND);
|
model.addAttribute("code", HttpStatus.NOT_FOUND);
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
@ -51,20 +50,20 @@ public class OAuthConfirmationController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ClientDetailsEntityService clientService;
|
private ClientDetailsEntityService clientService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SystemScopeService scopeService;
|
private SystemScopeService scopeService;
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(OAuthConfirmationController.class);
|
private static Logger logger = LoggerFactory.getLogger(OAuthConfirmationController.class);
|
||||||
|
|
||||||
public OAuthConfirmationController() {
|
public OAuthConfirmationController() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OAuthConfirmationController(ClientDetailsEntityService clientService) {
|
public OAuthConfirmationController(ClientDetailsEntityService clientService) {
|
||||||
this.clientService = clientService;
|
this.clientService = clientService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasRole('ROLE_USER')")
|
@PreAuthorize("hasRole('ROLE_USER')")
|
||||||
@RequestMapping("/oauth/confirm_access")
|
@RequestMapping("/oauth/confirm_access")
|
||||||
public String confimAccess(Map<String, Object> model, @ModelAttribute("authorizationRequest") AuthorizationRequest clientAuth) {
|
public String confimAccess(Map<String, Object> model, @ModelAttribute("authorizationRequest") AuthorizationRequest clientAuth) {
|
||||||
|
@ -77,14 +76,14 @@ public class OAuthConfirmationController {
|
||||||
model.put("code", HttpStatus.FORBIDDEN);
|
model.put("code", HttpStatus.FORBIDDEN);
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthorizationRequest clientAuth = (AuthorizationRequest) model.remove("authorizationRequest");
|
//AuthorizationRequest clientAuth = (AuthorizationRequest) model.remove("authorizationRequest");
|
||||||
|
|
||||||
ClientDetails client = null;
|
ClientDetails client = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
client = clientService.loadClientByClientId(clientAuth.getClientId());
|
client = clientService.loadClientByClientId(clientAuth.getClientId());
|
||||||
} catch (OAuth2Exception e) {
|
} catch (OAuth2Exception e) {
|
||||||
logger.error("confirmAccess: OAuth2Exception was thrown when attempting to load client: "
|
logger.error("confirmAccess: OAuth2Exception was thrown when attempting to load client: "
|
||||||
+ e.getStackTrace().toString());
|
+ e.getStackTrace().toString());
|
||||||
model.put("code", HttpStatus.BAD_REQUEST);
|
model.put("code", HttpStatus.BAD_REQUEST);
|
||||||
|
@ -95,7 +94,7 @@ public class OAuthConfirmationController {
|
||||||
model.put("code", HttpStatus.BAD_REQUEST);
|
model.put("code", HttpStatus.BAD_REQUEST);
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
logger.error("confirmAccess: could not find client " + clientAuth.getClientId());
|
logger.error("confirmAccess: could not find client " + clientAuth.getClientId());
|
||||||
model.put("code", HttpStatus.NOT_FOUND);
|
model.put("code", HttpStatus.NOT_FOUND);
|
||||||
|
@ -106,41 +105,41 @@ public class OAuthConfirmationController {
|
||||||
model.put("client", client);
|
model.put("client", client);
|
||||||
|
|
||||||
String redirect_uri = clientAuth.getAuthorizationParameters().get("redirect_uri");
|
String redirect_uri = clientAuth.getAuthorizationParameters().get("redirect_uri");
|
||||||
|
|
||||||
model.put("redirect_uri", redirect_uri);
|
model.put("redirect_uri", redirect_uri);
|
||||||
|
|
||||||
Set<SystemScope> scopes = scopeService.fromStrings(clientAuth.getScope());
|
Set<SystemScope> scopes = scopeService.fromStrings(clientAuth.getScope());
|
||||||
|
|
||||||
Set<SystemScope> sortedScopes = new LinkedHashSet<SystemScope>(scopes.size());
|
Set<SystemScope> sortedScopes = new LinkedHashSet<SystemScope>(scopes.size());
|
||||||
Set<SystemScope> systemScopes = scopeService.getAll();
|
Set<SystemScope> systemScopes = scopeService.getAll();
|
||||||
|
|
||||||
// sort scopes for display
|
// sort scopes for display
|
||||||
for (SystemScope s : systemScopes) {
|
for (SystemScope s : systemScopes) {
|
||||||
if (scopes.contains(s)) {
|
if (scopes.contains(s)) {
|
||||||
sortedScopes.add(s);
|
sortedScopes.add(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sortedScopes.addAll(Sets.difference(scopes, systemScopes));
|
sortedScopes.addAll(Sets.difference(scopes, systemScopes));
|
||||||
|
|
||||||
model.put("scopes", sortedScopes);
|
model.put("scopes", sortedScopes);
|
||||||
|
|
||||||
return "approve";
|
return "approve";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the clientService
|
* @return the clientService
|
||||||
*/
|
*/
|
||||||
public ClientDetailsEntityService getClientService() {
|
public ClientDetailsEntityService getClientService() {
|
||||||
return clientService;
|
return clientService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param clientService the clientService to set
|
* @param clientService the clientService to set
|
||||||
*/
|
*/
|
||||||
public void setClientService(ClientDetailsEntityService clientService) {
|
public void setClientService(ClientDetailsEntityService clientService) {
|
||||||
this.clientService = clientService;
|
this.clientService = clientService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ package org.mitre.oauth2.web;
|
||||||
|
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
|
||||||
import org.mitre.oauth2.exception.PermissionDeniedException;
|
|
||||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||||
|
@ -26,7 +25,6 @@ import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
|
@ -34,19 +32,18 @@ import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class RevocationEndpoint {
|
public class RevocationEndpoint {
|
||||||
@Autowired
|
@Autowired
|
||||||
OAuth2TokenEntityService tokenServices;
|
OAuth2TokenEntityService tokenServices;
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(RevocationEndpoint.class);
|
private static Logger logger = LoggerFactory.getLogger(RevocationEndpoint.class);
|
||||||
|
|
||||||
public RevocationEndpoint() {
|
public RevocationEndpoint() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
|
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
|
||||||
@RequestMapping("/revoke")
|
@RequestMapping("/revoke")
|
||||||
|
@ -54,16 +51,16 @@ public class RevocationEndpoint {
|
||||||
|
|
||||||
// This is the token as passed in from OAuth (in case we need it some day)
|
// This is the token as passed in from OAuth (in case we need it some day)
|
||||||
//OAuth2AccessTokenEntity tok = tokenServices.getAccessToken((OAuth2Authentication) principal);
|
//OAuth2AccessTokenEntity tok = tokenServices.getAccessToken((OAuth2Authentication) principal);
|
||||||
|
|
||||||
AuthorizationRequest clientAuth = null;
|
AuthorizationRequest clientAuth = null;
|
||||||
if (principal instanceof OAuth2Authentication) {
|
if (principal instanceof OAuth2Authentication) {
|
||||||
// if the client is acting on its own behalf (the common case), pull out the client authorization request
|
// if the client is acting on its own behalf (the common case), pull out the client authorization request
|
||||||
clientAuth = ((OAuth2Authentication) principal).getAuthorizationRequest();
|
clientAuth = ((OAuth2Authentication) principal).getAuthorizationRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// check and handle access tokens first
|
// check and handle access tokens first
|
||||||
|
|
||||||
OAuth2AccessTokenEntity accessToken = tokenServices.readAccessToken(tokenValue);
|
OAuth2AccessTokenEntity accessToken = tokenServices.readAccessToken(tokenValue);
|
||||||
if (clientAuth != null) {
|
if (clientAuth != null) {
|
||||||
// client acting on its own, make sure it owns the token
|
// client acting on its own, make sure it owns the token
|
||||||
|
@ -72,17 +69,17 @@ public class RevocationEndpoint {
|
||||||
model.addAttribute("code", HttpStatus.FORBIDDEN);
|
model.addAttribute("code", HttpStatus.FORBIDDEN);
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we got this far, we're allowed to do this
|
// if we got this far, we're allowed to do this
|
||||||
tokenServices.revokeAccessToken(accessToken);
|
tokenServices.revokeAccessToken(accessToken);
|
||||||
model.addAttribute("code", HttpStatus.OK);
|
model.addAttribute("code", HttpStatus.OK);
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
|
|
||||||
} catch (InvalidTokenException e) {
|
} catch (InvalidTokenException e) {
|
||||||
|
|
||||||
// access token wasn't found, check the refresh token
|
// access token wasn't found, check the refresh token
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OAuth2RefreshTokenEntity refreshToken = tokenServices.getRefreshToken(tokenValue);
|
OAuth2RefreshTokenEntity refreshToken = tokenServices.getRefreshToken(tokenValue);
|
||||||
if (clientAuth != null) {
|
if (clientAuth != null) {
|
||||||
|
@ -93,16 +90,16 @@ public class RevocationEndpoint {
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we got this far, we're allowed to do this
|
// if we got this far, we're allowed to do this
|
||||||
tokenServices.revokeRefreshToken(refreshToken);
|
tokenServices.revokeRefreshToken(refreshToken);
|
||||||
model.addAttribute("code", HttpStatus.OK);
|
model.addAttribute("code", HttpStatus.OK);
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
|
|
||||||
} catch (InvalidTokenException e1) {
|
} catch (InvalidTokenException e1) {
|
||||||
|
|
||||||
// neither token type was found, simply say "OK" and be on our way.
|
// neither token type was found, simply say "OK" and be on our way.
|
||||||
|
|
||||||
model.addAttribute("code", HttpStatus.OK);
|
model.addAttribute("code", HttpStatus.OK);
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,6 @@ package org.mitre.oauth2.web;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.persistence.EntityExistsException;
|
|
||||||
import javax.persistence.TransactionRequiredException;
|
|
||||||
|
|
||||||
import org.mitre.oauth2.model.SystemScope;
|
import org.mitre.oauth2.model.SystemScope;
|
||||||
import org.mitre.oauth2.service.SystemScopeService;
|
import org.mitre.oauth2.service.SystemScopeService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -35,35 +32,35 @@ public class ScopeAPI {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SystemScopeService scopeService;
|
private SystemScopeService scopeService;
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(ScopeAPI.class);
|
private static Logger logger = LoggerFactory.getLogger(ScopeAPI.class);
|
||||||
|
|
||||||
private Gson gson = new Gson();
|
private Gson gson = new Gson();
|
||||||
|
|
||||||
@RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json")
|
@RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json")
|
||||||
public String getAll(ModelMap m) {
|
public String getAll(ModelMap m) {
|
||||||
|
|
||||||
Set<SystemScope> allScopes = scopeService.getAll();
|
Set<SystemScope> allScopes = scopeService.getAll();
|
||||||
|
|
||||||
m.put("entity", allScopes);
|
m.put("entity", allScopes);
|
||||||
|
|
||||||
return "jsonEntityView";
|
return "jsonEntityView";
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/json")
|
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/json")
|
||||||
public String getScope(@PathVariable("id") Long id, ModelMap m) {
|
public String getScope(@PathVariable("id") Long id, ModelMap m) {
|
||||||
|
|
||||||
SystemScope scope = scopeService.getById(id);
|
SystemScope scope = scopeService.getById(id);
|
||||||
|
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
|
|
||||||
m.put("entity", scope);
|
m.put("entity", scope);
|
||||||
|
|
||||||
return "jsonEntityView";
|
return "jsonEntityView";
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
logger.error("getScope failed; scope not found: " + id);
|
logger.error("getScope failed; scope not found: " + id);
|
||||||
|
|
||||||
m.put("code", HttpStatus.NOT_FOUND);
|
m.put("code", HttpStatus.NOT_FOUND);
|
||||||
m.put("errorMessage", "The requested scope with id " + id + " could not be found.");
|
m.put("errorMessage", "The requested scope with id " + id + " could not be found.");
|
||||||
return "jsonErrorView";
|
return "jsonErrorView";
|
||||||
|
@ -73,46 +70,46 @@ public class ScopeAPI {
|
||||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, produces = "application/json", consumes = "application/json")
|
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, produces = "application/json", consumes = "application/json")
|
||||||
public String updateScope(@PathVariable("id") Long id, @RequestBody String json, ModelMap m) {
|
public String updateScope(@PathVariable("id") Long id, @RequestBody String json, ModelMap m) {
|
||||||
|
|
||||||
SystemScope existing = scopeService.getById(id);
|
SystemScope existing = scopeService.getById(id);
|
||||||
|
|
||||||
SystemScope scope = gson.fromJson(json, SystemScope.class);
|
SystemScope scope = gson.fromJson(json, SystemScope.class);
|
||||||
|
|
||||||
if (existing != null && scope != null) {
|
if (existing != null && scope != null) {
|
||||||
|
|
||||||
if (existing.getId().equals(scope.getId())) {
|
if (existing.getId().equals(scope.getId())) {
|
||||||
// sanity check
|
// sanity check
|
||||||
|
|
||||||
scope = scopeService.save(scope);
|
scope = scopeService.save(scope);
|
||||||
|
|
||||||
m.put("entity", scope);
|
m.put("entity", scope);
|
||||||
|
|
||||||
return "jsonEntityView";
|
return "jsonEntityView";
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
logger.error("updateScope failed; scope ids to not match: got "
|
logger.error("updateScope failed; scope ids to not match: got "
|
||||||
+ existing.getId() + " and " + scope.getId());
|
+ existing.getId() + " and " + scope.getId());
|
||||||
|
|
||||||
m.put("code", HttpStatus.BAD_REQUEST);
|
m.put("code", HttpStatus.BAD_REQUEST);
|
||||||
m.put("errorMessage", "Could not update scope. Scope ids to not match: got "
|
m.put("errorMessage", "Could not update scope. Scope ids to not match: got "
|
||||||
+ existing.getId() + " and " + scope.getId());
|
+ existing.getId() + " and " + scope.getId());
|
||||||
return "jsonErrorView";
|
return "jsonErrorView";
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
logger.error("updateScope failed; scope with id " + id + " not found.");
|
logger.error("updateScope failed; scope with id " + id + " not found.");
|
||||||
m.put("code", HttpStatus.NOT_FOUND);
|
m.put("code", HttpStatus.NOT_FOUND);
|
||||||
m.put("errorMessage", "Could not update scope. The scope with id " + id + " could not be found.");
|
m.put("errorMessage", "Could not update scope. The scope with id " + id + " could not be found.");
|
||||||
return "jsonErrorView";
|
return "jsonErrorView";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
@RequestMapping(value = "", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
|
@RequestMapping(value = "", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
|
||||||
public String createScope(@RequestBody String json, ModelMap m) {
|
public String createScope(@RequestBody String json, ModelMap m) {
|
||||||
SystemScope scope = gson.fromJson(json, SystemScope.class);
|
SystemScope scope = gson.fromJson(json, SystemScope.class);
|
||||||
|
|
||||||
SystemScope alreadyExists = scopeService.getByValue(scope.getValue());
|
SystemScope alreadyExists = scopeService.getByValue(scope.getValue());
|
||||||
if (alreadyExists != null) {
|
if (alreadyExists != null) {
|
||||||
//Error, cannot save a scope with the same value as an existing one
|
//Error, cannot save a scope with the same value as an existing one
|
||||||
|
@ -121,41 +118,41 @@ public class ScopeAPI {
|
||||||
m.put("errorMessage", "A scope with value " + scope.getValue() + " already exists, please choose a different value.");
|
m.put("errorMessage", "A scope with value " + scope.getValue() + " already exists, please choose a different value.");
|
||||||
return "jsonErrorView";
|
return "jsonErrorView";
|
||||||
}
|
}
|
||||||
|
|
||||||
scope = scopeService.save(scope);
|
scope = scopeService.save(scope);
|
||||||
|
|
||||||
if (scope != null && scope.getId() != null) {
|
if (scope != null && scope.getId() != null) {
|
||||||
|
|
||||||
m.put("entity", scope);
|
m.put("entity", scope);
|
||||||
|
|
||||||
return "jsonEntityView";
|
return "jsonEntityView";
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
logger.error("createScope failed; JSON was invalid: " + json);
|
logger.error("createScope failed; JSON was invalid: " + json);
|
||||||
m.put("code", HttpStatus.BAD_REQUEST);
|
m.put("code", HttpStatus.BAD_REQUEST);
|
||||||
m.put("errorMessage", "Could not save new scope " + scope.getValue() + ". The scope service failed to return a saved entity.");
|
m.put("errorMessage", "Could not save new scope " + scope.getValue() + ". The scope service failed to return a saved entity.");
|
||||||
return "jsonErrorView";
|
return "jsonErrorView";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||||
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
|
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
|
||||||
public String deleteScope(@PathVariable("id") Long id, ModelMap m) {
|
public String deleteScope(@PathVariable("id") Long id, ModelMap m) {
|
||||||
SystemScope existing = scopeService.getById(id);
|
SystemScope existing = scopeService.getById(id);
|
||||||
|
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
|
|
||||||
scopeService.remove(existing);
|
scopeService.remove(existing);
|
||||||
|
|
||||||
return "httpCodeView";
|
return "httpCodeView";
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
logger.error("deleteScope failed; scope with id " + id + " not found.");
|
logger.error("deleteScope failed; scope with id " + id + " not found.");
|
||||||
m.put("code", HttpStatus.NOT_FOUND);
|
m.put("code", HttpStatus.NOT_FOUND);
|
||||||
m.put("errorMessage", "Could not delete scope. The requested scope with id " + id + " could not be found.");
|
m.put("errorMessage", "Could not delete scope. The requested scope with id " + id + " could not be found.");
|
||||||
return "jsonErrorView";
|
return "jsonErrorView";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,10 @@ import com.nimbusds.jwt.SignedJWT;
|
||||||
public class ConnectAuthorizationRequestManager implements AuthorizationRequestManager {
|
public class ConnectAuthorizationRequestManager implements AuthorizationRequestManager {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(ConnectAuthorizationRequestManager.class);
|
private static Logger logger = LoggerFactory.getLogger(ConnectAuthorizationRequestManager.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private NonceService nonceService;
|
private NonceService nonceService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ClientDetailsEntityService clientDetailsService;
|
private ClientDetailsEntityService clientDetailsService;
|
||||||
|
|
||||||
|
@ -58,32 +58,32 @@ public class ConnectAuthorizationRequestManager implements AuthorizationRequestM
|
||||||
this.clientDetailsService = clientDetailsService;
|
this.clientDetailsService = clientDetailsService;
|
||||||
this.nonceService = nonceService;
|
this.nonceService = nonceService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default empty constructor
|
* Default empty constructor
|
||||||
*/
|
*/
|
||||||
public ConnectAuthorizationRequestManager() {
|
public ConnectAuthorizationRequestManager() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthorizationRequest createAuthorizationRequest(Map<String, String> inputParams) {
|
public AuthorizationRequest createAuthorizationRequest(Map<String, String> inputParams) {
|
||||||
|
|
||||||
Map<String, String> parameters = processRequestObject(inputParams);
|
Map<String, String> parameters = processRequestObject(inputParams);
|
||||||
|
|
||||||
String clientId = parameters.get("client_id");
|
String clientId = parameters.get("client_id");
|
||||||
if (clientId == null) {
|
if (clientId == null) {
|
||||||
throw new InvalidClientException("A client id must be provided");
|
throw new InvalidClientException("A client id must be provided");
|
||||||
}
|
}
|
||||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
|
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
|
||||||
|
|
||||||
String requestNonce = parameters.get("nonce");
|
String requestNonce = parameters.get("nonce");
|
||||||
|
|
||||||
//Only process if the user is authenticated. If the user is not authenticated yet, this
|
//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
|
//code will be called a second time once the user is redirected from the login page back
|
||||||
//to the auth endpoint.
|
//to the auth endpoint.
|
||||||
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
|
||||||
if (requestNonce != null && principal != null && principal instanceof User) {
|
if (requestNonce != null && principal != null && principal instanceof User) {
|
||||||
|
|
||||||
if (!nonceService.alreadyUsed(clientId, requestNonce)) {
|
if (!nonceService.alreadyUsed(clientId, requestNonce)) {
|
||||||
|
@ -93,17 +93,17 @@ public class ConnectAuthorizationRequestManager implements AuthorizationRequestM
|
||||||
else {
|
else {
|
||||||
throw new NonceReuseException(client.getClientId(), requestNonce);
|
throw new NonceReuseException(client.getClientId(), requestNonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> scopes = OAuth2Utils.parseParameterList(parameters.get("scope"));
|
Set<String> scopes = OAuth2Utils.parseParameterList(parameters.get("scope"));
|
||||||
if ((scopes == null || scopes.isEmpty())) {
|
if ((scopes == null || scopes.isEmpty())) {
|
||||||
//TODO: do we want to allow default scoping at all?
|
//TODO: do we want to allow default scoping at all?
|
||||||
Set<String> clientScopes = client.getScope();
|
Set<String> clientScopes = client.getScope();
|
||||||
scopes = clientScopes;
|
scopes = clientScopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// note that we have to inject the processed parameters in at this point so that SECOAUTH can find them later (and this object will get copy-constructored away anyway)
|
// note that we have to inject the processed parameters in at this point so that SECOAUTH can find them later (and this object will get copy-constructored away anyway)
|
||||||
DefaultAuthorizationRequest request = new DefaultAuthorizationRequest(parameters, Collections.<String, String> emptyMap(), clientId, scopes);
|
DefaultAuthorizationRequest request = new DefaultAuthorizationRequest(parameters, Collections.<String, String> emptyMap(), clientId, scopes);
|
||||||
request.addClientDetails(client);
|
request.addClientDetails(client);
|
||||||
|
@ -115,46 +115,46 @@ public class ConnectAuthorizationRequestManager implements AuthorizationRequestM
|
||||||
* @param inputParams
|
* @param inputParams
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Map<String, String> processRequestObject(Map<String, String> inputParams) {
|
private Map<String, String> processRequestObject(Map<String, String> inputParams) {
|
||||||
|
|
||||||
String jwtString = inputParams.get("request");
|
|
||||||
|
|
||||||
// if there's no request object, bail early
|
|
||||||
if (Strings.isNullOrEmpty(jwtString)) {
|
|
||||||
return inputParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
// start by copying over what's already in there
|
String jwtString = inputParams.get("request");
|
||||||
Map<String, String> parameters = new HashMap<String, String>(inputParams);
|
|
||||||
|
// if there's no request object, bail early
|
||||||
|
if (Strings.isNullOrEmpty(jwtString)) {
|
||||||
|
return inputParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start by copying over what's already in there
|
||||||
|
Map<String, String> parameters = new HashMap<String, String>(inputParams);
|
||||||
|
|
||||||
|
// parse the request object
|
||||||
|
try {
|
||||||
|
SignedJWT jwsObject = SignedJWT.parse(jwtString);
|
||||||
|
JSONObject claims = jwsObject.getPayload().toJSONObject();
|
||||||
|
|
||||||
// parse the request object
|
|
||||||
try {
|
|
||||||
SignedJWT jwsObject = SignedJWT.parse(jwtString);
|
|
||||||
JSONObject claims = jwsObject.getPayload().toJSONObject();
|
|
||||||
|
|
||||||
// TODO: check parameter consistency, move keys to constants
|
// TODO: check parameter consistency, move keys to constants
|
||||||
|
|
||||||
String clientId = JSONObjectUtils.getString(claims, "client_id");
|
String clientId = JSONObjectUtils.getString(claims, "client_id");
|
||||||
if (clientId != null) {
|
if (clientId != null) {
|
||||||
parameters.put("client_id", clientId);
|
parameters.put("client_id", clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientDetailsEntity client = clientDetailsService.loadClientByClientId(clientId);
|
ClientDetailsEntity client = clientDetailsService.loadClientByClientId(clientId);
|
||||||
|
|
||||||
if (client.getJwksUri() == null) {
|
if (client.getJwksUri() == null) {
|
||||||
throw new InvalidClientException("Client must have a JWKS URI registered to use request objects.");
|
throw new InvalidClientException("Client must have a JWKS URI registered to use request objects.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// check JWT signature
|
// check JWT signature
|
||||||
JwtSigningAndValidationService validator = validators.get(client.getJwksUri());
|
JwtSigningAndValidationService validator = validators.get(client.getJwksUri());
|
||||||
if (validator == null) {
|
if (validator == null) {
|
||||||
throw new InvalidClientException("Unable to create signature validator for client's JWKS URI: " + client.getJwksUri());
|
throw new InvalidClientException("Unable to create signature validator for client's JWKS URI: " + client.getJwksUri());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validator.validateSignature(jwsObject)) {
|
if (!validator.validateSignature(jwsObject)) {
|
||||||
throw new AuthenticationServiceException("Signature did not validate for presented JWT request object.");
|
throw new AuthenticationServiceException("Signature did not validate for presented JWT request object.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if (in Claims):
|
* if (in Claims):
|
||||||
* if (in params):
|
* if (in params):
|
||||||
|
@ -167,59 +167,59 @@ public class ConnectAuthorizationRequestManager implements AuthorizationRequestM
|
||||||
* else (not in claims):
|
* else (not in claims):
|
||||||
* we don't care
|
* we don't care
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String responseTypes = JSONObjectUtils.getString(claims, "response_type");
|
String responseTypes = JSONObjectUtils.getString(claims, "response_type");
|
||||||
if (responseTypes != null) {
|
if (responseTypes != null) {
|
||||||
parameters.put("response_type", responseTypes);
|
parameters.put("response_type", responseTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (claims.get("redirect_uri") != null) {
|
if (claims.get("redirect_uri") != null) {
|
||||||
if (inputParams.containsKey("redirect_uri") == false) {
|
if (inputParams.containsKey("redirect_uri") == false) {
|
||||||
parameters.put("redirect_uri", JSONObjectUtils.getString(claims, "redirect_uri"));
|
parameters.put("redirect_uri", JSONObjectUtils.getString(claims, "redirect_uri"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String state = JSONObjectUtils.getString(claims, "state");
|
String state = JSONObjectUtils.getString(claims, "state");
|
||||||
if(state != null) {
|
if(state != null) {
|
||||||
if (inputParams.containsKey("state") == false) {
|
if (inputParams.containsKey("state") == false) {
|
||||||
parameters.put("state", state);
|
parameters.put("state", state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String nonce = JSONObjectUtils.getString(claims, "nonce");
|
String nonce = JSONObjectUtils.getString(claims, "nonce");
|
||||||
if(nonce != null) {
|
if(nonce != null) {
|
||||||
if (inputParams.containsKey("nonce") == false) {
|
if (inputParams.containsKey("nonce") == false) {
|
||||||
parameters.put("nonce", nonce);
|
parameters.put("nonce", nonce);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String display = JSONObjectUtils.getString(claims, "display");
|
String display = JSONObjectUtils.getString(claims, "display");
|
||||||
if (display != null) {
|
if (display != null) {
|
||||||
if (inputParams.containsKey("display") == false) {
|
if (inputParams.containsKey("display") == false) {
|
||||||
parameters.put("display", display);
|
parameters.put("display", display);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String prompt = JSONObjectUtils.getString(claims, "prompt");
|
String prompt = JSONObjectUtils.getString(claims, "prompt");
|
||||||
if (prompt != null) {
|
if (prompt != null) {
|
||||||
if (inputParams.containsKey("prompt") == false) {
|
if (inputParams.containsKey("prompt") == false) {
|
||||||
parameters.put("prompt", prompt);
|
parameters.put("prompt", prompt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String scope = JSONObjectUtils.getString(claims, "scope");
|
String scope = JSONObjectUtils.getString(claims, "scope");
|
||||||
if (scope != null) {
|
if (scope != null) {
|
||||||
if (inputParams.containsKey("scope") == false) {
|
if (inputParams.containsKey("scope") == false) {
|
||||||
parameters.put("scope", scope);
|
parameters.put("scope", scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateParameters(Map<String, String> parameters, ClientDetails clientDetails) {
|
public void validateParameters(Map<String, String> parameters, ClientDetails clientDetails) {
|
||||||
|
|
|
@ -18,19 +18,19 @@ public class JwtBearerAssertionAuthenticationToken extends AbstractAuthenticatio
|
||||||
|
|
||||||
private String clientId;
|
private String clientId;
|
||||||
private JWT jwt;
|
private JWT jwt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an unauthenticated token with the given client ID and jwt
|
* Create an unauthenticated token with the given client ID and jwt
|
||||||
* @param clientId
|
* @param clientId
|
||||||
* @param jwt
|
* @param jwt
|
||||||
*/
|
*/
|
||||||
public JwtBearerAssertionAuthenticationToken(String clientId, JWT jwt) {
|
public JwtBearerAssertionAuthenticationToken(String clientId, JWT jwt) {
|
||||||
super(null);
|
super(null);
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.jwt = jwt;
|
this.jwt = jwt;
|
||||||
setAuthenticated(false);
|
setAuthenticated(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an authenticated token with the given clientID, jwt, and authorities set
|
* Create an authenticated token with the given clientID, jwt, and authorities set
|
||||||
* @param clientId
|
* @param clientId
|
||||||
|
@ -38,11 +38,11 @@ public class JwtBearerAssertionAuthenticationToken extends AbstractAuthenticatio
|
||||||
* @param authorities
|
* @param authorities
|
||||||
*/
|
*/
|
||||||
public JwtBearerAssertionAuthenticationToken(String clientId, JWT jwt, Collection<? extends GrantedAuthority> authorities) {
|
public JwtBearerAssertionAuthenticationToken(String clientId, JWT jwt, Collection<? extends GrantedAuthority> authorities) {
|
||||||
super(authorities);
|
super(authorities);
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.jwt = jwt;
|
this.jwt = jwt;
|
||||||
setAuthenticated(true);
|
setAuthenticated(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.security.core.Authentication#getCredentials()
|
* @see org.springframework.security.core.Authentication#getCredentials()
|
||||||
|
@ -61,42 +61,42 @@ public class JwtBearerAssertionAuthenticationToken extends AbstractAuthenticatio
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the clientId
|
* @return the clientId
|
||||||
*/
|
*/
|
||||||
public String getClientId() {
|
public String getClientId() {
|
||||||
return clientId;
|
return clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param clientId the clientId to set
|
* @param clientId the clientId to set
|
||||||
*/
|
*/
|
||||||
public void setClientId(String clientId) {
|
public void setClientId(String clientId) {
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the jwt
|
* @return the jwt
|
||||||
*/
|
*/
|
||||||
public JWT getJwt() {
|
public JWT getJwt() {
|
||||||
return jwt;
|
return jwt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param jwt the jwt to set
|
* @param jwt the jwt to set
|
||||||
*/
|
*/
|
||||||
public void setJwt(JWT jwt) {
|
public void setJwt(JWT jwt) {
|
||||||
this.jwt = jwt;
|
this.jwt = jwt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear out the JWT that this token holds.
|
* Clear out the JWT that this token holds.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void eraseCredentials() {
|
public void eraseCredentials() {
|
||||||
super.eraseCredentials();
|
super.eraseCredentials();
|
||||||
setJwt(null);
|
setJwt(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,49 +36,49 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
||||||
// map of verifiers, load keys for clients
|
// map of verifiers, load keys for clients
|
||||||
@Autowired
|
@Autowired
|
||||||
private JWKSetSigningAndValidationServiceCacheService validators;
|
private JWKSetSigningAndValidationServiceCacheService validators;
|
||||||
|
|
||||||
// Allow for time sync issues by having a window of X seconds.
|
// Allow for time sync issues by having a window of X seconds.
|
||||||
private int timeSkewAllowance = 300;
|
private int timeSkewAllowance = 300;
|
||||||
|
|
||||||
// to load clients
|
// to load clients
|
||||||
@Autowired
|
@Autowired
|
||||||
private ClientDetailsEntityService clientService;
|
private ClientDetailsEntityService clientService;
|
||||||
|
|
||||||
// to get our server's issuer url
|
// to get our server's issuer url
|
||||||
@Autowired
|
@Autowired
|
||||||
private ConfigurationPropertiesBean config;
|
private ConfigurationPropertiesBean config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to validate the client credentials by parsing and validating the JWT.
|
* Try to validate the client credentials by parsing and validating the JWT.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
|
|
||||||
JwtBearerAssertionAuthenticationToken jwtAuth = (JwtBearerAssertionAuthenticationToken)authentication;
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
ClientDetailsEntity client = clientService.loadClientByClientId(jwtAuth.getClientId());
|
|
||||||
|
|
||||||
JWT jwt = jwtAuth.getJwt();
|
JwtBearerAssertionAuthenticationToken jwtAuth = (JwtBearerAssertionAuthenticationToken)authentication;
|
||||||
ReadOnlyJWTClaimsSet jwtClaims = jwt.getJWTClaimsSet();
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
ClientDetailsEntity client = clientService.loadClientByClientId(jwtAuth.getClientId());
|
||||||
|
|
||||||
|
JWT jwt = jwtAuth.getJwt();
|
||||||
|
ReadOnlyJWTClaimsSet jwtClaims = jwt.getJWTClaimsSet();
|
||||||
|
|
||||||
|
// check the signature with nimbus
|
||||||
|
if (jwt instanceof SignedJWT) {
|
||||||
|
SignedJWT jws = (SignedJWT)jwt;
|
||||||
|
JwtSigningAndValidationService validator = validators.get(client.getJwksUri());
|
||||||
|
if (validator == null || !validator.validateSignature(jws)) {
|
||||||
|
throw new AuthenticationServiceException("Invalid signature");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check the signature with nimbus
|
|
||||||
if (jwt instanceof SignedJWT) {
|
|
||||||
SignedJWT jws = (SignedJWT)jwt;
|
|
||||||
JwtSigningAndValidationService validator = validators.get(client.getJwksUri());
|
|
||||||
if (validator == null || !validator.validateSignature(jws)) {
|
|
||||||
throw new AuthenticationServiceException("Invalid signature");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the issuer
|
// check the issuer
|
||||||
if (jwtClaims.getIssuer() == null) {
|
if (jwtClaims.getIssuer() == null) {
|
||||||
throw new AuthenticationServiceException("Assertion Token Issuer is null");
|
throw new AuthenticationServiceException("Assertion Token Issuer is null");
|
||||||
} else if (!jwtClaims.getIssuer().equals(client.getClientId())){
|
} else if (!jwtClaims.getIssuer().equals(client.getClientId())){
|
||||||
throw new AuthenticationServiceException("Issuers do not match, expected " + client.getClientId() + " got " + jwtClaims.getIssuer());
|
throw new AuthenticationServiceException("Issuers do not match, expected " + client.getClientId() + " got " + jwtClaims.getIssuer());
|
||||||
}
|
}
|
||||||
|
|
||||||
// check expiration
|
// check expiration
|
||||||
if (jwtClaims.getExpirationTime() == null) {
|
if (jwtClaims.getExpirationTime() == null) {
|
||||||
throw new AuthenticationServiceException("Assertion Token does not have required expiration claim");
|
throw new AuthenticationServiceException("Assertion Token does not have required expiration claim");
|
||||||
|
@ -89,7 +89,7 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
||||||
throw new AuthenticationServiceException("Assertion Token is expired: " + jwtClaims.getExpirationTime());
|
throw new AuthenticationServiceException("Assertion Token is expired: " + jwtClaims.getExpirationTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check not before
|
// check not before
|
||||||
if (jwtClaims.getNotBeforeTime() != null) {
|
if (jwtClaims.getNotBeforeTime() != null) {
|
||||||
Date now = new Date(System.currentTimeMillis() + (timeSkewAllowance * 1000));
|
Date now = new Date(System.currentTimeMillis() + (timeSkewAllowance * 1000));
|
||||||
|
@ -97,7 +97,7 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
||||||
throw new AuthenticationServiceException("Assertion Token not valid untill: " + jwtClaims.getNotBeforeTime());
|
throw new AuthenticationServiceException("Assertion Token not valid untill: " + jwtClaims.getNotBeforeTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check issued at
|
// check issued at
|
||||||
if (jwtClaims.getIssueTime() != null) {
|
if (jwtClaims.getIssueTime() != null) {
|
||||||
// since it's not null, see if it was issued in the future
|
// since it's not null, see if it was issued in the future
|
||||||
|
@ -106,32 +106,32 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
||||||
throw new AuthenticationServiceException("Assertion Token was issued in the future: " + jwtClaims.getIssueTime());
|
throw new AuthenticationServiceException("Assertion Token was issued in the future: " + jwtClaims.getIssueTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check audience
|
// check audience
|
||||||
if (jwtClaims.getAudience() == null) {
|
if (jwtClaims.getAudience() == null) {
|
||||||
throw new AuthenticationServiceException("Assertion token audience is null");
|
throw new AuthenticationServiceException("Assertion token audience is null");
|
||||||
} else if (!jwtClaims.getAudience().contains(config.getIssuer())) {
|
} else if (!jwtClaims.getAudience().contains(config.getIssuer())) {
|
||||||
throw new AuthenticationServiceException("Audience does not match, expected " + config.getIssuer() + " got " + jwtClaims.getAudience());
|
throw new AuthenticationServiceException("Audience does not match, expected " + config.getIssuer() + " got " + jwtClaims.getAudience());
|
||||||
}
|
}
|
||||||
|
|
||||||
// IFF we managed to get all the way down here, the token is valid
|
// IFF we managed to get all the way down here, the token is valid
|
||||||
return new JwtBearerAssertionAuthenticationToken(client.getClientId(), jwt, client.getAuthorities());
|
return new JwtBearerAssertionAuthenticationToken(client.getClientId(), jwt, client.getAuthorities());
|
||||||
|
|
||||||
} catch (InvalidClientException e) {
|
} catch (InvalidClientException e) {
|
||||||
throw new UsernameNotFoundException("Could not find client: " + jwtAuth.getClientId());
|
throw new UsernameNotFoundException("Could not find client: " + jwtAuth.getClientId());
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
throw new AuthenticationServiceException("Invalid JWT format");
|
throw new AuthenticationServiceException("Invalid JWT format");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We support {@link JwtBearerAssertionAuthenticationToken}s only.
|
* We support {@link JwtBearerAssertionAuthenticationToken}s only.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(Class<?> authentication) {
|
public boolean supports(Class<?> authentication) {
|
||||||
return (JwtBearerAssertionAuthenticationToken.class.isAssignableFrom(authentication));
|
return (JwtBearerAssertionAuthenticationToken.class.isAssignableFrom(authentication));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,74 +28,74 @@ import com.nimbusds.jwt.JWTParser;
|
||||||
public class JwtBearerClientAssertionTokenEndpointFilter extends ClientCredentialsTokenEndpointFilter {
|
public class JwtBearerClientAssertionTokenEndpointFilter extends ClientCredentialsTokenEndpointFilter {
|
||||||
|
|
||||||
public JwtBearerClientAssertionTokenEndpointFilter() {
|
public JwtBearerClientAssertionTokenEndpointFilter() {
|
||||||
super();
|
super();
|
||||||
// TODO Auto-generated constructor stub
|
// TODO Auto-generated constructor stub
|
||||||
}
|
}
|
||||||
|
|
||||||
public JwtBearerClientAssertionTokenEndpointFilter(String path) {
|
public JwtBearerClientAssertionTokenEndpointFilter(String path) {
|
||||||
super(path);
|
super(path);
|
||||||
// TODO Auto-generated constructor stub
|
// TODO Auto-generated constructor stub
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pull the assertion out of the request and send it up to the auth manager for processing.
|
* Pull the assertion out of the request and send it up to the auth manager for processing.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
|
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
|
||||||
|
|
||||||
// check for appropriate parameters
|
// check for appropriate parameters
|
||||||
String assertionType = request.getParameter("client_assertion_type");
|
String assertionType = request.getParameter("client_assertion_type");
|
||||||
String assertion = request.getParameter("client_assertion");
|
String assertion = request.getParameter("client_assertion");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
JWT jwt = JWTParser.parse(assertion);
|
JWT jwt = JWTParser.parse(assertion);
|
||||||
|
|
||||||
String clientId = jwt.getJWTClaimsSet().getSubject();
|
String clientId = jwt.getJWTClaimsSet().getSubject();
|
||||||
|
|
||||||
Authentication authRequest = new JwtBearerAssertionAuthenticationToken(clientId, jwt);
|
Authentication authRequest = new JwtBearerAssertionAuthenticationToken(clientId, jwt);
|
||||||
|
|
||||||
return this.getAuthenticationManager().authenticate(authRequest);
|
return this.getAuthenticationManager().authenticate(authRequest);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
throw new BadCredentialsException("Invalid JWT credential: " + assertion);
|
throw new BadCredentialsException("Invalid JWT credential: " + assertion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to see if the "client_assertion_type" and "client_assertion" parameters are present and contain the right values.
|
* Check to see if the "client_assertion_type" and "client_assertion" parameters are present and contain the right values.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
|
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
|
||||||
// check for appropriate parameters
|
// check for appropriate parameters
|
||||||
String assertionType = request.getParameter("client_assertion_type");
|
String assertionType = request.getParameter("client_assertion_type");
|
||||||
String assertion = request.getParameter("client_assertion");
|
String assertion = request.getParameter("client_assertion");
|
||||||
|
|
||||||
|
if (Strings.isNullOrEmpty(assertionType) || Strings.isNullOrEmpty(assertion)) {
|
||||||
|
return false;
|
||||||
|
} else if (!assertionType.equals("urn:ietf:params:oauth:client-assertion-type:jwt-bearer")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Can't call to superclass here b/c client creds would break for lack of client_id
|
||||||
|
// return super.requiresAuthentication(request, response);
|
||||||
|
|
||||||
|
String uri = request.getRequestURI();
|
||||||
|
int pathParamIndex = uri.indexOf(';');
|
||||||
|
|
||||||
|
if (pathParamIndex > 0) {
|
||||||
|
// strip everything after the first semi-colon
|
||||||
|
uri = uri.substring(0, pathParamIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("".equals(request.getContextPath())) {
|
||||||
|
return uri.endsWith(getFilterProcessesUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri.endsWith(request.getContextPath() + getFilterProcessesUrl());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(assertionType) || Strings.isNullOrEmpty(assertion)) {
|
|
||||||
return false;
|
|
||||||
} else if (!assertionType.equals("urn:ietf:params:oauth:client-assertion-type:jwt-bearer")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Can't call to superclass here b/c client creds would break for lack of client_id
|
|
||||||
// return super.requiresAuthentication(request, response);
|
|
||||||
|
|
||||||
String uri = request.getRequestURI();
|
|
||||||
int pathParamIndex = uri.indexOf(';');
|
|
||||||
|
|
||||||
if (pathParamIndex > 0) {
|
|
||||||
// strip everything after the first semi-colon
|
|
||||||
uri = uri.substring(0, pathParamIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("".equals(request.getContextPath())) {
|
|
||||||
return uri.endsWith(getFilterProcessesUrl());
|
|
||||||
}
|
|
||||||
|
|
||||||
return uri.endsWith(request.getContextPath() + getFilterProcessesUrl());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,11 @@ import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpSession;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
|
||||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.filter.GenericFilterBean;
|
import org.springframework.web.filter.GenericFilterBean;
|
||||||
|
|
||||||
|
@ -30,7 +27,7 @@ import com.google.common.base.Strings;
|
||||||
*/
|
*/
|
||||||
@Component("promptFilter")
|
@Component("promptFilter")
|
||||||
public class PromptFilter extends GenericFilterBean {
|
public class PromptFilter extends GenericFilterBean {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(PromptFilter.class);
|
private Logger logger = LoggerFactory.getLogger(PromptFilter.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,33 +35,33 @@ public class PromptFilter extends GenericFilterBean {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
||||||
|
|
||||||
HttpServletRequest request = (HttpServletRequest) req;
|
HttpServletRequest request = (HttpServletRequest) req;
|
||||||
HttpServletResponse response = (HttpServletResponse) res;
|
HttpServletResponse response = (HttpServletResponse) res;
|
||||||
|
|
||||||
if (!Strings.isNullOrEmpty(request.getParameter("prompt"))) {
|
if (!Strings.isNullOrEmpty(request.getParameter("prompt"))) {
|
||||||
// we have a "prompt" parameter
|
// we have a "prompt" parameter
|
||||||
|
|
||||||
if (request.getParameter("prompt").equals("none")) {
|
if (request.getParameter("prompt").equals("none")) {
|
||||||
logger.info("Client requested no prompt");
|
logger.info("Client requested no prompt");
|
||||||
// see if the user's logged in
|
// see if the user's logged in
|
||||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
if (auth != null) {
|
if (auth != null) {
|
||||||
// user's been logged in already (by session management)
|
// user's been logged in already (by session management)
|
||||||
// we're OK, continue without prompting
|
// we're OK, continue without prompting
|
||||||
chain.doFilter(req, res);
|
chain.doFilter(req, res);
|
||||||
} else {
|
} else {
|
||||||
// user hasn't been logged in, we need to "return an error"
|
// user hasn't been logged in, we need to "return an error"
|
||||||
logger.info("User not logged in, no prompt requested, returning 403 from filter");
|
logger.info("User not logged in, no prompt requested, returning 403 from filter");
|
||||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
|
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* TODO: this is an attempt to catch the prompt=login case, but it results in an infinite loop so it's commented out
|
/* TODO: this is an attempt to catch the prompt=login case, but it results in an infinite loop so it's commented out
|
||||||
} else if (request.getParameter("prompt").equals("login")) {
|
} else if (request.getParameter("prompt").equals("login")) {
|
||||||
// see if the user's logged in
|
// see if the user's logged in
|
||||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
if (auth != null) {
|
if (auth != null) {
|
||||||
// user's been logged in already (by session management)
|
// user's been logged in already (by session management)
|
||||||
// log them out and continue
|
// log them out and continue
|
||||||
|
@ -74,17 +71,17 @@ public class PromptFilter extends GenericFilterBean {
|
||||||
// user hasn't been logged in yet, we can keep going
|
// user hasn't been logged in yet, we can keep going
|
||||||
chain.doFilter(req, res);
|
chain.doFilter(req, res);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
} else {
|
} else {
|
||||||
// prompt parameter is a value we don't care about, not our business
|
// prompt parameter is a value we don't care about, not our business
|
||||||
chain.doFilter(req, res);
|
chain.doFilter(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// no prompt parameter, not our business
|
// no prompt parameter, not our business
|
||||||
chain.doFilter(req, res);
|
chain.doFilter(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.openid.connect.repository.impl;
|
package org.mitre.openid.connect.repository.impl;
|
||||||
|
|
||||||
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
|
|
||||||
|
@ -25,6 +23,8 @@ import org.mitre.openid.connect.repository.AddressRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA Address repository implementation
|
* JPA Address repository implementation
|
||||||
*
|
*
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.openid.connect.repository.impl;
|
package org.mitre.openid.connect.repository.impl;
|
||||||
|
|
||||||
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
@ -25,10 +23,11 @@ import javax.persistence.TypedQuery;
|
||||||
|
|
||||||
import org.mitre.openid.connect.model.ApprovedSite;
|
import org.mitre.openid.connect.model.ApprovedSite;
|
||||||
import org.mitre.openid.connect.repository.ApprovedSiteRepository;
|
import org.mitre.openid.connect.repository.ApprovedSiteRepository;
|
||||||
import org.mitre.util.jpa.JpaUtil;
|
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA ApprovedSite repository implementation
|
* JPA ApprovedSite repository implementation
|
||||||
*
|
*
|
||||||
|
@ -48,7 +47,7 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
|
||||||
"ApprovedSite.getAll", ApprovedSite.class);
|
"ApprovedSite.getAll", ApprovedSite.class);
|
||||||
return query.getResultList();
|
return query.getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public ApprovedSite getById(Long id) {
|
public ApprovedSite getById(Long id) {
|
||||||
|
@ -59,7 +58,7 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
|
||||||
@Transactional
|
@Transactional
|
||||||
public void remove(ApprovedSite approvedSite) {
|
public void remove(ApprovedSite approvedSite) {
|
||||||
ApprovedSite found = manager.find(ApprovedSite.class, approvedSite.getId());
|
ApprovedSite found = manager.find(ApprovedSite.class, approvedSite.getId());
|
||||||
|
|
||||||
if (found != null) {
|
if (found != null) {
|
||||||
manager.remove(found);
|
manager.remove(found);
|
||||||
} else {
|
} else {
|
||||||
|
@ -75,30 +74,30 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ApprovedSite> getByClientIdAndUserId(String clientId, String userId) {
|
public Collection<ApprovedSite> getByClientIdAndUserId(String clientId, String userId) {
|
||||||
|
|
||||||
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByClientIdAndUserId", ApprovedSite.class);
|
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByClientIdAndUserId", ApprovedSite.class);
|
||||||
query.setParameter("userId", userId);
|
query.setParameter("userId", userId);
|
||||||
query.setParameter("clientId", clientId);
|
query.setParameter("clientId", clientId);
|
||||||
|
|
||||||
return query.getResultList();
|
return query.getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Collection<ApprovedSite> getByUserId(String userId) {
|
public Collection<ApprovedSite> getByUserId(String userId) {
|
||||||
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByUserId", ApprovedSite.class);
|
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByUserId", ApprovedSite.class);
|
||||||
query.setParameter("userId", userId);
|
query.setParameter("userId", userId);
|
||||||
|
|
||||||
return query.getResultList();
|
return query.getResultList();
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
}
|
||||||
@Transactional
|
|
||||||
public Collection<ApprovedSite> getByClientId(String clientId) {
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public Collection<ApprovedSite> getByClientId(String clientId) {
|
||||||
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByClientId", ApprovedSite.class);
|
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByClientId", ApprovedSite.class);
|
||||||
query.setParameter("clientId", clientId);
|
query.setParameter("clientId", clientId);
|
||||||
|
|
||||||
return query.getResultList();
|
return query.getResultList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue