Skip to content

Commit

Permalink
fix(oxauth): simplified race condition fix for refresh token usage (v…
Browse files Browse the repository at this point in the history
…ersion_4.5.5)

#1909
  • Loading branch information
yuriyz committed Jul 31, 2024
1 parent 33c50fa commit 66144e6
Showing 1 changed file with 34 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.gluu.oxauth.audit.ApplicationAuditLogger;
import org.gluu.oxauth.model.audit.Action;
Expand All @@ -18,6 +19,7 @@
import org.gluu.oxauth.model.configuration.AppConfiguration;
import org.gluu.oxauth.model.crypto.binding.TokenBindingMessage;
import org.gluu.oxauth.model.error.ErrorResponseFactory;
import org.gluu.oxauth.model.ldap.TokenLdap;
import org.gluu.oxauth.model.registration.Client;
import org.gluu.oxauth.model.session.SessionClient;
import org.gluu.oxauth.model.session.SessionId;
Expand Down Expand Up @@ -52,6 +54,7 @@
import javax.ws.rs.core.SecurityContext;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.ConcurrentMap;

import static org.gluu.oxauth.util.ServerUtil.prepareForLogs;

Expand Down Expand Up @@ -112,10 +115,12 @@ public class TokenRestWebServiceImpl implements TokenRestWebService {

@Inject
private DeviceAuthorizationService deviceAuthorizationService;

@Inject
private ExternalUpdateTokenService externalUpdateTokenService;

private final ConcurrentMap<String, String> refreshTokenLocalLock = Maps.newConcurrentMap();

@Override
public Response requestAccessToken(String grantType, String code,
String redirectUri, String username, String password, String scope,
Expand Down Expand Up @@ -234,7 +239,7 @@ grantType, code, redirectUri, username, refreshToken, clientId, prepareForLogs(r
}
return null;
};

ExternalUpdateTokenContext context = ExternalUpdateTokenContext.of(executionContext);
Function<JsonWebResponse, Void> postProcessor = externalUpdateTokenService.buildModifyIdTokenProcessor(context);

Expand Down Expand Up @@ -305,8 +310,10 @@ grantType, code, redirectUri, username, refreshToken, clientId, prepareForLogs(r
null, authorizationGrant, includeIdTokenClaims, idTokenPreProcessing, postProcessor, executionContext);
}

if (reToken != null && refreshToken != null) {
grantService.removeByCode(refreshToken); // remove refresh token after access token and id_token is created.
TokenLdap lockedRefreshToken = lockRefreshToken(refreshToken);
if (lockedRefreshToken == null) {
log.trace("Failed to lock refresh token {}", refreshToken);
return response(error(400, TokenErrorResponseType.INVALID_GRANT, "Failed to lock refresh token."), oAuth2AuditLog);
}

builder.entity(getJSonResponse(accToken,
Expand Down Expand Up @@ -553,6 +560,29 @@ grantType, code, redirectUri, username, refreshToken, clientId, prepareForLogs(r
return response(builder, oAuth2AuditLog);
}

private TokenLdap lockRefreshToken(String refreshTokenCode) {
try {
synchronized (refreshTokenLocalLock) {
if (refreshTokenLocalLock.containsKey(refreshTokenCode)) {
log.trace("Refresh token is already used by another request. Refresh token code: {}", refreshTokenCode);
return null;
}

refreshTokenLocalLock.put(refreshTokenCode, refreshTokenCode);

final TokenLdap token = grantService.getGrantByCode(refreshTokenCode);
grantService.remove(token);
return token;
}
} catch (Exception e) {
// ignore
log.trace(e.getMessage(), e);
} finally {
refreshTokenLocalLock.remove(refreshTokenCode);
}
return null;
}

private void checkUser(AuthorizationGrant authorizationGrant, OAuth2AuditLog oAuth2AuditLog) {
if (!appConfiguration.getCheckUserPresenceOnRefreshToken()) {
return;
Expand Down

0 comments on commit 66144e6

Please sign in to comment.