whitespace, import, brace, annotation, and format cleanups
parent
b663cd5f8d
commit
8afab04544
|
@ -1,83 +1,85 @@
|
|||
package org.mitre.oauth2.introspectingfilter;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class AuthorizationRequestImpl implements AuthorizationRequest {
|
||||
|
||||
private JsonObject token;
|
||||
private String clientId;
|
||||
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());
|
||||
}
|
||||
}
|
||||
private JsonObject token;
|
||||
private String clientId;
|
||||
private Set<String> scopes = null;
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAuthorizationParameters() {
|
||||
return 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 Map<String, String> getApprovalParameters() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Map<String, String> getAuthorizationParameters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
@Override
|
||||
public Map<String, String> getApprovalParameters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getScope() {
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
return scopes;
|
||||
}
|
||||
@Override
|
||||
public Set<String> getScope() {
|
||||
|
||||
@Override
|
||||
public Set<String> getResourceIds() {
|
||||
return null;
|
||||
}
|
||||
return scopes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Set<String> getResourceIds() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApproved() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDenied() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isApproved() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getState() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public boolean isDenied() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRedirectUri() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getResponseTypes() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getRedirectUri() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getResponseTypes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,27 +1,14 @@
|
|||
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.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
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.OAuth2Authentication;
|
||||
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.RestTemplate;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
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() {
|
||||
return introspectionUrl;
|
||||
}
|
||||
private String clientId;
|
||||
private String clientSecret;
|
||||
private String introspectionUrl;
|
||||
|
||||
public void setIntrospectionUrl(String introspectionUrl) {
|
||||
this.introspectionUrl = 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 getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
public String getIntrospectionUrl() {
|
||||
return introspectionUrl;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
public void setIntrospectionUrl(String introspectionUrl) {
|
||||
this.introspectionUrl = introspectionUrl;
|
||||
}
|
||||
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
// 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 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;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
@ -12,79 +10,83 @@ import java.util.Set;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
|
||||
public class OAuth2AccessTokenImpl implements OAuth2AccessToken {
|
||||
|
||||
private JsonObject token;
|
||||
private String tokenString;
|
||||
private Set<String> scopes = null;
|
||||
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);
|
||||
}
|
||||
}
|
||||
private JsonObject token;
|
||||
private String tokenString;
|
||||
private Set<String> scopes = null;
|
||||
private Date expireDate;
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAdditionalInformation() {
|
||||
return null;
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getScope() {
|
||||
return scopes;
|
||||
}
|
||||
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 OAuth2RefreshToken getRefreshToken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTokenType() {
|
||||
return BEARER_TYPE;
|
||||
}
|
||||
@Override
|
||||
public Map<String, Object> getAdditionalInformation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpired() {
|
||||
if (expireDate != null && expireDate.before(new Date())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public Set<String> getScope() {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getExpiration() {
|
||||
return expireDate;
|
||||
}
|
||||
@Override
|
||||
public OAuth2RefreshToken getRefreshToken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExpiresIn() {
|
||||
if (expireDate != null) {
|
||||
return (int)TimeUnit.MILLISECONDS.toSeconds(expireDate.getTime() - (new Date()).getTime());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public String getTokenType() {
|
||||
return BEARER_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return tokenString;
|
||||
}
|
||||
@Override
|
||||
public boolean isExpired() {
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
@ -24,26 +22,26 @@ import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper
|
|||
*
|
||||
*/
|
||||
public class NamedAdminAuthoritiesMapper implements GrantedAuthoritiesMapper {
|
||||
|
||||
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_ADMIN = new SimpleGrantedAuthority("ROLE_ADMIN");
|
||||
private static final SimpleGrantedAuthority ROLE_USER = new SimpleGrantedAuthority("ROLE_USER");
|
||||
|
||||
private Set<SubjectIssuerGrantedAuthority> admins = new HashSet<SubjectIssuerGrantedAuthority>();
|
||||
|
||||
private GrantedAuthoritiesMapper chain = new NullAuthoritiesMapper();
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
|
||||
|
||||
Set<GrantedAuthority> out = new HashSet<GrantedAuthority>();
|
||||
out.addAll(authorities);
|
||||
|
||||
|
||||
for (GrantedAuthority authority : authorities) {
|
||||
if (admins.contains(authority)) {
|
||||
out.add(ROLE_ADMIN);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// everybody's a user by default
|
||||
out.add(ROLE_USER);
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ import java.math.BigInteger;
|
|||
import java.security.SecureRandom;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -29,8 +27,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import javax.servlet.http.HttpSession;
|
||||
|
||||
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.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||
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 String FILTER_PROCESSES_URL = "/openid_connect_login";
|
||||
|
||||
|
||||
// Allow for time sync issues by having a window of X seconds.
|
||||
private int timeSkewAllowance = 300;
|
||||
|
||||
|
@ -86,7 +82,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
private ClientConfigurationService clients;
|
||||
private IssuerService issuerService;
|
||||
private AuthRequestUrlBuilder authRequestBuilder;
|
||||
|
||||
|
||||
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
|
||||
handleError(request, response);
|
||||
return null; // no auth, response is sent to display page or something
|
||||
|
||||
|
||||
} else if (!Strings.isNullOrEmpty(request.getParameter("code"))) {
|
||||
|
||||
// we got back the code, need to process this to get our tokens
|
||||
Authentication auth = handleAuthorizationCodeResponse(request, response);
|
||||
return auth;
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
// not an error, not a code, must be an initial login of some type
|
||||
handleAuthorizationRequest(request, response);
|
||||
|
||||
|
||||
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 {
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
|
||||
|
||||
IssuerServiceResponse issResp = issuerService.getIssuer(request);
|
||||
|
||||
|
||||
if (issResp == null) {
|
||||
logger.error("Null issuer response returned from service.");
|
||||
throw new AuthenticationServiceException("No issuer found.");
|
||||
}
|
||||
|
||||
|
||||
if (issResp.shouldRedirect()) {
|
||||
response.sendRedirect(issResp.getRedirectUrl());
|
||||
} else {
|
||||
String issuer = issResp.getIssuer();
|
||||
|
||||
|
||||
if (Strings.isNullOrEmpty(issuer)) {
|
||||
logger.error("No issuer found: " + issuer);
|
||||
throw new AuthenticationServiceException("No issuer found: " + issuer);
|
||||
}
|
||||
|
||||
|
||||
session.setAttribute(ISSUER_SESSION_VARIABLE, issuer);
|
||||
|
||||
|
||||
ServerConfiguration serverConfig = servers.getServerConfiguration(issuer);
|
||||
if (serverConfig == null) {
|
||||
logger.error("No server configuration found for issuer: " + issuer);
|
||||
throw new AuthenticationServiceException("No server configuration found for issuer: " + issuer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ClientDetails clientConfig = clients.getClientConfiguration(serverConfig);
|
||||
if (clientConfig == null) {
|
||||
logger.error("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
|
||||
String redirectUri = request.getRequestURL().toString();
|
||||
session.setAttribute(REDIRECT_URI_SESION_VARIABLE, redirectUri);
|
||||
|
||||
|
||||
// this value comes back in the id token and is checked there
|
||||
String nonce = createNonce(session);
|
||||
|
||||
|
||||
// this value comes back in the auth code response
|
||||
String state = createState(session);
|
||||
|
||||
|
||||
String authRequest = authRequestBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state);
|
||||
|
||||
|
||||
logger.debug("Auth Request: " + authRequest);
|
||||
|
||||
|
||||
response.sendRedirect(authRequest);
|
||||
}
|
||||
}
|
||||
|
@ -210,9 +206,9 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
protected Authentication handleAuthorizationCodeResponse(HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
String authorizationCode = request.getParameter("code");
|
||||
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
|
||||
|
||||
// check for state, if it doesn't match we bail early
|
||||
String storedState = getStoredState(session);
|
||||
if (!StringUtils.isBlank(storedState)) {
|
||||
|
@ -224,20 +220,20 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
|
||||
// look up the issuer that we set out to talk to
|
||||
String issuer = getStoredSessionString(session, ISSUER_SESSION_VARIABLE);
|
||||
|
||||
|
||||
// pull the configurations based on that issuer
|
||||
ServerConfiguration serverConfig = servers.getServerConfiguration(issuer);
|
||||
ClientDetails clientConfig = clients.getClientConfiguration(serverConfig);
|
||||
|
||||
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
||||
form.add("grant_type", "authorization_code");
|
||||
form.add("code", authorizationCode);
|
||||
|
||||
|
||||
String redirectUri = getStoredSessionString(session, REDIRECT_URI_SESION_VARIABLE);
|
||||
if (redirectUri != null) {
|
||||
form.add("redirect_uri", redirectUri);
|
||||
}
|
||||
|
||||
|
||||
// Handle Token Endpoint interaction
|
||||
DefaultHttpClient httpClient = new DefaultHttpClient();
|
||||
|
||||
|
@ -252,7 +248,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
*/
|
||||
form.add("client_id", clientConfig.getClientId());
|
||||
form.add("client_secret", clientConfig.getClientSecret());
|
||||
/**/
|
||||
/**/
|
||||
|
||||
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
|
||||
|
@ -277,14 +273,14 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
}
|
||||
|
||||
logger.debug("from TokenEndpoint jsonString = " + jsonString);
|
||||
|
||||
|
||||
JsonElement jsonRoot = new JsonParser().parse(jsonString);
|
||||
if (!jsonRoot.isJsonObject()) {
|
||||
throw new AuthenticationServiceException("Token Endpoint did not return a JSON object: " + jsonRoot);
|
||||
}
|
||||
|
||||
JsonObject tokenResponse = jsonRoot.getAsJsonObject();
|
||||
|
||||
|
||||
if (tokenResponse.get("error") != null) {
|
||||
|
||||
// Handle error
|
||||
|
@ -299,125 +295,125 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
|
||||
// Extract the id_token to insert into the
|
||||
// OIDCAuthenticationToken
|
||||
|
||||
|
||||
// get out all the token strings
|
||||
String accessTokenValue = null;
|
||||
String idTokenValue = null;
|
||||
String refreshTokenValue = null;
|
||||
|
||||
|
||||
if (tokenResponse.has("access_token")) {
|
||||
accessTokenValue = tokenResponse.get("access_token").getAsString();
|
||||
} else {
|
||||
throw new AuthenticationServiceException("Token Endpoint did not return an access_token: " + jsonString);
|
||||
}
|
||||
|
||||
|
||||
if (tokenResponse.has("id_token")) {
|
||||
idTokenValue = tokenResponse.get("id_token").getAsString();
|
||||
} else {
|
||||
logger.error("Token Endpoint did not return an id_token");
|
||||
throw new AuthenticationServiceException("Token Endpoint did not return an id_token");
|
||||
}
|
||||
|
||||
|
||||
if (tokenResponse.has("refresh_token")) {
|
||||
refreshTokenValue = tokenResponse.get("refresh_token").getAsString();
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
SignedJWT idToken = SignedJWT.parse(idTokenValue);
|
||||
SignedJWT idToken = SignedJWT.parse(idTokenValue);
|
||||
|
||||
// validate our ID Token over a number of tests
|
||||
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.");
|
||||
// validate our ID Token over a number of tests
|
||||
ReadOnlyJWTClaimsSet idClaims = idToken.getJWTClaimsSet();
|
||||
|
||||
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);
|
||||
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 + ".");
|
||||
// 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());
|
||||
}
|
||||
|
||||
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 + ".");
|
||||
}
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a cryptographically random nonce and store it in the session
|
||||
* @param session
|
||||
|
@ -477,7 +473,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
protected static String getStoredNonce(HttpSession session) {
|
||||
return getStoredSessionString(session, NONCE_SESSION_VARIABLE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a cryptographically random state and store it in the session
|
||||
* @param session
|
||||
|
@ -486,10 +482,10 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
protected static String createState(HttpSession session) {
|
||||
String state = new BigInteger(50, new SecureRandom()).toString(16);
|
||||
session.setAttribute(STATE_SESSION_VARIABLE, state);
|
||||
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the state we stored in the session
|
||||
* @param session
|
||||
|
@ -498,14 +494,14 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
protected static String getStoredState(HttpSession session) {
|
||||
return getStoredSessionString(session, STATE_SESSION_VARIABLE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Getters and setters for configuration variables
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
public int getTimeSkewAllowance() {
|
||||
return timeSkewAllowance;
|
||||
}
|
||||
|
@ -582,6 +578,6 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
*/
|
||||
public void setAuthRequestUrlBuilder(AuthRequestUrlBuilder authRequestBuilder) {
|
||||
this.authRequestBuilder = authRequestBuilder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,25 +22,21 @@ import org.springframework.beans.factory.InitializingBean;
|
|||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
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.NullAuthoritiesMapper;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* @author nemonik
|
||||
*
|
||||
*/
|
||||
public class OIDCAuthenticationProvider implements
|
||||
AuthenticationProvider, InitializingBean {
|
||||
AuthenticationProvider, InitializingBean {
|
||||
|
||||
private UserInfoFetcher userInfoFetcher = new UserInfoFetcher();
|
||||
|
||||
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = new NamedAdminAuthoritiesMapper();
|
||||
|
||||
/*
|
||||
|
@ -69,24 +65,24 @@ public class OIDCAuthenticationProvider implements
|
|||
|
||||
if (authentication instanceof OIDCAuthenticationToken) {
|
||||
|
||||
|
||||
|
||||
OIDCAuthenticationToken token = (OIDCAuthenticationToken) authentication;
|
||||
|
||||
Collection<SubjectIssuerGrantedAuthority> authorities = Lists.newArrayList(new SubjectIssuerGrantedAuthority(token.getSub(), token.getIssuer()));
|
||||
|
||||
|
||||
UserInfo userInfo = userInfoFetcher.loadUserInfo(token);
|
||||
|
||||
if (userInfo == null) {
|
||||
// TODO: user Info not found -- error?
|
||||
} else {
|
||||
} else {
|
||||
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
|
||||
throw new UsernameNotFoundException("user_id mismatch between id_token and user_info call: " + userInfo.getSub() + " / " + token.getSub());
|
||||
}
|
||||
}
|
||||
|
||||
return new OIDCAuthenticationToken(token.getSub(),
|
||||
token.getIssuer(),
|
||||
|
||||
return new OIDCAuthenticationToken(token.getSub(),
|
||||
token.getIssuer(),
|
||||
userInfo, authoritiesMapper.mapAuthorities(authorities),
|
||||
token.getIdTokenValue(), token.getAccessTokenValue(), token.getRefreshTokenValue());
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ import com.google.common.collect.ImmutableMap;
|
|||
*/
|
||||
public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
private static final long serialVersionUID = 22100073066377804L;
|
||||
|
||||
private static final long serialVersionUID = 22100073066377804L;
|
||||
|
||||
private final Object principal;
|
||||
private final String idTokenValue; // string representation of the id 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 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.
|
||||
*
|
||||
|
@ -55,7 +55,7 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
|||
* @param principal
|
||||
* @param idToken
|
||||
*/
|
||||
public OIDCAuthenticationToken(String subject, String issuer,
|
||||
public OIDCAuthenticationToken(String subject, String issuer,
|
||||
UserInfo userInfo, Collection<? extends GrantedAuthority> authorities,
|
||||
String idTokenValue, String accessTokenValue, String refreshTokenValue) {
|
||||
|
||||
|
@ -70,12 +70,12 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
|||
this.refreshTokenValue = refreshTokenValue;
|
||||
|
||||
this.serverConfiguration = null; // we don't need a server config anymore
|
||||
|
||||
|
||||
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.
|
||||
*
|
||||
|
@ -83,8 +83,8 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
|||
* @param sub
|
||||
* @param idToken
|
||||
*/
|
||||
public OIDCAuthenticationToken(String subject, String issuer,
|
||||
ServerConfiguration serverConfiguration,
|
||||
public OIDCAuthenticationToken(String subject, String issuer,
|
||||
ServerConfiguration serverConfiguration,
|
||||
String idTokenValue, String accessTokenValue, String refreshTokenValue) {
|
||||
|
||||
super(new ArrayList<GrantedAuthority>(0));
|
||||
|
@ -97,10 +97,10 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
|||
this.refreshTokenValue = refreshTokenValue;
|
||||
|
||||
this.userInfo = null; // we don't have a UserInfo yet
|
||||
|
||||
|
||||
this.serverConfiguration = serverConfiguration;
|
||||
|
||||
|
||||
|
||||
|
||||
setAuthenticated(false);
|
||||
}
|
||||
|
||||
|
@ -128,46 +128,46 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the idTokenValue
|
||||
*/
|
||||
public String getIdTokenValue() {
|
||||
return idTokenValue;
|
||||
}
|
||||
* @return the idTokenValue
|
||||
*/
|
||||
public String getIdTokenValue() {
|
||||
return idTokenValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the accessTokenValue
|
||||
*/
|
||||
public String getAccessTokenValue() {
|
||||
return accessTokenValue;
|
||||
}
|
||||
* @return the accessTokenValue
|
||||
*/
|
||||
public String getAccessTokenValue() {
|
||||
return accessTokenValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the refreshTokenValue
|
||||
*/
|
||||
public String getRefreshTokenValue() {
|
||||
return refreshTokenValue;
|
||||
}
|
||||
* @return the refreshTokenValue
|
||||
*/
|
||||
public String getRefreshTokenValue() {
|
||||
return refreshTokenValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the serverConfiguration
|
||||
*/
|
||||
public ServerConfiguration getServerConfiguration() {
|
||||
return serverConfiguration;
|
||||
}
|
||||
* @return the serverConfiguration
|
||||
*/
|
||||
public ServerConfiguration getServerConfiguration() {
|
||||
return serverConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the issuer
|
||||
*/
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
* @return the issuer
|
||||
*/
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the userInfo
|
||||
*/
|
||||
public UserInfo getUserInfo() {
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
|
||||
* @return the userInfo
|
||||
*/
|
||||
public UserInfo getUserInfo() {
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -16,22 +16,22 @@ import com.google.common.base.Strings;
|
|||
*/
|
||||
public class SubjectIssuerGrantedAuthority implements GrantedAuthority {
|
||||
|
||||
private static final long serialVersionUID = 5584978219226664794L;
|
||||
|
||||
private static final long serialVersionUID = 5584978219226664794L;
|
||||
|
||||
private final String subject;
|
||||
private final String issuer;
|
||||
|
||||
|
||||
/**
|
||||
* @param subject
|
||||
* @param issuer
|
||||
*/
|
||||
public SubjectIssuerGrantedAuthority(String subject, String issuer) {
|
||||
if (Strings.isNullOrEmpty(subject) || Strings.isNullOrEmpty(issuer)) {
|
||||
throw new IllegalArgumentException("Neither subject nor issuer may be null or empty");
|
||||
}
|
||||
this.subject = subject;
|
||||
this.issuer = issuer;
|
||||
}
|
||||
public SubjectIssuerGrantedAuthority(String subject, String issuer) {
|
||||
if (Strings.isNullOrEmpty(subject) || Strings.isNullOrEmpty(issuer)) {
|
||||
throw new IllegalArgumentException("Neither subject nor issuer may be null or empty");
|
||||
}
|
||||
this.subject = subject;
|
||||
this.issuer = issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
return "OIDC_" + subject + "_" + issuer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the subject
|
||||
*/
|
||||
public String getSubject() {
|
||||
return subject;
|
||||
}
|
||||
public String getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @return the issuer
|
||||
*/
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
|
||||
result = prime * result + ((subject == null) ? 0 : subject.hashCode());
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
|
||||
result = prime * result + ((subject == null) ? 0 : subject.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof SubjectIssuerGrantedAuthority)) {
|
||||
return false;
|
||||
}
|
||||
SubjectIssuerGrantedAuthority other = (SubjectIssuerGrantedAuthority) obj;
|
||||
if (issuer == null) {
|
||||
if (other.issuer != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!issuer.equals(other.issuer)) {
|
||||
return false;
|
||||
}
|
||||
if (subject == null) {
|
||||
if (other.subject != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!subject.equals(other.subject)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getAuthority();
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof SubjectIssuerGrantedAuthority)) {
|
||||
return false;
|
||||
}
|
||||
SubjectIssuerGrantedAuthority other = (SubjectIssuerGrantedAuthority) obj;
|
||||
if (issuer == null) {
|
||||
if (other.issuer != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!issuer.equals(other.issuer)) {
|
||||
return false;
|
||||
}
|
||||
if (subject == null) {
|
||||
if (other.subject != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!subject.equals(other.subject)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getAuthority();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import com.google.gson.JsonParser;
|
|||
public class UserInfoFetcher {
|
||||
|
||||
public UserInfo loadUserInfo(OIDCAuthenticationToken token) {
|
||||
|
||||
|
||||
HttpClient httpClient = new DefaultHttpClient();
|
||||
|
||||
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
|
@ -25,15 +25,15 @@ public class UserInfoFetcher {
|
|||
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
||||
form.add("access_token", token.getAccessTokenValue());
|
||||
form.add("schema", "openid");
|
||||
|
||||
|
||||
String userInfoString = restTemplate.postForObject(token.getServerConfiguration().getUserInfoUri(), form, String.class);
|
||||
|
||||
|
||||
JsonObject userInfoJson = new JsonParser().parse(userInfoString).getAsJsonObject();
|
||||
|
||||
|
||||
UserInfo userInfo = DefaultUserInfo.fromJson(userInfoJson);
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
*/
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
if (!Strings.isNullOrEmpty(getJwkPublishUrl())) {
|
||||
|
||||
// add a mapping to this class
|
||||
BeanDefinitionBuilder clientKeyMapping = BeanDefinitionBuilder.rootBeanDefinition(ClientKeyPublisherMapping.class);
|
||||
// custom view resolver
|
||||
BeanDefinitionBuilder viewResolver = BeanDefinitionBuilder.rootBeanDefinition(JwkViewResolver.class);
|
||||
|
||||
|
||||
if (!Strings.isNullOrEmpty(getJwkPublishUrl())) {
|
||||
clientKeyMapping.addPropertyValue("jwkPublishUrl", getJwkPublishUrl());
|
||||
|
||||
|
@ -56,49 +56,49 @@ public class ClientKeyPublisher implements BeanDefinitionRegistryPostProcessor {
|
|||
registry.registerBeanDefinition("jwkKeyList", jwkView.getBeanDefinition());
|
||||
viewResolver.addPropertyReference("jwk", "jwkKeyList");
|
||||
}
|
||||
|
||||
|
||||
registry.registerBeanDefinition("clientKeyMapping", clientKeyMapping.getBeanDefinition());
|
||||
registry.registerBeanDefinition("jwkViewResolver", viewResolver.getBeanDefinition());
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||
*/
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
* @see org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||
*/
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
this.registry = registry;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a view to publish all keys in JWK format. Only used if jwkPublishUrl is set.
|
||||
* @return
|
||||
*/
|
||||
* Return a view to publish all keys in JWK format. Only used if jwkPublishUrl is set.
|
||||
* @return
|
||||
*/
|
||||
public ModelAndView publishClientJwk() {
|
||||
|
||||
|
||||
// map from key id to key
|
||||
Map<String, JWK> keys = signingAndValidationService.getAllPublicKeys();
|
||||
|
||||
// TODO: check if keys are empty, return a 404 here or just an empty list?
|
||||
|
||||
|
||||
return new ModelAndView(jwkViewName, "keys", keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jwkPublishUrl
|
||||
*/
|
||||
public String getJwkPublishUrl() {
|
||||
return jwkPublishUrl;
|
||||
}
|
||||
* @return the jwkPublishUrl
|
||||
*/
|
||||
public String getJwkPublishUrl() {
|
||||
return jwkPublishUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jwkPublishUrl the jwkPublishUrl to set
|
||||
*/
|
||||
public void setJwkPublishUrl(String jwkPublishUrl) {
|
||||
this.jwkPublishUrl = jwkPublishUrl;
|
||||
}
|
||||
* @param jwkPublishUrl the jwkPublishUrl to set
|
||||
*/
|
||||
public void setJwkPublishUrl(String jwkPublishUrl) {
|
||||
this.jwkPublishUrl = jwkPublishUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the signingAndValidationService
|
||||
|
|
|
@ -19,72 +19,72 @@ public class ClientKeyPublisherMapping extends RequestMappingInfoHandlerMapping
|
|||
|
||||
private String jwkPublishUrl;
|
||||
private String x509PublishUrl;
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#isHandler(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
protected boolean isHandler(Class<?> beanType) {
|
||||
return beanType.equals(ClientKeyPublisher.class);
|
||||
}
|
||||
* @see org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#isHandler(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
protected boolean isHandler(Class<?> beanType) {
|
||||
return beanType.equals(ClientKeyPublisher.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the "jwkKeyPublish" method to our jwkPublishUrl.
|
||||
* Map the "x509KeyPublish" method to our x509PublishUrl.
|
||||
*/
|
||||
@Override
|
||||
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||
|
||||
if (method.getName().equals("publishClientJwk") && getJwkPublishUrl() != null) {
|
||||
return new RequestMappingInfo(
|
||||
new PatternsRequestCondition(new String[] {getJwkPublishUrl()}, getUrlPathHelper(), getPathMatcher(), false, false),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
} else if (method.getName().equals("publishClientx509") && getX509PublishUrl() != null) {
|
||||
return new RequestMappingInfo(
|
||||
new PatternsRequestCondition(new String[] {getX509PublishUrl()}, getUrlPathHelper(), getPathMatcher(), false, false),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||
|
||||
if (method.getName().equals("publishClientJwk") && getJwkPublishUrl() != null) {
|
||||
return new RequestMappingInfo(
|
||||
new PatternsRequestCondition(new String[] {getJwkPublishUrl()}, getUrlPathHelper(), getPathMatcher(), false, false),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
} else if (method.getName().equals("publishClientx509") && getX509PublishUrl() != null) {
|
||||
return new RequestMappingInfo(
|
||||
new PatternsRequestCondition(new String[] {getX509PublishUrl()}, getUrlPathHelper(), getPathMatcher(), false, false),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jwkPublishUrl
|
||||
*/
|
||||
public String getJwkPublishUrl() {
|
||||
return jwkPublishUrl;
|
||||
}
|
||||
* @return the jwkPublishUrl
|
||||
*/
|
||||
public String getJwkPublishUrl() {
|
||||
return jwkPublishUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jwkPublishUrl the jwkPublishUrl to set
|
||||
*/
|
||||
public void setJwkPublishUrl(String jwkPublishUrl) {
|
||||
this.jwkPublishUrl = jwkPublishUrl;
|
||||
}
|
||||
* @param jwkPublishUrl the jwkPublishUrl to set
|
||||
*/
|
||||
public void setJwkPublishUrl(String jwkPublishUrl) {
|
||||
this.jwkPublishUrl = jwkPublishUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the x509PublishUrl
|
||||
*/
|
||||
public String getX509PublishUrl() {
|
||||
return x509PublishUrl;
|
||||
}
|
||||
* @return the x509PublishUrl
|
||||
*/
|
||||
public String getX509PublishUrl() {
|
||||
return x509PublishUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x509PublishUrl the x509PublishUrl to set
|
||||
*/
|
||||
public void setX509PublishUrl(String x509PublishUrl) {
|
||||
this.x509PublishUrl = x509PublishUrl;
|
||||
}
|
||||
* @param x509PublishUrl the x509PublishUrl to set
|
||||
*/
|
||||
public void setX509PublishUrl(String x509PublishUrl) {
|
||||
this.x509PublishUrl = x509PublishUrl;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,12 +20,12 @@ public class JwkViewResolver implements ViewResolver, Ordered {
|
|||
|
||||
private String jwkViewName = "jwkKeyList";
|
||||
private View jwk;
|
||||
|
||||
|
||||
private String x509ViewName = "x509certs";
|
||||
private View x509;
|
||||
|
||||
|
||||
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.
|
||||
* Everything else returns null
|
||||
|
@ -46,74 +46,74 @@ public class JwkViewResolver implements ViewResolver, Ordered {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the x509
|
||||
*/
|
||||
public View getX509() {
|
||||
return x509;
|
||||
}
|
||||
* @return the x509
|
||||
*/
|
||||
public View getX509() {
|
||||
return x509;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x509 the x509 to set
|
||||
*/
|
||||
public void setX509(View x509) {
|
||||
this.x509 = x509;
|
||||
}
|
||||
* @param x509 the x509 to set
|
||||
*/
|
||||
public void setX509(View x509) {
|
||||
this.x509 = x509;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jwk
|
||||
*/
|
||||
public View getJwk() {
|
||||
return jwk;
|
||||
}
|
||||
* @return the jwk
|
||||
*/
|
||||
public View getJwk() {
|
||||
return jwk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jwk the jwk to set
|
||||
*/
|
||||
public void setJwk(View jwk) {
|
||||
this.jwk = jwk;
|
||||
}
|
||||
* @param jwk the jwk to set
|
||||
*/
|
||||
public void setJwk(View jwk) {
|
||||
this.jwk = jwk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the order
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
* @return the order
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param order the order to set
|
||||
*/
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
* @param order the order to set
|
||||
*/
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jwkViewName
|
||||
*/
|
||||
public String getJwkViewName() {
|
||||
return jwkViewName;
|
||||
}
|
||||
* @return the jwkViewName
|
||||
*/
|
||||
public String getJwkViewName() {
|
||||
return jwkViewName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jwkViewName the jwkViewName to set
|
||||
*/
|
||||
public void setJwkViewName(String jwkViewName) {
|
||||
this.jwkViewName = jwkViewName;
|
||||
}
|
||||
* @param jwkViewName the jwkViewName to set
|
||||
*/
|
||||
public void setJwkViewName(String jwkViewName) {
|
||||
this.jwkViewName = jwkViewName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the x509ViewName
|
||||
*/
|
||||
public String getX509ViewName() {
|
||||
return x509ViewName;
|
||||
}
|
||||
* @return the x509ViewName
|
||||
*/
|
||||
public String getX509ViewName() {
|
||||
return x509ViewName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x509ViewName the x509ViewName to set
|
||||
*/
|
||||
public void setX509ViewName(String x509ViewName) {
|
||||
this.x509ViewName = x509ViewName;
|
||||
}
|
||||
* @param x509ViewName the x509ViewName to set
|
||||
*/
|
||||
public void setX509ViewName(String x509ViewName) {
|
||||
this.x509ViewName = x509ViewName;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,24 +16,24 @@ public class IssuerServiceResponse {
|
|||
private String loginHint;
|
||||
private String targetLinkUri;
|
||||
private String redirectUrl;
|
||||
|
||||
|
||||
/**
|
||||
* @param issuer
|
||||
* @param loginHint
|
||||
* @param targetLinkUri
|
||||
*/
|
||||
public IssuerServiceResponse(String issuer, String loginHint, String targetLinkUri) {
|
||||
this.issuer = issuer;
|
||||
this.loginHint = loginHint;
|
||||
this.targetLinkUri = targetLinkUri;
|
||||
}
|
||||
|
||||
public IssuerServiceResponse(String issuer, String loginHint, String targetLinkUri) {
|
||||
this.issuer = issuer;
|
||||
this.loginHint = loginHint;
|
||||
this.targetLinkUri = targetLinkUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param redirectUrl
|
||||
*/
|
||||
public IssuerServiceResponse(String redirectUrl) {
|
||||
this.redirectUrl = redirectUrl;
|
||||
}
|
||||
public IssuerServiceResponse(String redirectUrl) {
|
||||
this.redirectUrl = redirectUrl;
|
||||
}
|
||||
/**
|
||||
* @return the issuer
|
||||
*/
|
||||
|
@ -82,12 +82,12 @@ public class IssuerServiceResponse {
|
|||
public void setRedirectUrl(String redirectUrl) {
|
||||
this.redirectUrl = redirectUrl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the redirect url has been set, then we should send a redirect using it instead of processing things.
|
||||
*/
|
||||
public boolean shouldRedirect() {
|
||||
return this.redirectUrl != null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,6 @@ public interface AuthRequestUrlBuilder {
|
|||
* @param state
|
||||
* @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 ClientDetails getClientConfiguration(ServerConfiguration issuer);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -17,5 +17,5 @@ import org.mitre.openid.connect.client.model.IssuerServiceResponse;
|
|||
public interface IssuerService {
|
||||
|
||||
public IssuerServiceResponse getIssuer(HttpServletRequest request);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -12,5 +12,5 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
|||
public interface ServerConfigurationService {
|
||||
|
||||
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.LoadingCache;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
|
@ -35,66 +34,66 @@ import com.google.gson.JsonParser;
|
|||
public class DynamicRegistrationClientConfigurationService implements ClientConfigurationService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
|
||||
|
||||
|
||||
private LoadingCache<ServerConfiguration, ClientDetailsEntity> clients;
|
||||
|
||||
|
||||
private ClientDetailsEntity template;
|
||||
|
||||
|
||||
public DynamicRegistrationClientConfigurationService() {
|
||||
clients = CacheBuilder.newBuilder().build(new DynamicClientRegistrationLoader());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ClientDetails getClientConfiguration(ServerConfiguration issuer) {
|
||||
try {
|
||||
return clients.get(issuer);
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Unable to get client configuration", e);
|
||||
return null;
|
||||
}
|
||||
return clients.get(issuer);
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Unable to get client configuration", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @return the template
|
||||
*/
|
||||
public ClientDetailsEntity getTemplate() {
|
||||
return template;
|
||||
}
|
||||
public ClientDetailsEntity getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param template the template to set
|
||||
*/
|
||||
public void setTemplate(ClientDetailsEntity template) {
|
||||
this.template = template;
|
||||
}
|
||||
public void setTemplate(ClientDetailsEntity template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public class DynamicClientRegistrationLoader extends CacheLoader<ServerConfiguration, ClientDetailsEntity> {
|
||||
private HttpClient httpClient = new DefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private JsonParser parser = new JsonParser();
|
||||
|
||||
@Override
|
||||
public ClientDetailsEntity load(ServerConfiguration serverConfig) throws Exception {
|
||||
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;
|
||||
}
|
||||
@Override
|
||||
public ClientDetailsEntity load(ServerConfiguration serverConfig) throws Exception {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,72 +31,72 @@ import com.google.gson.JsonParser;
|
|||
public class DynamicServerConfigurationService implements ServerConfigurationService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
|
||||
|
||||
|
||||
// map of issuer -> server configuration, loaded dynamically from service discovery
|
||||
private LoadingCache<String, ServerConfiguration> servers;
|
||||
|
||||
|
||||
public DynamicServerConfigurationService() {
|
||||
// initialize the cache
|
||||
servers = CacheBuilder.newBuilder().build(new OpenIDConnectServiceConfigurationFetcher());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ServerConfiguration getServerConfiguration(String issuer) {
|
||||
try {
|
||||
return servers.get(issuer);
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Couldn't load configuration for " + issuer, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return servers.get(issuer);
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Couldn't load configuration for " + issuer, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
private class OpenIDConnectServiceConfigurationFetcher extends CacheLoader<String, ServerConfiguration> {
|
||||
private HttpClient httpClient = new DefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
private class OpenIDConnectServiceConfigurationFetcher extends CacheLoader<String, ServerConfiguration> {
|
||||
private HttpClient httpClient = new DefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private JsonParser parser = new JsonParser();
|
||||
|
||||
@Override
|
||||
public ServerConfiguration load(String issuer) throws Exception {
|
||||
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
@Override
|
||||
public ServerConfiguration load(String issuer) throws Exception {
|
||||
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
|
||||
// data holder
|
||||
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);
|
||||
// data holder
|
||||
ServerConfiguration conf = new ServerConfiguration();
|
||||
|
||||
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());
|
||||
// construct the well-known URI
|
||||
String url = issuer + "/.well-known/openid-configuration";
|
||||
|
||||
return conf;
|
||||
} else {
|
||||
throw new IllegalStateException("Couldn't parse server discovery results for " + url);
|
||||
}
|
||||
|
||||
}
|
||||
// fetch the value
|
||||
String jsonString = restTemplate.getForObject(url, String.class);
|
||||
|
||||
}
|
||||
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
|
||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, ClientDetails clientConfig, String redirectUri, String nonce, String state) {
|
||||
try {
|
||||
|
||||
|
||||
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
||||
uriBuilder.addParameter("response_type", "code");
|
||||
uriBuilder.addParameter("client_id", clientConfig.getClientId());
|
||||
|
@ -39,20 +39,20 @@ public class PlainAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
|||
uriBuilder.addParameter("nonce", nonce);
|
||||
|
||||
uriBuilder.addParameter("state", state);
|
||||
|
||||
|
||||
// Optional parameters:
|
||||
|
||||
// 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;
|
||||
|
||||
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.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||
|
@ -38,34 +33,34 @@ public class SignedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
|||
|
||||
// create our signed JWT for the request object
|
||||
JWTClaimsSet claims = new JWTClaimsSet();
|
||||
|
||||
|
||||
//set parameters to JwtClaims
|
||||
claims.setCustomClaim("response_type", "code");
|
||||
claims.setCustomClaim("client_id", clientConfig.getClientId());
|
||||
claims.setCustomClaim("scope", Joiner.on(" ").join(clientConfig.getScope()));
|
||||
|
||||
|
||||
// build our redirect URI
|
||||
claims.setCustomClaim("redirect_uri", redirectUri);
|
||||
|
||||
|
||||
// this comes back in the id token
|
||||
claims.setCustomClaim("nonce", nonce);
|
||||
|
||||
|
||||
// this comes back in the auth request return
|
||||
claims.setCustomClaim("state", state);
|
||||
|
||||
|
||||
SignedJWT jwt = new SignedJWT(new JWSHeader(signingAndValidationService.getDefaultSigningAlgorithm()), claims);
|
||||
|
||||
|
||||
signingAndValidationService.signJwt(jwt);
|
||||
|
||||
|
||||
try {
|
||||
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
||||
uriBuilder.addParameter("request", jwt.serialize());
|
||||
|
||||
// build out the URI
|
||||
return uriBuilder.build().toString();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new AuthenticationServiceException("Malformed Authorization Endpoint Uri", e);
|
||||
}
|
||||
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
||||
uriBuilder.addParameter("request", jwt.serialize());
|
||||
|
||||
// build out the URI
|
||||
return uriBuilder.build().toString();
|
||||
} catch (URISyntaxException 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
|
||||
private Map<String, ClientDetails> clients;
|
||||
|
||||
|
||||
/**
|
||||
* @return the clients
|
||||
*/
|
||||
|
@ -44,19 +44,19 @@ public class StaticClientConfigurationService implements ClientConfigurationServ
|
|||
*/
|
||||
@Override
|
||||
public ClientDetails getClientConfiguration(ServerConfiguration issuer) {
|
||||
|
||||
|
||||
return clients.get(issuer.getIssuer());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (clients == null || clients.isEmpty()) {
|
||||
throw new IllegalArgumentException("Clients map cannot be null or empty");
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (clients == null || clients.isEmpty()) {
|
||||
throw new IllegalArgumentException("Clients map cannot be null or empty");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,12 +45,12 @@ public class StaticServerConfigurationService implements ServerConfigurationServ
|
|||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (servers == null || servers.isEmpty()) {
|
||||
throw new IllegalArgumentException("Servers map cannot be null or empty.");
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (servers == null || servers.isEmpty()) {
|
||||
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 {
|
||||
|
||||
|
||||
private String issuer;
|
||||
|
||||
/**
|
||||
|
@ -46,13 +46,13 @@ public class StaticSingleIssuerService implements IssuerService, InitializingBea
|
|||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
if (Strings.isNullOrEmpty(issuer)) {
|
||||
throw new IllegalArgumentException("Issuer must not be null or empty.");
|
||||
}
|
||||
|
||||
}
|
||||
if (Strings.isNullOrEmpty(issuer)) {
|
||||
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 {
|
||||
|
||||
private String accountChooserUrl;
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.openid.connect.client.service.IssuerService#getIssuer(javax.servlet.http.HttpServletRequest)
|
||||
*/
|
||||
@Override
|
||||
public IssuerServiceResponse getIssuer(HttpServletRequest request) {
|
||||
|
||||
|
||||
// if the issuer is passed in, return that
|
||||
if (!Strings.isNullOrEmpty(request.getParameter("iss"))) {
|
||||
return new IssuerServiceResponse(request.getParameter("iss"), request.getParameter("login_hint"), request.getParameter("target_link_uri"));
|
||||
} else {
|
||||
|
||||
|
||||
try {
|
||||
// otherwise, need to forward to the account chooser
|
||||
String redirectUri = request.getRequestURL().toString();
|
||||
URIBuilder builder = new URIBuilder(accountChooserUrl);
|
||||
|
||||
builder.addParameter("redirect_uri", redirectUri);
|
||||
|
||||
return new IssuerServiceResponse(builder.build().toString());
|
||||
|
||||
} catch (URISyntaxException e) {
|
||||
throw new AuthenticationServiceException("Account Chooser URL is not valid", e);
|
||||
}
|
||||
|
||||
|
||||
URIBuilder builder = new URIBuilder(accountChooserUrl);
|
||||
|
||||
builder.addParameter("redirect_uri", redirectUri);
|
||||
|
||||
return new IssuerServiceResponse(builder.build().toString());
|
||||
|
||||
} catch (URISyntaxException e) {
|
||||
throw new AuthenticationServiceException("Account Chooser URL is not valid", e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,12 +72,12 @@ public class ThirdPartyIssuerService implements IssuerService, InitializingBean
|
|||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (Strings.isNullOrEmpty(this.accountChooserUrl)) {
|
||||
throw new IllegalArgumentException("Account Chooser URL cannot be null or empty");
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (Strings.isNullOrEmpty(this.accountChooserUrl)) {
|
||||
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 {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(WebfingerIssuerService.class);
|
||||
|
||||
|
||||
// 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:)?(([^@]+)@)?([^\\?]+)(\\?([^#]+))?(#(.*))?");
|
||||
|
||||
|
@ -47,7 +47,7 @@ public class WebfingerIssuerService implements IssuerService {
|
|||
* Name of the incoming parameter to check for discovery purposes.
|
||||
*/
|
||||
private String parameterName = "identifier";
|
||||
|
||||
|
||||
/**
|
||||
* URL of the page to forward to if no identifier is given.
|
||||
*/
|
||||
|
@ -56,53 +56,53 @@ public class WebfingerIssuerService implements IssuerService {
|
|||
public WebfingerIssuerService() {
|
||||
issuers = CacheBuilder.newBuilder().build(new WebfingerIssuerFetcher());
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.openid.connect.client.service.IssuerService#getIssuer(javax.servlet.http.HttpServletRequest)
|
||||
*/
|
||||
@Override
|
||||
public IssuerServiceResponse getIssuer(HttpServletRequest request) {
|
||||
|
||||
|
||||
String identifier = request.getParameter(parameterName);
|
||||
if (!Strings.isNullOrEmpty(identifier)) {
|
||||
try {
|
||||
String issuer = issuers.get(normalizeResource(identifier));
|
||||
return new IssuerServiceResponse(issuer, null, null);
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Issue fetching issuer for user input: " + identifier, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
String issuer = issuers.get(normalizeResource(identifier));
|
||||
return new IssuerServiceResponse(issuer, null, null);
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Issue fetching issuer for user input: " + identifier, e);
|
||||
return null;
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.warn("No user input given, directing to login page: " + loginPageUrl);
|
||||
return new IssuerServiceResponse(loginPageUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Normalize the resource string as per OIDC Discovery.
|
||||
* @param identifier
|
||||
* @return the normalized string, or null if the string can't be normalized
|
||||
*/
|
||||
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
|
||||
|
||||
|
||||
if (Strings.isNullOrEmpty(identifier)) {
|
||||
logger.warn("Can't normalize null or empty URI: " + identifier);
|
||||
return null; // nothing we can do
|
||||
} else {
|
||||
|
||||
NormalizedURI n = new NormalizedURI();
|
||||
Matcher m = pattern.matcher(identifier);
|
||||
|
||||
|
||||
NormalizedURI n = new NormalizedURI();
|
||||
Matcher m = pattern.matcher(identifier);
|
||||
|
||||
if (m.matches()) {
|
||||
n.scheme = m.group(1); // includes colon and maybe initial slashes
|
||||
n.user = m.group(2); // includes at sign
|
||||
n.hostportpath = m.group(4);
|
||||
n.query = m.group(5); // includes question mark
|
||||
n.hash = m.group(7); // includes hash mark
|
||||
|
||||
|
||||
// normalize scheme portion
|
||||
if (Strings.isNullOrEmpty(n.scheme)) {
|
||||
if (!Strings.isNullOrEmpty(n.user)) {
|
||||
|
@ -113,24 +113,24 @@ public class WebfingerIssuerService implements IssuerService {
|
|||
n.scheme = "https://";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
n.source = Strings.nullToEmpty(n.scheme) +
|
||||
Strings.nullToEmpty(n.user) +
|
||||
Strings.nullToEmpty(n.hostportpath) +
|
||||
Strings.nullToEmpty(n.hostportpath) +
|
||||
Strings.nullToEmpty(n.query); // note: leave fragment off
|
||||
|
||||
|
||||
return n;
|
||||
} else {
|
||||
logger.warn("Parser couldn't match input: " + identifier);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the parameterName
|
||||
*/
|
||||
|
@ -162,82 +162,82 @@ public class WebfingerIssuerService implements IssuerService {
|
|||
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
private class WebfingerIssuerFetcher extends CacheLoader<NormalizedURI, String> {
|
||||
private HttpClient httpClient = new DefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
private class WebfingerIssuerFetcher extends CacheLoader<NormalizedURI, String> {
|
||||
private HttpClient httpClient = new DefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private JsonParser parser = new JsonParser();
|
||||
|
||||
@Override
|
||||
public String load(NormalizedURI key) throws Exception {
|
||||
public String load(NormalizedURI key) throws Exception {
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
// 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);
|
||||
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
// construct the URL to go to
|
||||
|
||||
// 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;
|
||||
}
|
||||
//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
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
|
@ -18,10 +13,10 @@ public class AbstractOIDCAuthenticationFilterTest {
|
|||
|
||||
//@Autowired
|
||||
private OIDCAuthenticationFilter filter;
|
||||
|
||||
|
||||
//@Test
|
||||
public void testUrlConstruction() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,7 +32,7 @@ public class AbstractOIDCAuthenticationFilterTest {
|
|||
public void setFilter(OIDCAuthenticationFilter filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ package org.mitre.jose;
|
|||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
@ -22,16 +21,16 @@ import com.nimbusds.jose.JWEAlgorithm;
|
|||
public class JWEAlgorithmEmbed {
|
||||
|
||||
public static final JWEAlgorithmEmbed NONE = getForAlgorithmName("none");
|
||||
|
||||
|
||||
private JWEAlgorithm algorithm;
|
||||
|
||||
public JWEAlgorithmEmbed() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public JWEAlgorithmEmbed(JWEAlgorithm algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
public static JWEAlgorithmEmbed getForAlgorithmName (String algorithmName) {
|
||||
JWEAlgorithmEmbed ent = new JWEAlgorithmEmbed();
|
||||
|
@ -42,7 +41,7 @@ public class JWEAlgorithmEmbed {
|
|||
return ent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of this algorithm, return null if no algorithm set.
|
||||
* @return
|
||||
|
@ -55,9 +54,9 @@ public class JWEAlgorithmEmbed {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of this algorithm.
|
||||
* Set the name of this algorithm.
|
||||
* Calls JWEAlgorithm.parse()
|
||||
* @param algorithmName
|
||||
*/
|
||||
|
@ -72,15 +71,15 @@ public class JWEAlgorithmEmbed {
|
|||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JWEAlgorithmEmbed [algorithm=" + algorithm + "]";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JWEAlgorithmEmbed [algorithm=" + algorithm + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the algorithm
|
||||
*/
|
||||
@Transient
|
||||
@Transient
|
||||
public JWEAlgorithm getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
@ -91,5 +90,5 @@ public class JWEAlgorithmEmbed {
|
|||
public void setAlgorithm(JWEAlgorithm algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import javax.persistence.Transient;
|
|||
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jose.EncryptionMethod;
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
|
@ -19,16 +18,16 @@ import com.nimbusds.jose.JWEAlgorithm;
|
|||
public class JWEEncryptionMethodEmbed {
|
||||
|
||||
public static final JWEEncryptionMethodEmbed NONE = getForAlgorithmName("none");
|
||||
|
||||
|
||||
private EncryptionMethod algorithm;
|
||||
|
||||
public JWEEncryptionMethodEmbed() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public JWEEncryptionMethodEmbed(EncryptionMethod algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
public static JWEEncryptionMethodEmbed getForAlgorithmName (String algorithmName) {
|
||||
JWEEncryptionMethodEmbed ent = new JWEEncryptionMethodEmbed();
|
||||
|
@ -39,7 +38,7 @@ public class JWEEncryptionMethodEmbed {
|
|||
return ent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of this algorithm, return null if no algorithm set.
|
||||
* @return
|
||||
|
@ -52,9 +51,9 @@ public class JWEEncryptionMethodEmbed {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of this algorithm.
|
||||
* Set the name of this algorithm.
|
||||
* Calls EncryptionMethod.parse()
|
||||
* @param algorithmName
|
||||
*/
|
||||
|
@ -69,15 +68,15 @@ public class JWEEncryptionMethodEmbed {
|
|||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JWEEncryptionMethodEmbed [algorithm=" + algorithm + "]";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JWEEncryptionMethodEmbed [algorithm=" + algorithm + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the algorithm
|
||||
*/
|
||||
@Transient
|
||||
@Transient
|
||||
public EncryptionMethod getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
@ -88,6 +87,6 @@ public class JWEEncryptionMethodEmbed {
|
|||
public void setAlgorithm(EncryptionMethod algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ package org.mitre.jose;
|
|||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
@ -23,17 +21,17 @@ import com.nimbusds.jose.JWSAlgorithm;
|
|||
public class JWSAlgorithmEmbed {
|
||||
|
||||
public static final JWSAlgorithmEmbed NONE = getForAlgorithmName("none");
|
||||
|
||||
|
||||
private JWSAlgorithm algorithm;
|
||||
|
||||
public JWSAlgorithmEmbed() {
|
||||
|
||||
|
||||
public JWSAlgorithmEmbed() {
|
||||
|
||||
}
|
||||
|
||||
public JWSAlgorithmEmbed(JWSAlgorithm algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
public static JWSAlgorithmEmbed getForAlgorithmName (String algorithmName) {
|
||||
JWSAlgorithmEmbed ent = new JWSAlgorithmEmbed();
|
||||
ent.setAlgorithmName(algorithmName);
|
||||
|
@ -56,9 +54,9 @@ public class JWSAlgorithmEmbed {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of this algorithm.
|
||||
* Set the name of this algorithm.
|
||||
* Calls JWSAlgorithm.parse()
|
||||
* @param algorithmName
|
||||
*/
|
||||
|
@ -88,11 +86,11 @@ public class JWSAlgorithmEmbed {
|
|||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JWSAlgorithmEmbed [algorithm=" + algorithm + "]";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JWSAlgorithmEmbed [algorithm=" + algorithm + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -21,26 +21,26 @@ import com.nimbusds.jose.jwk.JWKSet;
|
|||
public class JWKSetKeyStore implements InitializingBean {
|
||||
|
||||
private JWKSet jwkSet;
|
||||
|
||||
|
||||
private Resource location;
|
||||
|
||||
|
||||
public JWKSetKeyStore() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public JWKSetKeyStore(JWKSet jwkSet) {
|
||||
this.jwkSet = jwkSet;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
|
||||
if (jwkSet == null) {
|
||||
if (location != null) {
|
||||
|
||||
|
||||
if (location.exists() && location.isReadable()) {
|
||||
|
||||
// read in the file from disk
|
||||
|
@ -48,11 +48,11 @@ public class JWKSetKeyStore implements InitializingBean {
|
|||
|
||||
// parse it into a jwkSet object
|
||||
jwkSet = JWKSet.parse(s);
|
||||
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Key Set resource could not be read: " + location);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
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
|
||||
*/
|
||||
public List<JWK> getKeys() {
|
||||
return jwkSet.getKeys();
|
||||
}
|
||||
|
||||
|
||||
public List<JWK> getKeys() {
|
||||
return jwkSet.getKeys();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package org.mitre.jwt.signer.service;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -30,7 +29,7 @@ public interface JwtSigningAndValidationService {
|
|||
* Get all public keys for this service, mapped by their Key ID
|
||||
*/
|
||||
public Map<String, JWK> getAllPublicKeys();
|
||||
|
||||
|
||||
/**
|
||||
* Checks the signature of the given JWT against all configured signers,
|
||||
* returns true if at least one of the signers validates it.
|
||||
|
@ -38,17 +37,17 @@ public interface JwtSigningAndValidationService {
|
|||
* @param jwtString
|
||||
* the string representation of the JWT as sent on the wire
|
||||
* @return true if the signature is valid, false if not
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public boolean validateSignature(SignedJWT jwtString);
|
||||
|
||||
|
||||
/**
|
||||
* Called to sign a jwt in place for a client that hasn't registered a preferred signing algorithm.
|
||||
* Use the default algorithm to sign.
|
||||
*
|
||||
* @param jwt the jwt to sign
|
||||
* @return the signed jwt
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
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.
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
|
@ -74,7 +73,7 @@ public interface JwtSigningAndValidationService {
|
|||
*/
|
||||
//TODO: implement later; only need signJwt(Jwt jwt) for now
|
||||
//public Jwt signJwt(Jwt jwt, String alg);
|
||||
|
||||
|
||||
/**
|
||||
* 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 String defaultSignerKeyId;
|
||||
|
||||
|
||||
private JWSAlgorithm defaultAlgorithm;
|
||||
|
||||
|
||||
// map of identifier to key
|
||||
private Map<String, JWK> keys = new HashMap<String, JWK>();
|
||||
|
||||
|
@ -73,10 +73,10 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
* @throws NoSuchAlgorithmException
|
||||
* If there is no appropriate algorithm to tie the keys to.
|
||||
*/
|
||||
public DefaultJwtSigningAndValidationService(Map<String, JWK> keys) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
this.keys = keys;
|
||||
buildSignersAndVerifiers();
|
||||
}
|
||||
public DefaultJwtSigningAndValidationService(Map<String, JWK> keys) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
this.keys = keys;
|
||||
buildSignersAndVerifiers();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* If there is no appropriate algorithm to tie the keys to.
|
||||
*/
|
||||
public DefaultJwtSigningAndValidationService(JWKSetKeyStore keyStore) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
// convert all keys in the keystore to a map based on key id
|
||||
for (JWK key : keyStore.getKeys()) {
|
||||
if (!Strings.isNullOrEmpty(key.getKeyID())) {
|
||||
this.keys.put(key.getKeyID(), key);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Tried to load a key from a keystore without a 'kid' field: " + key);
|
||||
}
|
||||
}
|
||||
buildSignersAndVerifiers();
|
||||
}
|
||||
|
||||
public DefaultJwtSigningAndValidationService(JWKSetKeyStore keyStore) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
// convert all keys in the keystore to a map based on key id
|
||||
for (JWK key : keyStore.getKeys()) {
|
||||
if (!Strings.isNullOrEmpty(key.getKeyID())) {
|
||||
this.keys.put(key.getKeyID(), key);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Tried to load a key from a keystore without a 'kid' field: " + key);
|
||||
}
|
||||
}
|
||||
buildSignersAndVerifiers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the defaultSignerKeyId
|
||||
*/
|
||||
|
@ -120,22 +120,22 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
* @return
|
||||
*/
|
||||
@Override
|
||||
public JWSAlgorithm getDefaultSigningAlgorithm() {
|
||||
return defaultAlgorithm;
|
||||
}
|
||||
|
||||
public void setDefaultSigningAlgorithmName(String algName) {
|
||||
defaultAlgorithm = JWSAlgorithm.parse(algName);
|
||||
}
|
||||
|
||||
public String getDefaultSigningAlgorithmName() {
|
||||
if (defaultAlgorithm != null) {
|
||||
return defaultAlgorithm.getName();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public JWSAlgorithm getDefaultSigningAlgorithm() {
|
||||
return defaultAlgorithm;
|
||||
}
|
||||
|
||||
public void setDefaultSigningAlgorithmName(String algName) {
|
||||
defaultAlgorithm = JWSAlgorithm.parse(algName);
|
||||
}
|
||||
|
||||
public String getDefaultSigningAlgorithmName() {
|
||||
if (defaultAlgorithm != null) {
|
||||
return defaultAlgorithm.getName();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
@ -148,9 +148,9 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
if (keys == null) {
|
||||
throw new IllegalArgumentException("Signing and validation service must have at least one key configured.");
|
||||
}
|
||||
|
||||
|
||||
buildSignersAndVerifiers();
|
||||
|
||||
|
||||
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 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()) {
|
||||
|
||||
String id = jwkEntry.getKey();
|
||||
JWK jwk = jwkEntry.getValue();
|
||||
|
||||
if (jwk instanceof RSAKey) {
|
||||
// build RSA signers & verifiers
|
||||
|
||||
if (jwk.isPrivate()) { // only add the signer if there's a private key
|
||||
RSASSASigner signer = new RSASSASigner(((RSAKey) jwk).toRSAPrivateKey());
|
||||
signers.put(id, signer);
|
||||
}
|
||||
|
||||
RSASSAVerifier verifier = new RSASSAVerifier(((RSAKey) jwk).toRSAPublicKey());
|
||||
verifiers.put(id, verifier);
|
||||
|
||||
} else if (jwk instanceof ECKey) {
|
||||
// build EC signers & verifiers
|
||||
|
||||
// TODO: add support for EC keys
|
||||
logger.warn("EC Keys are not yet supported.");
|
||||
|
||||
} else if (jwk instanceof OctetSequenceKey) {
|
||||
// build HMAC signers & verifiers
|
||||
|
||||
if (jwk.isPrivate()) { // technically redundant check because all HMAC keys are private
|
||||
MACSigner signer = new MACSigner(((OctetSequenceKey) jwk).toByteArray());
|
||||
signers.put(id, signer);
|
||||
}
|
||||
|
||||
MACVerifier verifier = new MACVerifier(((OctetSequenceKey) jwk).toByteArray());
|
||||
verifiers.put(id, verifier);
|
||||
|
||||
} else {
|
||||
logger.warn("Unknown key type: " + jwk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (jwk instanceof RSAKey) {
|
||||
// build RSA signers & verifiers
|
||||
|
||||
if (jwk.isPrivate()) { // only add the signer if there's a private key
|
||||
RSASSASigner signer = new RSASSASigner(((RSAKey) jwk).toRSAPrivateKey());
|
||||
signers.put(id, signer);
|
||||
}
|
||||
|
||||
RSASSAVerifier verifier = new RSASSAVerifier(((RSAKey) jwk).toRSAPublicKey());
|
||||
verifiers.put(id, verifier);
|
||||
|
||||
} else if (jwk instanceof ECKey) {
|
||||
// build EC signers & verifiers
|
||||
|
||||
// TODO: add support for EC keys
|
||||
logger.warn("EC Keys are not yet supported.");
|
||||
|
||||
} else if (jwk instanceof OctetSequenceKey) {
|
||||
// build HMAC signers & verifiers
|
||||
|
||||
if (jwk.isPrivate()) { // technically redundant check because all HMAC keys are private
|
||||
MACSigner signer = new MACSigner(((OctetSequenceKey) jwk).toByteArray());
|
||||
signers.put(id, signer);
|
||||
}
|
||||
|
||||
MACVerifier verifier = new MACVerifier(((OctetSequenceKey) jwk).toByteArray());
|
||||
verifiers.put(id, verifier);
|
||||
|
||||
} else {
|
||||
logger.warn("Unknown key type: " + jwk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a jwt in place using the configured default signer.
|
||||
|
@ -207,18 +207,18 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
if (getDefaultSignerKeyId() == null) {
|
||||
throw new IllegalStateException("Tried to call default signing with no default signer ID set");
|
||||
}
|
||||
|
||||
|
||||
JWSSigner signer = signers.get(getDefaultSignerKeyId());
|
||||
|
||||
try {
|
||||
jwt.sign(signer);
|
||||
} catch (JOSEException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
jwt.sign(signer);
|
||||
} catch (JOSEException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean validateSignature(SignedJWT jwt) {
|
||||
|
||||
|
@ -228,9 +228,9 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
return true;
|
||||
}
|
||||
} catch (JOSEException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -238,37 +238,37 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
@Override
|
||||
public Map<String, JWK> getAllPublicKeys() {
|
||||
Map<String, JWK> pubKeys = new HashMap<String, JWK>();
|
||||
|
||||
|
||||
// pull all keys out of the verifiers if we know how
|
||||
for (String keyId : keys.keySet()) {
|
||||
JWK key = keys.get(keyId);
|
||||
JWK pub = key.toPublicJWK();
|
||||
if (pub != null) {
|
||||
pubKeys.put(keyId, pub);
|
||||
}
|
||||
}
|
||||
|
||||
JWK key = keys.get(keyId);
|
||||
JWK pub = key.toPublicJWK();
|
||||
if (pub != null) {
|
||||
pubKeys.put(keyId, pub);
|
||||
}
|
||||
}
|
||||
|
||||
return pubKeys;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.jwt.signer.service.JwtSigningAndValidationService#getAllSigningAlgsSupported()
|
||||
*/
|
||||
@Override
|
||||
public Collection<JWSAlgorithm> getAllSigningAlgsSupported() {
|
||||
|
||||
Set<JWSAlgorithm> algs = new HashSet<JWSAlgorithm>();
|
||||
|
||||
for (JWSSigner signer : signers.values()) {
|
||||
algs.addAll(signer.supportedAlgorithms());
|
||||
}
|
||||
@Override
|
||||
public Collection<JWSAlgorithm> getAllSigningAlgsSupported() {
|
||||
|
||||
Set<JWSAlgorithm> algs = new HashSet<JWSAlgorithm>();
|
||||
|
||||
for (JWSSigner signer : signers.values()) {
|
||||
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;
|
||||
|
||||
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 org.apache.http.client.HttpClient;
|
||||
|
@ -21,19 +15,14 @@ import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
|||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.nimbusds.jose.JWSVerifier;
|
||||
import com.nimbusds.jose.crypto.RSASSAVerifier;
|
||||
import com.nimbusds.jose.jwk.JWK;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
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.
|
||||
*
|
||||
* @author jricher
|
||||
|
@ -43,7 +32,7 @@ import com.nimbusds.jose.jwk.RSAKey;
|
|||
public class JWKSetSigningAndValidationServiceCacheService {
|
||||
|
||||
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
|
||||
private LoadingCache<String, JwtSigningAndValidationService> cache;
|
||||
|
||||
|
@ -52,48 +41,48 @@ public class JWKSetSigningAndValidationServiceCacheService {
|
|||
.maximumSize(100)
|
||||
.build(new JWKSetVerifierFetcher());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param jwksUri
|
||||
* @return
|
||||
* @throws ExecutionException
|
||||
* @see com.google.common.cache.Cache#get(java.lang.Object)
|
||||
*/
|
||||
public JwtSigningAndValidationService get(String jwksUri) {
|
||||
try {
|
||||
return cache.get(jwksUri);
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Couldn't load JWK Set from " + jwksUri, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public JwtSigningAndValidationService get(String jwksUri) {
|
||||
try {
|
||||
return cache.get(jwksUri);
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Couldn't load JWK Set from " + jwksUri, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
private class JWKSetVerifierFetcher extends CacheLoader<String, JwtSigningAndValidationService> {
|
||||
private HttpClient httpClient = new DefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
|
||||
/**
|
||||
* Load the JWK Set and build the appropriate signing service.
|
||||
*/
|
||||
@Override
|
||||
public JwtSigningAndValidationService load(String key) throws Exception {
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
private class JWKSetVerifierFetcher extends CacheLoader<String, JwtSigningAndValidationService> {
|
||||
private HttpClient httpClient = new DefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
|
||||
String jsonString = restTemplate.getForObject(key, String.class);
|
||||
JWKSet jwkSet = JWKSet.parse(jsonString);
|
||||
|
||||
JWKSetKeyStore keyStore = new JWKSetKeyStore(jwkSet);
|
||||
|
||||
JwtSigningAndValidationService service = new DefaultJwtSigningAndValidationService(keyStore);
|
||||
/**
|
||||
* Load the JWK Set and build the appropriate signing service.
|
||||
*/
|
||||
@Override
|
||||
public JwtSigningAndValidationService load(String key) throws Exception {
|
||||
|
||||
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 {
|
||||
|
||||
private Long id;
|
||||
|
||||
|
||||
private Long ownerId;
|
||||
|
||||
|
||||
private OAuth2Authentication authentication;
|
||||
|
||||
|
||||
public AuthenticationHolderEntity() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Id
|
||||
|
@ -60,7 +60,7 @@ public class AuthenticationHolderEntity {
|
|||
public void setAuthentication(OAuth2Authentication authentication) {
|
||||
this.authentication = authentication;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -28,18 +28,18 @@ import org.springframework.security.oauth2.provider.code.AuthorizationRequestHol
|
|||
public class AuthorizationCodeEntity {
|
||||
|
||||
private Long id;
|
||||
|
||||
|
||||
private String code;
|
||||
|
||||
|
||||
private AuthorizationRequestHolder authorizationRequestHolder;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public AuthorizationCodeEntity() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new AuthorizationCodeEntity with the given code and AuthorizationRequestHolder.
|
||||
*
|
||||
|
@ -50,12 +50,12 @@ public class AuthorizationCodeEntity {
|
|||
this.code = code;
|
||||
this.authorizationRequestHolder = authRequest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -98,5 +98,5 @@ public class AuthorizationCodeEntity {
|
|||
public void setAuthorizationRequestHolder(AuthorizationRequestHolder authorizationRequestHolder) {
|
||||
this.authorizationRequestHolder = authorizationRequestHolder;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
private static final long serialVersionUID = -1617727085733786296L;
|
||||
|
||||
private Long id;
|
||||
|
||||
|
||||
/** Fields from the OAuth2 Dynamic Registration Specification */
|
||||
private String clientId = null; // client_id
|
||||
private String clientSecret = null; // client_secret
|
||||
|
@ -75,7 +75,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
private String clientName; // client_name
|
||||
private String clientUri; // client_uri
|
||||
private String logoUri; // logo_uri
|
||||
private Set<String> contacts; // contacts
|
||||
private Set<String> contacts; // contacts
|
||||
private String tosUri; // tos_uri
|
||||
private AuthMethod tokenEndpointAuthMethod = AuthMethod.SECRET_BASIC; // token_endpoint_auth_method
|
||||
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 String policyUri;
|
||||
private String jwksUri;
|
||||
|
||||
/** Fields from OIDC Client Registration Specification **/
|
||||
|
||||
/** Fields from OIDC Client Registration Specification **/
|
||||
private AppType applicationType; // application_type
|
||||
private String sectorIdentifierUri; // sector_identifier_uri
|
||||
private SubjectType subjectType; // subject_type
|
||||
|
||||
|
||||
private JWSAlgorithmEmbed requestObjectSigningAlg = JWSAlgorithmEmbed.NONE; // request_object_signing_alg
|
||||
|
||||
|
||||
private JWSAlgorithmEmbed userInfoSignedResponseAlg = JWSAlgorithmEmbed.NONE; // user_info_signed_response_alg
|
||||
private JWEAlgorithmEmbed userInfoEncryptedResponseAlg = JWEAlgorithmEmbed.NONE; // user_info_encrypted_response_alg
|
||||
private JWEEncryptionMethodEmbed userInfoEncryptedResponseEnc = JWEEncryptionMethodEmbed.NONE; // user_info_encrypted_response_enc
|
||||
|
||||
|
||||
private JWSAlgorithmEmbed idTokenSignedResponseAlg = JWSAlgorithmEmbed.NONE; // id_token_signed_response_alg
|
||||
private JWEAlgorithmEmbed idTokenEncryptedResponseAlg = JWEAlgorithmEmbed.NONE; // id_token_encrypted_response_alg
|
||||
private JWEEncryptionMethodEmbed idTokenEncryptedResponseEnc = JWEEncryptionMethodEmbed.NONE; // id_token_encrypted_response_enc
|
||||
|
||||
|
||||
private Integer defaultMaxAge; // default_max_age
|
||||
private Boolean requireAuthTime; // require_auth_time
|
||||
private Set<String> defaultACRvalues; // default_acr_values
|
||||
|
||||
|
||||
private String initiateLoginUri; // initiate_login_uri
|
||||
private String postLogoutRedirectUri; // post_logout_redirect_uri
|
||||
|
||||
|
||||
private Set<String> requestUris; // request_uris
|
||||
|
||||
|
||||
/** Fields to support the ClientDetails interface **/
|
||||
private Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
|
||||
private Integer accessTokenValiditySeconds = 0; // in seconds
|
||||
private Integer refreshTokenValiditySeconds = 0; // in seconds
|
||||
private Integer accessTokenValiditySeconds = 0; // in seconds
|
||||
private Integer refreshTokenValiditySeconds = 0; // in seconds
|
||||
private Set<String> resourceIds = new HashSet<String>();
|
||||
private Map<String, Object> additionalInformation = new HashMap<String, Object>();
|
||||
|
||||
|
||||
/** Our own fields **/
|
||||
private String clientDescription = ""; // human-readable description
|
||||
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 Integer idTokenValiditySeconds; //timeout for id tokens
|
||||
private Date createdAt; // time the client was created
|
||||
|
||||
|
||||
public enum AuthMethod {
|
||||
SECRET_POST("client_secret_post"),
|
||||
SECRET_BASIC("client_secret_basic"),
|
||||
SECRET_JWT("client_secret_jwt"),
|
||||
PRIVATE_KEY("private_key_jwt"),
|
||||
SECRET_POST("client_secret_post"),
|
||||
SECRET_BASIC("client_secret_basic"),
|
||||
SECRET_JWT("client_secret_jwt"),
|
||||
PRIVATE_KEY("private_key_jwt"),
|
||||
NONE("none");
|
||||
|
||||
|
||||
private final String value;
|
||||
|
||||
|
||||
// map to aid reverse lookup
|
||||
private static final Map<String, AuthMethod> lookup = new HashMap<String, AuthMethod>();
|
||||
static {
|
||||
|
@ -139,77 +139,77 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
lookup.put(a.getValue(), a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AuthMethod(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public static AuthMethod getByValue(String value) {
|
||||
return lookup.get(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum AppType {
|
||||
WEB("web"), NATIVE("native");
|
||||
|
||||
|
||||
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>();
|
||||
static {
|
||||
for (AppType a : AppType.values()) {
|
||||
lookup.put(a.getValue(), a);
|
||||
}
|
||||
lookup.put(a.getValue(), a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AppType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public static AppType getByValue(String value) {
|
||||
return lookup.get(value);
|
||||
}
|
||||
}
|
||||
|
||||
public enum SubjectType {
|
||||
PAIRWISE("pairwise"), PUBLIC("public");
|
||||
|
||||
public enum SubjectType {
|
||||
PAIRWISE("pairwise"), PUBLIC("public");
|
||||
|
||||
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>();
|
||||
static {
|
||||
for (SubjectType u : SubjectType.values()) {
|
||||
lookup.put(u.getValue(), u);
|
||||
}
|
||||
lookup.put(u.getValue(), u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SubjectType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public static SubjectType getByValue(String value) {
|
||||
return lookup.get(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a blank ClientDetailsEntity
|
||||
*/
|
||||
public ClientDetailsEntity() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,34 +228,34 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the clientDescription
|
||||
*/
|
||||
* @return the clientDescription
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="client_description")
|
||||
public String getClientDescription() {
|
||||
return clientDescription;
|
||||
}
|
||||
public String getClientDescription() {
|
||||
return clientDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientDescription Human-readable long description of the client (optional)
|
||||
*/
|
||||
public void setClientDescription(String clientDescription) {
|
||||
this.clientDescription = clientDescription;
|
||||
}
|
||||
* @param clientDescription Human-readable long description of the client (optional)
|
||||
*/
|
||||
public void setClientDescription(String clientDescription) {
|
||||
this.clientDescription = clientDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the allowRefresh
|
||||
*/
|
||||
* @return the allowRefresh
|
||||
*/
|
||||
@Transient
|
||||
public boolean isAllowRefresh() {
|
||||
public boolean isAllowRefresh() {
|
||||
if (grantTypes != null) {
|
||||
return getAuthorizedGrantTypes().contains("refresh_token");
|
||||
} else {
|
||||
return false; // if there are no grants, we can't be refreshing them, can we?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Column(name="reuse_refresh_tokens")
|
||||
|
@ -266,7 +266,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
public void setReuseRefreshToken(boolean reuseRefreshToken) {
|
||||
this.reuseRefreshToken = reuseRefreshToken;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the idTokenValiditySeconds
|
||||
*/
|
||||
|
@ -282,7 +282,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
public void setIdTokenValiditySeconds(Integer idTokenValiditySeconds) {
|
||||
this.idTokenValiditySeconds = idTokenValiditySeconds;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the dynamicallyRegistered
|
||||
*/
|
||||
|
@ -298,148 +298,149 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
public void setDynamicallyRegistered(boolean dynamicallyRegistered) {
|
||||
this.dynamicallyRegistered = dynamicallyRegistered;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the allowIntrospection
|
||||
*/
|
||||
* @return the allowIntrospection
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="allow_introspection")
|
||||
public boolean isAllowIntrospection() {
|
||||
return allowIntrospection;
|
||||
}
|
||||
public boolean isAllowIntrospection() {
|
||||
return allowIntrospection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param allowIntrospection the allowIntrospection to set
|
||||
*/
|
||||
public void setAllowIntrospection(boolean allowIntrospection) {
|
||||
this.allowIntrospection = allowIntrospection;
|
||||
}
|
||||
* @param allowIntrospection the allowIntrospection to set
|
||||
*/
|
||||
public void setAllowIntrospection(boolean allowIntrospection) {
|
||||
this.allowIntrospection = allowIntrospection;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
@Transient
|
||||
public boolean isSecretRequired() {
|
||||
// TODO: this should check the auth method field instead
|
||||
return getClientSecret() != null;
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
@Transient
|
||||
public boolean isSecretRequired() {
|
||||
// TODO: this should check the auth method field instead
|
||||
return getClientSecret() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the scope list is not null or empty, then this client has been scoped.
|
||||
*/
|
||||
@Override
|
||||
@Transient
|
||||
public boolean isScoped() {
|
||||
return getScope() != null && !getScope().isEmpty();
|
||||
}
|
||||
|
||||
*/
|
||||
@Override
|
||||
@Transient
|
||||
public boolean isScoped() {
|
||||
return getScope() != null && !getScope().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clientId
|
||||
*/
|
||||
* @return the clientId
|
||||
*/
|
||||
@Basic
|
||||
@Override
|
||||
@Column(name="client_id")
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientId The OAuth2 client_id, must be unique to this client
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
* @param clientId The OAuth2 client_id, must be unique to this client
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clientSecret
|
||||
*/
|
||||
* @return the clientSecret
|
||||
*/
|
||||
@Basic
|
||||
@Override
|
||||
@Column(name="client_secret")
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientSecret the OAuth2 client_secret (optional)
|
||||
*/
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
* @param clientSecret the OAuth2 client_secret (optional)
|
||||
*/
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the scope
|
||||
*/
|
||||
* @return the scope
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="client_scope",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
)
|
||||
@Override
|
||||
@Column(name="scope")
|
||||
public Set<String> getScope() {
|
||||
return scope;
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scope the set of scopes allowed to be issued to this client
|
||||
*/
|
||||
public void setScope(Set<String> scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
* @param scope the set of scopes allowed to be issued to this client
|
||||
*/
|
||||
public void setScope(Set<String> scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the authorizedGrantTypes
|
||||
*/
|
||||
* @return the authorizedGrantTypes
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="client_grant_type",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
)
|
||||
@Column(name="grant_type")
|
||||
public Set<String> getGrantTypes() {
|
||||
return grantTypes;
|
||||
}
|
||||
return grantTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authorizedGrantTypes the OAuth2 grant types that this client is allowed to use
|
||||
*/
|
||||
public void setGrantTypes(Set<String> grantTypes) {
|
||||
this.grantTypes = grantTypes;
|
||||
}
|
||||
* @param authorizedGrantTypes the OAuth2 grant types that this client is allowed to use
|
||||
*/
|
||||
public void setGrantTypes(Set<String> 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)
|
||||
@CollectionTable(
|
||||
name="client_authority",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
)
|
||||
@Override
|
||||
@Column(name="authority")
|
||||
public Set<GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
public Set<GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authorities the Spring Security authorities this client is given
|
||||
*/
|
||||
public void setAuthorities(Set<GrantedAuthority> authorities) {
|
||||
this.authorities = authorities;
|
||||
}
|
||||
* @param authorities the Spring Security authorities this client is given
|
||||
*/
|
||||
public void setAuthorities(Set<GrantedAuthority> authorities) {
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Basic
|
||||
|
@ -447,13 +448,13 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
public Integer getAccessTokenValiditySeconds() {
|
||||
return accessTokenValiditySeconds;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param accessTokenTimeout the accessTokenTimeout to set
|
||||
*/
|
||||
public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) {
|
||||
this.accessTokenValiditySeconds = accessTokenValiditySeconds;
|
||||
}
|
||||
* @param accessTokenTimeout the accessTokenTimeout to set
|
||||
*/
|
||||
public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) {
|
||||
this.accessTokenValiditySeconds = accessTokenValiditySeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Basic
|
||||
|
@ -461,64 +462,65 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
public Integer getRefreshTokenValiditySeconds() {
|
||||
return refreshTokenValiditySeconds;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param refreshTokenTimeout Lifetime of refresh tokens, in seconds (optional - leave null for no timeout)
|
||||
*/
|
||||
public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) {
|
||||
this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the registeredRedirectUri
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
* @param refreshTokenTimeout Lifetime of refresh tokens, in seconds (optional - leave null for no timeout)
|
||||
*/
|
||||
public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) {
|
||||
this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the registeredRedirectUri
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="client_redirect_uri",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="redirect_uri")
|
||||
public Set<String> getRedirectUris() {
|
||||
return redirectUris;
|
||||
}
|
||||
)
|
||||
@Column(name="redirect_uri")
|
||||
public Set<String> getRedirectUris() {
|
||||
return redirectUris;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param registeredRedirectUri the registeredRedirectUri to set
|
||||
*/
|
||||
public void setRedirectUris(Set<String> redirectUris) {
|
||||
this.redirectUris = redirectUris;
|
||||
}
|
||||
* @param registeredRedirectUri the registeredRedirectUri to set
|
||||
*/
|
||||
public void setRedirectUris(Set<String> 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)
|
||||
@CollectionTable(
|
||||
name="client_resource",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
)
|
||||
@Column(name="resource_id")
|
||||
public Set<String> getResourceIds() {
|
||||
return resourceIds;
|
||||
}
|
||||
public Set<String> getResourceIds() {
|
||||
return resourceIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resourceIds the resourceIds to set
|
||||
*/
|
||||
public void setResourceIds(Set<String> resourceIds) {
|
||||
this.resourceIds = resourceIds;
|
||||
}
|
||||
* @param resourceIds the resourceIds to set
|
||||
*/
|
||||
public void setResourceIds(Set<String> resourceIds) {
|
||||
this.resourceIds = resourceIds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This library does not make use of this field, so it is not
|
||||
* stored using our persistence layer.
|
||||
|
@ -533,7 +535,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
return this.additionalInformation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
|
@ -580,7 +582,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
@CollectionTable(
|
||||
name="client_contact",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
)
|
||||
@Column(name="contact")
|
||||
public Set<String> getContacts() {
|
||||
return contacts;
|
||||
|
@ -599,7 +601,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
public void setLogoUri(String logoUri) {
|
||||
this.logoUri = logoUri;
|
||||
}
|
||||
|
||||
|
||||
@Basic
|
||||
@Column(name="policy_uri")
|
||||
public String getPolicyUri() {
|
||||
|
@ -611,36 +613,36 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the clientUrl
|
||||
*/
|
||||
* @return the clientUrl
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="client_uri")
|
||||
public String getClientUri() {
|
||||
return clientUri;
|
||||
}
|
||||
public String getClientUri() {
|
||||
return clientUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientUrl the clientUrl to set
|
||||
*/
|
||||
public void setClientUri(String clientUri) {
|
||||
this.clientUri = clientUri;
|
||||
}
|
||||
* @param clientUrl the clientUrl to set
|
||||
*/
|
||||
public void setClientUri(String clientUri) {
|
||||
this.clientUri = clientUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tosUrl
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="tos_uri")
|
||||
public String getTosUri() {
|
||||
return tosUri;
|
||||
}
|
||||
* @return the tosUrl
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="tos_uri")
|
||||
public String getTosUri() {
|
||||
return tosUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tosUrl the tosUrl to set
|
||||
*/
|
||||
public void setTosUri(String tosUri) {
|
||||
this.tosUri = tosUri;
|
||||
}
|
||||
* @param tosUrl the tosUrl to set
|
||||
*/
|
||||
public void setTosUri(String tosUri) {
|
||||
this.tosUri = tosUri;
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Column(name="jwks_uri")
|
||||
|
@ -708,7 +710,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
|
||||
public void setUserInfoEncryptedResponseEnc(JWEEncryptionMethodEmbed userInfoEncryptedResponseEnc) {
|
||||
this.userInfoEncryptedResponseEnc = userInfoEncryptedResponseEnc;
|
||||
}
|
||||
}
|
||||
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
|
@ -773,7 +775,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
@CollectionTable(
|
||||
name="client_response_type",
|
||||
joinColumns=@JoinColumn(name="response_type")
|
||||
)
|
||||
)
|
||||
@Column(name="response_type")
|
||||
public Set<String> getResponseTypes() {
|
||||
return responseTypes;
|
||||
|
@ -793,7 +795,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
@CollectionTable(
|
||||
name="client_default_acr_value",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
)
|
||||
@Column(name="default_acr_value")
|
||||
public Set<String> getDefaultACRvalues() {
|
||||
return defaultACRvalues;
|
||||
|
@ -845,7 +847,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
@CollectionTable(
|
||||
name="client_request_uri",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
)
|
||||
@Column(name="request_uri")
|
||||
public Set<String> getRequestUris() {
|
||||
return requestUris;
|
||||
|
@ -863,15 +865,15 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
*/
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name="created_at")
|
||||
public Date getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
public Date getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param createdAt the createdAt to set
|
||||
*/
|
||||
public void setCreatedAt(Date createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
public void setCreatedAt(Date createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,9 +47,7 @@ import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
|||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.JWTParser;
|
||||
import com.nimbusds.jwt.PlainJWT;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
|
@ -73,17 +71,17 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
public static final String REGISTRATION_TOKEN_SCOPE = "registration-token";
|
||||
|
||||
public static String ID_TOKEN = "id_token";
|
||||
|
||||
|
||||
private Long id;
|
||||
|
||||
|
||||
private ClientDetailsEntity client;
|
||||
|
||||
|
||||
private AuthenticationHolderEntity authenticationHolder; // the authentication that made this access
|
||||
|
||||
|
||||
private JWT jwtValue; // JWT-encoded access token value
|
||||
|
||||
|
||||
private OAuth2AccessTokenEntity idToken; // JWT-encoded OpenID Connect IdToken
|
||||
|
||||
|
||||
private Date expiration;
|
||||
|
||||
private String tokenType = OAuth2AccessToken.BEARER_TYPE;
|
||||
|
@ -91,14 +89,14 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
private OAuth2RefreshTokenEntity refreshToken;
|
||||
|
||||
private Set<String> scope;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new, blank access token
|
||||
*/
|
||||
public OAuth2AccessTokenEntity() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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
|
||||
public Map<String, Object> getAdditionalInformation() {
|
||||
Map<String, Object> map = new HashMap<String, Object>(); //super.getAdditionalInformation();
|
||||
|
@ -126,121 +125,127 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The authentication in place when this token was created.
|
||||
* @return the authentication
|
||||
*/
|
||||
* @return the authentication
|
||||
*/
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "auth_holder_id")
|
||||
public AuthenticationHolderEntity getAuthenticationHolder() {
|
||||
return authenticationHolder;
|
||||
}
|
||||
public AuthenticationHolderEntity getAuthenticationHolder() {
|
||||
return authenticationHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authentication the authentication to set
|
||||
*/
|
||||
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
|
||||
this.authenticationHolder = authenticationHolder;
|
||||
}
|
||||
* @param authentication the authentication to set
|
||||
*/
|
||||
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
|
||||
this.authenticationHolder = authenticationHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the client
|
||||
*/
|
||||
* @return the client
|
||||
*/
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "client_id")
|
||||
public ClientDetailsEntity getClient() {
|
||||
return client;
|
||||
}
|
||||
public ClientDetailsEntity getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param client the client to set
|
||||
*/
|
||||
public void setClient(ClientDetailsEntity client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string-encoded value of this access token.
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="token_value")
|
||||
public String getValue() {
|
||||
return jwtValue.serialize();
|
||||
}
|
||||
* @param client the client to set
|
||||
*/
|
||||
public void setClient(ClientDetailsEntity client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "value" of this Access Token
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
/**
|
||||
* Get the string-encoded value of this access token.
|
||||
*/
|
||||
@Override
|
||||
@Basic
|
||||
@Column(name="token_value")
|
||||
public String getValue() {
|
||||
return jwtValue.serialize();
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
public Date getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
/**
|
||||
* Set the "value" of this Access Token
|
||||
*
|
||||
* @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) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
@Override
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
public Date getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Column(name="token_type")
|
||||
public String getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
public void setExpiration(Date expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
public void setTokenType(String tokenType) {
|
||||
this.tokenType = tokenType;
|
||||
}
|
||||
@Override
|
||||
@Basic
|
||||
@Column(name="token_type")
|
||||
public String getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name="refresh_token_id")
|
||||
public OAuth2RefreshTokenEntity getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
public void setTokenType(String tokenType) {
|
||||
this.tokenType = tokenType;
|
||||
}
|
||||
|
||||
public void setRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
@Override
|
||||
@ManyToOne
|
||||
@JoinColumn(name="refresh_token_id")
|
||||
public OAuth2RefreshTokenEntity getRefreshToken() {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public void setRefreshToken(OAuth2RefreshToken refreshToken) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ElementCollection(fetch=FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
joinColumns=@JoinColumn(name="owner_id"),
|
||||
name="token_scope"
|
||||
)
|
||||
public Set<String> getScope() {
|
||||
return scope;
|
||||
}
|
||||
public void setRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
|
||||
public void setScope(Set<String> scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
public void setRefreshToken(OAuth2RefreshToken refreshToken) {
|
||||
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() {
|
||||
return getExpiration() == null ? false : System.currentTimeMillis() > getExpiration().getTime();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the idToken
|
||||
*/
|
||||
@OneToOne(cascade=CascadeType.ALL) // one-to-one mapping for now
|
||||
@JoinColumn(name = "id_token_id")
|
||||
@OneToOne(cascade=CascadeType.ALL) // one-to-one mapping for now
|
||||
@JoinColumn(name = "id_token_id")
|
||||
public OAuth2AccessTokenEntity getIdToken() {
|
||||
return idToken;
|
||||
}
|
||||
|
@ -251,7 +256,7 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
public void setIdToken(OAuth2AccessTokenEntity idToken) {
|
||||
this.idToken = idToken;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the idTokenString
|
||||
*/
|
||||
|
|
|
@ -39,9 +39,7 @@ import javax.persistence.Transient;
|
|||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.JWTParser;
|
||||
import com.nimbusds.jwt.PlainJWT;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
|
@ -58,14 +56,14 @@ import com.nimbusds.jwt.PlainJWT;
|
|||
public class OAuth2RefreshTokenEntity implements OAuth2RefreshToken {
|
||||
|
||||
private Long id;
|
||||
|
||||
|
||||
private AuthenticationHolderEntity authenticationHolder;
|
||||
|
||||
|
||||
private ClientDetailsEntity client;
|
||||
|
||||
//JWT-encoded representation of this access token entity
|
||||
private JWT jwt;
|
||||
|
||||
|
||||
// our refresh tokens might expire
|
||||
private Date expiration;
|
||||
|
||||
|
@ -91,97 +89,98 @@ public class OAuth2RefreshTokenEntity implements OAuth2RefreshToken {
|
|||
public void setId(Long 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
|
||||
*/
|
||||
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
|
||||
this.authenticationHolder = authenticationHolder;
|
||||
}
|
||||
* 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
|
||||
*/
|
||||
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
|
||||
this.authenticationHolder = authenticationHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JWT-encoded value of this token
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="token_value")
|
||||
public String getValue() {
|
||||
return jwt.serialize();
|
||||
}
|
||||
@Override
|
||||
@Basic
|
||||
@Column(name="token_value")
|
||||
public String getValue() {
|
||||
return jwt.serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of this token as a string. Parses the string into a JWT.
|
||||
* @param value
|
||||
* @throws ParseException if the value is not a valid JWT string
|
||||
*/
|
||||
public void setValue(String value) throws ParseException {
|
||||
setJwt(JWTParser.parse(value));
|
||||
}
|
||||
/**
|
||||
* Set the value of this token as a string. Parses the string into a JWT.
|
||||
* @param value
|
||||
* @throws ParseException if the value is not a valid JWT string
|
||||
*/
|
||||
public void setValue(String value) throws ParseException {
|
||||
setJwt(JWTParser.parse(value));
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
public Date getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
public Date getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken#setExpiration(java.util.Date)
|
||||
*/
|
||||
|
||||
public void setExpiration(Date expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
* @see org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken#setExpiration(java.util.Date)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Has this token expired?
|
||||
* @return true if it has a timeout set and the timeout has passed
|
||||
*/
|
||||
@Transient
|
||||
public void setExpiration(Date expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this token expired?
|
||||
* @return true if it has a timeout set and the timeout has passed
|
||||
*/
|
||||
@Transient
|
||||
public boolean isExpired() {
|
||||
return getExpiration() == null ? false : System.currentTimeMillis() > getExpiration().getTime();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the client
|
||||
*/
|
||||
* @return the client
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "client_id")
|
||||
public ClientDetailsEntity getClient() {
|
||||
return client;
|
||||
}
|
||||
public ClientDetailsEntity getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param client the client to set
|
||||
*/
|
||||
public void setClient(ClientDetailsEntity client) {
|
||||
this.client = client;
|
||||
}
|
||||
* @param client the client to set
|
||||
*/
|
||||
public void setClient(ClientDetailsEntity 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 String value; // scope value
|
||||
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 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
|
||||
*/
|
||||
public SystemScope() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a system scope with the given scope value
|
||||
* @param value
|
||||
*/
|
||||
public SystemScope(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
public SystemScope(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
|
@ -117,7 +117,7 @@ public class SystemScope {
|
|||
public void setAllowDynReg(boolean allowDynReg) {
|
||||
this.allowDynReg = allowDynReg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the defaultScope
|
||||
*/
|
||||
|
@ -136,76 +136,76 @@ public class SystemScope {
|
|||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (allowDynReg ? 1231 : 1237);
|
||||
result = prime * result + (defaultScope ? 1231 : 1237);
|
||||
result = prime * result + ((description == null) ? 0 : description.hashCode());
|
||||
result = prime * result + ((icon == null) ? 0 : icon.hashCode());
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (allowDynReg ? 1231 : 1237);
|
||||
result = prime * result + (defaultScope ? 1231 : 1237);
|
||||
result = prime * result + ((description == null) ? 0 : description.hashCode());
|
||||
result = prime * result + ((icon == null) ? 0 : icon.hashCode());
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SystemScope other = (SystemScope) obj;
|
||||
if (allowDynReg != other.allowDynReg) {
|
||||
return false;
|
||||
}
|
||||
if (defaultScope != other.defaultScope) {
|
||||
return false;
|
||||
}
|
||||
if (description == null) {
|
||||
if (other.description != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!description.equals(other.description)) {
|
||||
return false;
|
||||
}
|
||||
if (icon == null) {
|
||||
if (other.icon != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!icon.equals(other.icon)) {
|
||||
return false;
|
||||
}
|
||||
if (id == null) {
|
||||
if (other.id != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (value == null) {
|
||||
if (other.value != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!value.equals(other.value)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SystemScope other = (SystemScope) obj;
|
||||
if (allowDynReg != other.allowDynReg) {
|
||||
return false;
|
||||
}
|
||||
if (defaultScope != other.defaultScope) {
|
||||
return false;
|
||||
}
|
||||
if (description == null) {
|
||||
if (other.description != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!description.equals(other.description)) {
|
||||
return false;
|
||||
}
|
||||
if (icon == null) {
|
||||
if (other.icon != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!icon.equals(other.icon)) {
|
||||
return false;
|
||||
}
|
||||
if (id == null) {
|
||||
if (other.id != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (value == null) {
|
||||
if (other.value != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!value.equals(other.value)) {
|
||||
return false;
|
||||
}
|
||||
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 AuthenticationHolderEntity getById(Long id);
|
||||
|
||||
|
||||
public AuthenticationHolderEntity getByAuthentication(OAuth2Authentication a);
|
||||
|
||||
|
||||
public void removeById(Long id);
|
||||
|
||||
|
||||
public void remove(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;
|
||||
|
||||
/**
|
||||
* Interface for saving and consuming OAuth2 authorization codes as AuthorizationCodeEntitys.
|
||||
* Interface for saving and consuming OAuth2 authorization codes as AuthorizationCodeEntitys.
|
||||
*
|
||||
* @author aanganes
|
||||
*
|
||||
|
@ -19,14 +19,14 @@ public interface AuthorizationCodeRepository {
|
|||
* @return the saved AuthorizationCodeEntity
|
||||
*/
|
||||
public AuthorizationCodeEntity save(AuthorizationCodeEntity authorizationCode);
|
||||
|
||||
|
||||
/**
|
||||
* Consume an authorization code.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public AuthorizationRequestHolder consume(String code) throws InvalidGrantException;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Collection;
|
|||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
|
||||
public interface OAuth2ClientRepository {
|
||||
|
||||
|
||||
public ClientDetailsEntity getById(Long id);
|
||||
|
||||
public ClientDetailsEntity getClientByClientId(String clientId);
|
||||
|
|
|
@ -27,17 +27,17 @@ public interface OAuth2TokenRepository {
|
|||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity token);
|
||||
|
||||
public OAuth2RefreshTokenEntity getRefreshTokenByValue(String refreshTokenValue);
|
||||
|
||||
|
||||
public OAuth2RefreshTokenEntity getRefreshTokenById(Long Id);
|
||||
|
||||
public void clearAccessTokensForRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||
|
||||
public void removeRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||
|
||||
|
||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||
|
||||
public OAuth2AccessTokenEntity getAccessTokenByValue(String accessTokenValue);
|
||||
|
||||
|
||||
public OAuth2AccessTokenEntity getAccessTokenById(Long id);
|
||||
|
||||
public void removeAccessToken(OAuth2AccessTokenEntity accessToken);
|
||||
|
@ -55,8 +55,8 @@ public interface OAuth2TokenRepository {
|
|||
public OAuth2AccessTokenEntity getByAuthentication(OAuth2Authentication auth);
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken);
|
||||
|
||||
* @return
|
||||
*/
|
||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken);
|
||||
|
||||
}
|
||||
|
|
|
@ -14,13 +14,13 @@ import org.mitre.oauth2.model.SystemScope;
|
|||
public interface SystemScopeRepository {
|
||||
|
||||
public Set<SystemScope> getAll();
|
||||
|
||||
|
||||
public SystemScope getById(Long id);
|
||||
|
||||
|
||||
public SystemScope getByValue(String value);
|
||||
|
||||
|
||||
public void remove(SystemScope scope);
|
||||
|
||||
|
||||
public SystemScope save(SystemScope scope);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -24,19 +24,20 @@ import org.springframework.security.oauth2.provider.ClientDetailsService;
|
|||
public interface ClientDetailsEntityService extends ClientDetailsService {
|
||||
|
||||
public ClientDetailsEntity saveNewClient(ClientDetailsEntity client);
|
||||
|
||||
|
||||
public ClientDetailsEntity getClientById(Long id);
|
||||
|
||||
|
||||
@Override
|
||||
public ClientDetailsEntity loadClientByClientId(String clientId) throws OAuth2Exception;
|
||||
|
||||
public void deleteClient(ClientDetailsEntity client);
|
||||
|
||||
|
||||
public ClientDetailsEntity updateClient(ClientDetailsEntity oldClient, ClientDetailsEntity newClient);
|
||||
|
||||
public Collection<ClientDetailsEntity> getAllClients();
|
||||
|
||||
public ClientDetailsEntity generateClientId(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 {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity readAccessToken(String accessTokenValue);
|
||||
|
||||
|
||||
public OAuth2RefreshTokenEntity getRefreshToken(String refreshTokenValue);
|
||||
|
||||
public void revokeRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||
|
||||
public void revokeAccessToken(OAuth2AccessTokenEntity accessToken);
|
||||
|
||||
|
||||
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client);
|
||||
|
||||
|
||||
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client);
|
||||
|
||||
public void clearExpiredTokens();
|
||||
|
||||
|
||||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity accessToken);
|
||||
|
||||
|
||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessToken(OAuth2Authentication authentication);
|
||||
|
||||
/**
|
||||
* @param incomingToken
|
||||
* @return
|
||||
*/
|
||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken);
|
||||
|
||||
* @param incomingToken
|
||||
* @return
|
||||
*/
|
||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken);
|
||||
|
||||
}
|
||||
|
|
|
@ -12,15 +12,15 @@ import org.mitre.oauth2.model.SystemScope;
|
|||
*
|
||||
*/
|
||||
public interface SystemScopeService {
|
||||
|
||||
|
||||
public Set<SystemScope> getAll();
|
||||
|
||||
|
||||
/**
|
||||
* Get all scopes that are defaulted to new clients on this system
|
||||
* @return
|
||||
*/
|
||||
public Set<SystemScope> getDefaults();
|
||||
|
||||
|
||||
/**
|
||||
* Get all scopes that are allowed for dynamic registration on this system
|
||||
* @return
|
||||
|
@ -28,20 +28,20 @@ public interface SystemScopeService {
|
|||
public Set<SystemScope> getDynReg();
|
||||
|
||||
public SystemScope getById(Long id);
|
||||
|
||||
|
||||
public SystemScope getByValue(String value);
|
||||
|
||||
|
||||
public void remove(SystemScope scope);
|
||||
|
||||
|
||||
public SystemScope save(SystemScope scope);
|
||||
|
||||
|
||||
/**
|
||||
* Translate the set of scope strings into a set of SystemScope objects.
|
||||
* @param scope
|
||||
* @return
|
||||
*/
|
||||
public Set<SystemScope> fromStrings(Set<String> scope);
|
||||
|
||||
|
||||
/**
|
||||
* Pluck the scope values from the set of SystemScope objects and return a list of strings
|
||||
* @param scope
|
||||
|
|
|
@ -17,7 +17,6 @@ package org.mitre.oauth2.service.impl;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
@ -44,32 +43,32 @@ public class DefaultClientUserDetailsService implements UserDetailsService {
|
|||
private ClientDetailsService clientDetailsService;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String clientId) throws UsernameNotFoundException, DataAccessException {
|
||||
public UserDetails loadUserByUsername(String clientId) throws UsernameNotFoundException, DataAccessException {
|
||||
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
|
||||
|
||||
|
||||
if (client != null) {
|
||||
|
||||
String password = client.getClientSecret();
|
||||
boolean enabled = true;
|
||||
boolean accountNonExpired = true;
|
||||
boolean credentialsNonExpired = true;
|
||||
boolean accountNonLocked = true;
|
||||
Collection<GrantedAuthority> authorities = client.getAuthorities();
|
||||
if (authorities == null || authorities.isEmpty()) {
|
||||
// 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
|
||||
authorities = new ArrayList<GrantedAuthority>();
|
||||
GrantedAuthority roleClient = new SimpleGrantedAuthority("ROLE_CLIENT");
|
||||
authorities.add(roleClient);
|
||||
}
|
||||
|
||||
return new User(clientId, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
||||
|
||||
String password = client.getClientSecret();
|
||||
boolean enabled = true;
|
||||
boolean accountNonExpired = true;
|
||||
boolean credentialsNonExpired = true;
|
||||
boolean accountNonLocked = true;
|
||||
Collection<GrantedAuthority> authorities = client.getAuthorities();
|
||||
if (authorities == null || authorities.isEmpty()) {
|
||||
// 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
|
||||
authorities = new ArrayList<GrantedAuthority>();
|
||||
GrantedAuthority roleClient = new SimpleGrantedAuthority("ROLE_CLIENT");
|
||||
authorities.add(roleClient);
|
||||
}
|
||||
|
||||
return new User(clientId, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
||||
} else {
|
||||
throw new UsernameNotFoundException("Client not found: " + clientId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public ClientDetailsService getClientDetailsService() {
|
||||
return clientDetailsService;
|
||||
|
@ -78,5 +77,5 @@ public class DefaultClientUserDetailsService implements UserDetailsService {
|
|||
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
|
||||
this.clientDetailsService = clientDetailsService;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import com.google.gson.reflect.TypeToken;
|
|||
*
|
||||
*/
|
||||
public class ClientDetailsEntityJsonProcessor {
|
||||
|
||||
|
||||
private static Gson gson = new Gson();
|
||||
private static JsonParser parser = new JsonParser();
|
||||
|
||||
|
@ -43,16 +43,16 @@ public class ClientDetailsEntityJsonProcessor {
|
|||
public static ClientDetailsEntity parse(String jsonString) {
|
||||
JsonElement jsonEl = parser.parse(jsonString);
|
||||
if (jsonEl.isJsonObject()) {
|
||||
|
||||
|
||||
JsonObject o = jsonEl.getAsJsonObject();
|
||||
ClientDetailsEntity c = new ClientDetailsEntity();
|
||||
|
||||
|
||||
// TODO: make these field names into constants
|
||||
|
||||
|
||||
// these two fields should only be sent in the update request, and MUST match existing values
|
||||
c.setClientId(getAsString(o, "client_id"));
|
||||
c.setClientSecret(getAsString(o, "client_secret"));
|
||||
|
||||
|
||||
// OAuth DynReg
|
||||
c.setRedirectUris(getAsStringSet(o, "redirect_uris"));
|
||||
c.setClientName(getAsString(o, "client_name"));
|
||||
|
@ -60,66 +60,66 @@ public class ClientDetailsEntityJsonProcessor {
|
|||
c.setLogoUri(getAsString(o, "logo_uri"));
|
||||
c.setContacts(getAsStringSet(o, "contacts"));
|
||||
c.setTosUri(getAsString(o, "tos_uri"));
|
||||
|
||||
|
||||
String authMethod = getAsString(o, "token_endpoint_auth_method");
|
||||
if (authMethod != null) {
|
||||
c.setTokenEndpointAuthMethod(AuthMethod.getByValue(authMethod));
|
||||
}
|
||||
|
||||
|
||||
// scope is a space-separated string
|
||||
String scope = getAsString(o, "scope");
|
||||
if (scope != null) {
|
||||
c.setScope(Sets.newHashSet(Splitter.on(" ").split(scope)));
|
||||
}
|
||||
|
||||
|
||||
c.setGrantTypes(getAsStringSet(o, "grant_types"));
|
||||
c.setPolicyUri(getAsString(o, "policy_uri"));
|
||||
c.setJwksUri(getAsString(o, "jwks_uri"));
|
||||
|
||||
|
||||
|
||||
|
||||
// OIDC Additions
|
||||
String appType = getAsString(o, "application_type");
|
||||
if (appType != null) {
|
||||
c.setApplicationType(AppType.getByValue(appType));
|
||||
}
|
||||
|
||||
|
||||
c.setSectorIdentifierUri(getAsString(o, "sector_identifier_uri"));
|
||||
|
||||
|
||||
String subjectType = getAsString(o, "subject_type");
|
||||
if (subjectType != null) {
|
||||
c.setSubjectType(SubjectType.getByValue(subjectType));
|
||||
}
|
||||
|
||||
|
||||
c.setRequestObjectSigningAlg(getAsJwsAlgorithm(o, "request_object_signing_alg"));
|
||||
|
||||
|
||||
c.setUserInfoSignedResponseAlg(getAsJwsAlgorithm(o, "userinfo_signed_response_alg"));
|
||||
c.setUserInfoEncryptedResponseAlg(getAsJweAlgorithm(o, "userinfo_encrypted_response_alg"));
|
||||
c.setUserInfoEncryptedResponseEnc(getAsJweEncryptionMethod(o, "userinfo_encrypted_response_enc"));
|
||||
|
||||
|
||||
c.setIdTokenSignedResponseAlg(getAsJwsAlgorithm(o, "id_token_signed_response_alg"));
|
||||
c.setIdTokenEncryptedResponseAlg(getAsJweAlgorithm(o, "id_token_encrypted_response_alg"));
|
||||
c.setIdTokenEncryptedResponseEnc(getAsJweEncryptionMethod(o, "id_token_encrypted_response_enc"));
|
||||
|
||||
|
||||
if (o.has("default_max_age")) {
|
||||
if (o.get("default_max_age").isJsonPrimitive()) {
|
||||
c.setDefaultMaxAge(o.get("default_max_age").getAsInt());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (o.has("require_auth_time")) {
|
||||
if (o.get("require_auth_time").isJsonPrimitive()) {
|
||||
c.setRequireAuthTime(o.get("require_auth_time").getAsBoolean());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
c.setDefaultACRvalues(getAsStringSet(o, "default_acr_values"));
|
||||
c.setInitiateLoginUri(getAsString(o, "initiate_login_uri"));
|
||||
c.setPostLogoutRedirectUri(getAsString(o, "post_logout_redirect_uri"));
|
||||
c.setRequestUris(getAsStringSet(o, "request_uris"));
|
||||
|
||||
|
||||
return c;
|
||||
} else {
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,28 +134,28 @@ public class ClientDetailsEntityJsonProcessor {
|
|||
* @return
|
||||
*/
|
||||
public static JsonObject serialize(ClientDetailsEntity c, OAuth2AccessTokenEntity token, String registrationUri) {
|
||||
JsonObject o = new JsonObject();
|
||||
|
||||
JsonObject o = new JsonObject();
|
||||
|
||||
o.addProperty("client_id", c.getClientId());
|
||||
if (c.getClientSecret() != null) {
|
||||
o.addProperty("client_secret", c.getClientSecret());
|
||||
o.addProperty("expires_at", 0); // TODO: do we want to let secrets expire?
|
||||
}
|
||||
|
||||
|
||||
if (c.getCreatedAt() != null) {
|
||||
o.addProperty("issued_at", c.getCreatedAt().getTime());
|
||||
}
|
||||
if (token != null) {
|
||||
o.addProperty("registration_access_token", token.getValue());
|
||||
}
|
||||
|
||||
|
||||
if (registrationUri != null) {
|
||||
o.addProperty("registration_client_uri", registrationUri);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// add in all other client properties
|
||||
|
||||
|
||||
// OAuth DynReg
|
||||
o.add("redirect_uris", getAsArray(c.getRedirectUris()));
|
||||
o.addProperty("client_name", c.getClientName());
|
||||
|
@ -168,7 +168,7 @@ public class ClientDetailsEntityJsonProcessor {
|
|||
o.add("grant_types", getAsArray(c.getGrantTypes()));
|
||||
o.addProperty("policy_uri", c.getPolicyUri());
|
||||
o.addProperty("jwks_uri", c.getJwksUri());
|
||||
|
||||
|
||||
// OIDC Registration
|
||||
o.addProperty("application_type", c.getApplicationType() != null ? c.getApplicationType().getValue() : null);
|
||||
o.addProperty("sector_identifier_uri", c.getSectorIdentifierUri());
|
||||
|
@ -186,7 +186,7 @@ public class ClientDetailsEntityJsonProcessor {
|
|||
o.addProperty("initiate_login_uri", c.getInitiateLoginUri());
|
||||
o.addProperty("post_logout_redirect_uri", c.getPostLogoutRedirectUri());
|
||||
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
|
||||
* 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
|
||||
*
|
||||
|
@ -28,22 +28,22 @@ package org.mitre.openid.connect.config;
|
|||
public class ConfigurationPropertiesBean {
|
||||
|
||||
private String issuer;
|
||||
|
||||
|
||||
private String topbarTitle;
|
||||
|
||||
|
||||
private String logoImageUrl;
|
||||
|
||||
|
||||
public ConfigurationPropertiesBean() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the issuer baseUrl
|
||||
*/
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param iss the issuer to set
|
||||
*/
|
||||
|
|
|
@ -29,13 +29,13 @@ public class ServerConfiguration {
|
|||
private String authorizationEndpointUri;
|
||||
|
||||
private String tokenEndpointUri;
|
||||
|
||||
|
||||
private String registrationEndpointUri;
|
||||
|
||||
private String issuer;
|
||||
|
||||
|
||||
private String jwksUri;
|
||||
|
||||
|
||||
private String userInfoUri;
|
||||
|
||||
/**
|
||||
|
@ -125,78 +125,78 @@ public class ServerConfiguration {
|
|||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((authorizationEndpointUri == null) ? 0 : authorizationEndpointUri.hashCode());
|
||||
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
|
||||
result = prime * result + ((jwksUri == null) ? 0 : jwksUri.hashCode());
|
||||
result = prime * result + ((registrationEndpointUri == null) ? 0 : registrationEndpointUri.hashCode());
|
||||
result = prime * result + ((tokenEndpointUri == null) ? 0 : tokenEndpointUri.hashCode());
|
||||
result = prime * result + ((userInfoUri == null) ? 0 : userInfoUri.hashCode());
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((authorizationEndpointUri == null) ? 0 : authorizationEndpointUri.hashCode());
|
||||
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
|
||||
result = prime * result + ((jwksUri == null) ? 0 : jwksUri.hashCode());
|
||||
result = prime * result + ((registrationEndpointUri == null) ? 0 : registrationEndpointUri.hashCode());
|
||||
result = prime * result + ((tokenEndpointUri == null) ? 0 : tokenEndpointUri.hashCode());
|
||||
result = prime * result + ((userInfoUri == null) ? 0 : userInfoUri.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ServerConfiguration other = (ServerConfiguration) obj;
|
||||
if (authorizationEndpointUri == null) {
|
||||
if (other.authorizationEndpointUri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!authorizationEndpointUri.equals(other.authorizationEndpointUri)) {
|
||||
return false;
|
||||
}
|
||||
if (issuer == null) {
|
||||
if (other.issuer != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!issuer.equals(other.issuer)) {
|
||||
return false;
|
||||
}
|
||||
if (jwksUri == null) {
|
||||
if (other.jwksUri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!jwksUri.equals(other.jwksUri)) {
|
||||
return false;
|
||||
}
|
||||
if (registrationEndpointUri == null) {
|
||||
if (other.registrationEndpointUri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!registrationEndpointUri.equals(other.registrationEndpointUri)) {
|
||||
return false;
|
||||
}
|
||||
if (tokenEndpointUri == null) {
|
||||
if (other.tokenEndpointUri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!tokenEndpointUri.equals(other.tokenEndpointUri)) {
|
||||
return false;
|
||||
}
|
||||
if (userInfoUri == null) {
|
||||
if (other.userInfoUri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!userInfoUri.equals(other.userInfoUri)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ServerConfiguration other = (ServerConfiguration) obj;
|
||||
if (authorizationEndpointUri == null) {
|
||||
if (other.authorizationEndpointUri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!authorizationEndpointUri.equals(other.authorizationEndpointUri)) {
|
||||
return false;
|
||||
}
|
||||
if (issuer == null) {
|
||||
if (other.issuer != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!issuer.equals(other.issuer)) {
|
||||
return false;
|
||||
}
|
||||
if (jwksUri == null) {
|
||||
if (other.jwksUri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!jwksUri.equals(other.jwksUri)) {
|
||||
return false;
|
||||
}
|
||||
if (registrationEndpointUri == null) {
|
||||
if (other.registrationEndpointUri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!registrationEndpointUri.equals(other.registrationEndpointUri)) {
|
||||
return false;
|
||||
}
|
||||
if (tokenEndpointUri == null) {
|
||||
if (other.tokenEndpointUri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!tokenEndpointUri.equals(other.tokenEndpointUri)) {
|
||||
return false;
|
||||
}
|
||||
if (userInfoUri == null) {
|
||||
if (other.userInfoUri != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!userInfoUri.equals(other.userInfoUri)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -27,7 +27,7 @@ import javax.persistence.Table;
|
|||
@Table(name="address")
|
||||
public class Address {
|
||||
|
||||
|
||||
|
||||
private Long id;
|
||||
private String formatted;
|
||||
private String streetAddress;
|
||||
|
@ -35,14 +35,14 @@ public class Address {
|
|||
private String region;
|
||||
private String postalCode;
|
||||
private String country;
|
||||
|
||||
|
||||
/**
|
||||
* Empty constructor
|
||||
*/
|
||||
public Address() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the formatted address string
|
||||
*/
|
||||
|
@ -125,19 +125,19 @@ public class Address {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,164 +45,164 @@ import javax.persistence.Transient;
|
|||
})
|
||||
public class ApprovedSite {
|
||||
|
||||
// unique id
|
||||
private Long id;
|
||||
|
||||
// which user made the approval
|
||||
// unique id
|
||||
private Long id;
|
||||
|
||||
// which user made the approval
|
||||
private String userId;
|
||||
|
||||
|
||||
// which OAuth2 client is this tied to
|
||||
private String clientId;
|
||||
|
||||
|
||||
// when was this first approved?
|
||||
private Date creationDate;
|
||||
|
||||
|
||||
// when was this last accessed?
|
||||
private Date accessDate;
|
||||
|
||||
|
||||
// if this is a time-limited access, when does it run out?
|
||||
private Date timeoutDate;
|
||||
|
||||
|
||||
// what scopes have been allowed
|
||||
// this should include all information for what data to access
|
||||
private Set<String> allowedScopes;
|
||||
|
||||
|
||||
// If this AP is a WS, link to the WS
|
||||
private WhitelistedSite whitelistedSite;
|
||||
|
||||
|
||||
// TODO: should we store the OAuth2 tokens and IdTokens here?
|
||||
|
||||
|
||||
/**
|
||||
* Empty constructor
|
||||
*/
|
||||
public ApprovedSite() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the userInfo
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="user_id")
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
* @return the userInfo
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="user_id")
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userInfo the userInfo to set
|
||||
*/
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
* @param userInfo the userInfo to set
|
||||
*/
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clientId
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="client_id")
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
* @return the clientId
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="client_id")
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientId the clientId to set
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
* @param clientId the clientId to set
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the creationDate
|
||||
*/
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name="creation_date")
|
||||
public Date getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
* @return the creationDate
|
||||
*/
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name="creation_date")
|
||||
public Date getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param creationDate the creationDate to set
|
||||
*/
|
||||
public void setCreationDate(Date creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
* @param creationDate the creationDate to set
|
||||
*/
|
||||
public void setCreationDate(Date creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the accessDate
|
||||
*/
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name="access_date")
|
||||
public Date getAccessDate() {
|
||||
return accessDate;
|
||||
}
|
||||
* @return the accessDate
|
||||
*/
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name="access_date")
|
||||
public Date getAccessDate() {
|
||||
return accessDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param accessDate the accessDate to set
|
||||
*/
|
||||
public void setAccessDate(Date accessDate) {
|
||||
this.accessDate = accessDate;
|
||||
}
|
||||
* @param accessDate the accessDate to set
|
||||
*/
|
||||
public void setAccessDate(Date accessDate) {
|
||||
this.accessDate = accessDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the allowedScopes
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="approved_site_scope",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="scope")
|
||||
public Set<String> getAllowedScopes() {
|
||||
return allowedScopes;
|
||||
}
|
||||
* @return the allowedScopes
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="approved_site_scope",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="scope")
|
||||
public Set<String> getAllowedScopes() {
|
||||
return allowedScopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param allowedScopes the allowedScopes to set
|
||||
*/
|
||||
public void setAllowedScopes(Set<String> allowedScopes) {
|
||||
this.allowedScopes = allowedScopes;
|
||||
}
|
||||
* @param allowedScopes the allowedScopes to set
|
||||
*/
|
||||
public void setAllowedScopes(Set<String> allowedScopes) {
|
||||
this.allowedScopes = allowedScopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the timeoutDate
|
||||
*/
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name="timeout_date")
|
||||
public Date getTimeoutDate() {
|
||||
return timeoutDate;
|
||||
}
|
||||
* @return the timeoutDate
|
||||
*/
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name="timeout_date")
|
||||
public Date getTimeoutDate() {
|
||||
return timeoutDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeoutDate the timeoutDate to set
|
||||
*/
|
||||
public void setTimeoutDate(Date timeoutDate) {
|
||||
this.timeoutDate = timeoutDate;
|
||||
}
|
||||
* @param timeoutDate the timeoutDate to set
|
||||
*/
|
||||
public void setTimeoutDate(Date timeoutDate) {
|
||||
this.timeoutDate = timeoutDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this AP entry correspond to a WS?
|
||||
* @return
|
||||
*/
|
||||
@Transient
|
||||
/**
|
||||
* Does this AP entry correspond to a WS?
|
||||
* @return
|
||||
*/
|
||||
@Transient
|
||||
public Boolean getIsWhitelisted() {
|
||||
return (whitelistedSite != null);
|
||||
}
|
||||
|
@ -220,10 +220,10 @@ public class ApprovedSite {
|
|||
|
||||
/**
|
||||
* Has this approval expired?
|
||||
* @return
|
||||
*/
|
||||
* @return
|
||||
*/
|
||||
@Transient
|
||||
public boolean isExpired() {
|
||||
public boolean isExpired() {
|
||||
if (getTimeoutDate() != null) {
|
||||
Date now = new Date();
|
||||
if (now.after(getTimeoutDate())) {
|
||||
|
@ -234,6 +234,6 @@ public class ApprovedSite {
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,41 +24,41 @@ import javax.persistence.Table;
|
|||
})
|
||||
public class BlacklistedSite {
|
||||
|
||||
// unique id
|
||||
private Long id;
|
||||
|
||||
// URI pattern to black list
|
||||
private String uri;
|
||||
|
||||
public BlacklistedSite() {
|
||||
|
||||
}
|
||||
|
||||
// unique id
|
||||
private Long id;
|
||||
|
||||
// URI pattern to black list
|
||||
private String uri;
|
||||
|
||||
public BlacklistedSite() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Column(name="uri")
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
@Basic
|
||||
@Column(name="uri")
|
||||
public String getUri() {
|
||||
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")
|
||||
@NamedQueries({
|
||||
@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.getBySubject", query = "select u from DefaultUserInfo u WHERE u.sub = :sub")
|
||||
@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")
|
||||
})
|
||||
public class DefaultUserInfo implements UserInfo {
|
||||
|
||||
|
||||
private Long id;
|
||||
private String sub;
|
||||
private String sub;
|
||||
private String preferredUsername;
|
||||
private String name;
|
||||
private String givenName;
|
||||
private String familyName;
|
||||
private String middleName;
|
||||
private String nickname;
|
||||
private String name;
|
||||
private String givenName;
|
||||
private String familyName;
|
||||
private String middleName;
|
||||
private String nickname;
|
||||
private String profile;
|
||||
private String picture;
|
||||
private String picture;
|
||||
private String website;
|
||||
private String email;
|
||||
private Boolean emailVerified;
|
||||
|
@ -58,8 +58,8 @@ public class DefaultUserInfo implements UserInfo {
|
|||
private Address address;
|
||||
private String updatedTime;
|
||||
private String birthdate;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
|
@ -356,21 +356,23 @@ public class DefaultUserInfo implements UserInfo {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the birthdate
|
||||
*/
|
||||
* @return the birthdate
|
||||
*/
|
||||
@Override
|
||||
@Basic
|
||||
@Column(name="birthdate")
|
||||
public String getBirthdate() {
|
||||
return birthdate;
|
||||
}
|
||||
public String getBirthdate() {
|
||||
return birthdate;
|
||||
}
|
||||
/**
|
||||
* @param birthdate the birthdate to set
|
||||
*/
|
||||
public void setBirthdate(String birthdate) {
|
||||
this.birthdate = birthdate;
|
||||
}
|
||||
* @param birthdate the birthdate to set
|
||||
*/
|
||||
@Override
|
||||
public void setBirthdate(String birthdate) {
|
||||
this.birthdate = birthdate;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Parse a JsonObject into a UserInfo.
|
||||
* @param o
|
||||
* @return
|
||||
|
@ -379,7 +381,7 @@ public class DefaultUserInfo implements UserInfo {
|
|||
DefaultUserInfo ui = new DefaultUserInfo();
|
||||
|
||||
ui.setSub(obj.has("sub") ? obj.get("sub").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.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.setUpdatedTime(obj.has("updated_time") ? obj.get("updated_time").getAsString() : null);
|
||||
ui.setBirthdate(obj.has("birthdate") ? obj.get("birthdate").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.setPhoneNumber(obj.has("phone_number") ? obj.get("phone_number").getAsString() : null);
|
||||
|
||||
|
||||
|
||||
if (obj.has("address") && obj.get("address").isJsonObject()) {
|
||||
JsonObject addr = obj.get("address").getAsJsonObject();
|
||||
ui.setAddress(new Address());
|
||||
|
||||
|
||||
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().setLocality(addr.has("locality") ? addr.get("locality").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().setCountry(addr.has("country") ? addr.get("country").getAsString() : null);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return ui;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,50 +37,50 @@ import javax.persistence.Temporal;
|
|||
public class Event {
|
||||
|
||||
public static enum EventType { LOGIN, AUTHORIZATION, ACCESS }
|
||||
|
||||
|
||||
private Long id;
|
||||
private EventType type;
|
||||
private Date timestamp;
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public EventType getType() {
|
||||
return type;
|
||||
}
|
||||
* @return the type
|
||||
*/
|
||||
public EventType getType() {
|
||||
return type;
|
||||
}
|
||||
/**
|
||||
* @param type the type to set
|
||||
*/
|
||||
public void setType(EventType type) {
|
||||
this.type = type;
|
||||
}
|
||||
* @param type the type to set
|
||||
*/
|
||||
public void setType(EventType type) {
|
||||
this.type = type;
|
||||
}
|
||||
/**
|
||||
* @return the timestamp
|
||||
*/
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
public Date getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
* @return the timestamp
|
||||
*/
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
public Date getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
/**
|
||||
* @param timestamp the timestamp to set
|
||||
*/
|
||||
public void setTimestamp(Date timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
* @param timestamp the timestamp to set
|
||||
*/
|
||||
public void setTimestamp(Date timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,16 +23,16 @@ import javax.persistence.Temporal;
|
|||
})
|
||||
public class Nonce {
|
||||
|
||||
|
||||
|
||||
private Long id; //the ID of this Nonce
|
||||
|
||||
|
||||
private String value; //the value of 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 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
|
||||
|
@ -86,7 +86,7 @@ public class Nonce {
|
|||
* @return the useDate
|
||||
*/
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name="use_date")
|
||||
public Date getUseDate() {
|
||||
return useDate;
|
||||
|
@ -103,7 +103,7 @@ public class Nonce {
|
|||
* @return the expireDate
|
||||
*/
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name="expire_date")
|
||||
public Date getExpireDate() {
|
||||
return expireDate;
|
||||
|
@ -115,8 +115,8 @@ public class Nonce {
|
|||
public void setExpireDate(Date expireDate) {
|
||||
this.expireDate = expireDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ public interface UserInfo {
|
|||
* @param sub the userId to set
|
||||
*/
|
||||
public abstract void setSub(String sub);
|
||||
|
||||
|
||||
/**
|
||||
* @return the preferred username
|
||||
*/
|
||||
public abstract String getPreferredUsername();
|
||||
|
||||
|
||||
/**
|
||||
* @param preferredUsername the preferredUsername to set
|
||||
*/
|
||||
|
@ -189,7 +189,7 @@ public interface UserInfo {
|
|||
* @return
|
||||
*/
|
||||
public abstract String getBirthdate();
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param birthdate
|
||||
|
|
|
@ -32,7 +32,7 @@ import javax.persistence.NamedQuery;
|
|||
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.
|
||||
* @author jricher, aanganes
|
||||
*
|
||||
|
@ -40,21 +40,21 @@ import javax.persistence.Table;
|
|||
@Entity
|
||||
@Table(name="whitelisted_site")
|
||||
@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.getByCreatoruserId", query = "select w from WhitelistedSite w where w.creatorUserId = :userId")
|
||||
})
|
||||
public class WhitelistedSite {
|
||||
|
||||
// unique id
|
||||
private Long id;
|
||||
|
||||
// Reference to the admin user who created this entry
|
||||
// unique id
|
||||
private Long id;
|
||||
|
||||
// Reference to the admin user who created this entry
|
||||
private String creatorUserId;
|
||||
|
||||
|
||||
// which OAuth2 client is this tied to
|
||||
private String clientId;
|
||||
|
||||
|
||||
// what scopes be allowed by default
|
||||
// this should include all information for what data to access
|
||||
private Set<String> allowedScopes;
|
||||
|
@ -63,14 +63,14 @@ public class WhitelistedSite {
|
|||
* Empty constructor
|
||||
*/
|
||||
public WhitelistedSite() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -103,9 +103,9 @@ public class WhitelistedSite {
|
|||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="whitelisted_site_scope",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
name="whitelisted_site_scope",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="scope")
|
||||
public Set<String> getAllowedScopes() {
|
||||
return allowedScopes;
|
||||
|
|
|
@ -50,7 +50,7 @@ public interface ApprovedSiteRepository {
|
|||
* @param clientId
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
*/
|
||||
public Collection<ApprovedSite> getByClientIdAndUserId(String clientId, String userId);
|
||||
|
||||
/**
|
||||
|
@ -69,14 +69,14 @@ public interface ApprovedSiteRepository {
|
|||
* @return the persisted entity
|
||||
*/
|
||||
public ApprovedSite save(ApprovedSite approvedSite);
|
||||
|
||||
|
||||
/**
|
||||
* Get all sites approved by this user
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
public Collection<ApprovedSite> getByUserId(String userId);
|
||||
|
||||
|
||||
/**
|
||||
* Get all sites associated with this client
|
||||
* @param clientId
|
||||
|
|
|
@ -14,13 +14,13 @@ import org.mitre.openid.connect.model.BlacklistedSite;
|
|||
public interface BlacklistedSiteRepository {
|
||||
|
||||
public Collection<BlacklistedSite> getAll();
|
||||
|
||||
|
||||
public BlacklistedSite getById(Long id);
|
||||
|
||||
|
||||
public void remove(BlacklistedSite blacklistedSite);
|
||||
|
||||
|
||||
public BlacklistedSite save(BlacklistedSite blacklistedSite);
|
||||
|
||||
|
||||
public BlacklistedSite update(BlacklistedSite oldBlacklistedSite, BlacklistedSite blacklistedSite);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -47,8 +47,8 @@ public interface EventRepository {
|
|||
* @param startChunk
|
||||
* the start chuck of a list you desire
|
||||
* @param chunkSize
|
||||
* the size of the chunk you desire
|
||||
*
|
||||
* the size of the chunk you desire
|
||||
*
|
||||
* @return a Collection of Events
|
||||
*/
|
||||
public Collection<Event> getEventsDuringPeriod(Date start, Date end, int startChunk, int chunkSize);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.mitre.openid.connect.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mitre.openid.connect.model.Nonce;
|
||||
|
||||
/**
|
||||
|
@ -19,14 +20,14 @@ public interface NonceRepository {
|
|||
* @return the nonce, if found
|
||||
*/
|
||||
public Nonce getById(Long id);
|
||||
|
||||
|
||||
/**
|
||||
* Remove the given Nonce from the database
|
||||
*
|
||||
* @param nonce the Nonce to remove
|
||||
*/
|
||||
public void remove(Nonce nonce);
|
||||
|
||||
|
||||
/**
|
||||
* Save a new Nonce in the database
|
||||
*
|
||||
|
@ -34,21 +35,21 @@ public interface NonceRepository {
|
|||
* @return the saved Nonce
|
||||
*/
|
||||
public Nonce save(Nonce nonce);
|
||||
|
||||
|
||||
/**
|
||||
* Return all nonces stored in the database
|
||||
*
|
||||
* @return the set of nonces
|
||||
*/
|
||||
public Collection<Nonce> getAll();
|
||||
|
||||
|
||||
/**
|
||||
* Return all expired nonces stored in the database
|
||||
*
|
||||
* @return the set of expired nonces
|
||||
*/
|
||||
public Collection<Nonce> getExpired();
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public Collection<Nonce> getByClientId(String clientId);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -26,24 +26,24 @@ import org.mitre.openid.connect.model.UserInfo;
|
|||
*
|
||||
*/
|
||||
public interface UserInfoRepository {
|
||||
|
||||
|
||||
/**
|
||||
* Returns the UserInfo for the given subject
|
||||
*
|
||||
* @param sub
|
||||
* the subject of the UserInfo
|
||||
* @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
|
||||
* @return
|
||||
*/
|
||||
public UserInfo save(UserInfo userInfo);
|
||||
|
||||
|
||||
/**
|
||||
* Removes the given UserInfo from the repository
|
||||
*
|
||||
|
@ -64,6 +64,6 @@ public interface UserInfoRepository {
|
|||
* @param username
|
||||
* @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
|
||||
*/
|
||||
public WhitelistedSite getById(Long id);
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public WhitelistedSite getByClientId(String clientId);
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param oldWhitelistedSite
|
||||
* @param whitelistedSite
|
||||
* @return
|
||||
*/
|
||||
public WhitelistedSite update(WhitelistedSite oldWhitelistedSite, WhitelistedSite whitelistedSite);
|
||||
* @param oldWhitelistedSite
|
||||
* @param whitelistedSite
|
||||
* @return
|
||||
*/
|
||||
public WhitelistedSite update(WhitelistedSite oldWhitelistedSite, WhitelistedSite whitelistedSite);
|
||||
|
||||
}
|
||||
|
|
|
@ -30,17 +30,17 @@ import org.springframework.security.oauth2.provider.ClientDetails;
|
|||
*
|
||||
*/
|
||||
public interface ApprovedSiteService {
|
||||
|
||||
|
||||
|
||||
|
||||
public ApprovedSite createApprovedSite(String clientId, String userId, Date timeoutDate, Set<String> allowedScopes, WhitelistedSite whitelistedSite);
|
||||
|
||||
|
||||
/**
|
||||
* Return a collection of all ApprovedSites
|
||||
*
|
||||
* @return the ApprovedSite collection, or null
|
||||
*/
|
||||
public Collection<ApprovedSite> getAll();
|
||||
|
||||
|
||||
/**
|
||||
* Return a collection of ApprovedSite managed by this repository matching the
|
||||
* provided client ID and user ID
|
||||
|
@ -48,9 +48,9 @@ public interface ApprovedSiteService {
|
|||
* @param clientId
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
*/
|
||||
public Collection<ApprovedSite> getByClientIdAndUserId(String clientId, String userId);
|
||||
|
||||
|
||||
/**
|
||||
* Save an ApprovedSite
|
||||
*
|
||||
|
@ -82,14 +82,14 @@ public interface ApprovedSiteService {
|
|||
* @return
|
||||
*/
|
||||
public Collection<ApprovedSite> getByUserId(String userId);
|
||||
|
||||
|
||||
/**
|
||||
* Get all sites associated with this client
|
||||
* @param clientId
|
||||
* @return
|
||||
*/
|
||||
public Collection<ApprovedSite> getByClientId(String clientId);
|
||||
|
||||
|
||||
/**
|
||||
* Clear out any approved sites for a given client.
|
||||
* @param client
|
||||
|
|
|
@ -14,15 +14,15 @@ import org.mitre.openid.connect.model.BlacklistedSite;
|
|||
public interface BlacklistedSiteService {
|
||||
|
||||
public Collection<BlacklistedSite> getAll();
|
||||
|
||||
|
||||
public BlacklistedSite getById(Long id);
|
||||
|
||||
|
||||
public void remove(BlacklistedSite blacklistedSite);
|
||||
|
||||
|
||||
public BlacklistedSite saveNew(BlacklistedSite blacklistedSite);
|
||||
|
||||
|
||||
public BlacklistedSite update(BlacklistedSite oldBlacklistedSite, BlacklistedSite blacklistedSite);
|
||||
|
||||
public boolean isBlacklisted(String uri);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -15,24 +15,24 @@ import org.mitre.openid.connect.model.Nonce;
|
|||
public interface NonceService {
|
||||
|
||||
/**
|
||||
* Create a new nonce.
|
||||
*
|
||||
* Create a new nonce.
|
||||
*
|
||||
* @param clientId the ID of the client
|
||||
* @param value the value of the Nonce
|
||||
* @return the saved Nonce
|
||||
*/
|
||||
public Nonce create(String clientId, String value);
|
||||
|
||||
|
||||
/**
|
||||
* 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 value the value of the nonce
|
||||
* @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
|
||||
*
|
||||
|
@ -40,14 +40,14 @@ public interface NonceService {
|
|||
* @return the nonce, if found
|
||||
*/
|
||||
public Nonce getById(Long id);
|
||||
|
||||
|
||||
/**
|
||||
* Remove the given Nonce from the database
|
||||
*
|
||||
* @param nonce the Nonce to remove
|
||||
*/
|
||||
public void remove(Nonce nonce);
|
||||
|
||||
|
||||
/**
|
||||
* Save a new Nonce in the database
|
||||
*
|
||||
|
@ -55,21 +55,21 @@ public interface NonceService {
|
|||
* @return the saved Nonce
|
||||
*/
|
||||
public Nonce save(Nonce nonce);
|
||||
|
||||
|
||||
/**
|
||||
* Return all nonces stored in the database
|
||||
*
|
||||
* @return the set of nonces
|
||||
*/
|
||||
public Collection<Nonce> getAll();
|
||||
|
||||
|
||||
/**
|
||||
* Return all expired nonces stored in the database
|
||||
*
|
||||
* @return the set of expired nonces
|
||||
*/
|
||||
public Collection<Nonce> getExpired();
|
||||
|
||||
|
||||
/**
|
||||
* Return the set of nonces registered to the given client ID
|
||||
*
|
||||
|
@ -82,5 +82,5 @@ public interface NonceService {
|
|||
* Clear expired nonces from the database
|
||||
*/
|
||||
void clearExpiredNonces();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ public interface StatsService {
|
|||
/**
|
||||
* Calculate summary statistics
|
||||
* approvalCount: total approved sites
|
||||
* userCount: unique users
|
||||
* clientCount: unique clients
|
||||
*
|
||||
* userCount: unique users
|
||||
* clientCount: unique clients
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<String, Integer> calculateSummaryStats();
|
||||
|
|
|
@ -41,7 +41,7 @@ public interface UserInfoService {
|
|||
* @return UserInfo for sub, or null
|
||||
*/
|
||||
public UserInfo getBySubject(String userId);
|
||||
|
||||
|
||||
/**
|
||||
* Remove the UserInfo
|
||||
*
|
||||
|
|
|
@ -33,7 +33,7 @@ public interface WhitelistedSiteService {
|
|||
* @return the WhitelistedSite collection, or null
|
||||
*/
|
||||
public Collection<WhitelistedSite> getAll();
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public WhitelistedSite getByClientId(String clientId);
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public Collection<WhitelistedSite> getByCreator(String creatorId);
|
||||
|
||||
|
||||
/**
|
||||
* Removes the given WhitelistedSite from the repository
|
||||
*
|
||||
|
@ -75,10 +75,10 @@ public interface WhitelistedSiteService {
|
|||
* @return
|
||||
*/
|
||||
public WhitelistedSite saveNew(WhitelistedSite whitelistedSite);
|
||||
|
||||
|
||||
/**
|
||||
* Updates an existing whitelisted site
|
||||
*/
|
||||
public WhitelistedSite update(WhitelistedSite oldWhitelistedSite, WhitelistedSite whitelistedSite);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -42,27 +42,27 @@ import com.nimbusds.jose.jwk.JWKSet;
|
|||
public class JwkKeyListView extends AbstractView {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(JwkKeyListView.class);
|
||||
|
||||
|
||||
@Override
|
||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
response.setContentType("application/json");
|
||||
|
||||
|
||||
|
||||
|
||||
//BiMap<String, PublicKey> keyMap = (BiMap<String, PublicKey>) model.get("keys");
|
||||
Map<String, JWK> keys = (Map<String, JWK>) model.get("keys");
|
||||
|
||||
|
||||
JWKSet jwkSet = new JWKSet(new ArrayList<JWK>(keys.values()));
|
||||
|
||||
|
||||
try {
|
||||
|
||||
|
||||
Writer out = response.getWriter();
|
||||
out.write(jwkSet.toString());
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
|
||||
logger.error("IOException in JwkKeyListView.java: ", e);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,26 +27,26 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
|||
* Time: 2:13 PM
|
||||
*/
|
||||
public class JpaUtil {
|
||||
public static <T> T getSingleResult(List<T> list) {
|
||||
switch(list.size()) {
|
||||
case 0:
|
||||
return null;
|
||||
case 1:
|
||||
return list.get(0);
|
||||
default:
|
||||
throw new IncorrectResultSizeDataAccessException(1);
|
||||
}
|
||||
}
|
||||
public static <T> T getSingleResult(List<T> list) {
|
||||
switch(list.size()) {
|
||||
case 0:
|
||||
return null;
|
||||
case 1:
|
||||
return list.get(0);
|
||||
default:
|
||||
throw new IncorrectResultSizeDataAccessException(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T, I> T saveOrUpdate(I id, EntityManager entityManager, T entity) {
|
||||
if (id == null) {
|
||||
entityManager.persist(entity);
|
||||
entityManager.flush();
|
||||
return entity;
|
||||
} else {
|
||||
T tmp = entityManager.merge(entity);
|
||||
entityManager.flush();
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
public static <T, I> T saveOrUpdate(I id, EntityManager entityManager, T entity) {
|
||||
if (id == null) {
|
||||
entityManager.persist(entity);
|
||||
entityManager.flush();
|
||||
return entity;
|
||||
} else {
|
||||
T tmp = entityManager.merge(entity);
|
||||
entityManager.flush();
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import java.util.Map;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mitre.openid.connect.view.JsonEntityView;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
@ -35,63 +34,66 @@ public class WebfingerView extends AbstractView {
|
|||
private static Logger logger = LoggerFactory.getLogger(WebfingerView.class);
|
||||
|
||||
private Gson gson = new GsonBuilder()
|
||||
.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();
|
||||
.setExclusionStrategies(new ExclusionStrategy() {
|
||||
|
||||
@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) {
|
||||
|
||||
response.setContentType("application/jrd+json");
|
||||
|
||||
|
||||
|
||||
HttpStatus code = (HttpStatus) model.get("code");
|
||||
if (code == null) {
|
||||
code = HttpStatus.OK; // default to 200
|
||||
}
|
||||
|
||||
|
||||
response.setStatus(code.value());
|
||||
|
||||
|
||||
try {
|
||||
|
||||
|
||||
String resource = (String)model.get("resource");
|
||||
String issuer = (String)model.get("issuer");
|
||||
|
||||
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty("subject", resource);
|
||||
|
||||
|
||||
JsonArray links = new JsonArray();
|
||||
JsonObject link = new JsonObject();
|
||||
link.addProperty("rel", "http://openid.net/specs/connect/1.0/issuer");
|
||||
link.addProperty("href", issuer);
|
||||
links.add(link);
|
||||
|
||||
|
||||
obj.add("links", links);
|
||||
|
||||
|
||||
Writer out = response.getWriter();
|
||||
gson.toJson(obj, out);
|
||||
|
||||
gson.toJson(obj, out);
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
|
||||
//TODO: Error Handling
|
||||
logger.error("IOException in JsonEntityView.java: ", e);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package org.mitre.discovery.web;
|
|||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -53,20 +52,20 @@ import com.nimbusds.jose.Algorithm;
|
|||
public class DiscoveryEndpoint {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DiscoveryEndpoint.class);
|
||||
|
||||
|
||||
@Autowired
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
@Autowired
|
||||
private SystemScopeService scopeService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private JwtSigningAndValidationService jwtService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private UserInfoService userService;
|
||||
|
||||
|
||||
|
||||
// used to map JWA algorithms objects to strings
|
||||
private Function<Algorithm, String> toAlgorithmName = new Function<Algorithm, String>() {
|
||||
@Override
|
||||
|
@ -78,7 +77,7 @@ public class DiscoveryEndpoint {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@RequestMapping(value={"/.well-known/webfinger"},
|
||||
params={"resource", "rel=http://openid.net/specs/connect/1.0/issuer"}, produces = "application/json")
|
||||
public String webfinger(@RequestParam("resource") String resource, Model model) {
|
||||
|
@ -89,10 +88,10 @@ public class DiscoveryEndpoint {
|
|||
try {
|
||||
URI resourceUri = new URI(resource);
|
||||
if (resourceUri != null
|
||||
&& resourceUri.getScheme() != null
|
||||
&& resourceUri.getScheme() != null
|
||||
&& resourceUri.getScheme().equals("acct")) {
|
||||
// acct: URI
|
||||
|
||||
|
||||
// split out the user and host parts
|
||||
List<String> parts = Lists.newArrayList(Splitter.on("@").split(resourceUri.getSchemeSpecificPart()));
|
||||
|
||||
|
@ -100,14 +99,14 @@ public class DiscoveryEndpoint {
|
|||
if (parts.size() > 0) {
|
||||
user = userService.getByUsername(parts.get(0)); // first part is the username
|
||||
}
|
||||
|
||||
|
||||
if (user == null) {
|
||||
logger.info("User not found: " + resource);
|
||||
model.addAttribute("code", HttpStatus.NOT_FOUND);
|
||||
return "httpCodeView";
|
||||
}
|
||||
// TODO: check the "host" part against our issuer
|
||||
|
||||
// TODO: check the "host" part against our issuer
|
||||
|
||||
} else {
|
||||
logger.info("Unknown URI format: " + resource);
|
||||
model.addAttribute("code", HttpStatus.NOT_FOUND);
|
||||
|
@ -119,96 +118,96 @@ public class DiscoveryEndpoint {
|
|||
return "httpCodeView";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if we got here, then we're good
|
||||
model.addAttribute("resource", resource);
|
||||
model.addAttribute("issuer", config.getIssuer());
|
||||
|
||||
|
||||
return "webfingerView";
|
||||
}
|
||||
|
||||
@RequestMapping("/.well-known/openid-configuration")
|
||||
public String providerConfiguration(Model model) {
|
||||
|
||||
/*
|
||||
/*
|
||||
*
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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();
|
||||
|
||||
|
||||
if (!baseUrl.endsWith("/")) {
|
||||
logger.warn("Configured issuer doesn't end in /, adding for discovery: " + baseUrl);
|
||||
baseUrl = baseUrl.concat("/");
|
||||
|
@ -242,25 +241,25 @@ public class DiscoveryEndpoint {
|
|||
//display_types_supported
|
||||
m.put("claim_types_supported", Lists.newArrayList("normal" /*, "aggregated", "distributed"*/));
|
||||
m.put("claims_supported", Lists.newArrayList(
|
||||
"sub",
|
||||
"name",
|
||||
"preferred_username",
|
||||
"given_name",
|
||||
"family_name",
|
||||
"middle_name",
|
||||
"nickname",
|
||||
"profile",
|
||||
"picture",
|
||||
"website",
|
||||
"gender",
|
||||
"zone_info",
|
||||
"locale",
|
||||
"updated_time",
|
||||
"birthdate",
|
||||
"email",
|
||||
"email_verified",
|
||||
"phone_number",
|
||||
"address"
|
||||
"sub",
|
||||
"name",
|
||||
"preferred_username",
|
||||
"given_name",
|
||||
"family_name",
|
||||
"middle_name",
|
||||
"nickname",
|
||||
"profile",
|
||||
"picture",
|
||||
"website",
|
||||
"gender",
|
||||
"zone_info",
|
||||
"locale",
|
||||
"updated_time",
|
||||
"birthdate",
|
||||
"email",
|
||||
"email_verified",
|
||||
"phone_number",
|
||||
"address"
|
||||
));
|
||||
m.put("service_documentation", baseUrl + "about");
|
||||
//claims_locales_supported
|
||||
|
@ -271,11 +270,11 @@ public class DiscoveryEndpoint {
|
|||
m.put("require_request_uri_registration", false);
|
||||
m.put("op_policy_uri", baseUrl + "about");
|
||||
m.put("op_tos_uri", baseUrl + "about");
|
||||
|
||||
|
||||
|
||||
|
||||
model.addAttribute("entity", m);
|
||||
|
||||
|
||||
return "jsonEntityView";
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -18,13 +18,13 @@ package org.mitre.oauth2.exception;
|
|||
public class DuplicateClientIdException extends RuntimeException {
|
||||
|
||||
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
|
||||
private EntityManager manager;
|
||||
|
||||
|
||||
@Override
|
||||
public AuthenticationHolderEntity getById(Long id) {
|
||||
return manager.find(AuthenticationHolderEntity.class, id);
|
||||
|
|
|
@ -27,16 +27,16 @@ public class JpaAuthorizationCodeRepository implements AuthorizationCodeReposito
|
|||
|
||||
@PersistenceContext
|
||||
EntityManager manager;
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.repository.AuthorizationCodeRepository#save(org.mitre.oauth2.model.AuthorizationCodeEntity)
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public AuthorizationCodeEntity save(AuthorizationCodeEntity authorizationCode) {
|
||||
|
||||
|
||||
return JpaUtil.saveOrUpdate(authorizationCode.getId(), manager, authorizationCode);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -45,20 +45,20 @@ public class JpaAuthorizationCodeRepository implements AuthorizationCodeReposito
|
|||
@Override
|
||||
@Transactional
|
||||
public AuthorizationRequestHolder consume(String code) throws InvalidGrantException {
|
||||
|
||||
|
||||
TypedQuery<AuthorizationCodeEntity> query = manager.createNamedQuery("AuthorizationCodeEntity.getByValue", AuthorizationCodeEntity.class);
|
||||
query.setParameter("code", code);
|
||||
|
||||
|
||||
AuthorizationCodeEntity result = JpaUtil.getSingleResult(query.getResultList());
|
||||
|
||||
|
||||
if (result == null) {
|
||||
throw new InvalidGrantException("JpaAuthorizationCodeRepository: no authorization code found for value " + code);
|
||||
}
|
||||
|
||||
|
||||
AuthorizationRequestHolder authRequest = result.getAuthorizationRequestHolder();
|
||||
|
||||
|
||||
manager.remove(result);
|
||||
|
||||
|
||||
return authRequest;
|
||||
|
||||
}
|
||||
|
|
|
@ -37,15 +37,16 @@ public class JpaOAuth2ClientRepository implements OAuth2ClientRepository {
|
|||
|
||||
@PersistenceContext
|
||||
private EntityManager manager;
|
||||
|
||||
|
||||
public JpaOAuth2ClientRepository() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public JpaOAuth2ClientRepository(EntityManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ClientDetailsEntity getById(Long id) {
|
||||
return manager.find(ClientDetailsEntity.class, id);
|
||||
}
|
||||
|
@ -82,17 +83,17 @@ public class JpaOAuth2ClientRepository implements OAuth2ClientRepository {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ClientDetailsEntity updateClient(Long id, ClientDetailsEntity client) {
|
||||
public ClientDetailsEntity updateClient(Long id, ClientDetailsEntity client) {
|
||||
// sanity check
|
||||
client.setId(id);
|
||||
|
||||
return JpaUtil.saveOrUpdate(id, manager, client);
|
||||
}
|
||||
|
||||
return JpaUtil.saveOrUpdate(id, manager, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ClientDetailsEntity> getAllClients() {
|
||||
public Collection<ClientDetailsEntity> getAllClients() {
|
||||
TypedQuery<ClientDetailsEntity> query = manager.createNamedQuery("ClientDetailsEntity.findAll", ClientDetailsEntity.class);
|
||||
return query.getResultList();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,18 +42,18 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
|
|||
query.setParameter("tokenValue", accessTokenValue);
|
||||
return JpaUtil.getSingleResult(query.getResultList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessTokenById(Long id) {
|
||||
return manager.find(OAuth2AccessTokenEntity.class, id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity token) {
|
||||
return JpaUtil.saveOrUpdate(token.getId(), manager, token);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void removeAccessToken(OAuth2AccessTokenEntity accessToken) {
|
||||
|
@ -64,17 +64,17 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
|
|||
throw new IllegalArgumentException("Access token not found: " + accessToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void clearAccessTokensForRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
public void clearAccessTokensForRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery("OAuth2AccessTokenEntity.getByRefreshToken", OAuth2AccessTokenEntity.class);
|
||||
query.setParameter("refreshToken", refreshToken);
|
||||
List<OAuth2AccessTokenEntity> accessTokens = query.getResultList();
|
||||
for (OAuth2AccessTokenEntity accessToken : accessTokens) {
|
||||
removeAccessToken(accessToken);
|
||||
}
|
||||
}
|
||||
List<OAuth2AccessTokenEntity> accessTokens = query.getResultList();
|
||||
for (OAuth2AccessTokenEntity accessToken : accessTokens) {
|
||||
removeAccessToken(accessToken);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2RefreshTokenEntity getRefreshTokenByValue(String refreshTokenValue) {
|
||||
|
@ -82,105 +82,105 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
|
|||
query.setParameter("tokenValue", refreshTokenValue);
|
||||
return JpaUtil.getSingleResult(query.getResultList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public OAuth2RefreshTokenEntity getRefreshTokenById(Long id) {
|
||||
return manager.find(OAuth2RefreshTokenEntity.class, id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
return JpaUtil.saveOrUpdate(refreshToken.getId(), manager, refreshToken);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void removeRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
public void removeRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
OAuth2RefreshTokenEntity found = getRefreshTokenByValue(refreshToken.getValue());
|
||||
if (found != null) {
|
||||
manager.remove(found);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Refresh token not found: " + refreshToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void clearTokensForClient(ClientDetailsEntity client) {
|
||||
public void clearTokensForClient(ClientDetailsEntity client) {
|
||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByClient", OAuth2AccessTokenEntity.class);
|
||||
queryA.setParameter("client", client);
|
||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||
for (OAuth2AccessTokenEntity accessToken : accessTokens) {
|
||||
removeAccessToken(accessToken);
|
||||
}
|
||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||
for (OAuth2AccessTokenEntity accessToken : accessTokens) {
|
||||
removeAccessToken(accessToken);
|
||||
}
|
||||
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getByClient", OAuth2RefreshTokenEntity.class);
|
||||
queryR.setParameter("client", client);
|
||||
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
||||
for (OAuth2RefreshTokenEntity refreshToken : refreshTokens) {
|
||||
removeRefreshToken(refreshToken);
|
||||
}
|
||||
}
|
||||
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
||||
for (OAuth2RefreshTokenEntity refreshToken : refreshTokens) {
|
||||
removeRefreshToken(refreshToken);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getAccessTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client) {
|
||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getAccessTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client) {
|
||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByClient", OAuth2AccessTokenEntity.class);
|
||||
queryA.setParameter("client", client);
|
||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||
return accessTokens;
|
||||
}
|
||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||
return accessTokens;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getRefreshTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client) {
|
||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getRefreshTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client) {
|
||||
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getByClient", OAuth2RefreshTokenEntity.class);
|
||||
queryR.setParameter("client", client);
|
||||
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
||||
return refreshTokens;
|
||||
}
|
||||
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
||||
return refreshTokens;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getExpiredAccessTokens()
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2AccessTokenEntity> getExpiredAccessTokens() {
|
||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getExpiredAccessTokens()
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2AccessTokenEntity> getExpiredAccessTokens() {
|
||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getExpired", OAuth2AccessTokenEntity.class);
|
||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||
return accessTokens;
|
||||
}
|
||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||
return accessTokens;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getExpiredRefreshTokens()
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2RefreshTokenEntity> getExpiredRefreshTokens() {
|
||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getExpiredRefreshTokens()
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2RefreshTokenEntity> getExpiredRefreshTokens() {
|
||||
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getExpired", OAuth2RefreshTokenEntity.class);
|
||||
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
||||
return refreshTokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getByAuthentication(OAuth2Authentication auth) {
|
||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByAuthentication", OAuth2AccessTokenEntity.class);
|
||||
queryA.setParameter("authentication", auth);
|
||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||
return JpaUtil.getSingleResult(accessTokens);
|
||||
}
|
||||
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
|
||||
return refreshTokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getByAuthentication(OAuth2Authentication auth) {
|
||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByAuthentication", OAuth2AccessTokenEntity.class);
|
||||
queryA.setParameter("authentication", auth);
|
||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||
return JpaUtil.getSingleResult(accessTokens);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getAccessTokenForIdToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
|
||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByIdToken", OAuth2AccessTokenEntity.class);
|
||||
queryA.setParameter("idToken", idToken);
|
||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||
return JpaUtil.getSingleResult(accessTokens);
|
||||
}
|
||||
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getAccessTokenForIdToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
|
||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByIdToken", OAuth2AccessTokenEntity.class);
|
||||
queryA.setParameter("idToken", idToken);
|
||||
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
|
||||
return JpaUtil.getSingleResult(accessTokens);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ public class JpaSystemScopeRepository implements SystemScopeRepository {
|
|||
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.repository.SystemScopeRepository#getAll()
|
||||
*/
|
||||
|
@ -35,7 +35,7 @@ public class JpaSystemScopeRepository implements SystemScopeRepository {
|
|||
@Transactional
|
||||
public Set<SystemScope> getAll() {
|
||||
TypedQuery<SystemScope> query = em.createNamedQuery("SystemScope.findAll", SystemScope.class);
|
||||
|
||||
|
||||
return new LinkedHashSet<SystemScope>(query.getResultList());
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ public class JpaSystemScopeRepository implements SystemScopeRepository {
|
|||
@Transactional
|
||||
public void remove(SystemScope scope) {
|
||||
SystemScope found = getById(scope.getId());
|
||||
|
||||
|
||||
if (found != null) {
|
||||
em.remove(found);
|
||||
}
|
||||
|
|
|
@ -23,9 +23,9 @@ public class DefaultOAuth2AuthorizationCodeService implements AuthorizationCodeS
|
|||
|
||||
@Autowired
|
||||
private AuthorizationCodeRepository repository;
|
||||
|
||||
|
||||
private RandomValueStringGenerator generator = new RandomValueStringGenerator();
|
||||
|
||||
|
||||
/**
|
||||
* Generate a random authorization code and create an AuthorizationCodeEntity,
|
||||
* which will be stored in the repository.
|
||||
|
@ -37,16 +37,16 @@ public class DefaultOAuth2AuthorizationCodeService implements AuthorizationCodeS
|
|||
@Override
|
||||
public String createAuthorizationCode(AuthorizationRequestHolder authentication) {
|
||||
String code = generator.generate();
|
||||
|
||||
|
||||
AuthorizationCodeEntity entity = new AuthorizationCodeEntity(code, authentication);
|
||||
repository.save(entity);
|
||||
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a given authorization code.
|
||||
* Match the provided string to an AuthorizationCodeEntity. If one is found, return
|
||||
* Consume a given authorization code.
|
||||
* 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
|
||||
* InvalidGrantException.
|
||||
*
|
||||
|
@ -56,7 +56,7 @@ public class DefaultOAuth2AuthorizationCodeService implements AuthorizationCodeS
|
|||
*/
|
||||
@Override
|
||||
public AuthorizationRequestHolder consumeAuthorizationCode(String code) throws InvalidGrantException {
|
||||
|
||||
|
||||
AuthorizationRequestHolder auth = repository.consume(code);
|
||||
return auth;
|
||||
}
|
||||
|
|
|
@ -39,32 +39,32 @@ import com.google.common.base.Strings;
|
|||
|
||||
@Service
|
||||
public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEntityService {
|
||||
|
||||
|
||||
@Autowired
|
||||
private OAuth2ClientRepository clientRepository;
|
||||
|
||||
|
||||
@Autowired
|
||||
private OAuth2TokenRepository tokenRepository;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ApprovedSiteService approvedSiteService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private WhitelistedSiteService whitelistedSiteService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private BlacklistedSiteService blacklistedSiteService;
|
||||
|
||||
|
||||
public DefaultOAuth2ClientDetailsEntityService() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
public DefaultOAuth2ClientDetailsEntityService(OAuth2ClientRepository clientRepository,
|
||||
|
||||
public DefaultOAuth2ClientDetailsEntityService(OAuth2ClientRepository clientRepository,
|
||||
OAuth2TokenRepository tokenRepository) {
|
||||
this.clientRepository = clientRepository;
|
||||
this.tokenRepository = tokenRepository;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ClientDetailsEntity saveNewClient(ClientDetailsEntity client) {
|
||||
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)) {
|
||||
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
|
||||
if (Strings.isNullOrEmpty(client.getClientId())) {
|
||||
client = generateClientId(client);
|
||||
}
|
||||
|
||||
// if the client is flagged to allow for refresh tokens, make sure it's got the right granted scopes
|
||||
if (client.isAllowRefresh()) {
|
||||
client.getScope().add("offline_access");
|
||||
} else {
|
||||
client.getScope().remove("offline_access");
|
||||
}
|
||||
|
||||
// timestamp this to right now
|
||||
client.setCreatedAt(new Date());
|
||||
|
||||
return clientRepository.saveClient(client);
|
||||
if (Strings.isNullOrEmpty(client.getClientId())) {
|
||||
client = generateClientId(client);
|
||||
}
|
||||
|
||||
// if the client is flagged to allow for refresh tokens, make sure it's got the right granted scopes
|
||||
if (client.isAllowRefresh()) {
|
||||
client.getScope().add("offline_access");
|
||||
} else {
|
||||
client.getScope().remove("offline_access");
|
||||
}
|
||||
|
||||
// timestamp this to right now
|
||||
client.setCreatedAt(new Date());
|
||||
|
||||
return clientRepository.saveClient(client);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the client by its internal ID
|
||||
*/
|
||||
@Override
|
||||
public ClientDetailsEntity getClientById(Long id) {
|
||||
ClientDetailsEntity client = clientRepository.getById(id);
|
||||
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the client for the given ClientID
|
||||
*/
|
||||
|
@ -121,87 +122,87 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
|
|||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
throw new IllegalArgumentException("Client id must not be empty!");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete a client and all its associated tokens
|
||||
*/
|
||||
@Override
|
||||
public void deleteClient(ClientDetailsEntity client) throws InvalidClientException {
|
||||
|
||||
public void deleteClient(ClientDetailsEntity client) throws InvalidClientException {
|
||||
|
||||
if (clientRepository.getById(client.getId()) == null) {
|
||||
throw new InvalidClientException("Client with id " + client.getClientId() + " was not found");
|
||||
}
|
||||
|
||||
|
||||
// clean out any tokens that this client had issued
|
||||
tokenRepository.clearTokensForClient(client);
|
||||
|
||||
|
||||
// clean out any approved sites for this client
|
||||
approvedSiteService.clearApprovedSitesForClient(client);
|
||||
|
||||
|
||||
// clear out any whitelisted sites for this client
|
||||
WhitelistedSite whitelistedSite = whitelistedSiteService.getByClientId(client.getClientId());
|
||||
if (whitelistedSite != null) {
|
||||
whitelistedSiteService.remove(whitelistedSite);
|
||||
whitelistedSiteService.remove(whitelistedSite);
|
||||
}
|
||||
|
||||
|
||||
// take care of the client itself
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
public ClientDetailsEntity updateClient(ClientDetailsEntity oldClient, ClientDetailsEntity newClient) throws IllegalArgumentException {
|
||||
public ClientDetailsEntity updateClient(ClientDetailsEntity oldClient, ClientDetailsEntity newClient) throws IllegalArgumentException {
|
||||
if (oldClient != null && newClient != null) {
|
||||
|
||||
|
||||
for (String uri : newClient.getRegisteredRedirectUri()) {
|
||||
if (blacklistedSiteService.isBlacklisted(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!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all clients in the system
|
||||
*/
|
||||
@Override
|
||||
public Collection<ClientDetailsEntity> getAllClients() {
|
||||
public Collection<ClientDetailsEntity> 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.
|
||||
*/
|
||||
@Override
|
||||
public ClientDetailsEntity generateClientId(ClientDetailsEntity client) {
|
||||
public ClientDetailsEntity generateClientId(ClientDetailsEntity client) {
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
public ClientDetailsEntity generateClientSecret(ClientDetailsEntity client) {
|
||||
public ClientDetailsEntity generateClientSecret(ClientDetailsEntity client) {
|
||||
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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
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.ClientDetailsEntity;
|
||||
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.service.ClientDetailsEntityService;
|
||||
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.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -62,142 +56,142 @@ import com.nimbusds.jwt.PlainJWT;
|
|||
*/
|
||||
@Service
|
||||
public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityService {
|
||||
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DefaultOAuth2ProviderTokenService.class);
|
||||
|
||||
@Autowired
|
||||
private OAuth2TokenRepository tokenRepository;
|
||||
|
||||
|
||||
@Autowired
|
||||
private AuthenticationHolderRepository authenticationHolderRepository;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ClientDetailsEntityService clientDetailsService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private TokenEnhancer tokenEnhancer;
|
||||
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity createAccessToken(OAuth2Authentication authentication) throws AuthenticationException, InvalidClientException {
|
||||
public OAuth2AccessTokenEntity createAccessToken(OAuth2Authentication authentication) throws AuthenticationException, InvalidClientException {
|
||||
if (authentication != null && authentication.getAuthorizationRequest() != null) {
|
||||
// look up our client
|
||||
AuthorizationRequest clientAuth = authentication.getAuthorizationRequest();
|
||||
|
||||
|
||||
ClientDetailsEntity client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
||||
|
||||
|
||||
if (client == null) {
|
||||
throw new InvalidClientException("Client not found: " + clientAuth.getClientId());
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
if (client.getAccessTokenValiditySeconds() != null && client.getAccessTokenValiditySeconds() > 0) {
|
||||
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();
|
||||
// attach the client
|
||||
token.setClient(client);
|
||||
|
||||
|
||||
// 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());
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
// make it expire if necessary
|
||||
if (client.getAccessTokenValiditySeconds() != null && client.getAccessTokenValiditySeconds() > 0) {
|
||||
Date expiration = new Date(System.currentTimeMillis() + (client.getAccessTokenValiditySeconds() * 1000L));
|
||||
token.setExpiration(expiration);
|
||||
}
|
||||
|
||||
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;
|
||||
// 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();
|
||||
|
||||
|
||||
// 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
|
||||
public OAuth2AccessTokenEntity refreshAccessToken(String refreshTokenValue, AuthorizationRequest authRequest) throws AuthenticationException {
|
||||
|
||||
public OAuth2AccessTokenEntity refreshAccessToken(String refreshTokenValue, AuthorizationRequest authRequest) throws AuthenticationException {
|
||||
|
||||
OAuth2RefreshTokenEntity refreshToken = tokenRepository.getRefreshTokenByValue(refreshTokenValue);
|
||||
|
||||
|
||||
if (refreshToken == null) {
|
||||
throw new InvalidTokenException("Invalid refresh token: " + refreshTokenValue);
|
||||
}
|
||||
|
||||
|
||||
ClientDetailsEntity client = refreshToken.getClient();
|
||||
|
||||
|
||||
AuthenticationHolderEntity authHolder = refreshToken.getAuthenticationHolder();
|
||||
|
||||
|
||||
//Make sure this client allows access token refreshing
|
||||
if (!client.isAllowRefresh()) {
|
||||
throw new InvalidClientException("Client does not allow refreshing access token!");
|
||||
}
|
||||
|
||||
|
||||
// clear out any access tokens
|
||||
// TODO: make this a configurable option
|
||||
tokenRepository.clearAccessTokensForRefreshToken(refreshToken);
|
||||
|
||||
|
||||
if (refreshToken.isExpired()) {
|
||||
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
|
||||
// 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
|
||||
Set<String> refreshScopes = new HashSet<String>(refreshToken.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().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
|
||||
if (refreshScopes != null && refreshScopes.containsAll(scope)) {
|
||||
// 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)
|
||||
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());
|
||||
|
||||
tokenRepository.saveAccessToken(token);
|
||||
|
||||
return token;
|
||||
|
||||
}
|
||||
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());
|
||||
|
||||
tokenRepository.saveAccessToken(token);
|
||||
|
||||
return token;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException {
|
||||
|
||||
public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException {
|
||||
|
||||
OAuth2AccessTokenEntity accessToken = tokenRepository.getAccessTokenByValue(accessTokenValue);
|
||||
|
||||
|
||||
if (accessToken == null) {
|
||||
throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
|
||||
}
|
||||
|
||||
|
||||
if (accessToken.isExpired()) {
|
||||
//tokenRepository.removeAccessToken(accessToken);
|
||||
revokeAccessToken(accessToken);
|
||||
throw new InvalidTokenException("Expired access token: " + accessTokenValue);
|
||||
}
|
||||
|
||||
return accessToken.getAuthenticationHolder().getAuthentication();
|
||||
}
|
||||
|
||||
return accessToken.getAuthenticationHolder().getAuthentication();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an access token from its token value.
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity readAccessToken(String accessTokenValue) throws AuthenticationException {
|
||||
public OAuth2AccessTokenEntity readAccessToken(String accessTokenValue) throws AuthenticationException {
|
||||
OAuth2AccessTokenEntity accessToken = tokenRepository.getAccessTokenByValue(accessTokenValue);
|
||||
if (accessToken == null) {
|
||||
throw new InvalidTokenException("Access token for value " + accessTokenValue + " was not found");
|
||||
}
|
||||
else {
|
||||
return accessToken;
|
||||
return accessToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an access token by its authentication object.
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessToken(OAuth2Authentication authentication) {
|
||||
|
||||
|
||||
OAuth2AccessTokenEntity accessToken = tokenRepository.getByAuthentication(authentication);
|
||||
|
||||
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a refresh token by its token value.
|
||||
*/
|
||||
@Override
|
||||
public OAuth2RefreshTokenEntity getRefreshToken(String refreshTokenValue) throws AuthenticationException {
|
||||
public OAuth2RefreshTokenEntity getRefreshToken(String refreshTokenValue) throws AuthenticationException {
|
||||
OAuth2RefreshTokenEntity refreshToken = tokenRepository.getRefreshTokenByValue(refreshTokenValue);
|
||||
if (refreshToken == null) {
|
||||
throw new InvalidTokenException("Refresh token for value " + refreshTokenValue + " was not found");
|
||||
}
|
||||
else {
|
||||
return refreshToken;
|
||||
return refreshToken;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a refresh token and all access tokens issued to it.
|
||||
*/
|
||||
@Override
|
||||
public void revokeRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
tokenRepository.clearAccessTokensForRefreshToken(refreshToken);
|
||||
tokenRepository.removeRefreshToken(refreshToken);
|
||||
}
|
||||
public void revokeRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
tokenRepository.clearAccessTokensForRefreshToken(refreshToken);
|
||||
tokenRepository.removeRefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke an access token.
|
||||
* Revoke an access token.
|
||||
*/
|
||||
@Override
|
||||
public void revokeAccessToken(OAuth2AccessTokenEntity accessToken) {
|
||||
tokenRepository.removeAccessToken(accessToken);
|
||||
}
|
||||
|
||||
public void revokeAccessToken(OAuth2AccessTokenEntity accessToken) {
|
||||
tokenRepository.removeAccessToken(accessToken);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getAccessTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client) {
|
||||
return tokenRepository.getAccessTokensForClient(client);
|
||||
}
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getAccessTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client) {
|
||||
return tokenRepository.getAccessTokensForClient(client);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getRefreshTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client) {
|
||||
return tokenRepository.getRefreshTokensForClient(client);
|
||||
}
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getRefreshTokensForClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||
*/
|
||||
@Override
|
||||
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client) {
|
||||
return tokenRepository.getRefreshTokensForClient(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Scheduled(fixedRate = 5 * 60 * 1000) // schedule this task every five minutes
|
||||
public void clearExpiredTokens() {
|
||||
logger.info("Cleaning out all expired tokens");
|
||||
|
||||
List<OAuth2AccessTokenEntity> accessTokens = tokenRepository.getExpiredAccessTokens();
|
||||
logger.info("Found " + accessTokens.size() + " expired access tokens");
|
||||
for (OAuth2AccessTokenEntity oAuth2AccessTokenEntity : accessTokens) {
|
||||
revokeAccessToken(oAuth2AccessTokenEntity);
|
||||
}
|
||||
|
||||
List<OAuth2RefreshTokenEntity> refreshTokens = tokenRepository.getExpiredRefreshTokens();
|
||||
logger.info("Found " + refreshTokens.size() + " expired refresh tokens");
|
||||
for (OAuth2RefreshTokenEntity oAuth2RefreshTokenEntity : refreshTokens) {
|
||||
revokeRefreshToken(oAuth2RefreshTokenEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@Override
|
||||
@Scheduled(fixedRate = 5 * 60 * 1000) // schedule this task every five minutes
|
||||
public void clearExpiredTokens() {
|
||||
logger.info("Cleaning out all expired tokens");
|
||||
|
||||
List<OAuth2AccessTokenEntity> accessTokens = tokenRepository.getExpiredAccessTokens();
|
||||
logger.info("Found " + accessTokens.size() + " expired access tokens");
|
||||
for (OAuth2AccessTokenEntity oAuth2AccessTokenEntity : accessTokens) {
|
||||
revokeAccessToken(oAuth2AccessTokenEntity);
|
||||
}
|
||||
|
||||
List<OAuth2RefreshTokenEntity> refreshTokens = tokenRepository.getExpiredRefreshTokens();
|
||||
logger.info("Found " + refreshTokens.size() + " expired refresh tokens");
|
||||
for (OAuth2RefreshTokenEntity oAuth2RefreshTokenEntity : refreshTokens) {
|
||||
revokeRefreshToken(oAuth2RefreshTokenEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a builder object for this class (for tests)
|
||||
* @return
|
||||
*/
|
||||
public static DefaultOAuth2ProviderTokenServicesBuilder makeBuilder() {
|
||||
return new DefaultOAuth2ProviderTokenServicesBuilder();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builder class for test harnesses.
|
||||
*/
|
||||
public static class DefaultOAuth2ProviderTokenServicesBuilder {
|
||||
private DefaultOAuth2ProviderTokenService instance;
|
||||
|
||||
|
||||
private DefaultOAuth2ProviderTokenServicesBuilder() {
|
||||
instance = new DefaultOAuth2ProviderTokenService();
|
||||
}
|
||||
|
||||
|
||||
public DefaultOAuth2ProviderTokenServicesBuilder setTokenRepository(OAuth2TokenRepository tokenRepository) {
|
||||
instance.tokenRepository = tokenRepository;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DefaultOAuth2ProviderTokenServicesBuilder setClientDetailsService(ClientDetailsEntityService clientDetailsService) {
|
||||
instance.clientDetailsService = clientDetailsService;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DefaultOAuth2ProviderTokenServicesBuilder setTokenEnhancer(TokenEnhancer tokenEnhancer) {
|
||||
instance.tokenEnhancer = tokenEnhancer;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public OAuth2TokenEntityService finish() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveAccessToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity accessToken) {
|
||||
return tokenRepository.saveAccessToken(accessToken);
|
||||
}
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveAccessToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity accessToken) {
|
||||
return tokenRepository.saveAccessToken(accessToken);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveRefreshToken(org.mitre.oauth2.model.OAuth2RefreshTokenEntity)
|
||||
*/
|
||||
@Override
|
||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
return tokenRepository.saveRefreshToken(refreshToken);
|
||||
}
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveRefreshToken(org.mitre.oauth2.model.OAuth2RefreshTokenEntity)
|
||||
*/
|
||||
@Override
|
||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
return tokenRepository.saveRefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tokenEnhancer
|
||||
|
@ -410,11 +404,11 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
|
|||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getAccessTokenForIdToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
|
||||
return tokenRepository.getAccessTokenForIdToken(idToken);
|
||||
}
|
||||
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getAccessTokenForIdToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
|
||||
return tokenRepository.getAccessTokenForIdToken(idToken);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,132 +27,132 @@ public class DefaultSystemScopeService implements SystemScopeService {
|
|||
|
||||
@Autowired
|
||||
private SystemScopeRepository repository;
|
||||
|
||||
|
||||
private Predicate<SystemScope> isDefault = new Predicate<SystemScope>() {
|
||||
@Override
|
||||
public boolean apply(SystemScope input) {
|
||||
public boolean apply(SystemScope input) {
|
||||
return (input != null && input.isDefaultScope());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
private Predicate<SystemScope> isDynReg = new Predicate<SystemScope>() {
|
||||
@Override
|
||||
public boolean apply(SystemScope input) {
|
||||
public boolean apply(SystemScope input) {
|
||||
return (input != null && input.isAllowDynReg());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private Function<String, SystemScope> stringToSystemScope = new Function<String, SystemScope>() {
|
||||
@Override
|
||||
public SystemScope apply(String input) {
|
||||
public SystemScope apply(String input) {
|
||||
if (input == null) {
|
||||
return null;
|
||||
} else {
|
||||
SystemScope s = getByValue(input);
|
||||
if (s != null) {
|
||||
// get the real scope if it's available
|
||||
return s;
|
||||
} else {
|
||||
// make a fake one otherwise
|
||||
return new SystemScope(input);
|
||||
}
|
||||
SystemScope s = getByValue(input);
|
||||
if (s != null) {
|
||||
// get the real scope if it's available
|
||||
return s;
|
||||
} else {
|
||||
// make a fake one otherwise
|
||||
return new SystemScope(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private Function<SystemScope, String> systemScopeToString = new Function<SystemScope, String>() {
|
||||
@Override
|
||||
public String apply(SystemScope input) {
|
||||
public String apply(SystemScope input) {
|
||||
if (input == null) {
|
||||
return null;
|
||||
} else {
|
||||
return input.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.SystemScopeService#getAll()
|
||||
*/
|
||||
@Override
|
||||
public Set<SystemScope> getAll() {
|
||||
return repository.getAll();
|
||||
}
|
||||
@Override
|
||||
public Set<SystemScope> getAll() {
|
||||
return repository.getAll();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.SystemScopeService#getDefaults()
|
||||
*/
|
||||
@Override
|
||||
public Set<SystemScope> getDefaults() {
|
||||
@Override
|
||||
public Set<SystemScope> getDefaults() {
|
||||
return Sets.filter(getAll(), isDefault);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.SystemScopeService#getDynReg()
|
||||
*/
|
||||
@Override
|
||||
public Set<SystemScope> getDynReg() {
|
||||
return Sets.filter(getAll(), isDynReg);
|
||||
}
|
||||
@Override
|
||||
public Set<SystemScope> getDynReg() {
|
||||
return Sets.filter(getAll(), isDynReg);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.SystemScopeService#getById(java.lang.Long)
|
||||
*/
|
||||
@Override
|
||||
public SystemScope getById(Long id) {
|
||||
return repository.getById(id);
|
||||
}
|
||||
@Override
|
||||
public SystemScope getById(Long id) {
|
||||
return repository.getById(id);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.SystemScopeService#getByValue(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public SystemScope getByValue(String value) {
|
||||
return repository.getByValue(value);
|
||||
}
|
||||
@Override
|
||||
public SystemScope getByValue(String value) {
|
||||
return repository.getByValue(value);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.SystemScopeService#remove(org.mitre.oauth2.model.SystemScope)
|
||||
*/
|
||||
@Override
|
||||
public void remove(SystemScope scope) {
|
||||
repository.remove(scope);
|
||||
|
||||
}
|
||||
@Override
|
||||
public void remove(SystemScope scope) {
|
||||
repository.remove(scope);
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.SystemScopeService#save(org.mitre.oauth2.model.SystemScope)
|
||||
*/
|
||||
@Override
|
||||
public SystemScope save(SystemScope scope) {
|
||||
return repository.save(scope);
|
||||
}
|
||||
@Override
|
||||
public SystemScope save(SystemScope scope) {
|
||||
return repository.save(scope);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.SystemScopeService#fromStrings(java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public Set<SystemScope> fromStrings(Set<String> scope) {
|
||||
if (scope == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new LinkedHashSet<SystemScope>(Collections2.filter(Collections2.transform(scope, stringToSystemScope), Predicates.notNull()));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Set<SystemScope> fromStrings(Set<String> scope) {
|
||||
if (scope == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new LinkedHashSet<SystemScope>(Collections2.filter(Collections2.transform(scope, stringToSystemScope), Predicates.notNull()));
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.SystemScopeService#toStrings(java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public Set<String> toStrings(Set<SystemScope> scope) {
|
||||
if (scope == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new LinkedHashSet<String>(Collections2.filter(Collections2.transform(scope, systemScopeToString), Predicates.notNull()));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Set<String> toStrings(Set<SystemScope> scope) {
|
||||
if (scope == null) {
|
||||
return null;
|
||||
} else {
|
||||
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
|
||||
private OAuth2TokenEntityService tokenServices;
|
||||
|
||||
|
||||
/**
|
||||
* @param tokenServices
|
||||
* @param clientDetailsService
|
||||
|
@ -46,55 +46,55 @@ public class ChainedTokenGranter extends AbstractTokenGranter {
|
|||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
||||
*/
|
||||
@Override
|
||||
protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest authorizationRequest) throws AuthenticationException, InvalidTokenException {
|
||||
// read and load up the existing token
|
||||
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("token");
|
||||
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)) {
|
||||
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
||||
*/
|
||||
@Override
|
||||
protected OAuth2Authentication getOAuth2Authentication(AuthorizationRequest authorizationRequest) throws AuthenticationException, InvalidTokenException {
|
||||
// read and load up the existing token
|
||||
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("token");
|
||||
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
||||
|
||||
// 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
|
||||
// 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
|
||||
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;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.ParseException;
|
||||
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
|
||||
private OAuth2TokenEntityService tokenServices;
|
||||
|
||||
|
||||
@Autowired
|
||||
private JwtSigningAndValidationService jwtService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
|
||||
@Autowired
|
||||
public JwtAssertionTokenGranter(OAuth2TokenEntityService tokenServices, ClientDetailsEntityService clientDetailsService) {
|
||||
super(tokenServices, clientDetailsService, grantType);
|
||||
this.tokenServices = tokenServices;
|
||||
}
|
||||
super(tokenServices, clientDetailsService, grantType);
|
||||
this.tokenServices = tokenServices;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
||||
*/
|
||||
@Override
|
||||
protected OAuth2AccessToken getAccessToken(AuthorizationRequest authorizationRequest) throws AuthenticationException, InvalidTokenException {
|
||||
// read and load up the existing token
|
||||
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("assertion");
|
||||
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
||||
|
||||
ClientDetailsEntity client = incomingToken.getClient();
|
||||
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
|
||||
*/
|
||||
@Override
|
||||
protected OAuth2AccessToken getAccessToken(AuthorizationRequest authorizationRequest) throws AuthenticationException, InvalidTokenException {
|
||||
// read and load up the existing token
|
||||
String incomingTokenValue = authorizationRequest.getAuthorizationParameters().get("assertion");
|
||||
OAuth2AccessTokenEntity incomingToken = tokenServices.readAccessToken(incomingTokenValue);
|
||||
|
||||
|
||||
if (incomingToken.getScope().contains(OAuth2AccessTokenEntity.ID_TOKEN_SCOPE)) {
|
||||
|
||||
if (!client.getClientId().equals(authorizationRequest.getClientId())) {
|
||||
throw new InvalidClientException("Not the right client for this token");
|
||||
}
|
||||
ClientDetailsEntity client = incomingToken.getClient();
|
||||
|
||||
// it's an ID token, process it accordingly
|
||||
|
||||
try {
|
||||
|
||||
// TODO: make this use a more specific idtoken class
|
||||
JWT idToken = JWTParser.parse(incomingTokenValue);
|
||||
|
||||
OAuth2AccessTokenEntity accessToken = tokenServices.getAccessTokenForIdToken(incomingToken);
|
||||
|
||||
if (accessToken != null) {
|
||||
|
||||
//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 (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
|
||||
|
||||
try {
|
||||
|
||||
// TODO: make this use a more specific idtoken class
|
||||
JWT idToken = JWTParser.parse(incomingTokenValue);
|
||||
|
||||
OAuth2AccessTokenEntity accessToken = tokenServices.getAccessTokenForIdToken(incomingToken);
|
||||
|
||||
if (accessToken != null) {
|
||||
|
||||
//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) {
|
||||
Date expiration = new Date(System.currentTimeMillis() + (client.getIdTokenValiditySeconds() * 1000L));
|
||||
claims.setExpirationTime(expiration);
|
||||
newIdTokenEntity.setExpiration(expiration);
|
||||
}
|
||||
claims.setIssueTime(new Date());
|
||||
|
||||
|
||||
|
||||
|
||||
SignedJWT newIdToken = new SignedJWT((JWSHeader) idToken.getHeader(), claims);
|
||||
jwtService.signJwt(newIdToken);
|
||||
|
||||
jwtService.signJwt(newIdToken);
|
||||
|
||||
newIdTokenEntity.setJwt(newIdToken);
|
||||
newIdTokenEntity.setAuthenticationHolder(incomingToken.getAuthenticationHolder());
|
||||
newIdTokenEntity.setScope(incomingToken.getScope());
|
||||
newIdTokenEntity.setClient(incomingToken.getClient());
|
||||
|
||||
|
||||
newIdTokenEntity = tokenServices.saveAccessToken(newIdTokenEntity);
|
||||
|
||||
|
||||
// attach the ID token to the access token entity
|
||||
accessToken.setIdToken(newIdTokenEntity);
|
||||
accessToken = tokenServices.saveAccessToken(accessToken);
|
||||
|
||||
|
||||
// delete the old ID token
|
||||
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;
|
||||
|
||||
/*
|
||||
* Otherwise, process it like an access token assertion ... which we don't support yet so this is all commented out
|
||||
* /
|
||||
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;
|
||||
|
||||
/*
|
||||
* Otherwise, process it like an access token assertion ... which we don't support yet so this is all commented out
|
||||
* /
|
||||
if (jwtService.validateSignature(incomingTokenValue)) {
|
||||
|
||||
Jwt jwt = Jwt.parse(incomingTokenValue);
|
||||
|
||||
|
||||
|
||||
|
||||
if (oldToken.getScope().contains("id-token")) {
|
||||
// TODO: things
|
||||
}
|
||||
|
||||
|
||||
// TODO: should any of these throw an exception instead of returning null?
|
||||
JwtClaims claims = jwt.getClaims();
|
||||
if (!config.getIssuer().equals(claims.getIssuer())) {
|
||||
// issuer isn't us
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (!authorizationRequest.getClientId().equals(claims.getAudience())) {
|
||||
// audience isn't the client
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Date now = new Date();
|
||||
if (!now.after(claims.getExpiration())) {
|
||||
// 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
|
||||
// need to handle id tokens separately.
|
||||
return new OAuth2Authentication(authorizationRequest, null);
|
||||
|
||||
|
||||
} else {
|
||||
return null; // throw error??
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -43,11 +43,11 @@ import com.google.gson.JsonSerializer;
|
|||
|
||||
@Component("tokenIntrospection")
|
||||
public class TokenIntrospectionView extends AbstractView {
|
||||
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(TokenIntrospectionView.class);
|
||||
|
||||
@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() {
|
||||
|
||||
|
@ -68,7 +68,7 @@ public class TokenIntrospectionView extends AbstractView {
|
|||
// serialize other classes without filter (lists and sets and things)
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -84,28 +84,29 @@ public class TokenIntrospectionView extends AbstractView {
|
|||
|
||||
})
|
||||
.registerTypeAdapter(OAuth2AccessTokenEntity.class, new JsonSerializer<OAuth2AccessTokenEntity>() {
|
||||
public JsonElement serialize(OAuth2AccessTokenEntity src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject token = new JsonObject();
|
||||
|
||||
token.addProperty("valid", true);
|
||||
|
||||
JsonArray scopes = new JsonArray();
|
||||
for (String scope : src.getScope()) {
|
||||
scopes.add(new JsonPrimitive(scope));
|
||||
}
|
||||
token.add("scope", scopes);
|
||||
|
||||
token.add("expires_at", context.serialize(src.getExpiration()));
|
||||
|
||||
//token.addProperty("audience", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
|
||||
|
||||
token.addProperty("subject", src.getAuthenticationHolder().getAuthentication().getName());
|
||||
|
||||
token.addProperty("client_id", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(OAuth2AccessTokenEntity src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject token = new JsonObject();
|
||||
|
||||
token.addProperty("valid", true);
|
||||
|
||||
JsonArray scopes = new JsonArray();
|
||||
for (String scope : src.getScope()) {
|
||||
scopes.add(new JsonPrimitive(scope));
|
||||
}
|
||||
token.add("scope", scopes);
|
||||
|
||||
token.add("expires_at", context.serialize(src.getExpiration()));
|
||||
|
||||
//token.addProperty("audience", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
|
||||
|
||||
token.addProperty("subject", src.getAuthenticationHolder().getAuthentication().getName());
|
||||
|
||||
token.addProperty("client_id", src.getAuthenticationHolder().getAuthentication().getAuthorizationRequest().getClientId());
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
})
|
||||
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
.create();
|
||||
|
@ -113,9 +114,9 @@ public class TokenIntrospectionView extends AbstractView {
|
|||
response.setContentType("application/json");
|
||||
|
||||
Writer out;
|
||||
|
||||
|
||||
try {
|
||||
|
||||
|
||||
out = response.getWriter();
|
||||
Object obj = model.get("entity");
|
||||
if (obj == null) {
|
||||
|
@ -123,13 +124,13 @@ public class TokenIntrospectionView extends AbstractView {
|
|||
}
|
||||
|
||||
gson.toJson(obj, out);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
|
||||
logger.error("IOException occurred in TokenIntrospectionView.java: ", e);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package org.mitre.oauth2.web;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
|
@ -28,14 +27,11 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
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.RequestParam;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
@ -45,53 +41,53 @@ public class IntrospectionEndpoint {
|
|||
|
||||
@Autowired
|
||||
private OAuth2TokenEntityService tokenServices;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ClientDetailsEntityService clientService;
|
||||
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(IntrospectionEndpoint.class);
|
||||
|
||||
|
||||
public IntrospectionEndpoint() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public IntrospectionEndpoint(OAuth2TokenEntityService tokenServices) {
|
||||
this.tokenServices = tokenServices;
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_CLIENT')")
|
||||
@RequestMapping("/introspect")
|
||||
public String verify(@RequestParam("token") String tokenValue, Principal p, Model model) {
|
||||
|
||||
|
||||
if (Strings.isNullOrEmpty(tokenValue)) {
|
||||
logger.error("Verify failed; token value is null");
|
||||
Map<String,Boolean> entity = ImmutableMap.of("valid", Boolean.FALSE);
|
||||
model.addAttribute("entity", entity);
|
||||
return "jsonEntityView";
|
||||
}
|
||||
|
||||
|
||||
OAuth2AccessTokenEntity token = null;
|
||||
|
||||
|
||||
try {
|
||||
token = tokenServices.readAccessToken(tokenValue);
|
||||
token = tokenServices.readAccessToken(tokenValue);
|
||||
} catch (InvalidTokenException e) {
|
||||
logger.error("Verify failed; AuthenticationException: " + e.getStackTrace().toString());
|
||||
Map<String,Boolean> entity = ImmutableMap.of("valid", Boolean.FALSE);
|
||||
model.addAttribute("entity", entity);
|
||||
return "jsonEntityView";
|
||||
}
|
||||
|
||||
|
||||
ClientDetailsEntity tokenClient = token.getClient();
|
||||
// clientID is the principal name in the authentication
|
||||
String clientId = p.getName();
|
||||
ClientDetailsEntity authClient = clientService.loadClientByClientId(clientId);
|
||||
|
||||
|
||||
if (tokenClient != null && authClient != null) {
|
||||
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 (authClient.equals(tokenClient) || authClient.getScope().containsAll(token.getScope())) {
|
||||
|
||||
|
||||
// if it's a valid token, we'll print out information on it
|
||||
model.addAttribute("entity", token);
|
||||
return "tokenIntrospection";
|
||||
|
@ -111,7 +107,7 @@ public class IntrospectionEndpoint {
|
|||
model.addAttribute("code", HttpStatus.NOT_FOUND);
|
||||
return "httpCodeView";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.springframework.stereotype.Controller;
|
|||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
|
@ -51,20 +50,20 @@ public class OAuthConfirmationController {
|
|||
|
||||
@Autowired
|
||||
private ClientDetailsEntityService clientService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private SystemScopeService scopeService;
|
||||
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(OAuthConfirmationController.class);
|
||||
|
||||
|
||||
public OAuthConfirmationController() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public OAuthConfirmationController(ClientDetailsEntityService clientService) {
|
||||
this.clientService = clientService;
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
@RequestMapping("/oauth/confirm_access")
|
||||
public String confimAccess(Map<String, Object> model, @ModelAttribute("authorizationRequest") AuthorizationRequest clientAuth) {
|
||||
|
@ -77,14 +76,14 @@ public class OAuthConfirmationController {
|
|||
model.put("code", HttpStatus.FORBIDDEN);
|
||||
return "httpCodeView";
|
||||
}
|
||||
|
||||
|
||||
//AuthorizationRequest clientAuth = (AuthorizationRequest) model.remove("authorizationRequest");
|
||||
|
||||
ClientDetails client = null;
|
||||
|
||||
|
||||
try {
|
||||
client = clientService.loadClientByClientId(clientAuth.getClientId());
|
||||
} catch (OAuth2Exception e) {
|
||||
} catch (OAuth2Exception e) {
|
||||
logger.error("confirmAccess: OAuth2Exception was thrown when attempting to load client: "
|
||||
+ e.getStackTrace().toString());
|
||||
model.put("code", HttpStatus.BAD_REQUEST);
|
||||
|
@ -95,7 +94,7 @@ public class OAuthConfirmationController {
|
|||
model.put("code", HttpStatus.BAD_REQUEST);
|
||||
return "httpCodeView";
|
||||
}
|
||||
|
||||
|
||||
if (client == null) {
|
||||
logger.error("confirmAccess: could not find client " + clientAuth.getClientId());
|
||||
model.put("code", HttpStatus.NOT_FOUND);
|
||||
|
@ -106,41 +105,41 @@ public class OAuthConfirmationController {
|
|||
model.put("client", client);
|
||||
|
||||
String redirect_uri = clientAuth.getAuthorizationParameters().get("redirect_uri");
|
||||
|
||||
model.put("redirect_uri", redirect_uri);
|
||||
|
||||
Set<SystemScope> scopes = scopeService.fromStrings(clientAuth.getScope());
|
||||
|
||||
Set<SystemScope> sortedScopes = new LinkedHashSet<SystemScope>(scopes.size());
|
||||
Set<SystemScope> systemScopes = scopeService.getAll();
|
||||
|
||||
// sort scopes for display
|
||||
for (SystemScope s : systemScopes) {
|
||||
if (scopes.contains(s)) {
|
||||
sortedScopes.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
sortedScopes.addAll(Sets.difference(scopes, systemScopes));
|
||||
|
||||
model.put("scopes", sortedScopes);
|
||||
|
||||
return "approve";
|
||||
|
||||
model.put("redirect_uri", redirect_uri);
|
||||
|
||||
Set<SystemScope> scopes = scopeService.fromStrings(clientAuth.getScope());
|
||||
|
||||
Set<SystemScope> sortedScopes = new LinkedHashSet<SystemScope>(scopes.size());
|
||||
Set<SystemScope> systemScopes = scopeService.getAll();
|
||||
|
||||
// sort scopes for display
|
||||
for (SystemScope s : systemScopes) {
|
||||
if (scopes.contains(s)) {
|
||||
sortedScopes.add(s);
|
||||
}
|
||||
}
|
||||
|
||||
sortedScopes.addAll(Sets.difference(scopes, systemScopes));
|
||||
|
||||
model.put("scopes", sortedScopes);
|
||||
|
||||
return "approve";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clientService
|
||||
*/
|
||||
public ClientDetailsEntityService getClientService() {
|
||||
return clientService;
|
||||
}
|
||||
* @return the clientService
|
||||
*/
|
||||
public ClientDetailsEntityService getClientService() {
|
||||
return clientService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientService the clientService to set
|
||||
*/
|
||||
public void setClientService(ClientDetailsEntityService clientService) {
|
||||
this.clientService = clientService;
|
||||
}
|
||||
|
||||
|
||||
* @param clientService the clientService to set
|
||||
*/
|
||||
public void setClientService(ClientDetailsEntityService clientService) {
|
||||
this.clientService = clientService;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package org.mitre.oauth2.web;
|
|||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.mitre.oauth2.exception.PermissionDeniedException;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||
|
@ -26,7 +25,6 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
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.provider.AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
|
@ -34,19 +32,18 @@ import org.springframework.stereotype.Controller;
|
|||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@Controller
|
||||
public class RevocationEndpoint {
|
||||
@Autowired
|
||||
OAuth2TokenEntityService tokenServices;
|
||||
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(RevocationEndpoint.class);
|
||||
|
||||
|
||||
public RevocationEndpoint() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// TODO
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
|
||||
@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)
|
||||
//OAuth2AccessTokenEntity tok = tokenServices.getAccessToken((OAuth2Authentication) principal);
|
||||
|
||||
|
||||
AuthorizationRequest clientAuth = null;
|
||||
if (principal instanceof OAuth2Authentication) {
|
||||
// if the client is acting on its own behalf (the common case), pull out the client authorization request
|
||||
clientAuth = ((OAuth2Authentication) principal).getAuthorizationRequest();
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// check and handle access tokens first
|
||||
|
||||
|
||||
OAuth2AccessTokenEntity accessToken = tokenServices.readAccessToken(tokenValue);
|
||||
if (clientAuth != null) {
|
||||
// client acting on its own, make sure it owns the token
|
||||
|
@ -72,17 +69,17 @@ public class RevocationEndpoint {
|
|||
model.addAttribute("code", HttpStatus.FORBIDDEN);
|
||||
return "httpCodeView";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if we got this far, we're allowed to do this
|
||||
tokenServices.revokeAccessToken(accessToken);
|
||||
model.addAttribute("code", HttpStatus.OK);
|
||||
return "httpCodeView";
|
||||
|
||||
|
||||
} catch (InvalidTokenException e) {
|
||||
|
||||
|
||||
// access token wasn't found, check the refresh token
|
||||
|
||||
|
||||
try {
|
||||
OAuth2RefreshTokenEntity refreshToken = tokenServices.getRefreshToken(tokenValue);
|
||||
if (clientAuth != null) {
|
||||
|
@ -93,16 +90,16 @@ public class RevocationEndpoint {
|
|||
return "httpCodeView";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if we got this far, we're allowed to do this
|
||||
tokenServices.revokeRefreshToken(refreshToken);
|
||||
model.addAttribute("code", HttpStatus.OK);
|
||||
return "httpCodeView";
|
||||
|
||||
|
||||
} catch (InvalidTokenException e1) {
|
||||
|
||||
|
||||
// neither token type was found, simply say "OK" and be on our way.
|
||||
|
||||
|
||||
model.addAttribute("code", HttpStatus.OK);
|
||||
return "httpCodeView";
|
||||
}
|
||||
|
|
|
@ -5,9 +5,6 @@ package org.mitre.oauth2.web;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.EntityExistsException;
|
||||
import javax.persistence.TransactionRequiredException;
|
||||
|
||||
import org.mitre.oauth2.model.SystemScope;
|
||||
import org.mitre.oauth2.service.SystemScopeService;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -35,35 +32,35 @@ public class ScopeAPI {
|
|||
|
||||
@Autowired
|
||||
private SystemScopeService scopeService;
|
||||
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ScopeAPI.class);
|
||||
|
||||
|
||||
private Gson gson = new Gson();
|
||||
|
||||
|
||||
@RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json")
|
||||
public String getAll(ModelMap m) {
|
||||
|
||||
|
||||
Set<SystemScope> allScopes = scopeService.getAll();
|
||||
|
||||
|
||||
m.put("entity", allScopes);
|
||||
|
||||
|
||||
return "jsonEntityView";
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/json")
|
||||
public String getScope(@PathVariable("id") Long id, ModelMap m) {
|
||||
|
||||
|
||||
SystemScope scope = scopeService.getById(id);
|
||||
|
||||
|
||||
if (scope != null) {
|
||||
|
||||
|
||||
m.put("entity", scope);
|
||||
|
||||
|
||||
return "jsonEntityView";
|
||||
} else {
|
||||
|
||||
|
||||
logger.error("getScope failed; scope not found: " + id);
|
||||
|
||||
|
||||
m.put("code", HttpStatus.NOT_FOUND);
|
||||
m.put("errorMessage", "The requested scope with id " + id + " could not be found.");
|
||||
return "jsonErrorView";
|
||||
|
@ -73,46 +70,46 @@ public class ScopeAPI {
|
|||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, produces = "application/json", consumes = "application/json")
|
||||
public String updateScope(@PathVariable("id") Long id, @RequestBody String json, ModelMap m) {
|
||||
|
||||
|
||||
SystemScope existing = scopeService.getById(id);
|
||||
|
||||
|
||||
SystemScope scope = gson.fromJson(json, SystemScope.class);
|
||||
|
||||
|
||||
if (existing != null && scope != null) {
|
||||
|
||||
|
||||
if (existing.getId().equals(scope.getId())) {
|
||||
// sanity check
|
||||
|
||||
|
||||
scope = scopeService.save(scope);
|
||||
|
||||
|
||||
m.put("entity", scope);
|
||||
|
||||
|
||||
return "jsonEntityView";
|
||||
} 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());
|
||||
|
||||
|
||||
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());
|
||||
return "jsonErrorView";
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
logger.error("updateScope failed; scope with id " + id + " not found.");
|
||||
m.put("code", HttpStatus.NOT_FOUND);
|
||||
m.put("errorMessage", "Could not update scope. The scope with id " + id + " could not be found.");
|
||||
return "jsonErrorView";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping(value = "", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
|
||||
public String createScope(@RequestBody String json, ModelMap m) {
|
||||
SystemScope scope = gson.fromJson(json, SystemScope.class);
|
||||
|
||||
|
||||
SystemScope alreadyExists = scopeService.getByValue(scope.getValue());
|
||||
if (alreadyExists != null) {
|
||||
//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.");
|
||||
return "jsonErrorView";
|
||||
}
|
||||
|
||||
|
||||
scope = scopeService.save(scope);
|
||||
|
||||
if (scope != null && scope.getId() != null) {
|
||||
|
||||
m.put("entity", scope);
|
||||
|
||||
|
||||
return "jsonEntityView";
|
||||
} else {
|
||||
|
||||
|
||||
logger.error("createScope failed; JSON was invalid: " + json);
|
||||
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.");
|
||||
return "jsonErrorView";
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
|
||||
public String deleteScope(@PathVariable("id") Long id, ModelMap m) {
|
||||
SystemScope existing = scopeService.getById(id);
|
||||
|
||||
|
||||
if (existing != null) {
|
||||
|
||||
scopeService.remove(existing);
|
||||
|
||||
|
||||
return "httpCodeView";
|
||||
} else {
|
||||
|
||||
|
||||
logger.error("deleteScope failed; scope with id " + id + " 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.");
|
||||
return "jsonErrorView";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -38,10 +38,10 @@ import com.nimbusds.jwt.SignedJWT;
|
|||
public class ConnectAuthorizationRequestManager implements AuthorizationRequestManager {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ConnectAuthorizationRequestManager.class);
|
||||
|
||||
|
||||
@Autowired
|
||||
private NonceService nonceService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ClientDetailsEntityService clientDetailsService;
|
||||
|
||||
|
@ -58,32 +58,32 @@ public class ConnectAuthorizationRequestManager implements AuthorizationRequestM
|
|||
this.clientDetailsService = clientDetailsService;
|
||||
this.nonceService = nonceService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default empty constructor
|
||||
*/
|
||||
public ConnectAuthorizationRequestManager() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationRequest createAuthorizationRequest(Map<String, String> inputParams) {
|
||||
|
||||
Map<String, String> parameters = processRequestObject(inputParams);
|
||||
|
||||
|
||||
String clientId = parameters.get("client_id");
|
||||
if (clientId == null) {
|
||||
throw new InvalidClientException("A client id must be provided");
|
||||
}
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
|
||||
|
||||
|
||||
String requestNonce = parameters.get("nonce");
|
||||
|
||||
//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
|
||||
|
||||
//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
|
||||
//to the auth endpoint.
|
||||
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
|
||||
|
||||
if (requestNonce != null && principal != null && principal instanceof User) {
|
||||
|
||||
if (!nonceService.alreadyUsed(clientId, requestNonce)) {
|
||||
|
@ -93,17 +93,17 @@ public class ConnectAuthorizationRequestManager implements AuthorizationRequestM
|
|||
else {
|
||||
throw new NonceReuseException(client.getClientId(), requestNonce);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Set<String> scopes = OAuth2Utils.parseParameterList(parameters.get("scope"));
|
||||
if ((scopes == null || scopes.isEmpty())) {
|
||||
//TODO: do we want to allow default scoping at all?
|
||||
Set<String> clientScopes = client.getScope();
|
||||
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)
|
||||
DefaultAuthorizationRequest request = new DefaultAuthorizationRequest(parameters, Collections.<String, String> emptyMap(), clientId, scopes);
|
||||
request.addClientDetails(client);
|
||||
|
@ -115,46 +115,46 @@ public class ConnectAuthorizationRequestManager implements AuthorizationRequestM
|
|||
* @param inputParams
|
||||
* @return
|
||||
*/
|
||||
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;
|
||||
}
|
||||
private Map<String, String> processRequestObject(Map<String, String> inputParams) {
|
||||
|
||||
// start by copying over what's already in there
|
||||
Map<String, String> parameters = new HashMap<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
|
||||
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
|
||||
|
||||
|
||||
String clientId = JSONObjectUtils.getString(claims, "client_id");
|
||||
if (clientId != null) {
|
||||
parameters.put("client_id", clientId);
|
||||
}
|
||||
|
||||
|
||||
ClientDetailsEntity client = clientDetailsService.loadClientByClientId(clientId);
|
||||
|
||||
if (client.getJwksUri() == null) {
|
||||
throw new InvalidClientException("Client must have a JWKS URI registered to use request objects.");
|
||||
}
|
||||
|
||||
|
||||
// check JWT signature
|
||||
JwtSigningAndValidationService validator = validators.get(client.getJwksUri());
|
||||
if (validator == null) {
|
||||
throw new InvalidClientException("Unable to create signature validator for client's JWKS URI: " + client.getJwksUri());
|
||||
}
|
||||
|
||||
|
||||
if (!validator.validateSignature(jwsObject)) {
|
||||
throw new AuthenticationServiceException("Signature did not validate for presented JWT request object.");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* if (in Claims):
|
||||
* if (in params):
|
||||
|
@ -167,59 +167,59 @@ public class ConnectAuthorizationRequestManager implements AuthorizationRequestM
|
|||
* else (not in claims):
|
||||
* we don't care
|
||||
*/
|
||||
|
||||
|
||||
String responseTypes = JSONObjectUtils.getString(claims, "response_type");
|
||||
if (responseTypes != null) {
|
||||
parameters.put("response_type", responseTypes);
|
||||
}
|
||||
|
||||
|
||||
if (claims.get("redirect_uri") != null) {
|
||||
if (inputParams.containsKey("redirect_uri") == false) {
|
||||
parameters.put("redirect_uri", JSONObjectUtils.getString(claims, "redirect_uri"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String state = JSONObjectUtils.getString(claims, "state");
|
||||
if(state != null) {
|
||||
if (inputParams.containsKey("state") == false) {
|
||||
parameters.put("state", state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String nonce = JSONObjectUtils.getString(claims, "nonce");
|
||||
if(nonce != null) {
|
||||
if (inputParams.containsKey("nonce") == false) {
|
||||
parameters.put("nonce", nonce);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String display = JSONObjectUtils.getString(claims, "display");
|
||||
if (display != null) {
|
||||
if (inputParams.containsKey("display") == false) {
|
||||
parameters.put("display", display);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String prompt = JSONObjectUtils.getString(claims, "prompt");
|
||||
if (prompt != null) {
|
||||
if (inputParams.containsKey("prompt") == false) {
|
||||
parameters.put("prompt", prompt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String scope = JSONObjectUtils.getString(claims, "scope");
|
||||
if (scope != null) {
|
||||
if (inputParams.containsKey("scope") == false) {
|
||||
parameters.put("scope", scope);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (ParseException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
} catch (ParseException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateParameters(Map<String, String> parameters, ClientDetails clientDetails) {
|
||||
|
|
|
@ -18,19 +18,19 @@ public class JwtBearerAssertionAuthenticationToken extends AbstractAuthenticatio
|
|||
|
||||
private String clientId;
|
||||
private JWT jwt;
|
||||
|
||||
|
||||
/**
|
||||
* Create an unauthenticated token with the given client ID and jwt
|
||||
* @param clientId
|
||||
* @param jwt
|
||||
*/
|
||||
public JwtBearerAssertionAuthenticationToken(String clientId, JWT jwt) {
|
||||
super(null);
|
||||
this.clientId = clientId;
|
||||
this.jwt = jwt;
|
||||
setAuthenticated(false);
|
||||
}
|
||||
|
||||
super(null);
|
||||
this.clientId = clientId;
|
||||
this.jwt = jwt;
|
||||
setAuthenticated(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an authenticated token with the given clientID, jwt, and authorities set
|
||||
* @param clientId
|
||||
|
@ -38,11 +38,11 @@ public class JwtBearerAssertionAuthenticationToken extends AbstractAuthenticatio
|
|||
* @param authorities
|
||||
*/
|
||||
public JwtBearerAssertionAuthenticationToken(String clientId, JWT jwt, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(authorities);
|
||||
this.clientId = clientId;
|
||||
this.jwt = jwt;
|
||||
setAuthenticated(true);
|
||||
}
|
||||
super(authorities);
|
||||
this.clientId = clientId;
|
||||
this.jwt = jwt;
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.core.Authentication#getCredentials()
|
||||
|
@ -61,42 +61,42 @@ public class JwtBearerAssertionAuthenticationToken extends AbstractAuthenticatio
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the clientId
|
||||
*/
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
* @return the clientId
|
||||
*/
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientId the clientId to set
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
* @param clientId the clientId to set
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jwt
|
||||
*/
|
||||
public JWT getJwt() {
|
||||
return jwt;
|
||||
}
|
||||
* @return the jwt
|
||||
*/
|
||||
public JWT getJwt() {
|
||||
return jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jwt the jwt to set
|
||||
*/
|
||||
public void setJwt(JWT jwt) {
|
||||
this.jwt = jwt;
|
||||
}
|
||||
* @param jwt the jwt to set
|
||||
*/
|
||||
public void setJwt(JWT jwt) {
|
||||
this.jwt = jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear out the JWT that this token holds.
|
||||
*/
|
||||
@Override
|
||||
public void eraseCredentials() {
|
||||
super.eraseCredentials();
|
||||
setJwt(null);
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
@Override
|
||||
public void eraseCredentials() {
|
||||
super.eraseCredentials();
|
||||
setJwt(null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -36,49 +36,49 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
|||
// map of verifiers, load keys for clients
|
||||
@Autowired
|
||||
private JWKSetSigningAndValidationServiceCacheService validators;
|
||||
|
||||
|
||||
// Allow for time sync issues by having a window of X seconds.
|
||||
private int timeSkewAllowance = 300;
|
||||
|
||||
// to load clients
|
||||
@Autowired
|
||||
private ClientDetailsEntityService clientService;
|
||||
|
||||
|
||||
// to get our server's issuer url
|
||||
@Autowired
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
|
||||
/**
|
||||
* Try to validate the client credentials by parsing and validating the JWT.
|
||||
*/
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
|
||||
JwtBearerAssertionAuthenticationToken jwtAuth = (JwtBearerAssertionAuthenticationToken)authentication;
|
||||
|
||||
|
||||
try {
|
||||
ClientDetailsEntity client = clientService.loadClientByClientId(jwtAuth.getClientId());
|
||||
*/
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
|
||||
JWT jwt = jwtAuth.getJwt();
|
||||
ReadOnlyJWTClaimsSet jwtClaims = jwt.getJWTClaimsSet();
|
||||
JwtBearerAssertionAuthenticationToken jwtAuth = (JwtBearerAssertionAuthenticationToken)authentication;
|
||||
|
||||
|
||||
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
|
||||
if (jwtClaims.getIssuer() == null) {
|
||||
throw new AuthenticationServiceException("Assertion Token Issuer is null");
|
||||
} else if (!jwtClaims.getIssuer().equals(client.getClientId())){
|
||||
throw new AuthenticationServiceException("Issuers do not match, expected " + client.getClientId() + " got " + jwtClaims.getIssuer());
|
||||
}
|
||||
|
||||
|
||||
// check expiration
|
||||
if (jwtClaims.getExpirationTime() == null) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check not before
|
||||
if (jwtClaims.getNotBeforeTime() != null) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check issued at
|
||||
if (jwtClaims.getIssueTime() != null) {
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check audience
|
||||
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())) {
|
||||
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());
|
||||
|
||||
} catch (InvalidClientException e) {
|
||||
throw new UsernameNotFoundException("Could not find client: " + jwtAuth.getClientId());
|
||||
} catch (ParseException e) {
|
||||
// TODO Auto-generated catch block
|
||||
throw new AuthenticationServiceException("Invalid JWT format");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (InvalidClientException e) {
|
||||
throw new UsernameNotFoundException("Could not find client: " + jwtAuth.getClientId());
|
||||
} catch (ParseException e) {
|
||||
// TODO Auto-generated catch block
|
||||
throw new AuthenticationServiceException("Invalid JWT format");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We support {@link JwtBearerAssertionAuthenticationToken}s only.
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return (JwtBearerAssertionAuthenticationToken.class.isAssignableFrom(authentication));
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return (JwtBearerAssertionAuthenticationToken.class.isAssignableFrom(authentication));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -28,74 +28,74 @@ import com.nimbusds.jwt.JWTParser;
|
|||
public class JwtBearerClientAssertionTokenEndpointFilter extends ClientCredentialsTokenEndpointFilter {
|
||||
|
||||
public JwtBearerClientAssertionTokenEndpointFilter() {
|
||||
super();
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
super();
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public JwtBearerClientAssertionTokenEndpointFilter(String path) {
|
||||
super(path);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
super(path);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the assertion out of the request and send it up to the auth manager for processing.
|
||||
*/
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
|
||||
*/
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
|
||||
|
||||
// check for appropriate parameters
|
||||
String assertionType = request.getParameter("client_assertion_type");
|
||||
String assertion = request.getParameter("client_assertion");
|
||||
|
||||
try {
|
||||
JWT jwt = JWTParser.parse(assertion);
|
||||
|
||||
String clientId = jwt.getJWTClaimsSet().getSubject();
|
||||
|
||||
Authentication authRequest = new JwtBearerAssertionAuthenticationToken(clientId, jwt);
|
||||
|
||||
return this.getAuthenticationManager().authenticate(authRequest);
|
||||
} catch (ParseException e) {
|
||||
throw new BadCredentialsException("Invalid JWT credential: " + assertion);
|
||||
}
|
||||
}
|
||||
// check for appropriate parameters
|
||||
String assertionType = request.getParameter("client_assertion_type");
|
||||
String assertion = request.getParameter("client_assertion");
|
||||
|
||||
try {
|
||||
JWT jwt = JWTParser.parse(assertion);
|
||||
|
||||
String clientId = jwt.getJWTClaimsSet().getSubject();
|
||||
|
||||
Authentication authRequest = new JwtBearerAssertionAuthenticationToken(clientId, jwt);
|
||||
|
||||
return this.getAuthenticationManager().authenticate(authRequest);
|
||||
} catch (ParseException e) {
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
|
||||
// check for appropriate parameters
|
||||
String assertionType = request.getParameter("client_assertion_type");
|
||||
String assertion = request.getParameter("client_assertion");
|
||||
*/
|
||||
@Override
|
||||
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
|
||||
// check for appropriate parameters
|
||||
String assertionType = request.getParameter("client_assertion_type");
|
||||
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.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
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.web.filter.GenericFilterBean;
|
||||
|
||||
|
@ -30,7 +27,7 @@ import com.google.common.base.Strings;
|
|||
*/
|
||||
@Component("promptFilter")
|
||||
public class PromptFilter extends GenericFilterBean {
|
||||
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(PromptFilter.class);
|
||||
|
||||
/**
|
||||
|
@ -38,33 +35,33 @@ public class PromptFilter extends GenericFilterBean {
|
|||
*/
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
|
||||
if (!Strings.isNullOrEmpty(request.getParameter("prompt"))) {
|
||||
// we have a "prompt" parameter
|
||||
|
||||
if (request.getParameter("prompt").equals("none")) {
|
||||
logger.info("Client requested no prompt");
|
||||
// see if the user's logged in
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (auth != null) {
|
||||
// user's been logged in already (by session management)
|
||||
// we're OK, continue without prompting
|
||||
chain.doFilter(req, res);
|
||||
} else {
|
||||
// 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");
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
|
||||
return;
|
||||
}
|
||||
/* TODO: this is an attempt to catch the prompt=login case, but it results in an infinite loop so it's commented out
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
|
||||
if (!Strings.isNullOrEmpty(request.getParameter("prompt"))) {
|
||||
// we have a "prompt" parameter
|
||||
|
||||
if (request.getParameter("prompt").equals("none")) {
|
||||
logger.info("Client requested no prompt");
|
||||
// see if the user's logged in
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (auth != null) {
|
||||
// user's been logged in already (by session management)
|
||||
// we're OK, continue without prompting
|
||||
chain.doFilter(req, res);
|
||||
} else {
|
||||
// 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");
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
|
||||
return;
|
||||
}
|
||||
/* 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")) {
|
||||
// see if the user's logged in
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
|
||||
if (auth != null) {
|
||||
// user's been logged in already (by session management)
|
||||
// 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
|
||||
chain.doFilter(req, res);
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
// prompt parameter is a value we don't care about, not our business
|
||||
chain.doFilter(req, res);
|
||||
}
|
||||
|
||||
} else {
|
||||
// no prompt parameter, not our business
|
||||
chain.doFilter(req, res);
|
||||
}
|
||||
|
||||
*/
|
||||
} else {
|
||||
// prompt parameter is a value we don't care about, not our business
|
||||
chain.doFilter(req, res);
|
||||
}
|
||||
|
||||
} else {
|
||||
// no prompt parameter, not our business
|
||||
chain.doFilter(req, res);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
******************************************************************************/
|
||||
package org.mitre.openid.connect.repository.impl;
|
||||
|
||||
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
|
@ -25,6 +23,8 @@ import org.mitre.openid.connect.repository.AddressRepository;
|
|||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
|
||||
|
||||
/**
|
||||
* JPA Address repository implementation
|
||||
*
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
******************************************************************************/
|
||||
package org.mitre.openid.connect.repository.impl;
|
||||
|
||||
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
@ -25,10 +23,11 @@ import javax.persistence.TypedQuery;
|
|||
|
||||
import org.mitre.openid.connect.model.ApprovedSite;
|
||||
import org.mitre.openid.connect.repository.ApprovedSiteRepository;
|
||||
import org.mitre.util.jpa.JpaUtil;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
|
||||
|
||||
/**
|
||||
* JPA ApprovedSite repository implementation
|
||||
*
|
||||
|
@ -48,7 +47,7 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
|
|||
"ApprovedSite.getAll", ApprovedSite.class);
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ApprovedSite getById(Long id) {
|
||||
|
@ -59,7 +58,7 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
|
|||
@Transactional
|
||||
public void remove(ApprovedSite approvedSite) {
|
||||
ApprovedSite found = manager.find(ApprovedSite.class, approvedSite.getId());
|
||||
|
||||
|
||||
if (found != null) {
|
||||
manager.remove(found);
|
||||
} else {
|
||||
|
@ -75,30 +74,30 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
|
|||
|
||||
@Override
|
||||
public Collection<ApprovedSite> getByClientIdAndUserId(String clientId, String userId) {
|
||||
|
||||
|
||||
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByClientIdAndUserId", ApprovedSite.class);
|
||||
query.setParameter("userId", userId);
|
||||
query.setParameter("clientId", clientId);
|
||||
|
||||
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Collection<ApprovedSite> getByUserId(String userId) {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Collection<ApprovedSite> getByUserId(String userId) {
|
||||
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByUserId", ApprovedSite.class);
|
||||
query.setParameter("userId", userId);
|
||||
|
||||
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);
|
||||
query.setParameter("clientId", clientId);
|
||||
|
||||
|
||||
return query.getResultList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue