Merge branch 'master' of github.com:jricher/OpenID-Connect-Java-Spring-Server
commit
fe88ea4e7a
18
pom.xml
18
pom.xml
|
@ -7,10 +7,20 @@
|
|||
<name>OpenIdConnect</name>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.1</version>
|
||||
<modules>
|
||||
<module>spring-security-oauth/spring-security-oauth2</module>
|
||||
<module>server</module>
|
||||
</modules>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<id>default</id>
|
||||
<modules>
|
||||
<module>spring-security-oauth/spring-security-oauth2</module>
|
||||
<module>server</module>
|
||||
</modules>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<properties>
|
||||
<java-version>1.6</java-version>
|
||||
<spring.version>3.1.0.RELEASE</spring.version>
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package org.mitre.oauth2.exception;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @author aanganes
|
||||
*
|
||||
*/
|
||||
public class ClientNotFoundException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final Long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public ClientNotFoundException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
*/
|
||||
public ClientNotFoundException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
*/
|
||||
public ClientNotFoundException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param cause
|
||||
*/
|
||||
public ClientNotFoundException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package org.mitre.oauth2.exception;
|
||||
|
||||
public class DuplicateClientIdException extends RuntimeException {
|
||||
|
||||
public DuplicateClientIdException(String clientId) {
|
||||
super("Duplicate client id: " + clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.oauth2.exception;
|
||||
|
||||
/**
|
||||
* @author AANGANES
|
||||
*
|
||||
*/
|
||||
public class PermissionDeniedException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final Long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public PermissionDeniedException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
*/
|
||||
public PermissionDeniedException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
*/
|
||||
public PermissionDeniedException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param cause
|
||||
*/
|
||||
public PermissionDeniedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,473 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name="clientdetails")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "ClientDetailsEntity.findAll", query = "SELECT c FROM ClientDetailsEntity c")
|
||||
})
|
||||
public class ClientDetailsEntity implements ClientDetails {
|
||||
|
||||
/**
|
||||
* Create a blank ClientDetailsEntity
|
||||
*/
|
||||
public ClientDetailsEntity() {
|
||||
|
||||
}
|
||||
|
||||
private String clientId;
|
||||
private String clientSecret;
|
||||
private Set<String> scope;
|
||||
private Set<String> authorizedGrantTypes;
|
||||
private Set<GrantedAuthority> authorities = Collections.emptySet();
|
||||
private String clientName;
|
||||
private String clientDescription;
|
||||
private boolean allowRefresh = false; // do we allow refresh tokens for this client?
|
||||
private Long accessTokenTimeout; // in seconds
|
||||
private Long refreshTokenTimeout; // in seconds
|
||||
private String owner; // userid of who registered it
|
||||
private String registeredRedirectUri;
|
||||
private Set<String> resourceIds;
|
||||
|
||||
// TODO:
|
||||
/*
|
||||
private boolean allowMultipleAccessTokens; // do we allow multiple access tokens, or not?
|
||||
private boolean reuseRefreshToken; // do we let someone reuse a refresh token?
|
||||
*/
|
||||
|
||||
/**
|
||||
* @return the clientId
|
||||
*/
|
||||
@Id
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clientSecret
|
||||
*/
|
||||
@Basic
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientSecret the OAuth2 client_secret (optional)
|
||||
*/
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the scope
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="scope",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
public Set<String> getScope() {
|
||||
return 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
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="authorizedgranttypes",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
public Set<String> getAuthorizedGrantTypes() {
|
||||
return authorizedGrantTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authorizedGrantTypes the OAuth2 grant types that this client is allowed to use
|
||||
*/
|
||||
public void setAuthorizedGrantTypes(Set<String> authorizedGrantTypes) {
|
||||
this.authorizedGrantTypes = authorizedGrantTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the authorities
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="authorities",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the clientSecret is not null, then it is always required.
|
||||
*/
|
||||
@Override
|
||||
public boolean isSecretRequired() {
|
||||
return getClientSecret() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the scope list is not null or empty, then this client has been scoped.
|
||||
*/
|
||||
@Override
|
||||
public boolean isScoped() {
|
||||
return getScope() != null && !getScope().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clientName
|
||||
*/
|
||||
@Basic
|
||||
public String getClientName() {
|
||||
return clientName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientName Human-readable name of the client (optional)
|
||||
*/
|
||||
public void setClientName(String clientName) {
|
||||
this.clientName = clientName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clientDescription
|
||||
*/
|
||||
@Basic
|
||||
public String getClientDescription() {
|
||||
return clientDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientDescription Human-readable long description of the client (optional)
|
||||
*/
|
||||
public void setClientDescription(String clientDescription) {
|
||||
this.clientDescription = clientDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the allowRefresh
|
||||
*/
|
||||
@Basic
|
||||
public boolean isAllowRefresh() {
|
||||
return allowRefresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param allowRefresh Whether to allow for issuance of refresh tokens or not (defaults to false)
|
||||
*/
|
||||
public void setAllowRefresh(boolean allowRefresh) {
|
||||
this.allowRefresh = allowRefresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param accessTokenTimeout Lifetime of access tokens, in seconds (optional - leave null for no timeout)
|
||||
*/
|
||||
@Basic
|
||||
public Long getAccessTokenTimeout() {
|
||||
return accessTokenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param accessTokenTimeout the accessTokenTimeout to set
|
||||
*/
|
||||
public void setAccessTokenTimeout(Long accessTokenTimeout) {
|
||||
this.accessTokenTimeout = accessTokenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the refreshTokenTimeout
|
||||
*/
|
||||
@Basic
|
||||
public Long getRefreshTokenTimeout() {
|
||||
return refreshTokenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param refreshTokenTimeout Lifetime of refresh tokens, in seconds (optional - leave null for no timeout)
|
||||
*/
|
||||
public void setRefreshTokenTimeout(Long refreshTokenTimeout) {
|
||||
this.refreshTokenTimeout = refreshTokenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the owner
|
||||
*/
|
||||
@Basic
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param owner User ID of the person who registered this client (optional)
|
||||
*/
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the registeredRedirectUri
|
||||
*/
|
||||
@Basic
|
||||
public String getRegisteredRedirectUri() {
|
||||
return registeredRedirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param registeredRedirectUri the registeredRedirectUri to set
|
||||
*/
|
||||
public void setRegisteredRedirectUri(String registeredRedirectUri) {
|
||||
this.registeredRedirectUri = registeredRedirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the resourceIds
|
||||
*/
|
||||
public Set<String> getResourceIds() {
|
||||
return resourceIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resourceIds the resourceIds to set
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="resource_ids",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
public void setResourceIds(Set<String> resourceIds) {
|
||||
this.resourceIds = resourceIds;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClientDetailsEntity [" + (clientId != null ? "clientId=" + clientId + ", " : "") + (scope != null ? "scope=" + scope + ", " : "") + (clientName != null ? "clientName=" + clientName + ", " : "") + (owner != null ? "owner=" + owner : "") + "]";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((clientId == null) ? 0 : clientId.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;
|
||||
}
|
||||
ClientDetailsEntity other = (ClientDetailsEntity) obj;
|
||||
if (clientId == null) {
|
||||
if (other.clientId != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!clientId.equals(other.clientId)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ClientDetailsEntityBuilder makeBuilder() {
|
||||
return new ClientDetailsEntityBuilder();
|
||||
}
|
||||
|
||||
public static class ClientDetailsEntityBuilder {
|
||||
private ClientDetailsEntity instance;
|
||||
|
||||
private ClientDetailsEntityBuilder() {
|
||||
instance = new ClientDetailsEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientId
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setClientId(java.lang.String)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setClientId(String clientId) {
|
||||
instance.setClientId(clientId);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientSecret
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setClientSecret(java.lang.String)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setClientSecret(String clientSecret) {
|
||||
instance.setClientSecret(clientSecret);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scope
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setScope(java.util.List)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setScope(Set<String> scope) {
|
||||
instance.setScope(scope);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authorizedGrantTypes
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setAuthorizedGrantTypes(java.util.List)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setAuthorizedGrantTypes(Set<String> authorizedGrantTypes) {
|
||||
instance.setAuthorizedGrantTypes(authorizedGrantTypes);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authorities
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setAuthorities(java.util.List)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setAuthorities(Set<GrantedAuthority> authorities) {
|
||||
instance.setAuthorities(authorities);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientName
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setClientName(java.lang.String)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setClientName(String clientName) {
|
||||
instance.setClientName(clientName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientDescription
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setClientDescription(java.lang.String)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setClientDescription(String clientDescription) {
|
||||
instance.setClientDescription(clientDescription);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param allowRefresh
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setAllowRefresh(boolean)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setAllowRefresh(boolean allowRefresh) {
|
||||
instance.setAllowRefresh(allowRefresh);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param accessTokenTimeout
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setAccessTokenTimeout(java.lang.Long)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setAccessTokenTimeout(Long accessTokenTimeout) {
|
||||
instance.setAccessTokenTimeout(accessTokenTimeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param refreshTokenTimeout
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setRefreshTokenTimeout(java.lang.Long)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setRefreshTokenTimeout(Long refreshTokenTimeout) {
|
||||
instance.setRefreshTokenTimeout(refreshTokenTimeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param owner
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setOwner(java.lang.String)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setOwner(String owner) {
|
||||
instance.setOwner(owner);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Complete the builder
|
||||
* @return
|
||||
*/
|
||||
public ClientDetailsEntity finish() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param registeredRedirectUri
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setRegisteredRedirectUri(java.lang.String)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setRegisteredRedirectUri(String registeredRedirectUri) {
|
||||
instance.setRegisteredRedirectUri(registeredRedirectUri);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resourceIds
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setResourceIds(java.util.List)
|
||||
*/
|
||||
public ClientDetailsEntityBuilder setResourceIds(Set<String> resourceIds) {
|
||||
instance.setResourceIds(resourceIds);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.mitre.oauth2.model;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity.ClientDetailsEntityBuilder;
|
||||
|
||||
public interface ClientDetailsEntityFactory {
|
||||
|
||||
public ClientDetailsEntity createClient(String clientId, String clientSecret);
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity.ClientDetailsEntityBuilder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* A factory for making OAuth2 clients with autogenerated IDs and secrets (as desired)
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class ClientGeneratorFactory implements ClientDetailsEntityFactory {
|
||||
|
||||
@Override
|
||||
public ClientDetailsEntity createClient(String clientId, String clientSecret) {
|
||||
ClientDetailsEntityBuilder builder = ClientDetailsEntity.makeBuilder();
|
||||
if (clientId == null) {
|
||||
clientId = UUID.randomUUID().toString();
|
||||
}
|
||||
builder.setClientId(clientId);
|
||||
if (clientSecret == null) {
|
||||
clientSecret = Base64.encodeBase64((UUID.randomUUID().toString() + UUID.randomUUID().toString()).getBytes()).toString();
|
||||
}
|
||||
builder.setClientSecret(clientSecret);
|
||||
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.Lob;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name="accesstoken")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "OAuth2AccessTokenEntity.getByRefreshToken", query = "select a from OAuth2AccessTokenEntity a where a.refreshToken = :refreshToken"),
|
||||
@NamedQuery(name = "OAuth2AccessTokenEntity.getByClient", query = "select a from OAuth2AccessTokenEntity a where a.client = :client"),
|
||||
@NamedQuery(name = "OAuth2AccessTokenEntity.getExpired", query = "select a from OAuth2AccessTokenEntity a where a.expiration is not null and a.expiration < current_timestamp")
|
||||
})
|
||||
public class OAuth2AccessTokenEntity extends OAuth2AccessToken {
|
||||
|
||||
private ClientDetailsEntity client;
|
||||
|
||||
private OAuth2Authentication authentication; // the authentication that made this access
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public OAuth2AccessTokenEntity() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the authentication
|
||||
*/
|
||||
@Lob
|
||||
@Basic
|
||||
public OAuth2Authentication getAuthentication() {
|
||||
return authentication;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param authentication the authentication to set
|
||||
*/
|
||||
public void setAuthentication(OAuth2Authentication authentication) {
|
||||
this.authentication = authentication;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the client
|
||||
*/
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "client_id")
|
||||
public ClientDetailsEntity getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param client the client to set
|
||||
*/
|
||||
public void setClient(ClientDetailsEntity client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#getValue()
|
||||
*/
|
||||
@Override
|
||||
@Id
|
||||
@Column(name="id")
|
||||
public String getValue() {
|
||||
// TODO Auto-generated method stub
|
||||
return super.getValue();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#setValue(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setValue(String value) {
|
||||
// TODO Auto-generated method stub
|
||||
super.setValue(value);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#getExpiration()
|
||||
*/
|
||||
@Override
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
public Date getExpiration() {
|
||||
// TODO Auto-generated method stub
|
||||
return super.getExpiration();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#setExpiration(java.util.Date)
|
||||
*/
|
||||
@Override
|
||||
public void setExpiration(Date expiration) {
|
||||
// TODO Auto-generated method stub
|
||||
super.setExpiration(expiration);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#getTokenType()
|
||||
*/
|
||||
@Override
|
||||
@Basic
|
||||
public String getTokenType() {
|
||||
// TODO Auto-generated method stub
|
||||
return super.getTokenType();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#setTokenType(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setTokenType(String tokenType) {
|
||||
// TODO Auto-generated method stub
|
||||
super.setTokenType(tokenType);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#getRefreshToken()
|
||||
*/
|
||||
@Override
|
||||
@ManyToOne
|
||||
@JoinColumn(name="refresh_token_id")
|
||||
public OAuth2RefreshTokenEntity getRefreshToken() {
|
||||
// TODO Auto-generated method stub
|
||||
return (OAuth2RefreshTokenEntity) super.getRefreshToken();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#setRefreshToken(org.springframework.security.oauth2.common.OAuth2RefreshToken)
|
||||
*/
|
||||
public void setRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
// TODO Auto-generated method stub
|
||||
super.setRefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#setRefreshToken(org.springframework.security.oauth2.common.OAuth2RefreshToken)
|
||||
*/
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#getScope()
|
||||
*/
|
||||
@Override
|
||||
@ElementCollection(fetch=FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
joinColumns=@JoinColumn(name="owner_id"),
|
||||
name="scope"
|
||||
)
|
||||
public Set<String> getScope() {
|
||||
// TODO Auto-generated method stub
|
||||
return super.getScope();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2AccessToken#setScope(java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
public void setScope(Set<String> scope) {
|
||||
// TODO Auto-generated method stub
|
||||
super.setScope(scope);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public boolean isExpired() {
|
||||
return getExpiration() == null ? false : System.currentTimeMillis() > getExpiration().getTime();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.mitre.oauth2.model;
|
||||
|
||||
public interface OAuth2AccessTokenEntityFactory {
|
||||
|
||||
public OAuth2AccessTokenEntity createNewAccessToken();
|
||||
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name="refreshtoken")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "OAuth2RefreshTokenEntity.getByClient", query = "select r from OAuth2RefreshTokenEntity r where r.client = :client"),
|
||||
@NamedQuery(name = "OAuth2RefreshTokenEntity.getExpired", query = "select r from OAuth2RefreshTokenEntity r where r.expiration is not null and r.expiration < current_timestamp")
|
||||
})
|
||||
public class OAuth2RefreshTokenEntity extends ExpiringOAuth2RefreshToken {
|
||||
|
||||
private ClientDetailsEntity client;
|
||||
|
||||
private Set<String> scope; // we save the scope issued to the refresh token so that we can reissue a new access token
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public OAuth2RefreshTokenEntity() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2RefreshToken#getValue()
|
||||
*/
|
||||
@Override
|
||||
@Id
|
||||
@Column(name="id")
|
||||
public String getValue() {
|
||||
// TODO Auto-generated method stub
|
||||
return super.getValue();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.OAuth2RefreshToken#setValue(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setValue(String value) {
|
||||
// TODO Auto-generated method stub
|
||||
super.setValue(value);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken#getExpiration()
|
||||
*/
|
||||
@Override
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
public Date getExpiration() {
|
||||
// TODO Auto-generated method stub
|
||||
return super.getExpiration();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken#setExpiration(java.util.Date)
|
||||
*/
|
||||
@Override
|
||||
public void setExpiration(Date expiration) {
|
||||
// TODO Auto-generated method stub
|
||||
super.setExpiration(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
|
||||
*/
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "client_id")
|
||||
public ClientDetailsEntity getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param client the client to set
|
||||
*/
|
||||
public void setClient(ClientDetailsEntity client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the scope
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
joinColumns=@JoinColumn(name="owner_id"),
|
||||
name="scope"
|
||||
)
|
||||
public Set<String> getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scope the scope to set
|
||||
*/
|
||||
public void setScope(Set<String> scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.mitre.oauth2.model;
|
||||
|
||||
public interface OAuth2RefreshTokenEntityFactory {
|
||||
|
||||
public OAuth2RefreshTokenEntity createNewRefreshToken();
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class UUIDTokenFactory implements OAuth2AccessTokenEntityFactory, OAuth2RefreshTokenEntityFactory {
|
||||
|
||||
/**
|
||||
* Create a new access token and set its value to a random UUID
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity createNewAccessToken() {
|
||||
// create our token container
|
||||
OAuth2AccessTokenEntity token = new OAuth2AccessTokenEntity();
|
||||
|
||||
// set a random value (TODO: support JWT)
|
||||
String tokenValue = UUID.randomUUID().toString();
|
||||
token.setValue(tokenValue);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new refresh token and set its value to a random UUID
|
||||
*/
|
||||
@Override
|
||||
public OAuth2RefreshTokenEntity createNewRefreshToken() {
|
||||
OAuth2RefreshTokenEntity refreshToken = new OAuth2RefreshTokenEntity();
|
||||
|
||||
// set a random value for the refresh
|
||||
String refreshTokenValue = UUID.randomUUID().toString();
|
||||
refreshToken.setValue(refreshTokenValue);
|
||||
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package org.mitre.oauth2.model.serializer;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
public class JSONOAuthClientView extends AbstractView {
|
||||
|
||||
@Override
|
||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
Gson gson = new GsonBuilder().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;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
.registerTypeAdapter(GrantedAuthority.class, new JsonSerializer<GrantedAuthority>() {
|
||||
@Override
|
||||
public JsonElement serialize(GrantedAuthority src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.getAuthority());
|
||||
}
|
||||
})
|
||||
.create();
|
||||
|
||||
response.setContentType("application/json");
|
||||
|
||||
Writer out = response.getWriter();
|
||||
|
||||
Object obj = model.get("entity");
|
||||
if (obj == null) {
|
||||
obj = model;
|
||||
}
|
||||
|
||||
gson.toJson(obj, out);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package org.mitre.oauth2.model.serializer;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
public class TokenIntrospection extends AbstractView {
|
||||
|
||||
@Override
|
||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
|
||||
Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
/*
|
||||
if (f.getDeclaringClass().isAssignableFrom(OAuth2AccessTokenEntity.class)) {
|
||||
// we don't want to serialize the whole object, just the scope and timeout
|
||||
if (f.getName().equals("scope")) {
|
||||
return false;
|
||||
} else if (f.getName().equals("expiration")) {
|
||||
return false;
|
||||
} else {
|
||||
// skip everything else on this class
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// serialize other classes without filter (lists and sets and things)
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
// skip the JPA binding wrapper
|
||||
if (clazz.equals(BeanPropertyBindingResult.class)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
.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", context.serialize(src.getExpiration()));
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
})
|
||||
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
.create();
|
||||
|
||||
response.setContentType("application/json");
|
||||
|
||||
Writer out = response.getWriter();
|
||||
|
||||
Object obj = model.get("entity");
|
||||
if (obj == null) {
|
||||
obj = model;
|
||||
}
|
||||
|
||||
gson.toJson(obj, out);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.mitre.oauth2.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
public interface OAuth2ClientRepository {
|
||||
|
||||
public ClientDetailsEntity getClientById(String clientId);
|
||||
|
||||
public ClientDetailsEntity saveClient(ClientDetailsEntity client);
|
||||
|
||||
public void deleteClient(ClientDetailsEntity client);
|
||||
|
||||
public ClientDetailsEntity updateClient(String clientId, ClientDetailsEntity client);
|
||||
|
||||
public Collection<ClientDetailsEntity> getAllClients();
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package org.mitre.oauth2.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
|
||||
public interface OAuth2TokenRepository {
|
||||
|
||||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity token);
|
||||
|
||||
public OAuth2RefreshTokenEntity getRefreshTokenByValue(String refreshTokenValue);
|
||||
|
||||
public void clearAccessTokensForRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||
|
||||
public void removeRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||
|
||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||
|
||||
public OAuth2AccessTokenEntity getAccessTokenByValue(String accessTokenValue);
|
||||
|
||||
public void removeAccessToken(OAuth2AccessTokenEntity accessToken);
|
||||
|
||||
public void clearTokensForClient(ClientDetailsEntity client);
|
||||
|
||||
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client);
|
||||
|
||||
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client);
|
||||
|
||||
public List<OAuth2AccessTokenEntity> getExpiredAccessTokens();
|
||||
|
||||
public List<OAuth2RefreshTokenEntity> getExpiredRefreshTokens();
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package org.mitre.oauth2.repository.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.repository.OAuth2ClientRepository;
|
||||
import org.mitre.util.jpa.JpaUtil;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Repository
|
||||
@Transactional
|
||||
public class JpaOAuth2ClientRepository implements OAuth2ClientRepository {
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager manager;
|
||||
|
||||
public JpaOAuth2ClientRepository() {
|
||||
|
||||
}
|
||||
|
||||
public JpaOAuth2ClientRepository(EntityManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.repository.OAuth2ClientRepository#getClientById(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public ClientDetailsEntity getClientById(String clientId) {
|
||||
return manager.find(ClientDetailsEntity.class, clientId);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.repository.OAuth2ClientRepository#saveClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||
*/
|
||||
@Override
|
||||
public ClientDetailsEntity saveClient(ClientDetailsEntity client) {
|
||||
return JpaUtil.saveOrUpdate(client.getClientId(), manager, client);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.repository.OAuth2ClientRepository#deleteClient(org.mitre.oauth2.model.ClientDetailsEntity)
|
||||
*/
|
||||
@Override
|
||||
public void deleteClient(ClientDetailsEntity client) {
|
||||
ClientDetailsEntity found = getClientById(client.getClientId());
|
||||
if (found != null) {
|
||||
manager.remove(found);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Client not found: " + client);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDetailsEntity updateClient(String clientId, ClientDetailsEntity client) {
|
||||
return JpaUtil.saveOrUpdate(clientId, manager, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ClientDetailsEntity> getAllClients() {
|
||||
TypedQuery<ClientDetailsEntity> query = manager.createNamedQuery("ClientDetailsEntity.findAll", ClientDetailsEntity.class);
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
package org.mitre.oauth2.repository.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
import org.mitre.oauth2.repository.OAuth2TokenRepository;
|
||||
import org.mitre.util.jpa.JpaUtil;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Repository
|
||||
@Transactional
|
||||
public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager manager;
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessTokenByValue(String accessTokenValue) {
|
||||
return manager.find(OAuth2AccessTokenEntity.class, accessTokenValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity token) {
|
||||
return JpaUtil.saveOrUpdate(token.getValue(), manager, token);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void removeAccessToken(OAuth2AccessTokenEntity accessToken) {
|
||||
OAuth2AccessTokenEntity found = getAccessTokenByValue(accessToken.getValue());
|
||||
if (found != null) {
|
||||
manager.remove(found);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Access token not found: " + accessToken);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2RefreshTokenEntity getRefreshTokenByValue(String refreshTokenValue) {
|
||||
return manager.find(OAuth2RefreshTokenEntity.class, refreshTokenValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
return JpaUtil.saveOrUpdate(refreshToken.getValue(), manager, refreshToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
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) {
|
||||
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByClient", OAuth2AccessTokenEntity.class);
|
||||
queryA.setParameter("client", client);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @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;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @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;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @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;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.mitre.oauth2.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||
import org.springframework.security.oauth2.provider.ClientDetailsService;
|
||||
|
||||
public interface ClientDetailsEntityService extends ClientDetailsService {
|
||||
|
||||
public ClientDetailsEntity loadClientByClientId(String clientId) throws OAuth2Exception;
|
||||
|
||||
public ClientDetailsEntity createClient(String clientId, String clientSecret, Set<String> scope, Set<String> grantTypes, String redirectUri, Set<GrantedAuthority> authorities, Set<String> resourceIds, String name, String description, boolean allowRefresh, Long accessTokenTimeout, Long refreshTokenTimeout, String owner);
|
||||
|
||||
public void deleteClient(ClientDetailsEntity client);
|
||||
|
||||
public ClientDetailsEntity updateClient(ClientDetailsEntity oldClient, ClientDetailsEntity newClient);
|
||||
|
||||
public Collection<ClientDetailsEntity> getAllClients();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package org.mitre.oauth2.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
|
||||
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||
|
||||
public interface OAuth2TokenEntityService extends AuthorizationServerTokenServices, ResourceServerTokenServices {
|
||||
|
||||
public OAuth2AccessTokenEntity getAccessToken(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();
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package org.mitre.oauth2.service.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntityFactory;
|
||||
import org.mitre.oauth2.repository.OAuth2ClientRepository;
|
||||
import org.mitre.oauth2.repository.OAuth2TokenRepository;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
@Service
|
||||
public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEntityService {
|
||||
|
||||
@Autowired
|
||||
private OAuth2ClientRepository clientRepository;
|
||||
|
||||
@Autowired
|
||||
private OAuth2TokenRepository tokenRepository;
|
||||
|
||||
@Autowired
|
||||
private ClientDetailsEntityFactory clientFactory;
|
||||
|
||||
public DefaultOAuth2ClientDetailsEntityService() {
|
||||
|
||||
}
|
||||
|
||||
public DefaultOAuth2ClientDetailsEntityService(OAuth2ClientRepository clientRepository,
|
||||
OAuth2TokenRepository tokenRepository, ClientDetailsEntityFactory clientFactory) {
|
||||
this.clientRepository = clientRepository;
|
||||
this.tokenRepository = tokenRepository;
|
||||
this.clientFactory = clientFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client for the given ID
|
||||
*/
|
||||
@Override
|
||||
public ClientDetailsEntity loadClientByClientId(String clientId) throws OAuth2Exception, InvalidClientException, IllegalArgumentException {
|
||||
if (!Strings.isNullOrEmpty(clientId)) {
|
||||
ClientDetailsEntity client = clientRepository.getClientById(clientId);
|
||||
if (client == null) {
|
||||
throw new InvalidClientException("Client with id " + clientId + " was not found");
|
||||
}
|
||||
else {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Client id must not be empty!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new client with the appropriate fields filled in
|
||||
*/
|
||||
@Override
|
||||
public ClientDetailsEntity createClient(String clientId, String clientSecret,
|
||||
Set<String> scope, Set<String> grantTypes, String redirectUri, Set<GrantedAuthority> authorities,
|
||||
Set<String> resourceIds,
|
||||
String name, String description, boolean allowRefresh, Long accessTokenTimeout,
|
||||
Long refreshTokenTimeout, String owner) {
|
||||
|
||||
// TODO: check "owner" locally?
|
||||
|
||||
ClientDetailsEntity client = clientFactory.createClient(clientId, clientSecret);
|
||||
client.setScope(scope);
|
||||
client.setAuthorizedGrantTypes(grantTypes);
|
||||
client.setRegisteredRedirectUri(redirectUri);
|
||||
client.setAuthorities(authorities);
|
||||
client.setClientName(name);
|
||||
client.setClientDescription(description);
|
||||
client.setAllowRefresh(allowRefresh);
|
||||
client.setAccessTokenTimeout(accessTokenTimeout);
|
||||
client.setRefreshTokenTimeout(refreshTokenTimeout);
|
||||
client.setResourceIds(resourceIds);
|
||||
client.setOwner(owner);
|
||||
|
||||
clientRepository.saveClient(client);
|
||||
|
||||
return client;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a client and all its associated tokens
|
||||
*/
|
||||
@Override
|
||||
public void deleteClient(ClientDetailsEntity client) throws InvalidClientException {
|
||||
|
||||
if (clientRepository.getClientById(client.getClientId()) == null) {
|
||||
throw new InvalidClientException("Client with id " + client.getClientId() + " was not found");
|
||||
}
|
||||
|
||||
// clean out any tokens that this client had issued
|
||||
tokenRepository.clearTokensForClient(client);
|
||||
|
||||
// take care of the client itself
|
||||
clientRepository.deleteClient(client);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the oldClient with information from the newClient. The
|
||||
* id from oldClient is retained.
|
||||
*/
|
||||
@Override
|
||||
public ClientDetailsEntity updateClient(ClientDetailsEntity oldClient, ClientDetailsEntity newClient) throws IllegalArgumentException {
|
||||
if (oldClient != null && newClient != null) {
|
||||
return clientRepository.updateClient(oldClient.getClientId(), newClient);
|
||||
}
|
||||
throw new IllegalArgumentException("Neither old client or new client can be null!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all clients in the system
|
||||
*/
|
||||
@Override
|
||||
public Collection<ClientDetailsEntity> getAllClients() {
|
||||
return clientRepository.getAllClients();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,319 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.oauth2.service.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntityFactory;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntityFactory;
|
||||
import org.mitre.oauth2.repository.OAuth2TokenRepository;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.client.ClientAuthenticationToken;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DefaultOAuth2ProviderTokenService.class);
|
||||
|
||||
@Autowired
|
||||
private OAuth2TokenRepository tokenRepository;
|
||||
|
||||
@Autowired
|
||||
private ClientDetailsEntityService clientDetailsService;
|
||||
|
||||
@Autowired
|
||||
private OAuth2AccessTokenEntityFactory accessTokenFactory;
|
||||
|
||||
@Autowired
|
||||
private OAuth2RefreshTokenEntityFactory refreshTokenFactory;
|
||||
|
||||
@Override
|
||||
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 = accessTokenFactory.createNewAccessToken();
|
||||
|
||||
// attach the client
|
||||
token.setClient(client);
|
||||
|
||||
// inherit the scope from the auth
|
||||
// this lets us match which scope is requested
|
||||
if (client.isScoped()) {
|
||||
|
||||
// restrict granted scopes to a valid subset of those
|
||||
Set<String> validScopes = Sets.newHashSet();
|
||||
|
||||
for (String requested : clientAuth.getScope()) {
|
||||
if (client.getScope().contains(requested)) {
|
||||
validScopes.add(requested);
|
||||
} else {
|
||||
logger.warn("Client " + client.getClientId() + " requested out of permission scope: " + requested);
|
||||
}
|
||||
}
|
||||
|
||||
token.setScope(validScopes);
|
||||
}
|
||||
|
||||
// make it expire if necessary
|
||||
if (client.getAccessTokenTimeout() != null) {
|
||||
Date expiration = new Date(System.currentTimeMillis() + (client.getAccessTokenTimeout() * 1000L));
|
||||
token.setExpiration(expiration);
|
||||
}
|
||||
|
||||
// attach the authorization so that we can look it up later
|
||||
token.setAuthentication(authentication);
|
||||
|
||||
// attach a refresh token, if this client is allowed to request them
|
||||
if (client.isAllowRefresh()) {
|
||||
OAuth2RefreshTokenEntity refreshToken = refreshTokenFactory.createNewRefreshToken();
|
||||
|
||||
// make it expire if necessary
|
||||
if (client.getRefreshTokenTimeout() != null) {
|
||||
Date expiration = new Date(System.currentTimeMillis() + (client.getRefreshTokenTimeout() * 1000L));
|
||||
refreshToken.setExpiration(expiration);
|
||||
}
|
||||
|
||||
// save our scopes so that we can reuse them later for more auth tokens
|
||||
// TODO: save the auth instead of the just the scope?
|
||||
if (client.isScoped()) {
|
||||
refreshToken.setScope(clientAuth.getScope());
|
||||
}
|
||||
|
||||
tokenRepository.saveRefreshToken(refreshToken);
|
||||
|
||||
token.setRefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
tokenRepository.saveAccessToken(token);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
throw new AuthenticationCredentialsNotFoundException("No authentication credentials found");
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity refreshAccessToken(String refreshTokenValue, Set<String> scope) throws AuthenticationException {
|
||||
|
||||
OAuth2RefreshTokenEntity refreshToken = tokenRepository.getRefreshTokenByValue(refreshTokenValue);
|
||||
|
||||
if (refreshToken == null) {
|
||||
throw new InvalidTokenException("Invalid refresh token: " + refreshTokenValue);
|
||||
}
|
||||
|
||||
ClientDetailsEntity client = refreshToken.getClient();
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
// 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 = accessTokenFactory.createNewAccessToken();
|
||||
|
||||
|
||||
if (scope != null && !scope.isEmpty()) {
|
||||
// ensure a proper subset of scopes
|
||||
if (refreshToken.getScope() != null && refreshToken.getScope().containsAll(scope)) {
|
||||
// set the scope of the new access token if requested
|
||||
refreshToken.setScope(scope);
|
||||
} else {
|
||||
// up-scoping is not allowed
|
||||
// (TODO: should this throw InvalidScopeException? For now just pass through)
|
||||
token.setScope(refreshToken.getScope());
|
||||
}
|
||||
} else {
|
||||
// otherwise inherit the scope of the refresh token (if it's there -- this can return a null scope set)
|
||||
token.setScope(refreshToken.getScope());
|
||||
}
|
||||
|
||||
token.setClient(client);
|
||||
|
||||
if (client.getAccessTokenTimeout() != null) {
|
||||
Date expiration = new Date(System.currentTimeMillis() + (client.getAccessTokenTimeout() * 1000L));
|
||||
token.setExpiration(expiration);
|
||||
}
|
||||
|
||||
token.setRefreshToken(refreshToken);
|
||||
|
||||
tokenRepository.saveAccessToken(token);
|
||||
|
||||
return token;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
throw new InvalidTokenException("Expired access token: " + accessTokenValue);
|
||||
}
|
||||
|
||||
return accessToken.getAuthentication();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessToken(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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revokeRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
tokenRepository.clearAccessTokensForRefreshToken(refreshToken);
|
||||
tokenRepository.removeRefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
/* (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);
|
||||
}
|
||||
|
||||
@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 setAccessTokenFactory(OAuth2AccessTokenEntityFactory accessTokenFactory) {
|
||||
instance.accessTokenFactory = accessTokenFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultOAuth2ProviderTokenServicesBuilder setRefreshTokenFactory(OAuth2RefreshTokenEntityFactory refreshTokenFactory) {
|
||||
instance.refreshTokenFactory = refreshTokenFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OAuth2TokenEntityService finish() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.mitre.oauth2.web;
|
||||
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@Controller
|
||||
public class IntrospectionEndpoint {
|
||||
|
||||
@Autowired
|
||||
OAuth2TokenEntityService tokenServices;
|
||||
|
||||
public IntrospectionEndpoint() {
|
||||
|
||||
}
|
||||
|
||||
public IntrospectionEndpoint(OAuth2TokenEntityService tokenServices) {
|
||||
this.tokenServices = tokenServices;
|
||||
}
|
||||
|
||||
// TODO
|
||||
@RequestMapping("/oauth/verify")
|
||||
public ModelAndView verify(@RequestParam("token") String tokenValue,
|
||||
ModelAndView modelAndView) {
|
||||
OAuth2AccessTokenEntity token = tokenServices.getAccessToken(tokenValue);
|
||||
|
||||
if (token == null) {
|
||||
// if it's not a valid token, we'll print a 404
|
||||
modelAndView.setViewName("tokenNotFound");
|
||||
} else {
|
||||
// if it's a valid token, we'll print out the scope and expiration
|
||||
modelAndView.setViewName("tokenIntrospection");
|
||||
modelAndView.addObject("entity", token);
|
||||
}
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
package org.mitre.oauth2.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.exception.ClientNotFoundException;
|
||||
import org.mitre.oauth2.exception.DuplicateClientIdException;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.stereotype.Controller;
|
||||
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.Function;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/manager/oauth/clients/api")
|
||||
public class OAuthClientAPI {
|
||||
|
||||
@Autowired
|
||||
private ClientDetailsEntityService clientService;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OAuthClientAPI.class);
|
||||
|
||||
public OAuthClientAPI() {
|
||||
|
||||
}
|
||||
|
||||
public OAuthClientAPI(ClientDetailsEntityService clientService) {
|
||||
this.clientService = clientService;
|
||||
}
|
||||
|
||||
// TODO: i think this needs a fancier binding than just strings on the way in
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/add")
|
||||
public ModelAndView apiAddClient(ModelAndView modelAndView,
|
||||
@RequestParam String clientId, @RequestParam String clientSecret,
|
||||
@RequestParam String scope, // space delimited
|
||||
@RequestParam String grantTypes, // space delimited
|
||||
@RequestParam(required=false) String redirectUri,
|
||||
@RequestParam String authorities, // space delimited
|
||||
@RequestParam(required=false) String resourceIds, // space delimited
|
||||
@RequestParam(required=false) String name,
|
||||
@RequestParam(required=false) String description,
|
||||
@RequestParam(required=false, defaultValue="false") boolean allowRefresh,
|
||||
@RequestParam(required=false) Long accessTokenTimeout,
|
||||
@RequestParam(required=false) Long refreshTokenTimeout,
|
||||
@RequestParam(required=false) String owner
|
||||
) {
|
||||
logger.info("apiAddClient - start");
|
||||
ClientDetailsEntity oldClient = clientService.loadClientByClientId(clientId);
|
||||
if (oldClient != null) {
|
||||
throw new DuplicateClientIdException(clientId);
|
||||
}
|
||||
|
||||
Splitter spaceDelimited = Splitter.on(" ");
|
||||
// parse all of our space-delimited lists
|
||||
Set<String> scopeSet = Sets.newHashSet(spaceDelimited.split(scope));
|
||||
Set<String> grantTypesSet = Sets.newHashSet(spaceDelimited.split(grantTypes)); // TODO: make a stronger binding to GrantTypes
|
||||
logger.info("apiAddClient - before creating authorities list");
|
||||
Set<GrantedAuthority> authoritiesSet = Sets.newHashSet(
|
||||
Iterables.transform(spaceDelimited.split(authorities), new Function<String, GrantedAuthority>() {
|
||||
@Override
|
||||
public GrantedAuthority apply(String auth) {
|
||||
return new GrantedAuthorityImpl(auth);
|
||||
}
|
||||
}));
|
||||
logger.info("apiAddClient - printing client details");
|
||||
logger.info("Making call to create client with " + clientId + ", " + clientSecret
|
||||
+ ", " + scopeSet + ", " + grantTypesSet + ", " + redirectUri + ", "
|
||||
+ authoritiesSet + ", " + name + ", " + description + ", " + allowRefresh
|
||||
+ ", " + accessTokenTimeout + ", " + refreshTokenTimeout + ", " + owner);
|
||||
|
||||
Set<String> resourceIdSet = Sets.newHashSet(spaceDelimited.split(resourceIds));
|
||||
|
||||
ClientDetailsEntity client = clientService.createClient(clientId, clientSecret,
|
||||
scopeSet, grantTypesSet, redirectUri, authoritiesSet, resourceIdSet, name, description,
|
||||
allowRefresh, accessTokenTimeout, refreshTokenTimeout, owner);
|
||||
logger.info("apiAddClient - adding model objects");
|
||||
modelAndView.addObject("entity", client);
|
||||
modelAndView.setViewName("jsonOAuthClientView");
|
||||
logger.info("apiAddClient - end");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/delete")
|
||||
public ModelAndView apiDeleteClient(ModelAndView modelAndView,
|
||||
@RequestParam String clientId) {
|
||||
|
||||
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
||||
|
||||
if (client == null) {
|
||||
throw new ClientNotFoundException("Client not found: " + clientId);
|
||||
}
|
||||
|
||||
clientService.deleteClient(client);
|
||||
|
||||
modelAndView.setViewName("management/successfullyRemoved");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
// TODO: the serializtion of this falls over, don't know why
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/getAll")
|
||||
public ModelAndView apiGetAllClients(ModelAndView modelAndView) {
|
||||
|
||||
Collection<ClientDetailsEntity> clients = clientService.getAllClients();
|
||||
modelAndView.addObject("entity", clients);
|
||||
modelAndView.setViewName("jsonOAuthClientView");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/update")
|
||||
public ModelAndView apiUpdateClient(ModelAndView modelAndView,
|
||||
@RequestParam String clientId, @RequestParam String clientSecret,
|
||||
@RequestParam String scope, // space delimited
|
||||
@RequestParam String grantTypes, // space delimited
|
||||
@RequestParam(required=false) String redirectUri,
|
||||
@RequestParam String authorities, // space delimited
|
||||
@RequestParam(required=false) String resourceIds, // space delimited
|
||||
@RequestParam(required=false) String name,
|
||||
@RequestParam(required=false) String description,
|
||||
@RequestParam(required=false, defaultValue="false") boolean allowRefresh,
|
||||
@RequestParam(required=false) Long accessTokenTimeout,
|
||||
@RequestParam(required=false) Long refreshTokenTimeout,
|
||||
@RequestParam(required=false) String owner
|
||||
) {
|
||||
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
||||
|
||||
if (client == null) {
|
||||
throw new ClientNotFoundException("Client not found: " + clientId);
|
||||
}
|
||||
|
||||
Splitter spaceDelimited = Splitter.on(" ");
|
||||
// parse all of our space-delimited lists
|
||||
Set<String> scopeSet = Sets.newHashSet(spaceDelimited.split(scope));
|
||||
Set<String> grantTypesSet = Sets.newHashSet(spaceDelimited.split(grantTypes)); // TODO: make a stronger binding to GrantTypes
|
||||
Set<GrantedAuthority> authoritiesSet = Sets.newHashSet(
|
||||
Iterables.transform(spaceDelimited.split(authorities), new Function<String, GrantedAuthority>() {
|
||||
@Override
|
||||
public GrantedAuthority apply(String auth) {
|
||||
return new GrantedAuthorityImpl(auth);
|
||||
}
|
||||
}));
|
||||
Set<String> resourceIdSet = Sets.newHashSet(spaceDelimited.split(resourceIds));
|
||||
|
||||
|
||||
client.setClientSecret(clientSecret);
|
||||
client.setScope(scopeSet);
|
||||
client.setAuthorizedGrantTypes(grantTypesSet);
|
||||
client.setRegisteredRedirectUri(redirectUri);
|
||||
client.setAuthorities(authoritiesSet);
|
||||
client.setResourceIds(resourceIdSet);
|
||||
client.setClientName(name);
|
||||
client.setClientDescription(description);
|
||||
client.setAllowRefresh(allowRefresh);
|
||||
client.setAccessTokenTimeout(accessTokenTimeout);
|
||||
client.setRefreshTokenTimeout(refreshTokenTimeout);
|
||||
client.setOwner(owner);
|
||||
|
||||
clientService.updateClient(client, client);
|
||||
|
||||
modelAndView.addObject("entity", client);
|
||||
modelAndView.setViewName("jsonOAuthClientView");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/getById")
|
||||
public ModelAndView getClientById(ModelAndView modelAndView,
|
||||
@RequestParam String clientId) {
|
||||
|
||||
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
||||
|
||||
if (client == null) {
|
||||
throw new ClientNotFoundException("Client not found: " + clientId);
|
||||
}
|
||||
|
||||
modelAndView.addObject("entity", client);
|
||||
modelAndView.setViewName("jsonOAuthClientView");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.oauth2.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Endpoint for managing OAuth2 clients
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/manager/oauth/clients")
|
||||
public class OAuthClientController {
|
||||
|
||||
private final static Set<String> GRANT_TYPES = Sets.newHashSet("authorization_code", "client_credentials", "password", "implicit");
|
||||
|
||||
@Autowired
|
||||
private ClientDetailsEntityService clientService;
|
||||
|
||||
@Autowired
|
||||
private OAuth2TokenEntityService tokenService;
|
||||
|
||||
private Logger logger;
|
||||
|
||||
public OAuthClientController() {
|
||||
logger = LoggerFactory.getLogger(this.getClass());
|
||||
}
|
||||
|
||||
public OAuthClientController(ClientDetailsEntityService clientService, OAuth2TokenEntityService tokenService) {
|
||||
this.clientService = clientService;
|
||||
this.tokenService = tokenService;
|
||||
logger = LoggerFactory.getLogger(this.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the "/" version of the root
|
||||
* @param modelAndView
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("")
|
||||
public ModelAndView redirectRoot(ModelAndView modelAndView) {
|
||||
modelAndView.setViewName("redirect:/manager/oauth/clients/");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
/**
|
||||
* View all clients
|
||||
* @param modelAndView
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/")
|
||||
public ModelAndView viewAllClients(ModelAndView modelAndView) {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
//ClientAuthenticationToken clientAuth = (ClientAuthenticationToken) ((OAuth2Authentication) auth).getClientAuthentication();
|
||||
AuthorizationRequest clientAuth = ((OAuth2Authentication) auth).getAuthorizationRequest();
|
||||
|
||||
logger.info("Client auth = " + clientAuth);
|
||||
logger.info("Granted authorities = " + clientAuth.getAuthorities().toString());
|
||||
|
||||
Collection<ClientDetailsEntity> clients = clientService.getAllClients();
|
||||
modelAndView.addObject("clients", clients);
|
||||
modelAndView.setViewName("/management/oauth/clientIndex");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/add")
|
||||
public ModelAndView redirectAdd(ModelAndView modelAndView) {
|
||||
modelAndView.setViewName("redirect:/manager/oauth/clients/add/");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/add/")
|
||||
public ModelAndView addClientPage(ModelAndView modelAndView) {
|
||||
|
||||
Set<GrantedAuthority> auth = Sets.newHashSet();
|
||||
auth.add(new GrantedAuthorityImpl("ROLE_CLIENT"));
|
||||
|
||||
ClientDetailsEntity client = ClientDetailsEntity.makeBuilder()
|
||||
.setScope(Sets.newHashSet("scope"))
|
||||
.setAuthorities(auth) // why do we have to pull this into a separate list?
|
||||
.setAuthorizedGrantTypes(Sets.newHashSet("authorization_code"))
|
||||
.finish();
|
||||
modelAndView.addObject("availableGrantTypes", GRANT_TYPES);
|
||||
modelAndView.addObject("client", client);
|
||||
|
||||
modelAndView.setViewName("/management/oauth/editClient");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/delete/{clientId}")
|
||||
public ModelAndView deleteClientConfirmation(ModelAndView modelAndView,
|
||||
@PathVariable String clientId) {
|
||||
|
||||
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
||||
modelAndView.addObject("client", client);
|
||||
modelAndView.setViewName("/management/oauth/deleteClientConfirm");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/edit/{clientId}")
|
||||
public ModelAndView editClientPage(ModelAndView modelAndView,
|
||||
@PathVariable String clientId) {
|
||||
|
||||
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
||||
|
||||
modelAndView.addObject("availableGrantTypes", GRANT_TYPES);
|
||||
modelAndView.addObject("client", client);
|
||||
modelAndView.setViewName("/management/oauth/editClient");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@RequestMapping("/view/{clientId}")
|
||||
public ModelAndView viewClientDetails(ModelAndView modelAndView,
|
||||
@PathVariable String clientId) {
|
||||
|
||||
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
|
||||
|
||||
List<OAuth2AccessTokenEntity> accessTokens = tokenService.getAccessTokensForClient(client);
|
||||
List<OAuth2RefreshTokenEntity> refreshTokens = tokenService.getRefreshTokensForClient(client);
|
||||
|
||||
modelAndView.addObject("client", client);
|
||||
modelAndView.addObject("accessTokens", accessTokens);
|
||||
modelAndView.addObject("refreshTokens", refreshTokens);
|
||||
|
||||
modelAndView.setViewName("/management/oauth/viewClient");
|
||||
return modelAndView;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.oauth2.web;
|
||||
|
||||
import org.mitre.oauth2.exception.ClientNotFoundException;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
@SessionAttributes(types = AuthorizationRequest.class)
|
||||
public class OAuthConfirmationController {
|
||||
|
||||
private ClientDetailsEntityService clientService;
|
||||
|
||||
public OAuthConfirmationController() {
|
||||
|
||||
}
|
||||
|
||||
public OAuthConfirmationController(ClientDetailsEntityService clientService) {
|
||||
this.clientService = clientService;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
@RequestMapping("/oauth/user/approve")
|
||||
public ModelAndView confimAccess(@ModelAttribute AuthorizationRequest clientAuth,
|
||||
ModelAndView modelAndView) {
|
||||
|
||||
ClientDetails client = clientService.loadClientByClientId(clientAuth.getClientId());
|
||||
|
||||
if (client == null) {
|
||||
throw new ClientNotFoundException("Client not found: " + clientAuth.getClientId());
|
||||
}
|
||||
|
||||
modelAndView.addObject("auth_request", clientAuth);
|
||||
modelAndView.addObject("client", client);
|
||||
modelAndView.setViewName("oauth/approve");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clientService
|
||||
*/
|
||||
public ClientDetailsEntityService getClientService() {
|
||||
return clientService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientService the clientService to set
|
||||
*/
|
||||
@Autowired
|
||||
public void setClientService(ClientDetailsEntityService clientService) {
|
||||
this.clientService = clientService;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package org.mitre.oauth2.web;
|
||||
|
||||
import org.mitre.oauth2.exception.PermissionDeniedException;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
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;
|
||||
|
||||
public RevocationEndpoint() {
|
||||
|
||||
}
|
||||
|
||||
public RevocationEndpoint(OAuth2TokenEntityService tokenServices) {
|
||||
this.tokenServices = tokenServices;
|
||||
}
|
||||
|
||||
// TODO
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
|
||||
@RequestMapping("/oauth/revoke")
|
||||
public ModelAndView revoke(@RequestParam("token") String tokenValue,
|
||||
ModelAndView modelAndView) {
|
||||
|
||||
OAuth2RefreshTokenEntity refreshToken = tokenServices.getRefreshToken(tokenValue);
|
||||
OAuth2AccessTokenEntity accessToken = tokenServices.getAccessToken(tokenValue);
|
||||
|
||||
if (refreshToken == null && accessToken == null) {
|
||||
// TODO: this should throw a 400 with a JSON error code
|
||||
throw new InvalidTokenException("Invalid OAuth token: " + tokenValue);
|
||||
}
|
||||
|
||||
// TODO: there should be a way to do this in SPEL, right?
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (auth instanceof OAuth2Authentication) {
|
||||
// we've got a client acting on its own behalf, not an admin
|
||||
//ClientAuthentication clientAuth = (ClientAuthenticationToken) ((OAuth2Authentication) auth).getClientAuthentication();
|
||||
AuthorizationRequest clientAuth = ((OAuth2Authentication) auth).getAuthorizationRequest();
|
||||
|
||||
if (refreshToken != null) {
|
||||
if (!refreshToken.getClient().getClientId().equals(clientAuth.getClientId())) {
|
||||
// trying to revoke a token we don't own, fail
|
||||
// TODO: this should throw a 403
|
||||
throw new PermissionDeniedException("Client tried to revoke a token it doesn't own");
|
||||
}
|
||||
} else {
|
||||
if (!accessToken.getClient().getClientId().equals(clientAuth.getClientId())) {
|
||||
// trying to revoke a token we don't own, fail
|
||||
// TODO: this should throw a 403
|
||||
throw new PermissionDeniedException("Client tried to revoke a token it doesn't own");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we got this far, we're allowed to do this
|
||||
if (refreshToken != null) {
|
||||
tokenServices.revokeRefreshToken(refreshToken);
|
||||
} else {
|
||||
tokenServices.revokeAccessToken(accessToken);
|
||||
}
|
||||
|
||||
// TODO: throw a 200 back (no content?)
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
package org.mitre.openid.connect.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Address {
|
||||
|
||||
private Long id;
|
||||
private String formatted;
|
||||
private String street_address;
|
||||
private String locality;
|
||||
|
@ -12,6 +16,8 @@ public class Address {
|
|||
private String postal_code;
|
||||
private String country;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the formatted
|
||||
*/
|
||||
|
@ -85,4 +91,20 @@ public class Address {
|
|||
this.country = country;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import javax.persistence.Entity;
|
|||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Temporal;
|
||||
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
|
@ -48,7 +50,7 @@ public class ApprovedSite {
|
|||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -63,6 +65,7 @@ public class ApprovedSite {
|
|||
/**
|
||||
* @return the userInfo
|
||||
*/
|
||||
@ManyToOne
|
||||
public UserInfo getUserInfo() {
|
||||
return userInfo;
|
||||
}
|
||||
|
@ -123,6 +126,7 @@ public class ApprovedSite {
|
|||
/**
|
||||
* @return the allowedScopes
|
||||
*/
|
||||
@OneToMany
|
||||
public Collection<String> getAllowedScopes() {
|
||||
return allowedScopes;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,12 @@ package org.mitre.openid.connect.model;
|
|||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Temporal;
|
||||
|
||||
/**
|
||||
* Class to contain a logged event in the system.
|
||||
|
@ -20,4 +25,45 @@ public class Event {
|
|||
private EventType type;
|
||||
private Date timestamp;
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public EventType getType() {
|
||||
return 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;
|
||||
}
|
||||
/**
|
||||
* @param timestamp the timestamp to set
|
||||
*/
|
||||
public void setTimestamp(Date timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
package org.mitre.openid.connect.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
import org.mitre.jwt.model.Jwt;
|
||||
|
||||
/*
|
||||
* TODO: This class needs to be encoded as a JWT
|
||||
*/
|
||||
@Entity
|
||||
public class IdToken extends Jwt {
|
||||
|
||||
private String iss;
|
||||
private String user_id;
|
||||
private String aud;
|
||||
private String exp;
|
||||
private String iso29115;
|
||||
private String nonce;
|
||||
private String auth_time;
|
||||
/**
|
||||
* @return the iss
|
||||
*/
|
||||
public String getIss() {
|
||||
return iss;
|
||||
}
|
||||
/**
|
||||
* @param iss the iss to set
|
||||
*/
|
||||
public void setIss(String iss) {
|
||||
this.iss = iss;
|
||||
}
|
||||
/**
|
||||
* @return the user_id
|
||||
*/
|
||||
public String getUser_id() {
|
||||
return user_id;
|
||||
}
|
||||
/**
|
||||
* @param user_id the user_id to set
|
||||
*/
|
||||
public void setUser_id(String user_id) {
|
||||
this.user_id = user_id;
|
||||
}
|
||||
/**
|
||||
* @return the aud
|
||||
*/
|
||||
public String getAud() {
|
||||
return aud;
|
||||
}
|
||||
/**
|
||||
* @param aud the aud to set
|
||||
*/
|
||||
public void setAud(String aud) {
|
||||
this.aud = aud;
|
||||
}
|
||||
/**
|
||||
* @return the exp
|
||||
*/
|
||||
public String getExp() {
|
||||
return exp;
|
||||
}
|
||||
/**
|
||||
* @param exp the exp to set
|
||||
*/
|
||||
public void setExp(String exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
/**
|
||||
* @return the iso29115
|
||||
*/
|
||||
public String getIso29115() {
|
||||
return iso29115;
|
||||
}
|
||||
/**
|
||||
* @param iso29115 the iso29115 to set
|
||||
*/
|
||||
public void setIso29115(String iso29115) {
|
||||
this.iso29115 = iso29115;
|
||||
}
|
||||
/**
|
||||
* @return the nonce
|
||||
*/
|
||||
public String getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
/**
|
||||
* @param nonce the nonce to set
|
||||
*/
|
||||
public void setNonce(String nonce) {
|
||||
this.nonce = nonce;
|
||||
}
|
||||
/**
|
||||
* @return the auth_time
|
||||
*/
|
||||
public String getAuth_time() {
|
||||
return auth_time;
|
||||
}
|
||||
/**
|
||||
* @param auth_time the auth_time to set
|
||||
*/
|
||||
public void setAuth_time(String auth_time) {
|
||||
this.auth_time = auth_time;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package org.mitre.openid.connect.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.mitre.jwt.model.Jwt;
|
||||
import org.mitre.jwt.model.JwtClaims;
|
||||
|
||||
/*
|
||||
* TODO: This class needs to be encoded as a JWT
|
||||
*/
|
||||
@Entity
|
||||
public class IdTokenClaims extends JwtClaims {
|
||||
|
||||
public static final String USER_ID = "user_id";
|
||||
public static final String AUTHENTICATION_CONTEXT_CLASS_REFERENCE = "acr";
|
||||
public static final String NONCE = "nonce";
|
||||
public static final String AUTH_TIME = "auth_time";
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
public String getUserId() {
|
||||
return getClaimAsString(USER_ID);
|
||||
}
|
||||
|
||||
public void setUserId(String user_id) {
|
||||
setClaim(USER_ID, user_id);
|
||||
}
|
||||
|
||||
|
||||
public String getAuthContext() {
|
||||
return getClaimAsString(AUTHENTICATION_CONTEXT_CLASS_REFERENCE);
|
||||
}
|
||||
|
||||
public void setAuthContext(String acr) {
|
||||
setClaim(AUTHENTICATION_CONTEXT_CLASS_REFERENCE, acr);
|
||||
}
|
||||
|
||||
|
||||
public String getNonce() {
|
||||
return getClaimAsString(NONCE);
|
||||
}
|
||||
|
||||
public void setNonce(String nonce) {
|
||||
setClaim(NONCE, nonce);
|
||||
}
|
||||
|
||||
|
||||
public Date getAuthTime() {
|
||||
return getClaimAsDate(AUTH_TIME);
|
||||
}
|
||||
|
||||
public void setAuthTime(Date authTime) {
|
||||
setClaim(AUTH_TIME, authTime);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package org.mitre.openid.connect.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class UserInfo {
|
||||
|
@ -29,6 +30,7 @@ public class UserInfo {
|
|||
/**
|
||||
* @return the user_id
|
||||
*/
|
||||
@Id
|
||||
public String getUser_id() {
|
||||
return user_id;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.Date;
|
|||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
|
||||
|
@ -19,7 +20,7 @@ public class WhitelistedSite {
|
|||
|
||||
// unique id
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
// who added this site to the whitelist (should be an admin)
|
||||
|
@ -30,5 +31,6 @@ public class WhitelistedSite {
|
|||
|
||||
// what scopes be allowed by default
|
||||
// this should include all information for what data to access
|
||||
@ManyToOne
|
||||
private Collection<String> allowedScopes;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package org.mitre.openid.connect.repository;
|
||||
|
||||
import org.mitre.openid.connect.model.IdToken;
|
||||
import org.mitre.openid.connect.model.IdTokenClaims;
|
||||
|
||||
public interface IdTokenRepository {
|
||||
|
||||
public IdToken getById(Long id);
|
||||
public IdTokenClaims getById(Long id);
|
||||
|
||||
public IdToken save(IdToken idToken);
|
||||
public IdTokenClaims save(IdTokenClaims idToken);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package org.mitre.openid.connect.web;
|
||||
|
||||
import org.mitre.openid.connect.model.IdToken;
|
||||
import org.mitre.openid.connect.model.IdTokenClaims;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
@ -13,7 +13,7 @@ public class CheckIDEndpoint {
|
|||
@RequestMapping("/")
|
||||
public ModelAndView checkID(@RequestParam("id_token") String idToken, ModelAndView mav) {
|
||||
|
||||
IdToken token = new IdToken();
|
||||
IdTokenClaims token = new IdTokenClaims();
|
||||
|
||||
//TODO: Set claims
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package org.mitre.pushee.openid.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
public class OpenIDUserDetailsService implements UserDetailsService {
|
||||
|
||||
private String openIdRoot;
|
||||
private String admins;
|
||||
private List<String> adminList = new ArrayList<String>();
|
||||
|
||||
private GrantedAuthority roleUser = new GrantedAuthorityImpl("ROLE_USER");
|
||||
private GrantedAuthority roleAdmin = new GrantedAuthorityImpl("ROLE_ADMIN");
|
||||
|
||||
/**
|
||||
* @return the roleUser
|
||||
*/
|
||||
public GrantedAuthority getRoleUser() {
|
||||
return roleUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param roleUser the roleUser to set
|
||||
*/
|
||||
public void setRoleUser(GrantedAuthority roleUser) {
|
||||
this.roleUser = roleUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the roleAdmin
|
||||
*/
|
||||
public GrantedAuthority getRoleAdmin() {
|
||||
return roleAdmin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param roleAdmin the roleAdmin to set
|
||||
*/
|
||||
public void setRoleAdmin(GrantedAuthority roleAdmin) {
|
||||
this.roleAdmin = roleAdmin;
|
||||
}
|
||||
|
||||
public String getOpenIdRoot() {
|
||||
return openIdRoot;
|
||||
}
|
||||
|
||||
public void setOpenIdRoot(String openIdRoot) {
|
||||
this.openIdRoot = openIdRoot;
|
||||
}
|
||||
|
||||
public String getAdmins() {
|
||||
return admins;
|
||||
}
|
||||
|
||||
public void setAdmins(String admins) {
|
||||
this.admins = admins;
|
||||
adminList.clear();
|
||||
Iterables.addAll(adminList, Splitter.on(',').omitEmptyStrings().split(admins));
|
||||
}
|
||||
|
||||
public UserDetails loadUserByUsername(String identifier) throws UsernameNotFoundException, DataAccessException {
|
||||
|
||||
if (identifier != null && identifier.startsWith(openIdRoot)) {
|
||||
String username = identifier;
|
||||
//String username = identifier.replace(openIdRoot, ""); // strip off the OpenID root
|
||||
String password = "notused";
|
||||
boolean enabled = true;
|
||||
boolean accountNonExpired = true;
|
||||
boolean credentialsNonExpired = true;
|
||||
boolean accountNonLocked = true;
|
||||
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
|
||||
authorities.add(roleUser);
|
||||
|
||||
// calculate raw user id (SUI)
|
||||
// TODO: make this more generic, right now only works with postfix names
|
||||
String userid = identifier.replace(openIdRoot, "");
|
||||
|
||||
if (adminList.contains(userid)) {
|
||||
authorities.add(roleAdmin);
|
||||
}
|
||||
|
||||
return new User(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
||||
} else {
|
||||
throw new UsernameNotFoundException("Identifier " + identifier + " did not match OpenID root " + openIdRoot);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package org.mitre.util.jpa;
|
||||
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author mfranklin
|
||||
* Date: 4/28/11
|
||||
* 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, 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit 7a55ca546a3567a8a1833340d0ff9e2b47cf4bdc
|
||||
Subproject commit 0aa98f09467f90b36ed06ba5cdbb82722f08de26
|
|
@ -0,0 +1 @@
|
|||
This directory contains .patch files which must be applied to the upstream spring-security-oauth2 module in order for the project to build.
|
|
@ -0,0 +1,113 @@
|
|||
diff --git a/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/ExpiringOAuth2RefreshToken.java b/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/ExpiringOAuth2RefreshToken.java
|
||||
index 20d2512..a773b29 100644
|
||||
--- a/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/ExpiringOAuth2RefreshToken.java
|
||||
+++ b/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/ExpiringOAuth2RefreshToken.java
|
||||
@@ -9,9 +9,17 @@ public class ExpiringOAuth2RefreshToken extends OAuth2RefreshToken {
|
||||
|
||||
private static final long serialVersionUID = 3449554332764129719L;
|
||||
|
||||
- private final Date expiration;
|
||||
+ private Date expiration;
|
||||
|
||||
/**
|
||||
+ * Create an expiring refresh token with a null value and no expiration
|
||||
+ * @param expiration
|
||||
+ */
|
||||
+ public ExpiringOAuth2RefreshToken() {
|
||||
+ this(null, null);
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
* @param value
|
||||
*/
|
||||
public ExpiringOAuth2RefreshToken(String value, Date expiration) {
|
||||
@@ -28,4 +36,11 @@ public class ExpiringOAuth2RefreshToken extends OAuth2RefreshToken {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * Set the expiration of this token
|
||||
+ */
|
||||
+ public void setExpiration(Date expiration) {
|
||||
+ this.expiration = expiration;
|
||||
+ }
|
||||
+
|
||||
}
|
||||
diff --git a/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessToken.java b/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessToken.java
|
||||
index 791780f..25edf77 100644
|
||||
--- a/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessToken.java
|
||||
+++ b/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessToken.java
|
||||
@@ -57,7 +57,7 @@ public class OAuth2AccessToken implements Serializable {
|
||||
*/
|
||||
public static String SCOPE = "scope";
|
||||
|
||||
- private final String value;
|
||||
+ private String value;
|
||||
|
||||
private Date expiration;
|
||||
|
||||
@@ -74,8 +74,10 @@ public class OAuth2AccessToken implements Serializable {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
- @SuppressWarnings("unused")
|
||||
- private OAuth2AccessToken() {
|
||||
+ /**
|
||||
+ * Create an access token with no value
|
||||
+ */
|
||||
+ public OAuth2AccessToken() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
@@ -88,6 +90,14 @@ public class OAuth2AccessToken implements Serializable {
|
||||
return value;
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * Set the value of the token.
|
||||
+ * @param value the token value
|
||||
+ */
|
||||
+ public void setValue(String value) {
|
||||
+ this.value = value;
|
||||
+ }
|
||||
+
|
||||
public int getExpiresIn() {
|
||||
return expiration != null ? Long.valueOf((expiration.getTime() - System.currentTimeMillis()) / 1000L)
|
||||
.intValue() : 0;
|
||||
diff --git a/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/OAuth2RefreshToken.java b/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/OAuth2RefreshToken.java
|
||||
index 00b002c..96f3f1b 100644
|
||||
--- a/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/OAuth2RefreshToken.java
|
||||
+++ b/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/OAuth2RefreshToken.java
|
||||
@@ -15,9 +15,16 @@ public class OAuth2RefreshToken implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8349970621900575838L;
|
||||
|
||||
- private final String value;
|
||||
+ private String value;
|
||||
|
||||
/**
|
||||
+ * Create an empty token with no value
|
||||
+ */
|
||||
+ public OAuth2RefreshToken() {
|
||||
+ this(null);
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
* Create a new refresh token.
|
||||
*/
|
||||
@JsonCreator
|
||||
@@ -35,6 +42,14 @@ public class OAuth2RefreshToken implements Serializable {
|
||||
return value;
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * Set the value of the token
|
||||
+ * @param value the value of the token
|
||||
+ */
|
||||
+ public void setValue(String value) {
|
||||
+ this.value = value;
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public String toString() {
|
||||
return getValue();
|
Loading…
Reference in New Issue