v 1.5.0 RC2
v 1.5.0 RC2
This commit is contained in:
@@ -15,65 +15,70 @@ import org.springframework.jdbc.core.support.SqlLobValue;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of authorization code services that stores the codes and authentication in a database.
|
||||
* Implementation of authorization code services that stores the codes and
|
||||
* authentication in a database.
|
||||
*
|
||||
* @author Crystal.Sea
|
||||
*/
|
||||
public class JdbcAuthorizationCodeServices extends RandomValueAuthorizationCodeServices {
|
||||
|
||||
private static final String DEFAULT_SELECT_STATEMENT = "select code, authentication from oauth_code where code = ?";
|
||||
private static final String DEFAULT_INSERT_STATEMENT = "insert into oauth_code (code, authentication) values (?, ?)";
|
||||
private static final String DEFAULT_DELETE_STATEMENT = "delete from oauth_code where code = ?";
|
||||
private static final String DEFAULT_SELECT_STATEMENT = "select code, authentication from oauth_code where code = ?";
|
||||
private static final String DEFAULT_INSERT_STATEMENT = "insert into oauth_code (code, authentication) values (?, ?)";
|
||||
private static final String DEFAULT_DELETE_STATEMENT = "delete from oauth_code where code = ?";
|
||||
|
||||
private String selectAuthenticationSql = DEFAULT_SELECT_STATEMENT;
|
||||
private String insertAuthenticationSql = DEFAULT_INSERT_STATEMENT;
|
||||
private String deleteAuthenticationSql = DEFAULT_DELETE_STATEMENT;
|
||||
private String selectAuthenticationSql = DEFAULT_SELECT_STATEMENT;
|
||||
private String insertAuthenticationSql = DEFAULT_INSERT_STATEMENT;
|
||||
private String deleteAuthenticationSql = DEFAULT_DELETE_STATEMENT;
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public JdbcAuthorizationCodeServices(DataSource dataSource) {
|
||||
Assert.notNull(dataSource, "DataSource required");
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
public JdbcAuthorizationCodeServices(DataSource dataSource) {
|
||||
Assert.notNull(dataSource, "DataSource required");
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void store(String code, OAuth2Authentication authentication) {
|
||||
jdbcTemplate.update(insertAuthenticationSql,
|
||||
new Object[] { code, new SqlLobValue(SerializationUtils.serialize(authentication)) }, new int[] {
|
||||
Types.VARCHAR, Types.BLOB });
|
||||
}
|
||||
public JdbcAuthorizationCodeServices(JdbcTemplate jdbcTemplate) {
|
||||
Assert.notNull(jdbcTemplate, "jdbcTemplate required");
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void store(String code, OAuth2Authentication authentication) {
|
||||
jdbcTemplate.update(insertAuthenticationSql,
|
||||
new Object[] { code, new SqlLobValue(SerializationUtils.serialize(authentication)) },
|
||||
new int[] { Types.VARCHAR, Types.BLOB });
|
||||
}
|
||||
|
||||
public OAuth2Authentication remove(String code) {
|
||||
OAuth2Authentication authentication;
|
||||
public OAuth2Authentication remove(String code) {
|
||||
OAuth2Authentication authentication;
|
||||
|
||||
try {
|
||||
authentication = jdbcTemplate.queryForObject(selectAuthenticationSql,
|
||||
new RowMapper<OAuth2Authentication>() {
|
||||
public OAuth2Authentication mapRow(ResultSet rs, int rowNum)
|
||||
throws SQLException {
|
||||
return SerializationUtils.deserialize(rs.getBytes("authentication"));
|
||||
}
|
||||
}, code);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
authentication = jdbcTemplate.queryForObject(selectAuthenticationSql,
|
||||
new RowMapper<OAuth2Authentication>() {
|
||||
public OAuth2Authentication mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return SerializationUtils.deserialize(rs.getBytes("authentication"));
|
||||
}
|
||||
}, code);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (authentication != null) {
|
||||
jdbcTemplate.update(deleteAuthenticationSql, code);
|
||||
}
|
||||
if (authentication != null) {
|
||||
jdbcTemplate.update(deleteAuthenticationSql, code);
|
||||
}
|
||||
|
||||
return authentication;
|
||||
}
|
||||
return authentication;
|
||||
}
|
||||
|
||||
public void setSelectAuthenticationSql(String selectAuthenticationSql) {
|
||||
this.selectAuthenticationSql = selectAuthenticationSql;
|
||||
}
|
||||
public void setSelectAuthenticationSql(String selectAuthenticationSql) {
|
||||
this.selectAuthenticationSql = selectAuthenticationSql;
|
||||
}
|
||||
|
||||
public void setInsertAuthenticationSql(String insertAuthenticationSql) {
|
||||
this.insertAuthenticationSql = insertAuthenticationSql;
|
||||
}
|
||||
public void setInsertAuthenticationSql(String insertAuthenticationSql) {
|
||||
this.insertAuthenticationSql = insertAuthenticationSql;
|
||||
}
|
||||
|
||||
public void setDeleteAuthenticationSql(String deleteAuthenticationSql) {
|
||||
this.deleteAuthenticationSql = deleteAuthenticationSql;
|
||||
}
|
||||
public void setDeleteAuthenticationSql(String deleteAuthenticationSql) {
|
||||
this.deleteAuthenticationSql = deleteAuthenticationSql;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,423 +37,416 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class JdbcTokenStore implements TokenStore {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(JdbcTokenStore.class);
|
||||
private static final Log LOG = LogFactory.getLog(JdbcTokenStore.class);
|
||||
|
||||
private static final String DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT = "insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?)";
|
||||
private static final String DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT = "insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
private static final String DEFAULT_ACCESS_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_access_token where token_id = ?";
|
||||
private static final String DEFAULT_ACCESS_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_access_token where token_id = ?";
|
||||
|
||||
private static final String DEFAULT_ACCESS_TOKEN_AUTHENTICATION_SELECT_STATEMENT = "select token_id, authentication from oauth_access_token where token_id = ?";
|
||||
private static final String DEFAULT_ACCESS_TOKEN_AUTHENTICATION_SELECT_STATEMENT = "select token_id, authentication from oauth_access_token where token_id = ?";
|
||||
|
||||
private static final String DEFAULT_ACCESS_TOKEN_FROM_AUTHENTICATION_SELECT_STATEMENT = "select token_id, token from oauth_access_token where authentication_id = ?";
|
||||
private static final String DEFAULT_ACCESS_TOKEN_FROM_AUTHENTICATION_SELECT_STATEMENT = "select token_id, token from oauth_access_token where authentication_id = ?";
|
||||
|
||||
private static final String DEFAULT_ACCESS_TOKENS_FROM_USERNAME_AND_CLIENT_SELECT_STATEMENT = "select token_id, token from oauth_access_token where user_name = ? and client_id = ?";
|
||||
private static final String DEFAULT_ACCESS_TOKENS_FROM_USERNAME_AND_CLIENT_SELECT_STATEMENT = "select token_id, token from oauth_access_token where user_name = ? and client_id = ?";
|
||||
|
||||
private static final String DEFAULT_ACCESS_TOKENS_FROM_USERNAME_SELECT_STATEMENT = "select token_id, token from oauth_access_token where user_name = ?";
|
||||
|
||||
private static final String DEFAULT_ACCESS_TOKENS_FROM_CLIENTID_SELECT_STATEMENT = "select token_id, token from oauth_access_token where client_id = ?";
|
||||
private static final String DEFAULT_ACCESS_TOKENS_FROM_USERNAME_SELECT_STATEMENT = "select token_id, token from oauth_access_token where user_name = ?";
|
||||
|
||||
private static final String DEFAULT_ACCESS_TOKEN_DELETE_STATEMENT = "delete from oauth_access_token where token_id = ?";
|
||||
private static final String DEFAULT_ACCESS_TOKENS_FROM_CLIENTID_SELECT_STATEMENT = "select token_id, token from oauth_access_token where client_id = ?";
|
||||
|
||||
private static final String DEFAULT_ACCESS_TOKEN_DELETE_FROM_REFRESH_TOKEN_STATEMENT = "delete from oauth_access_token where refresh_token = ?";
|
||||
private static final String DEFAULT_ACCESS_TOKEN_DELETE_STATEMENT = "delete from oauth_access_token where token_id = ?";
|
||||
|
||||
private static final String DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT = "insert into oauth_refresh_token (token_id, token, authentication) values (?, ?, ?)";
|
||||
private static final String DEFAULT_ACCESS_TOKEN_DELETE_FROM_REFRESH_TOKEN_STATEMENT = "delete from oauth_access_token where refresh_token = ?";
|
||||
|
||||
private static final String DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_refresh_token where token_id = ?";
|
||||
private static final String DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT = "insert into oauth_refresh_token (token_id, token, authentication) values (?, ?, ?)";
|
||||
|
||||
private static final String DEFAULT_REFRESH_TOKEN_AUTHENTICATION_SELECT_STATEMENT = "select token_id, authentication from oauth_refresh_token where token_id = ?";
|
||||
private static final String DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_refresh_token where token_id = ?";
|
||||
|
||||
private static final String DEFAULT_REFRESH_TOKEN_DELETE_STATEMENT = "delete from oauth_refresh_token where token_id = ?";
|
||||
private static final String DEFAULT_REFRESH_TOKEN_AUTHENTICATION_SELECT_STATEMENT = "select token_id, authentication from oauth_refresh_token where token_id = ?";
|
||||
|
||||
private String insertAccessTokenSql = DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT;
|
||||
private static final String DEFAULT_REFRESH_TOKEN_DELETE_STATEMENT = "delete from oauth_refresh_token where token_id = ?";
|
||||
|
||||
private String selectAccessTokenSql = DEFAULT_ACCESS_TOKEN_SELECT_STATEMENT;
|
||||
private String insertAccessTokenSql = DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT;
|
||||
|
||||
private String selectAccessTokenAuthenticationSql = DEFAULT_ACCESS_TOKEN_AUTHENTICATION_SELECT_STATEMENT;
|
||||
private String selectAccessTokenSql = DEFAULT_ACCESS_TOKEN_SELECT_STATEMENT;
|
||||
|
||||
private String selectAccessTokenFromAuthenticationSql = DEFAULT_ACCESS_TOKEN_FROM_AUTHENTICATION_SELECT_STATEMENT;
|
||||
private String selectAccessTokenAuthenticationSql = DEFAULT_ACCESS_TOKEN_AUTHENTICATION_SELECT_STATEMENT;
|
||||
|
||||
private String selectAccessTokensFromUserNameAndClientIdSql = DEFAULT_ACCESS_TOKENS_FROM_USERNAME_AND_CLIENT_SELECT_STATEMENT;
|
||||
private String selectAccessTokenFromAuthenticationSql = DEFAULT_ACCESS_TOKEN_FROM_AUTHENTICATION_SELECT_STATEMENT;
|
||||
|
||||
private String selectAccessTokensFromUserNameSql = DEFAULT_ACCESS_TOKENS_FROM_USERNAME_SELECT_STATEMENT;
|
||||
|
||||
private String selectAccessTokensFromClientIdSql = DEFAULT_ACCESS_TOKENS_FROM_CLIENTID_SELECT_STATEMENT;
|
||||
private String selectAccessTokensFromUserNameAndClientIdSql = DEFAULT_ACCESS_TOKENS_FROM_USERNAME_AND_CLIENT_SELECT_STATEMENT;
|
||||
|
||||
private String deleteAccessTokenSql = DEFAULT_ACCESS_TOKEN_DELETE_STATEMENT;
|
||||
private String selectAccessTokensFromUserNameSql = DEFAULT_ACCESS_TOKENS_FROM_USERNAME_SELECT_STATEMENT;
|
||||
|
||||
private String insertRefreshTokenSql = DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT;
|
||||
private String selectAccessTokensFromClientIdSql = DEFAULT_ACCESS_TOKENS_FROM_CLIENTID_SELECT_STATEMENT;
|
||||
|
||||
private String selectRefreshTokenSql = DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT;
|
||||
private String deleteAccessTokenSql = DEFAULT_ACCESS_TOKEN_DELETE_STATEMENT;
|
||||
|
||||
private String selectRefreshTokenAuthenticationSql = DEFAULT_REFRESH_TOKEN_AUTHENTICATION_SELECT_STATEMENT;
|
||||
private String insertRefreshTokenSql = DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT;
|
||||
|
||||
private String deleteRefreshTokenSql = DEFAULT_REFRESH_TOKEN_DELETE_STATEMENT;
|
||||
private String selectRefreshTokenSql = DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT;
|
||||
|
||||
private String deleteAccessTokenFromRefreshTokenSql = DEFAULT_ACCESS_TOKEN_DELETE_FROM_REFRESH_TOKEN_STATEMENT;
|
||||
private String selectRefreshTokenAuthenticationSql = DEFAULT_REFRESH_TOKEN_AUTHENTICATION_SELECT_STATEMENT;
|
||||
|
||||
private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();
|
||||
private String deleteRefreshTokenSql = DEFAULT_REFRESH_TOKEN_DELETE_STATEMENT;
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private String deleteAccessTokenFromRefreshTokenSql = DEFAULT_ACCESS_TOKEN_DELETE_FROM_REFRESH_TOKEN_STATEMENT;
|
||||
|
||||
public JdbcTokenStore(DataSource dataSource) {
|
||||
Assert.notNull(dataSource, "DataSource required");
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();
|
||||
|
||||
public void setAuthenticationKeyGenerator(AuthenticationKeyGenerator authenticationKeyGenerator) {
|
||||
this.authenticationKeyGenerator = authenticationKeyGenerator;
|
||||
}
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
|
||||
OAuth2AccessToken accessToken = null;
|
||||
|
||||
String key = authenticationKeyGenerator.extractKey(authentication);
|
||||
try {
|
||||
accessToken = jdbcTemplate.queryForObject(selectAccessTokenFromAuthenticationSql,
|
||||
new RowMapper<OAuth2AccessToken>() {
|
||||
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return deserializeAccessToken(rs.getBytes(2));
|
||||
}
|
||||
}, key);
|
||||
}
|
||||
catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.debug("Failed to find access token for authentication " + authentication);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
LOG.error("Could not extract access token for authentication " + authentication, e);
|
||||
}
|
||||
|
||||
if (accessToken != null
|
||||
&& !key.equals(authenticationKeyGenerator.extractKey(readAuthentication(accessToken.getValue())))) {
|
||||
removeAccessToken(accessToken.getValue());
|
||||
// Keep the store consistent (maybe the same user is represented by this authentication but the details have
|
||||
// changed)
|
||||
storeAccessToken(accessToken, authentication);
|
||||
}
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
|
||||
String refreshToken = null;
|
||||
if (token.getRefreshToken() != null) {
|
||||
refreshToken = token.getRefreshToken().getValue();
|
||||
}
|
||||
|
||||
if (readAccessToken(token.getValue())!=null) {
|
||||
removeAccessToken(token.getValue());
|
||||
}
|
||||
|
||||
jdbcTemplate.update(insertAccessTokenSql, new Object[] { extractTokenKey(token.getValue()),
|
||||
new SqlLobValue(serializeAccessToken(token)), authenticationKeyGenerator.extractKey(authentication),
|
||||
authentication.isClientOnly() ? null : authentication.getName(),
|
||||
authentication.getOAuth2Request().getClientId(),
|
||||
new SqlLobValue(serializeAuthentication(authentication)), extractTokenKey(refreshToken) }, new int[] {
|
||||
Types.VARCHAR, Types.BLOB, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.BLOB, Types.VARCHAR });
|
||||
}
|
||||
|
||||
public OAuth2AccessToken readAccessToken(String tokenValue) {
|
||||
OAuth2AccessToken accessToken = null;
|
||||
|
||||
try {
|
||||
accessToken = jdbcTemplate.queryForObject(selectAccessTokenSql, new RowMapper<OAuth2AccessToken>() {
|
||||
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return deserializeAccessToken(rs.getBytes(2));
|
||||
}
|
||||
}, extractTokenKey(tokenValue));
|
||||
}
|
||||
catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find access token for token " + tokenValue);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
LOG.warn("Failed to deserialize access token for " + tokenValue, e);
|
||||
removeAccessToken(tokenValue);
|
||||
}
|
||||
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void removeAccessToken(OAuth2AccessToken token) {
|
||||
removeAccessToken(token.getValue());
|
||||
}
|
||||
|
||||
public void removeAccessToken(String tokenValue) {
|
||||
jdbcTemplate.update(deleteAccessTokenSql, extractTokenKey(tokenValue));
|
||||
}
|
||||
|
||||
public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
|
||||
return readAuthentication(token.getValue());
|
||||
}
|
||||
|
||||
public OAuth2Authentication readAuthentication(String token) {
|
||||
OAuth2Authentication authentication = null;
|
||||
|
||||
try {
|
||||
authentication = jdbcTemplate.queryForObject(selectAccessTokenAuthenticationSql,
|
||||
new RowMapper<OAuth2Authentication>() {
|
||||
public OAuth2Authentication mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return deserializeAuthentication(rs.getBytes(2));
|
||||
}
|
||||
}, extractTokenKey(token));
|
||||
}
|
||||
catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find access token for token " + token);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
LOG.warn("Failed to deserialize authentication for " + token, e);
|
||||
removeAccessToken(token);
|
||||
}
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
|
||||
jdbcTemplate.update(insertRefreshTokenSql, new Object[] { extractTokenKey(refreshToken.getValue()),
|
||||
new SqlLobValue(serializeRefreshToken(refreshToken)),
|
||||
new SqlLobValue(serializeAuthentication(authentication)) }, new int[] { Types.VARCHAR, Types.BLOB,
|
||||
Types.BLOB });
|
||||
}
|
||||
|
||||
public OAuth2RefreshToken readRefreshToken(String token) {
|
||||
OAuth2RefreshToken refreshToken = null;
|
||||
|
||||
try {
|
||||
refreshToken = jdbcTemplate.queryForObject(selectRefreshTokenSql, new RowMapper<OAuth2RefreshToken>() {
|
||||
public OAuth2RefreshToken mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return deserializeRefreshToken(rs.getBytes(2));
|
||||
}
|
||||
}, extractTokenKey(token));
|
||||
}
|
||||
catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find refresh token for token " + token);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
LOG.warn("Failed to deserialize refresh token for token " + token, e);
|
||||
removeRefreshToken(token);
|
||||
}
|
||||
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public void removeRefreshToken(OAuth2RefreshToken token) {
|
||||
removeRefreshToken(token.getValue());
|
||||
}
|
||||
|
||||
public void removeRefreshToken(String token) {
|
||||
jdbcTemplate.update(deleteRefreshTokenSql, extractTokenKey(token));
|
||||
}
|
||||
|
||||
public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) {
|
||||
return readAuthenticationForRefreshToken(token.getValue());
|
||||
}
|
||||
|
||||
public OAuth2Authentication readAuthenticationForRefreshToken(String value) {
|
||||
OAuth2Authentication authentication = null;
|
||||
|
||||
try {
|
||||
authentication = jdbcTemplate.queryForObject(selectRefreshTokenAuthenticationSql,
|
||||
new RowMapper<OAuth2Authentication>() {
|
||||
public OAuth2Authentication mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return deserializeAuthentication(rs.getBytes(2));
|
||||
}
|
||||
}, extractTokenKey(value));
|
||||
}
|
||||
catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find access token for token " + value);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
LOG.warn("Failed to deserialize access token for " + value, e);
|
||||
removeRefreshToken(value);
|
||||
}
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
|
||||
removeAccessTokenUsingRefreshToken(refreshToken.getValue());
|
||||
}
|
||||
|
||||
public void removeAccessTokenUsingRefreshToken(String refreshToken) {
|
||||
jdbcTemplate.update(deleteAccessTokenFromRefreshTokenSql, new Object[] { extractTokenKey(refreshToken) },
|
||||
new int[] { Types.VARCHAR });
|
||||
}
|
||||
|
||||
public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
|
||||
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>();
|
||||
|
||||
try {
|
||||
accessTokens = jdbcTemplate.query(selectAccessTokensFromClientIdSql, new SafeAccessTokenRowMapper(),
|
||||
clientId);
|
||||
}
|
||||
catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find access token for clientId " + clientId);
|
||||
}
|
||||
}
|
||||
accessTokens = removeNulls(accessTokens);
|
||||
|
||||
return accessTokens;
|
||||
}
|
||||
|
||||
public Collection<OAuth2AccessToken> findTokensByUserName(String userName) {
|
||||
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>();
|
||||
|
||||
try {
|
||||
accessTokens = jdbcTemplate.query(selectAccessTokensFromUserNameSql, new SafeAccessTokenRowMapper(),
|
||||
userName);
|
||||
}
|
||||
catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("Failed to find access token for userName " + userName);
|
||||
}
|
||||
accessTokens = removeNulls(accessTokens);
|
||||
|
||||
return accessTokens;
|
||||
}
|
||||
|
||||
public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
|
||||
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>();
|
||||
|
||||
try {
|
||||
accessTokens = jdbcTemplate.query(selectAccessTokensFromUserNameAndClientIdSql, new SafeAccessTokenRowMapper(),
|
||||
userName, clientId);
|
||||
}
|
||||
catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find access token for clientId " + clientId + " and userName " + userName);
|
||||
}
|
||||
}
|
||||
accessTokens = removeNulls(accessTokens);
|
||||
|
||||
return accessTokens;
|
||||
}
|
||||
|
||||
private List<OAuth2AccessToken> removeNulls(List<OAuth2AccessToken> accessTokens) {
|
||||
List<OAuth2AccessToken> tokens = new ArrayList<OAuth2AccessToken>();
|
||||
for (OAuth2AccessToken token : accessTokens) {
|
||||
if (token != null) {
|
||||
tokens.add(token);
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
protected String extractTokenKey(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
MessageDigest digest;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("MD5");
|
||||
}
|
||||
catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).");
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] bytes = digest.digest(value.getBytes("UTF-8"));
|
||||
return String.format("%032x", new BigInteger(1, bytes));
|
||||
}
|
||||
catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
|
||||
}
|
||||
}
|
||||
|
||||
private final class SafeAccessTokenRowMapper implements RowMapper<OAuth2AccessToken> {
|
||||
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
try {
|
||||
return deserializeAccessToken(rs.getBytes(2));
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
String token = rs.getString(1);
|
||||
jdbcTemplate.update(deleteAccessTokenSql, token);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] serializeAccessToken(OAuth2AccessToken token) {
|
||||
return SerializationUtils.serialize(token);
|
||||
}
|
||||
|
||||
protected byte[] serializeRefreshToken(OAuth2RefreshToken token) {
|
||||
return SerializationUtils.serialize(token);
|
||||
}
|
||||
|
||||
protected byte[] serializeAuthentication(OAuth2Authentication authentication) {
|
||||
return SerializationUtils.serialize(authentication);
|
||||
}
|
||||
|
||||
protected OAuth2AccessToken deserializeAccessToken(byte[] token) {
|
||||
return SerializationUtils.deserialize(token);
|
||||
}
|
||||
|
||||
protected OAuth2RefreshToken deserializeRefreshToken(byte[] token) {
|
||||
return SerializationUtils.deserialize(token);
|
||||
}
|
||||
|
||||
protected OAuth2Authentication deserializeAuthentication(byte[] authentication) {
|
||||
return SerializationUtils.deserialize(authentication);
|
||||
}
|
||||
|
||||
public void setInsertAccessTokenSql(String insertAccessTokenSql) {
|
||||
this.insertAccessTokenSql = insertAccessTokenSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokenSql(String selectAccessTokenSql) {
|
||||
this.selectAccessTokenSql = selectAccessTokenSql;
|
||||
}
|
||||
|
||||
public void setDeleteAccessTokenSql(String deleteAccessTokenSql) {
|
||||
this.deleteAccessTokenSql = deleteAccessTokenSql;
|
||||
}
|
||||
|
||||
public void setInsertRefreshTokenSql(String insertRefreshTokenSql) {
|
||||
this.insertRefreshTokenSql = insertRefreshTokenSql;
|
||||
}
|
||||
|
||||
public void setSelectRefreshTokenSql(String selectRefreshTokenSql) {
|
||||
this.selectRefreshTokenSql = selectRefreshTokenSql;
|
||||
}
|
||||
|
||||
public void setDeleteRefreshTokenSql(String deleteRefreshTokenSql) {
|
||||
this.deleteRefreshTokenSql = deleteRefreshTokenSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokenAuthenticationSql(String selectAccessTokenAuthenticationSql) {
|
||||
this.selectAccessTokenAuthenticationSql = selectAccessTokenAuthenticationSql;
|
||||
}
|
||||
|
||||
public void setSelectRefreshTokenAuthenticationSql(String selectRefreshTokenAuthenticationSql) {
|
||||
this.selectRefreshTokenAuthenticationSql = selectRefreshTokenAuthenticationSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokenFromAuthenticationSql(String selectAccessTokenFromAuthenticationSql) {
|
||||
this.selectAccessTokenFromAuthenticationSql = selectAccessTokenFromAuthenticationSql;
|
||||
}
|
||||
|
||||
public void setDeleteAccessTokenFromRefreshTokenSql(String deleteAccessTokenFromRefreshTokenSql) {
|
||||
this.deleteAccessTokenFromRefreshTokenSql = deleteAccessTokenFromRefreshTokenSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokensFromUserNameSql(String selectAccessTokensFromUserNameSql) {
|
||||
this.selectAccessTokensFromUserNameSql = selectAccessTokensFromUserNameSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokensFromUserNameAndClientIdSql(String selectAccessTokensFromUserNameAndClientIdSql) {
|
||||
this.selectAccessTokensFromUserNameAndClientIdSql = selectAccessTokensFromUserNameAndClientIdSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokensFromClientIdSql(String selectAccessTokensFromClientIdSql) {
|
||||
this.selectAccessTokensFromClientIdSql = selectAccessTokensFromClientIdSql;
|
||||
}
|
||||
public JdbcTokenStore(DataSource dataSource) {
|
||||
Assert.notNull(dataSource, "DataSource required");
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
public JdbcTokenStore(JdbcTemplate jdbcTemplate) {
|
||||
Assert.notNull(jdbcTemplate, "jdbcTemplate required");
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
public void setAuthenticationKeyGenerator(AuthenticationKeyGenerator authenticationKeyGenerator) {
|
||||
this.authenticationKeyGenerator = authenticationKeyGenerator;
|
||||
}
|
||||
|
||||
public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
|
||||
OAuth2AccessToken accessToken = null;
|
||||
|
||||
String key = authenticationKeyGenerator.extractKey(authentication);
|
||||
try {
|
||||
accessToken = jdbcTemplate.queryForObject(selectAccessTokenFromAuthenticationSql,
|
||||
new RowMapper<OAuth2AccessToken>() {
|
||||
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return deserializeAccessToken(rs.getBytes(2));
|
||||
}
|
||||
}, key);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.debug("Failed to find access token for authentication " + authentication);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.error("Could not extract access token for authentication " + authentication, e);
|
||||
}
|
||||
|
||||
if (accessToken != null
|
||||
&& !key.equals(authenticationKeyGenerator.extractKey(readAuthentication(accessToken.getValue())))) {
|
||||
removeAccessToken(accessToken.getValue());
|
||||
// Keep the store consistent (maybe the same user is represented by this
|
||||
// authentication but the details have
|
||||
// changed)
|
||||
storeAccessToken(accessToken, authentication);
|
||||
}
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
|
||||
String refreshToken = null;
|
||||
if (token.getRefreshToken() != null) {
|
||||
refreshToken = token.getRefreshToken().getValue();
|
||||
}
|
||||
|
||||
if (readAccessToken(token.getValue()) != null) {
|
||||
removeAccessToken(token.getValue());
|
||||
}
|
||||
|
||||
jdbcTemplate.update(insertAccessTokenSql,
|
||||
new Object[] { extractTokenKey(token.getValue()), new SqlLobValue(serializeAccessToken(token)),
|
||||
authenticationKeyGenerator.extractKey(authentication),
|
||||
authentication.isClientOnly() ? null : authentication.getName(),
|
||||
authentication.getOAuth2Request().getClientId(),
|
||||
new SqlLobValue(serializeAuthentication(authentication)), extractTokenKey(refreshToken) },
|
||||
new int[] { Types.VARCHAR, Types.BLOB, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.BLOB,
|
||||
Types.VARCHAR });
|
||||
}
|
||||
|
||||
public OAuth2AccessToken readAccessToken(String tokenValue) {
|
||||
OAuth2AccessToken accessToken = null;
|
||||
|
||||
try {
|
||||
accessToken = jdbcTemplate.queryForObject(selectAccessTokenSql, new RowMapper<OAuth2AccessToken>() {
|
||||
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return deserializeAccessToken(rs.getBytes(2));
|
||||
}
|
||||
}, extractTokenKey(tokenValue));
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find access token for token " + tokenValue);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn("Failed to deserialize access token for " + tokenValue, e);
|
||||
removeAccessToken(tokenValue);
|
||||
}
|
||||
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void removeAccessToken(OAuth2AccessToken token) {
|
||||
removeAccessToken(token.getValue());
|
||||
}
|
||||
|
||||
public void removeAccessToken(String tokenValue) {
|
||||
jdbcTemplate.update(deleteAccessTokenSql, extractTokenKey(tokenValue));
|
||||
}
|
||||
|
||||
public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
|
||||
return readAuthentication(token.getValue());
|
||||
}
|
||||
|
||||
public OAuth2Authentication readAuthentication(String token) {
|
||||
OAuth2Authentication authentication = null;
|
||||
|
||||
try {
|
||||
authentication = jdbcTemplate.queryForObject(selectAccessTokenAuthenticationSql,
|
||||
new RowMapper<OAuth2Authentication>() {
|
||||
public OAuth2Authentication mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return deserializeAuthentication(rs.getBytes(2));
|
||||
}
|
||||
}, extractTokenKey(token));
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find access token for token " + token);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn("Failed to deserialize authentication for " + token, e);
|
||||
removeAccessToken(token);
|
||||
}
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
|
||||
jdbcTemplate.update(insertRefreshTokenSql,
|
||||
new Object[] { extractTokenKey(refreshToken.getValue()),
|
||||
new SqlLobValue(serializeRefreshToken(refreshToken)),
|
||||
new SqlLobValue(serializeAuthentication(authentication)) },
|
||||
new int[] { Types.VARCHAR, Types.BLOB, Types.BLOB });
|
||||
}
|
||||
|
||||
public OAuth2RefreshToken readRefreshToken(String token) {
|
||||
OAuth2RefreshToken refreshToken = null;
|
||||
|
||||
try {
|
||||
refreshToken = jdbcTemplate.queryForObject(selectRefreshTokenSql, new RowMapper<OAuth2RefreshToken>() {
|
||||
public OAuth2RefreshToken mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return deserializeRefreshToken(rs.getBytes(2));
|
||||
}
|
||||
}, extractTokenKey(token));
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find refresh token for token " + token);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn("Failed to deserialize refresh token for token " + token, e);
|
||||
removeRefreshToken(token);
|
||||
}
|
||||
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public void removeRefreshToken(OAuth2RefreshToken token) {
|
||||
removeRefreshToken(token.getValue());
|
||||
}
|
||||
|
||||
public void removeRefreshToken(String token) {
|
||||
jdbcTemplate.update(deleteRefreshTokenSql, extractTokenKey(token));
|
||||
}
|
||||
|
||||
public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) {
|
||||
return readAuthenticationForRefreshToken(token.getValue());
|
||||
}
|
||||
|
||||
public OAuth2Authentication readAuthenticationForRefreshToken(String value) {
|
||||
OAuth2Authentication authentication = null;
|
||||
|
||||
try {
|
||||
authentication = jdbcTemplate.queryForObject(selectRefreshTokenAuthenticationSql,
|
||||
new RowMapper<OAuth2Authentication>() {
|
||||
public OAuth2Authentication mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
return deserializeAuthentication(rs.getBytes(2));
|
||||
}
|
||||
}, extractTokenKey(value));
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find access token for token " + value);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn("Failed to deserialize access token for " + value, e);
|
||||
removeRefreshToken(value);
|
||||
}
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
|
||||
removeAccessTokenUsingRefreshToken(refreshToken.getValue());
|
||||
}
|
||||
|
||||
public void removeAccessTokenUsingRefreshToken(String refreshToken) {
|
||||
jdbcTemplate.update(deleteAccessTokenFromRefreshTokenSql, new Object[] { extractTokenKey(refreshToken) },
|
||||
new int[] { Types.VARCHAR });
|
||||
}
|
||||
|
||||
public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
|
||||
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>();
|
||||
|
||||
try {
|
||||
accessTokens = jdbcTemplate.query(selectAccessTokensFromClientIdSql, new SafeAccessTokenRowMapper(),
|
||||
clientId);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find access token for clientId " + clientId);
|
||||
}
|
||||
}
|
||||
accessTokens = removeNulls(accessTokens);
|
||||
|
||||
return accessTokens;
|
||||
}
|
||||
|
||||
public Collection<OAuth2AccessToken> findTokensByUserName(String userName) {
|
||||
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>();
|
||||
|
||||
try {
|
||||
accessTokens = jdbcTemplate.query(selectAccessTokensFromUserNameSql, new SafeAccessTokenRowMapper(),
|
||||
userName);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("Failed to find access token for userName " + userName);
|
||||
}
|
||||
accessTokens = removeNulls(accessTokens);
|
||||
|
||||
return accessTokens;
|
||||
}
|
||||
|
||||
public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
|
||||
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>();
|
||||
|
||||
try {
|
||||
accessTokens = jdbcTemplate.query(selectAccessTokensFromUserNameAndClientIdSql,
|
||||
new SafeAccessTokenRowMapper(), userName, clientId);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Failed to find access token for clientId " + clientId + " and userName " + userName);
|
||||
}
|
||||
}
|
||||
accessTokens = removeNulls(accessTokens);
|
||||
|
||||
return accessTokens;
|
||||
}
|
||||
|
||||
private List<OAuth2AccessToken> removeNulls(List<OAuth2AccessToken> accessTokens) {
|
||||
List<OAuth2AccessToken> tokens = new ArrayList<OAuth2AccessToken>();
|
||||
for (OAuth2AccessToken token : accessTokens) {
|
||||
if (token != null) {
|
||||
tokens.add(token);
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
protected String extractTokenKey(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
MessageDigest digest;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).");
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] bytes = digest.digest(value.getBytes("UTF-8"));
|
||||
return String.format("%032x", new BigInteger(1, bytes));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
|
||||
}
|
||||
}
|
||||
|
||||
private final class SafeAccessTokenRowMapper implements RowMapper<OAuth2AccessToken> {
|
||||
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
try {
|
||||
return deserializeAccessToken(rs.getBytes(2));
|
||||
} catch (IllegalArgumentException e) {
|
||||
String token = rs.getString(1);
|
||||
jdbcTemplate.update(deleteAccessTokenSql, token);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] serializeAccessToken(OAuth2AccessToken token) {
|
||||
return SerializationUtils.serialize(token);
|
||||
}
|
||||
|
||||
protected byte[] serializeRefreshToken(OAuth2RefreshToken token) {
|
||||
return SerializationUtils.serialize(token);
|
||||
}
|
||||
|
||||
protected byte[] serializeAuthentication(OAuth2Authentication authentication) {
|
||||
return SerializationUtils.serialize(authentication);
|
||||
}
|
||||
|
||||
protected OAuth2AccessToken deserializeAccessToken(byte[] token) {
|
||||
return SerializationUtils.deserialize(token);
|
||||
}
|
||||
|
||||
protected OAuth2RefreshToken deserializeRefreshToken(byte[] token) {
|
||||
return SerializationUtils.deserialize(token);
|
||||
}
|
||||
|
||||
protected OAuth2Authentication deserializeAuthentication(byte[] authentication) {
|
||||
return SerializationUtils.deserialize(authentication);
|
||||
}
|
||||
|
||||
public void setInsertAccessTokenSql(String insertAccessTokenSql) {
|
||||
this.insertAccessTokenSql = insertAccessTokenSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokenSql(String selectAccessTokenSql) {
|
||||
this.selectAccessTokenSql = selectAccessTokenSql;
|
||||
}
|
||||
|
||||
public void setDeleteAccessTokenSql(String deleteAccessTokenSql) {
|
||||
this.deleteAccessTokenSql = deleteAccessTokenSql;
|
||||
}
|
||||
|
||||
public void setInsertRefreshTokenSql(String insertRefreshTokenSql) {
|
||||
this.insertRefreshTokenSql = insertRefreshTokenSql;
|
||||
}
|
||||
|
||||
public void setSelectRefreshTokenSql(String selectRefreshTokenSql) {
|
||||
this.selectRefreshTokenSql = selectRefreshTokenSql;
|
||||
}
|
||||
|
||||
public void setDeleteRefreshTokenSql(String deleteRefreshTokenSql) {
|
||||
this.deleteRefreshTokenSql = deleteRefreshTokenSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokenAuthenticationSql(String selectAccessTokenAuthenticationSql) {
|
||||
this.selectAccessTokenAuthenticationSql = selectAccessTokenAuthenticationSql;
|
||||
}
|
||||
|
||||
public void setSelectRefreshTokenAuthenticationSql(String selectRefreshTokenAuthenticationSql) {
|
||||
this.selectRefreshTokenAuthenticationSql = selectRefreshTokenAuthenticationSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokenFromAuthenticationSql(String selectAccessTokenFromAuthenticationSql) {
|
||||
this.selectAccessTokenFromAuthenticationSql = selectAccessTokenFromAuthenticationSql;
|
||||
}
|
||||
|
||||
public void setDeleteAccessTokenFromRefreshTokenSql(String deleteAccessTokenFromRefreshTokenSql) {
|
||||
this.deleteAccessTokenFromRefreshTokenSql = deleteAccessTokenFromRefreshTokenSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokensFromUserNameSql(String selectAccessTokensFromUserNameSql) {
|
||||
this.selectAccessTokensFromUserNameSql = selectAccessTokensFromUserNameSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokensFromUserNameAndClientIdSql(String selectAccessTokensFromUserNameAndClientIdSql) {
|
||||
this.selectAccessTokensFromUserNameAndClientIdSql = selectAccessTokensFromUserNameAndClientIdSql;
|
||||
}
|
||||
|
||||
public void setSelectAccessTokensFromClientIdSql(String selectAccessTokensFromClientIdSql) {
|
||||
this.selectAccessTokensFromClientIdSql = selectAccessTokensFromClientIdSql;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,9 @@ import org.springframework.security.crypto.codec.Base64;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper that translates between JWT encoded token values and OAuth authentication information (in both directions).
|
||||
* Also acts as a {@link TokenEnhancer} when tokens are granted.
|
||||
* Helper that translates between JWT encoded token values and OAuth
|
||||
* authentication information (in both directions). Also acts as a
|
||||
* {@link TokenEnhancer} when tokens are granted.
|
||||
*
|
||||
* @see TokenEnhancer
|
||||
* @see AccessTokenConverter
|
||||
@@ -60,219 +61,218 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class JwtAccessTokenConverter implements TokenEnhancer, AccessTokenConverter, InitializingBean {
|
||||
|
||||
/**
|
||||
* Field name for token id.
|
||||
*/
|
||||
public static final String TOKEN_ID = AccessTokenConverter.JTI;
|
||||
/**
|
||||
* Field name for token id.
|
||||
*/
|
||||
public static final String TOKEN_ID = AccessTokenConverter.JTI;
|
||||
|
||||
private static final Log logger = LogFactory.getLog(JwtAccessTokenConverter.class);
|
||||
private static final Log logger = LogFactory.getLog(JwtAccessTokenConverter.class);
|
||||
|
||||
private AccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
|
||||
private AccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
|
||||
|
||||
private JsonParser objectMapper = JsonParserFactory.create();
|
||||
private JsonParser objectMapper = JsonParserFactory.create();
|
||||
|
||||
private String verifierKey = new RandomValueStringGenerator().generate();
|
||||
private String verifierKey = new RandomValueStringGenerator().generate();
|
||||
|
||||
private Signer signer = new MacSigner(verifierKey);
|
||||
private Signer signer = new MacSigner(verifierKey);
|
||||
|
||||
private String signingKey = verifierKey;
|
||||
private String signingKey = verifierKey;
|
||||
|
||||
private SignatureVerifier verifier;
|
||||
private SignatureVerifier verifier;
|
||||
|
||||
/**
|
||||
* @param tokenConverter the tokenConverter to set
|
||||
*/
|
||||
public void setAccessTokenConverter(AccessTokenConverter tokenConverter) {
|
||||
this.tokenConverter = tokenConverter;
|
||||
}
|
||||
/**
|
||||
* @param tokenConverter the tokenConverter to set
|
||||
*/
|
||||
public void setAccessTokenConverter(AccessTokenConverter tokenConverter) {
|
||||
this.tokenConverter = tokenConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tokenConverter in use
|
||||
*/
|
||||
public AccessTokenConverter getAccessTokenConverter() {
|
||||
return tokenConverter;
|
||||
}
|
||||
/**
|
||||
* @return the tokenConverter in use
|
||||
*/
|
||||
public AccessTokenConverter getAccessTokenConverter() {
|
||||
return tokenConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
|
||||
return tokenConverter.convertAccessToken(token, authentication);
|
||||
}
|
||||
@Override
|
||||
public Map<String, ?> convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
|
||||
return tokenConverter.convertAccessToken(token, authentication);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessToken extractAccessToken(String value, Map<String, ?> map) {
|
||||
return tokenConverter.extractAccessToken(value, map);
|
||||
}
|
||||
@Override
|
||||
public OAuth2AccessToken extractAccessToken(String value, Map<String, ?> map) {
|
||||
return tokenConverter.extractAccessToken(value, map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
|
||||
return tokenConverter.extractAuthentication(map);
|
||||
}
|
||||
@Override
|
||||
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
|
||||
return tokenConverter.extractAuthentication(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the verification key for the token signatures.
|
||||
*
|
||||
* @return the key used to verify tokens
|
||||
*/
|
||||
public Map<String, String> getKey() {
|
||||
Map<String, String> result = new LinkedHashMap<String, String>();
|
||||
result.put("alg", signer.algorithm());
|
||||
result.put("value", verifierKey);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Get the verification key for the token signatures.
|
||||
*
|
||||
* @return the key used to verify tokens
|
||||
*/
|
||||
public Map<String, String> getKey() {
|
||||
Map<String, String> result = new LinkedHashMap<String, String>();
|
||||
result.put("alg", signer.algorithm());
|
||||
result.put("value", verifierKey);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setKeyPair(KeyPair keyPair) {
|
||||
PrivateKey privateKey = keyPair.getPrivate();
|
||||
Assert.state(privateKey instanceof RSAPrivateKey, "KeyPair must be an RSA ");
|
||||
signer = new RsaSigner((RSAPrivateKey) privateKey);
|
||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
verifier = new RsaVerifier(publicKey);
|
||||
verifierKey = "-----BEGIN PUBLIC KEY-----\n" + new String(Base64.encode(publicKey.getEncoded())) + "\n-----END PUBLIC KEY-----";
|
||||
}
|
||||
/**
|
||||
* Sets the JWT signing key. It can be either a simple MAC key or an RSA key. RSA keys should be in OpenSSH format,
|
||||
* as produced by <tt>ssh-keygen</tt>.
|
||||
*
|
||||
* @param key the key to be used for signing JWTs.
|
||||
*/
|
||||
public void setSigningKey(String key) {
|
||||
Assert.hasText(key);
|
||||
key = key.trim();
|
||||
public void setKeyPair(KeyPair keyPair) {
|
||||
PrivateKey privateKey = keyPair.getPrivate();
|
||||
Assert.state(privateKey instanceof RSAPrivateKey, "KeyPair must be an RSA ");
|
||||
signer = new RsaSigner((RSAPrivateKey) privateKey);
|
||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
verifier = new RsaVerifier(publicKey);
|
||||
verifierKey = "-----BEGIN PUBLIC KEY-----\n" + new String(Base64.encode(publicKey.getEncoded()))
|
||||
+ "\n-----END PUBLIC KEY-----";
|
||||
}
|
||||
|
||||
this.signingKey = key;
|
||||
/**
|
||||
* Sets the JWT signing key. It can be either a simple MAC key or an RSA key.
|
||||
* RSA keys should be in OpenSSH format, as produced by <tt>ssh-keygen</tt>.
|
||||
*
|
||||
* @param key the key to be used for signing JWTs.
|
||||
*/
|
||||
public void setSigningKey(String key) {
|
||||
Assert.hasText(key);
|
||||
key = key.trim();
|
||||
|
||||
if (isPublic(key)) {
|
||||
signer = new RsaSigner(key);
|
||||
logger.info("Configured with RSA signing key");
|
||||
}
|
||||
else {
|
||||
// Assume it's a MAC key
|
||||
this.verifierKey = key;
|
||||
signer = new MacSigner(key);
|
||||
}
|
||||
}
|
||||
this.signingKey = key;
|
||||
|
||||
/**
|
||||
* @return true if the key has a public verifier
|
||||
*/
|
||||
private boolean isPublic(String key) {
|
||||
return key.startsWith("-----BEGIN");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the signing key is a public key
|
||||
*/
|
||||
public boolean isPublic() {
|
||||
return signer instanceof RsaSigner;
|
||||
}
|
||||
if (isPublic(key)) {
|
||||
signer = new RsaSigner(key);
|
||||
logger.info("Configured with RSA signing key");
|
||||
} else {
|
||||
// Assume it's a MAC key
|
||||
this.verifierKey = key;
|
||||
signer = new MacSigner(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The key used for verifying signatures produced by this class. This is not used but is returned from the endpoint
|
||||
* to allow resource servers to obtain the key.
|
||||
*
|
||||
* For an HMAC key it will be the same value as the signing key and does not need to be set. For and RSA key, it
|
||||
* should be set to the String representation of the public key, in a standard format (e.g. OpenSSH keys)
|
||||
*
|
||||
* @param key the signature verification key (typically an RSA public key)
|
||||
*/
|
||||
public void setVerifierKey(String key) {
|
||||
this.verifierKey = key;
|
||||
try {
|
||||
new RsaSigner(verifierKey);
|
||||
throw new IllegalArgumentException("Private key cannot be set as verifierKey property");
|
||||
}
|
||||
catch (Exception expected) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return true if the key has a public verifier
|
||||
*/
|
||||
private boolean isPublic(String key) {
|
||||
return key.startsWith("-----BEGIN");
|
||||
}
|
||||
|
||||
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
|
||||
DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);
|
||||
Map<String, Object> info = new LinkedHashMap<String, Object>(accessToken.getAdditionalInformation());
|
||||
String tokenId = result.getValue();
|
||||
if (!info.containsKey(TOKEN_ID)) {
|
||||
info.put(TOKEN_ID, tokenId);
|
||||
}
|
||||
result.setAdditionalInformation(info);
|
||||
result.setValue(encode(result, authentication));
|
||||
OAuth2RefreshToken refreshToken = result.getRefreshToken();
|
||||
if (refreshToken != null) {
|
||||
DefaultOAuth2AccessToken encodedRefreshToken = new DefaultOAuth2AccessToken(accessToken);
|
||||
encodedRefreshToken.setValue(refreshToken.getValue());
|
||||
Map<String, Object> refreshTokenInfo = new LinkedHashMap<String, Object>(accessToken.getAdditionalInformation());
|
||||
refreshTokenInfo.put(TOKEN_ID, encodedRefreshToken.getValue());
|
||||
encodedRefreshToken.setAdditionalInformation(refreshTokenInfo);
|
||||
DefaultOAuth2RefreshToken token = new DefaultOAuth2RefreshToken(encode(encodedRefreshToken, authentication));
|
||||
if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
|
||||
Date expiration = ((ExpiringOAuth2RefreshToken) refreshToken).getExpiration();
|
||||
encodedRefreshToken.setExpiration(expiration);
|
||||
token = new DefaultExpiringOAuth2RefreshToken(encode(encodedRefreshToken, authentication), expiration);
|
||||
}
|
||||
result.setRefreshToken(token);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* @return true if the signing key is a public key
|
||||
*/
|
||||
public boolean isPublic() {
|
||||
return signer instanceof RsaSigner;
|
||||
}
|
||||
|
||||
protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
|
||||
String content;
|
||||
try {
|
||||
content = objectMapper.formatMap(tokenConverter.convertAccessToken(accessToken, authentication));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException("Cannot convert access token to JSON", e);
|
||||
}
|
||||
String token = JwtHelper.encode(content, signer).getEncoded();
|
||||
return token;
|
||||
}
|
||||
/**
|
||||
* The key used for verifying signatures produced by this class. This is not
|
||||
* used but is returned from the endpoint to allow resource servers to obtain
|
||||
* the key.
|
||||
*
|
||||
* For an HMAC key it will be the same value as the signing key and does not
|
||||
* need to be set. For and RSA key, it should be set to the String
|
||||
* representation of the public key, in a standard format (e.g. OpenSSH keys)
|
||||
*
|
||||
* @param key the signature verification key (typically an RSA public key)
|
||||
*/
|
||||
public void setVerifierKey(String key) {
|
||||
this.verifierKey = key;
|
||||
try {
|
||||
new RsaSigner(verifierKey);
|
||||
throw new IllegalArgumentException("Private key cannot be set as verifierKey property");
|
||||
} catch (Exception expected) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, Object> decode(String token) {
|
||||
try {
|
||||
Jwt jwt = JwtHelper.decodeAndVerify(token, verifier);
|
||||
String content = jwt.getClaims();
|
||||
Map<String, Object> map = objectMapper.parseMap(content);
|
||||
if (map.containsKey(EXP) && map.get(EXP) instanceof Integer) {
|
||||
Integer intValue = (Integer) map.get(EXP);
|
||||
map.put(EXP, new Long(intValue));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new InvalidTokenException("Cannot convert access token to JSON", e);
|
||||
}
|
||||
}
|
||||
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
|
||||
DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);
|
||||
Map<String, Object> info = new LinkedHashMap<String, Object>(accessToken.getAdditionalInformation());
|
||||
String tokenId = result.getValue();
|
||||
if (!info.containsKey(TOKEN_ID)) {
|
||||
info.put(TOKEN_ID, tokenId);
|
||||
}
|
||||
result.setAdditionalInformation(info);
|
||||
result.setValue(encode(result, authentication));
|
||||
OAuth2RefreshToken refreshToken = result.getRefreshToken();
|
||||
if (refreshToken != null) {
|
||||
DefaultOAuth2AccessToken encodedRefreshToken = new DefaultOAuth2AccessToken(accessToken);
|
||||
encodedRefreshToken.setValue(refreshToken.getValue());
|
||||
Map<String, Object> refreshTokenInfo = new LinkedHashMap<String, Object>(
|
||||
accessToken.getAdditionalInformation());
|
||||
refreshTokenInfo.put(TOKEN_ID, encodedRefreshToken.getValue());
|
||||
encodedRefreshToken.setAdditionalInformation(refreshTokenInfo);
|
||||
DefaultOAuth2RefreshToken token = new DefaultOAuth2RefreshToken(
|
||||
encode(encodedRefreshToken, authentication));
|
||||
if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
|
||||
Date expiration = ((ExpiringOAuth2RefreshToken) refreshToken).getExpiration();
|
||||
encodedRefreshToken.setExpiration(expiration);
|
||||
token = new DefaultExpiringOAuth2RefreshToken(encode(encodedRefreshToken, authentication), expiration);
|
||||
}
|
||||
result.setRefreshToken(token);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// Check the signing and verification keys match
|
||||
if (signer instanceof RsaSigner) {
|
||||
RsaVerifier verifier;
|
||||
try {
|
||||
verifier = new RsaVerifier(verifierKey);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("Unable to create an RSA verifier from verifierKey");
|
||||
return;
|
||||
}
|
||||
protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
|
||||
String content;
|
||||
try {
|
||||
content = objectMapper.formatMap(tokenConverter.convertAccessToken(accessToken, authentication));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Cannot convert access token to JSON", e);
|
||||
}
|
||||
String token = JwtHelper.encode(content, signer).getEncoded();
|
||||
return token;
|
||||
}
|
||||
|
||||
byte[] test = "test".getBytes();
|
||||
try {
|
||||
verifier.verify(test, signer.sign(test));
|
||||
logger.info("Signing and verification RSA keys match");
|
||||
}
|
||||
catch (InvalidSignatureException e) {
|
||||
logger.error("Signing and verification RSA keys do not match");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Avoid a race condition where setters are called in the wrong order. Use of == is intentional.
|
||||
Assert.state(this.signingKey == this.verifierKey,
|
||||
"For MAC signing you do not need to specify the verifier key separately, and if you do it must match the signing key");
|
||||
}
|
||||
SignatureVerifier verifier = new MacSigner(verifierKey);
|
||||
try {
|
||||
verifier = new RsaVerifier(verifierKey);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("Unable to create an RSA verifier from verifierKey");
|
||||
}
|
||||
this.verifier = verifier;
|
||||
}
|
||||
protected Map<String, Object> decode(String token) {
|
||||
try {
|
||||
Jwt jwt = JwtHelper.decodeAndVerify(token, verifier);
|
||||
String content = jwt.getClaims();
|
||||
Map<String, Object> map = objectMapper.parseMap(content);
|
||||
if (map.containsKey(EXP) && map.get(EXP) instanceof Integer) {
|
||||
Integer intValue = (Integer) map.get(EXP);
|
||||
map.put(EXP, new Long(intValue));
|
||||
}
|
||||
return map;
|
||||
} catch (Exception e) {
|
||||
throw new InvalidTokenException("Cannot convert access token to JSON", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// Check the signing and verification keys match
|
||||
if (signer instanceof RsaSigner) {
|
||||
RsaVerifier verifier;
|
||||
try {
|
||||
verifier = new RsaVerifier(verifierKey);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Unable to create an RSA verifier from verifierKey");
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] test = "test".getBytes();
|
||||
try {
|
||||
verifier.verify(test, signer.sign(test));
|
||||
logger.info("Signing and verification RSA keys match");
|
||||
} catch (InvalidSignatureException e) {
|
||||
logger.error("Signing and verification RSA keys do not match");
|
||||
}
|
||||
} else {
|
||||
// Avoid a race condition where setters are called in the wrong order. Use of ==
|
||||
// is intentional.
|
||||
Assert.state(this.signingKey == this.verifierKey,
|
||||
"For MAC signing you do not need to specify the verifier key separately, and if you do it must match the signing key");
|
||||
}
|
||||
SignatureVerifier verifier = new MacSigner(verifierKey);
|
||||
try {
|
||||
verifier = new RsaVerifier(verifierKey);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Unable to create an RSA verifier from verifierKey");
|
||||
}
|
||||
this.verifier = verifier;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user