Commit 27f3614d authored by Matija Obreza's avatar Matija Obreza
Browse files

Extra OAuth service methods

parent b67c173c
......@@ -36,51 +36,71 @@ import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonView;
import org.apache.commons.lang3.StringUtils;
import org.genesys.blocks.model.AuditedVersionedModel;
import org.genesys.blocks.model.Copyable;
import org.genesys.blocks.model.JsonViews;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.provider.ClientDetails;
@Entity
@Table(name = "oauthclient")
public class OAuthClient extends AuditedVersionedModel implements ClientDetails {
public class OAuthClient extends AuditedVersionedModel implements ClientDetails, Copyable<OAuthClient> {
private static final long serialVersionUID = -4204753722663196007L;
@JsonView(JsonViews.Public.class)
@Column(unique = true, nullable = false, length = 100)
private String clientId;
@JsonView(JsonViews.Protected.class)
@Column(nullable = true, length = 100)
private String clientSecret;
@JsonIgnore
@Column(nullable = true, length = 200)
private String resource;
@JsonView(JsonViews.Protected.class)
@Transient
private final Set<String> resourceIds = new HashSet<>();
@Column(nullable = false)
boolean autoApprove = false;
@JsonIgnore
@Column(nullable = true, length = 200)
private String autoApproveScope;
@JsonView(JsonViews.Protected.class)
@Transient
private final Set<String> autoApproveScopes = new HashSet<>();
@JsonIgnore
@Column(nullable = true, length = 200)
private String scope;
@JsonView(JsonViews.Protected.class)
@Transient
private final Set<String> scopes = new HashSet<>();
@JsonIgnore
@Column(nullable = true, length = 200)
private String grants;
@JsonView(JsonViews.Protected.class)
@Transient
private final Set<String> grantTypes = new HashSet<>();
@JsonIgnore
@Column(nullable = true, length = 200)
private String redirect;
@JsonView(JsonViews.Protected.class)
@Transient
private final Set<String> redirectUris = new HashSet<>();
@JsonView(JsonViews.Protected.class)
@ElementCollection
@Enumerated(EnumType.STRING)
@CollectionTable(name = "oauthclientrole", joinColumns = @JoinColumn(name = "clientId"))
......@@ -290,4 +310,13 @@ public class OAuthClient extends AuditedVersionedModel implements ClientDetails
public String getDescription() {
return description;
}
/**
* Returns null
*/
@Override
public OAuthClient copy() {
// Unsupported
return null;
}
}
......@@ -39,6 +39,9 @@ public class RefreshToken implements Serializable {
@Lob
private byte[] authentication;
@Column(length = 100, updatable=false)
private String clientId;
public String getId(){
return tokenId;
}
......@@ -67,4 +70,11 @@ public class RefreshToken implements Serializable {
return authentication;
}
public void setClientId(String clientId) {
this.clientId=clientId;
}
public String getClientId() {
return clientId;
}
}
......@@ -40,4 +40,6 @@ public interface AccessTokenRepository extends JpaRepository<AccessToken, String
@Query("delete from AccessToken at where at.authenticationId = ?1")
void deleteByAuthenticationId(String key);
List<AccessToken> findByUsername(String uuid);
}
......@@ -24,4 +24,6 @@ public interface OAuthClientRepository extends JpaRepository<OAuthClient, Long>
OAuthClient findByClientId(String clientId);
OAuthClient findByIdAndVersion(long id, int version);
}
......@@ -15,6 +15,8 @@
*/
package org.genesys.blocks.oauth.persistence;
import java.util.List;
import org.genesys.blocks.oauth.model.RefreshToken;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
......@@ -22,4 +24,6 @@ import org.springframework.stereotype.Repository;
@Repository
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, String> {
List<RefreshToken> findByClientId(String clientId);
}
......@@ -15,8 +15,20 @@
*/
package org.genesys.blocks.oauth.service;
import java.util.List;
import org.genesys.blocks.oauth.model.OAuthClient;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
public interface OAuthClientDetailsService extends ClientDetailsService {
List<OAuthClient> listClientDetails();
void removeClient(ClientDetails clientDetails);
OAuthClient addClient(String title, String description, String redirectUris, Integer accessTokenValiditySeconds, Integer refreshTokenValiditySeconds);
OAuthClient updateClient(long id, int version, OAuthClient updates);
}
......@@ -20,20 +20,25 @@ import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.genesys.blocks.oauth.model.AccessToken;
import org.genesys.blocks.oauth.model.OAuthClient;
import org.genesys.blocks.oauth.model.OAuthRole;
import org.genesys.blocks.oauth.model.RefreshToken;
import org.genesys.blocks.oauth.persistence.AccessTokenRepository;
import org.genesys.blocks.oauth.persistence.OAuthClientRepository;
import org.genesys.blocks.oauth.persistence.RefreshTokenRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Sort;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.common.util.SerializationUtils;
......@@ -47,10 +52,13 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional(readOnly = false)
@Transactional(readOnly = true)
public class OAuthServiceImpl implements OAuthClientDetailsService, OAuthTokenStoreService {
private static final Logger LOG = LoggerFactory.getLogger(OAuthServiceImpl.class);
@Value("${host.name}")
private String hostname;
@Autowired
private OAuthClientRepository oauthClientRepository;
......@@ -78,6 +86,7 @@ public class OAuthServiceImpl implements OAuthClientDetailsService, OAuthTokenSt
}
@Override
@Transactional
@CacheEvict(cacheNames = { "oauthaccesstoken", "oauthaccesstokenauth" }, allEntries = true)
public void storeAccessToken(final OAuth2AccessToken token, final OAuth2Authentication authentication) {
String refreshToken = null;
......@@ -91,7 +100,8 @@ public class OAuthServiceImpl implements OAuthClientDetailsService, OAuthTokenSt
accessTokenRepository.deleteByAuthenticationId(authenticationKeyGenerator.extractKey(authentication));
// "insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication,
// "insert into oauth_access_token (token_id, token, authentication_id,
// user_name, client_id, authentication,
// refresh_token)
// values (?, ?, ?, ?, ?, ?, ?)";
final AccessToken storedToken = new AccessToken();
......@@ -126,11 +136,13 @@ public class OAuthServiceImpl implements OAuthClientDetailsService, OAuthTokenSt
}
@Override
@Transactional
@CacheEvict(cacheNames = { "oauthaccesstoken", "oauthaccesstokenauth" }, allEntries = true)
public void removeAccessToken(final OAuth2AccessToken token) {
removeAccessToken(token.getValue());
}
@Transactional
@CacheEvict(cacheNames = { "oauthaccesstoken", "oauthaccesstokenauth" }, allEntries = true)
public void removeAccessToken(final String tokenValue) {
accessTokenRepository.delete(extractTokenKey(tokenValue));
......@@ -160,10 +172,13 @@ public class OAuthServiceImpl implements OAuthClientDetailsService, OAuthTokenSt
}
@Override
@Transactional
@CacheEvict(cacheNames = { "oauthaccesstoken", "oauthaccesstokenauth" }, allEntries = true)
public void storeRefreshToken(final OAuth2RefreshToken refreshToken, final OAuth2Authentication authentication) {
// insert into oauth_refresh_token (token_id, token, authentication) values (?, ?, ?)
// insert into oauth_refresh_token (token_id, token, authentication) values (?,
// ?, ?)
final RefreshToken storedToken = new RefreshToken();
storedToken.setClientId(authentication.getOAuth2Request().getClientId());
storedToken.setTokenId(extractTokenKey(refreshToken.getValue()));
storedToken.setToken(serializeRefreshToken(refreshToken));
storedToken.setAuthentication(serializeAuthentication(authentication));
......@@ -188,11 +203,13 @@ public class OAuthServiceImpl implements OAuthClientDetailsService, OAuthTokenSt
}
@Override
@Transactional
@CacheEvict(cacheNames = { "oauthaccesstoken", "oauthaccesstokenauth" }, allEntries = true)
public void removeRefreshToken(final OAuth2RefreshToken token) {
removeRefreshToken(token.getValue());
}
@Transactional
@CacheEvict(cacheNames = { "oauthaccesstoken", "oauthaccesstokenauth" }, allEntries = true)
public void removeRefreshToken(final String token) {
refreshTokenRepository.delete(extractTokenKey(token));
......@@ -219,11 +236,13 @@ public class OAuthServiceImpl implements OAuthClientDetailsService, OAuthTokenSt
}
@Override
@Transactional
@CacheEvict(cacheNames = { "oauthaccesstoken", "oauthaccesstokenauth" }, allEntries = true)
public void removeAccessTokenUsingRefreshToken(final OAuth2RefreshToken refreshToken) {
removeAccessTokenUsingRefreshToken(refreshToken.getValue());
}
@Transactional
@CacheEvict(cacheNames = { "oauthaccesstoken", "oauthaccesstokenauth" }, allEntries = true)
public void removeAccessTokenUsingRefreshToken(final String refreshToken) {
accessTokenRepository.deleteByRefreshToken(extractTokenKey(refreshToken));
......@@ -258,7 +277,8 @@ public class OAuthServiceImpl implements OAuthClientDetailsService, OAuthTokenSt
@Override
public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(final String clientId, final String username) {
return accessTokenRepository.findByClientIdAndUsername(clientId, username).stream().filter(at -> at != null).map(at -> deserializeAccessToken(at.getToken())).collect(Collectors.toList());
return accessTokenRepository.findByClientIdAndUsername(clientId, username).stream().filter(at -> at != null).map(at -> deserializeAccessToken(at.getToken())).collect(Collectors
.toList());
}
@Override
......@@ -339,4 +359,60 @@ public class OAuthServiceImpl implements OAuthClientDetailsService, OAuthTokenSt
}
}
@Override
public List<OAuthClient> listClientDetails() {
return oauthClientRepository.findAll(new Sort("clientId"));
}
@Override
public List<AccessToken> findAccessTokensByClientId(String clientId) {
return accessTokenRepository.findByClientId(clientId);
}
@Override
public List<RefreshToken> findRefreshTokensByClientId(String clientId) {
return refreshTokenRepository.findByClientId(clientId);
}
@Override
public List<AccessToken> findTokensByUserUuid(String uuid) {
return accessTokenRepository.findByUsername(uuid);
}
@Override
@Transactional
public void removeClient(ClientDetails clientDetails) {
OAuthClient client = oauthClientRepository.findByClientId(clientDetails.getClientId());
oauthClientRepository.delete(client);
}
@Override
@Transactional
public OAuthClient addClient(String title, String description, String redirectUris, Integer accessTokenValidity, Integer refreshTokenValidity) {
String clientId = RandomStringUtils.randomAlphanumeric(5) + "." + RandomStringUtils.randomAlphanumeric(20) + "@" + hostname;
String clientSecret = RandomStringUtils.randomAlphanumeric(32);
OAuthClient client = new OAuthClient();
client.setTitle(title);
client.setDescription(description);
client.setRedirect(StringUtils.defaultIfBlank(redirectUris, null));
client.setAccessTokenValidity(accessTokenValidity);
client.setRefreshTokenValidity(refreshTokenValidity);
client.setClientId(clientId);
client.setClientSecret(clientSecret);
client.getScope().add("read");
client.getScope().add("write");
client.getAuthorizedGrantTypes().add("authorization_code");
client.getAuthorizedGrantTypes().add("refresh_token");
client.getRoles().add(OAuthRole.CLIENT);
return oauthClientRepository.save(client);
}
@Override
public OAuthClient updateClient(long id, int version, OAuthClient updates) {
OAuthClient client = oauthClientRepository.findByIdAndVersion(id, version);
client.apply(updates);
return oauthClientRepository.save(client);
}
}
......@@ -15,8 +15,24 @@
*/
package org.genesys.blocks.oauth.service;
import java.util.List;
import org.genesys.blocks.oauth.model.AccessToken;
import org.genesys.blocks.oauth.model.RefreshToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
public interface OAuthTokenStoreService extends TokenStore {
List<AccessToken> findAccessTokensByClientId(String clientId);
void removeAccessToken(String tokenId);
List<AccessToken> findTokensByUserUuid(String uuid);
List<RefreshToken> findRefreshTokensByClientId(String clientId);
void removeRefreshToken(String tokenId);
}
......@@ -37,6 +37,9 @@ databaseChangeLog:
onDelete: CASCADE
onUpdate: CASCADE
# appblocks-1.3-SNAPSHOT
- changeSet:
id: application-blocks-security-1506594404000-3
author: matijaobreza
......@@ -53,3 +56,18 @@ databaseChangeLog:
- column:
name: description
type: clob
- changeSet:
id: application-blocks-security-1507137884-1
author: matijaobreza
comment: Add refreshToken#clientId
changes:
- addColumn:
tableName: oauthrefreshtoken
columns:
- column:
name: clientId
type: varchar(100)
constraints:
nullable: false
moc
host.name=localhost:8080
# Database connection
db.url=jdbc:hsqldb:mem:test;sql.syntax_mys=true;sql.ignore_case=true
db.driverClassName=org.hsqldb.jdbc.JDBCDriver
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment