Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
74 views
in Technique[技术] by (71.8m points)

java - TokenStore in Spring Security 5.x after removal of Spring Security OAuth 2.x

Are there plans to provide TokenStore in Spring Security 5.x after end of life of Spring Security OAuth 2.x? Currently we are using JdbcTokenStore to cache the tokens, which later on are used to accomplish long running processes on behalf of the user.

Here is the current application setup:

  • App is running on several instances in Cloud Foundry
  • App uses postgre as backing service
  • App receives oauth tokens
  • App acts on behalf of the user, by using the tokens, to call Cloud Controller. Actual computing and external calls can be done on different app instances.

The current flow regarding the tokens is:

  1. App clients call some of the app instances and trigger long running process, let's say app instance #0 is called. Oauth token is provided in the API call.

  2. Custom filter (before="PRE_AUTH_FILTER") on #0 stores the token in JdbcTokenStore. security-context.xml

    <sec:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
    ....
    <oauth:resource-server id="resourceServerFilter" resource-id="springsec"
    token-services-ref="customTokenServices" />
    

CustomTokenServices

@Override
public OAuth2Authentication loadAuthentication(String tokenString) {

    // Get an access token for the specified token string
    OAuth2AccessToken token = readAccessToken(tokenString);

    // Check if a valid access token has been obtained
    if (token == null) {
        logToAuditLogAndThrow("Invalid access token");
    }

    // Check if the token has expired and there is no refresh token
    if (token.isExpired() && token.getRefreshToken() == null) {
        tokenStore.removeAccessToken(token);
        logToAuditLogAndThrow(MessageFormat.format("The access token has expired on {0}", token.getExpiration()));
    }

    // Check if an authentication for this token already exists in the token store
    OAuth2Authentication auth = tokenStore.readAuthentication(token);
    if (auth == null) {
        // Create an authentication for the token and store it in the token store
        TokenProperties tokenProperties = TokenProperties.fromToken(token);
        auth = SecurityUtil.createAuthentication(tokenProperties.getClientId(), token.getScope(), SecurityUtil.getTokenUserInfo(token));
        try {
            LOGGER.info(MessageFormat.format(Messages.STORING_TOKEN_FOR_USER_0_WITH_EXPIRATION_TIME_1, tokenProperties.getUserName(),
                                             token.getExpiresIn()));
            tokenStore.storeAccessToken(token, auth);
        } catch (DataIntegrityViolationException e) {
            LOGGER.debug(Messages.ERROR_STORING_TOKEN_DUE_TO_INTEGRITY_VIOLATION, e);
            // Ignoring the exception as the token and authentication are already persisted by another client.
        }
    }

    return auth;
}

@Override
public OAuth2AccessToken readAccessToken(String tokenString) {
    // Check if an access token for the received token string already exists in the token store
    OAuth2AccessToken token = tokenStore.readAccessToken(tokenString);
    if (token != null) {
        LOGGER.debug("Stored token value: " + token.getValue());
        LOGGER.debug("Stored token type: " + token.getTokenType());
        LOGGER.debug("Stored token expires in: " + token.getExpiresIn());
    } else {
        token = tokenParserChain.parse(tokenString);
    }
    return token;
}
  1. Custom filter (position="LAST") on #0, reads the token from JdbcToken store and performs some basic validations, such as expiration time, desired scopes and so on. If everything is ok, continue. security-context.xml

    <sec:custom-filter ref="compositeUriAuthorizationFilter" position="LAST" />
    
  2. Actual execution of the long process starts, where it is split in smaller processing steps. Each processing step can be executed on different app instance depending on the load. The esential thing is that everything is stored in DB which serves as single source of truth. NOTE Next steps describe basically what one step does

  3. Processing step starts, let's say on app instance #1. App searches and finds tokens in JdbcTokenStore by user, who started the process. The token that has largest expiration time is get

TokenService

public OAuth2AccessToken getToken(String userName) {
        OAuth2AccessToken token = null;
        Collection<OAuth2AccessToken> tokens = tokenStore.findTokensByUserName(userName);
        for (OAuth2AccessToken tokenx : tokens) {
            // If a token is already found, overwrite it if the new token:
            // 1) has a refresh token, and the current token hasn't, or
            // 2) expires later than the current token
            if (token == null || ((tokenx.getRefreshToken() != null) && (token.getRefreshToken() == null))
                || (tokenx.getExpiresIn() > token.getExpiresIn())) {
                token = tokenx;
            }
        }
        return token;
    }
  1. The token is used for next external calls to Cloud Controller.

CloudControllerClientProvider

private OAuth2AccessToken getValidToken(String userName) {
        OAuth2AccessToken token = tokenService.getToken(userName);
        if (token == null) {
            throw new SLException(Messages.NO_VALID_TOKEN_FOUND, userName);
        }

        if (token.isExpired() && token.getRefreshToken() == null) {
            tokenService.removeToken(token);
            throw new SLException(Messages.TOKEN_EXPIRED, userName);
        }

        return token;
    }
...
public CloudControllerClient getControllerClient(String userName) {
        try {
            return clientFactory.createClient(getValidToken(userName));
        } catch (CloudOperationException e) {
            throw new SLException(e, Messages.CANT_CREATE_CLIENT);
        }
    }

Best Regards, Boyan

question from:https://stackoverflow.com/questions/65904062/tokenstore-in-spring-security-5-x-after-removal-of-spring-security-oauth-2-x

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...