package org.springframework.security.oauth2.provider;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.annotate.JsonAnyGetter;
import org.codehaus.jackson.annotate.JsonAnySetter;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
import org.codehaus.jackson.map.deser.std.StdDeserializer;
import org.codehaus.jackson.map.type.SimpleType;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.util.StringUtils;
/**
* Base implementation of {@link org.springframework.security.oauth2.provider.ClientDetails}.
*
* @author Ryan Heaton
* @author Dave Syer
*/
@JsonSerialize(include = Inclusion.NON_DEFAULT)
@JsonIgnoreProperties(ignoreUnknown = true)
public class BaseClientDetails implements ClientDetails {
@JsonProperty("client_id")
private String clientId;
@JsonProperty("client_secret")
private String clientSecret;
@JsonDeserialize(using = ArrayOrStringDeserializer.class)
private Set<String> scope = Collections.emptySet();
@JsonProperty("resource_ids")
@JsonDeserialize(using = ArrayOrStringDeserializer.class)
private Set<String> resourceIds = Collections.emptySet();
@JsonProperty("authorized_grant_types")
@JsonDeserialize(using = ArrayOrStringDeserializer.class)
private Set<String> authorizedGrantTypes = Collections.emptySet();
@JsonProperty("redirect_uri")
@JsonDeserialize(using = ArrayOrStringDeserializer.class)
private Set<String> registeredRedirectUris;
private List<GrantedAuthority> authorities = Collections.emptyList();
@JsonProperty("access_token_validity")
private Integer accessTokenValiditySeconds;
@JsonProperty("refresh_token_validity")
private Integer refreshTokenValiditySeconds;
@JsonIgnore
private Map<String, Object> additionalInformation = new LinkedHashMap<String, Object>();
public BaseClientDetails() {
}
public BaseClientDetails(ClientDetails prototype) {
this();
setAccessTokenValiditySeconds(prototype.getAccessTokenValiditySeconds());
setRefreshTokenValiditySeconds(prototype.getRefreshTokenValiditySeconds());
setAuthorities(prototype.getAuthorities());
setAuthorizedGrantTypes(prototype.getAuthorizedGrantTypes());
setClientId(prototype.getClientId());
setClientSecret(prototype.getClientSecret());
setRegisteredRedirectUri(prototype.getRegisteredRedirectUri());
setScope(prototype.getScope());
setResourceIds(prototype.getResourceIds());
}
public BaseClientDetails(String clientId, String resourceIds, String scopes, String grantTypes, String authorities) {
this(clientId, resourceIds, scopes, grantTypes, authorities, null);
}
public BaseClientDetails(String clientId, String resourceIds, String scopes, String grantTypes, String authorities,
String redirectUris) {
this.clientId = clientId;
if (StringUtils.hasText(resourceIds)) {
Set<String> resources = StringUtils.commaDelimitedListToSet(resourceIds);
if (!resources.isEmpty()) {
this.resourceIds = resources;
}
}
if (StringUtils.hasText(scopes)) {
Set<String> scopeList = StringUtils.commaDelimitedListToSet(scopes);
if (!scopeList.isEmpty()) {
this.scope = scopeList;
}
}
if (StringUtils.hasText(grantTypes)) {
this.authorizedGrantTypes = StringUtils.commaDelimitedListToSet(grantTypes);
}
else {
this.authorizedGrantTypes = new HashSet<String>(Arrays.asList("authorization_code", "refresh_token"));
}
if (StringUtils.hasText(authorities)) {
this.authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(authorities);
}
if (StringUtils.hasText(redirectUris)) {
this.registeredRedirectUris = StringUtils.commaDelimitedListToSet(redirectUris);
}
}
@JsonIgnore
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
@JsonIgnore
public boolean isSecretRequired() {
return this.clientSecret != null;
}
@JsonIgnore
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
@JsonIgnore
public boolean isScoped() {
return this.scope != null && !this.scope.isEmpty();
}
public Set<String> getScope() {
return scope;
}
public void setScope(Collection<String> scope) {
this.scope = scope == null ? Collections.<String> emptySet() : new LinkedHashSet<String>(scope);
}
@JsonIgnore
public Set<String> getResourceIds() {
return resourceIds;
}
public void setResourceIds(Collection<String> resourceIds) {
this.resourceIds = resourceIds == null ? Collections.<String> emptySet() : new LinkedHashSet<String>(
resourceIds);
}
@JsonIgnore
public Set<String> getAuthorizedGrantTypes() {
return authorizedGrantTypes;
}
public void setAuthorizedGrantTypes(Collection<String> authorizedGrantTypes) {
this.authorizedGrantTypes = new LinkedHashSet<String>(authorizedGrantTypes);
}
@JsonIgnore
public Set<String> getRegisteredRedirectUri() {
return registeredRedirectUris;
}
public void setRegisteredRedirectUri(Set<String> registeredRedirectUris) {
this.registeredRedirectUris = registeredRedirectUris == null ? null : new LinkedHashSet<String>(
registeredRedirectUris);
}
@JsonProperty("authorities")
private List<String> getAuthoritiesAsStrings() {
return new ArrayList<String>(AuthorityUtils.authorityListToSet(authorities));
}
@JsonProperty("authorities")
@JsonDeserialize(using = ArrayOrStringDeserializer.class)
private void setAuthoritiesAsStrings(Set<String> values) {
setAuthorities(AuthorityUtils.createAuthorityList(values.toArray(new String[values.size()])));
}
public static class ArrayOrStringDeserializer extends StdDeserializer<Set<String>> {
public ArrayOrStringDeserializer() {
super(Set.class);
}
@Override
public JavaType getValueType() {
return SimpleType.construct(String.class);
}
@Override
public Set<String> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
JsonToken token = jp.getCurrentToken();
if (token.isScalarValue()) {
String list = jp.getText();
list = list.replaceAll("\\s+", ",");
return new LinkedHashSet<String>(Arrays.asList(StringUtils.commaDelimitedListToStringArray(list)));
}
return jp.readValueAs(new TypeReference<Set<String>>() {
});
}
}
@JsonIgnore
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}
@JsonIgnore
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = new ArrayList<GrantedAuthority>(authorities);
}
@JsonIgnore
public Integer getAccessTokenValiditySeconds() {
return accessTokenValiditySeconds;
}
public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) {
this.accessTokenValiditySeconds = accessTokenValiditySeconds;
}
@JsonIgnore
public Integer getRefreshTokenValiditySeconds() {
return refreshTokenValiditySeconds;
}
public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) {
this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
}
public void setAdditionalInformation(Map<String, ?> additionalInformation) {
this.additionalInformation = new LinkedHashMap<String, Object>(additionalInformation);
}
@JsonAnyGetter
public Map<String, Object> getAdditionalInformation() {
return Collections.unmodifiableMap(this.additionalInformation);
}
@JsonAnySetter
public void addAdditionalInformation(String key, Object value) {
this.additionalInformation.put(key, value);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((accessTokenValiditySeconds==null) ? 0 : accessTokenValiditySeconds);
result = prime * result + ((refreshTokenValiditySeconds == null) ? 0 : refreshTokenValiditySeconds);
result = prime * result + ((authorities == null) ? 0 : authorities.hashCode());
result = prime * result + ((authorizedGrantTypes == null) ? 0 : authorizedGrantTypes.hashCode());
result = prime * result + ((clientId == null) ? 0 : clientId.hashCode());
result = prime * result + ((clientSecret == null) ? 0 : clientSecret.hashCode());
result = prime * result + ((registeredRedirectUris == null) ? 0 : registeredRedirectUris.hashCode());
result = prime * result + ((resourceIds == null) ? 0 : resourceIds.hashCode());
result = prime * result + ((scope == null) ? 0 : scope.hashCode());
result = prime * result + additionalInformation.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BaseClientDetails other = (BaseClientDetails) obj;
if (accessTokenValiditySeconds != other.accessTokenValiditySeconds)
return false;
if (refreshTokenValiditySeconds != other.refreshTokenValiditySeconds)
return false;
if (authorities == null) {
if (other.authorities != null)
return false;
}
else if (!authorities.equals(other.authorities))
return false;
if (authorizedGrantTypes == null) {
if (other.authorizedGrantTypes != null)
return false;
}
else if (!authorizedGrantTypes.equals(other.authorizedGrantTypes))
return false;
if (clientId == null) {
if (other.clientId != null)
return false;
}
else if (!clientId.equals(other.clientId))
return false;
if (clientSecret == null) {
if (other.clientSecret != null)
return false;
}
else if (!clientSecret.equals(other.clientSecret))
return false;
if (registeredRedirectUris == null) {
if (other.registeredRedirectUris != null)
return false;
}
else if (!registeredRedirectUris.equals(other.registeredRedirectUris))
return false;
if (resourceIds == null) {
if (other.resourceIds != null)
return false;
}
else if (!resourceIds.equals(other.resourceIds))
return false;
if (scope == null) {
if (other.scope != null)
return false;
}
else if (!scope.equals(other.scope))
return false;
if (additionalInformation == null) {
if (other.additionalInformation != null)
return false;
}
else if (!additionalInformation.equals(other.additionalInformation))
return false;
return true;
}
@Override
public String toString() {
return "BaseClientDetails [clientId=" + clientId + ", clientSecret=" + clientSecret + ", scope=" + scope
+ ", resourceIds=" + resourceIds + ", authorizedGrantTypes=" + authorizedGrantTypes
+ ", registeredRedirectUris=" + registeredRedirectUris + ", authorities=" + authorities
+ ", accessTokenValiditySeconds=" + accessTokenValiditySeconds + ", refreshTokenValiditySeconds="
+ refreshTokenValiditySeconds + ", additionalInformation=" + additionalInformation + "]";
}
}