org.springframework.security.oauth2.provider.token.store.JwtTokenStore Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-security-oauth2 Show documentation
Show all versions of spring-security-oauth2 Show documentation
Module for providing OAuth2 support to Spring Security
/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.springframework.security.oauth2.provider.token.store;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken;
import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.token.TokenStore;
import java.util.*;
/**
* A {@link TokenStore} implementation that just reads data from the tokens themselves. Not really a store since it
* never persists anything, and methods like {@link #getAccessToken(OAuth2Authentication)} always return null. But
* nevertheless a useful tool since it translates access tokens to and from authentications. Use this wherever a
* {@link TokenStore} is needed, but remember to use the same {@link JwtAccessTokenConverter} instance (or one with the same
* verifier) as was used when the tokens were minted.
*
* @author Dave Syer
*
*/
public class JwtTokenStore implements TokenStore {
private JwtAccessTokenConverter jwtTokenEnhancer;
private ApprovalStore approvalStore;
/**
* Create a JwtTokenStore with this token enhancer (should be shared with the DefaultTokenServices if used).
*
* @param jwtTokenEnhancer
*/
public JwtTokenStore(JwtAccessTokenConverter jwtTokenEnhancer) {
this.jwtTokenEnhancer = jwtTokenEnhancer;
}
/**
* ApprovalStore to be used to validate and restrict refresh tokens.
*
* @param approvalStore the approvalStore to set
*/
public void setApprovalStore(ApprovalStore approvalStore) {
this.approvalStore = approvalStore;
}
@Override
public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
return readAuthentication(token.getValue());
}
@Override
public OAuth2Authentication readAuthentication(String token) {
return jwtTokenEnhancer.extractAuthentication(jwtTokenEnhancer.decode(token));
}
@Override
public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
}
@Override
public OAuth2AccessToken readAccessToken(String tokenValue) {
OAuth2AccessToken accessToken = convertAccessToken(tokenValue);
if (jwtTokenEnhancer.isRefreshToken(accessToken)) {
throw new InvalidTokenException("Encoded token is a refresh token");
}
return accessToken;
}
private OAuth2AccessToken convertAccessToken(String tokenValue) {
return jwtTokenEnhancer.extractAccessToken(tokenValue, jwtTokenEnhancer.decode(tokenValue));
}
@Override
public void removeAccessToken(OAuth2AccessToken token) {
// gh-807 Approvals (if any) should only be removed when Refresh Tokens are removed (or expired)
}
@Override
public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
}
@Override
public OAuth2RefreshToken readRefreshToken(String tokenValue) {
OAuth2AccessToken encodedRefreshToken = convertAccessToken(tokenValue);
OAuth2RefreshToken refreshToken = createRefreshToken(encodedRefreshToken);
if (approvalStore != null) {
OAuth2Authentication authentication = readAuthentication(tokenValue);
if (authentication.getUserAuthentication() != null) {
String userId = authentication.getUserAuthentication().getName();
String clientId = authentication.getOAuth2Request().getClientId();
Collection approvals = approvalStore.getApprovals(userId, clientId);
Collection approvedScopes = new HashSet();
for (Approval approval : approvals) {
if (approval.isApproved()) {
approvedScopes.add(approval.getScope());
}
}
if (!approvedScopes.containsAll(authentication.getOAuth2Request().getScope())) {
return null;
}
}
}
return refreshToken;
}
private OAuth2RefreshToken createRefreshToken(OAuth2AccessToken encodedRefreshToken) {
if (!jwtTokenEnhancer.isRefreshToken(encodedRefreshToken)) {
throw new InvalidTokenException("Encoded token is not a refresh token");
}
if (encodedRefreshToken.getExpiration()!=null) {
return new DefaultExpiringOAuth2RefreshToken(encodedRefreshToken.getValue(),
encodedRefreshToken.getExpiration());
}
return new DefaultOAuth2RefreshToken(encodedRefreshToken.getValue());
}
@Override
public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) {
return readAuthentication(token.getValue());
}
@Override
public void removeRefreshToken(OAuth2RefreshToken token) {
remove(token.getValue());
}
@Override
public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
// gh-807 Approvals (if any) should only be removed when Refresh Tokens are removed (or expired)
}
@Override
public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
// We don't want to accidentally issue a token, and we have no way to reconstruct the refresh token
return null;
}
@Override
public Collection findTokensByClientIdAndUserName(String clientId, String userName) {
return Collections.emptySet();
}
@Override
public Collection findTokensByClientId(String clientId) {
return Collections.emptySet();
}
public void setTokenEnhancer(JwtAccessTokenConverter tokenEnhancer) {
this.jwtTokenEnhancer = tokenEnhancer;
}
private void remove(String token) {
if (approvalStore != null) {
OAuth2Authentication auth = readAuthentication(token);
String clientId = auth.getOAuth2Request().getClientId();
Authentication user = auth.getUserAuthentication();
if (user != null) {
Collection approvals = new ArrayList();
for (String scope : auth.getOAuth2Request().getScope()) {
approvals.add(new Approval(user.getName(), clientId, scope, new Date(), ApprovalStatus.APPROVED));
}
approvalStore.revokeApprovals(approvals);
}
}
}
}