Skip to content
Snippets Groups Projects
Commit ac2ecbab authored by Dominik František Bučík's avatar Dominik František Bučík
Browse files

chore: merge branch 'fix_refresh_audience' into 'main'

fix: :bug: Set correct audience for refreshed access_token

See merge request !372
parents 6f87a32e 54652852
Branches
Tags
1 merge request!372fix: 🐛 Set correct audience for refreshed access_token
Pipeline #392153 passed
......@@ -64,6 +64,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
......@@ -75,6 +77,7 @@ import static cz.muni.ics.openid.connect.request.ConnectRequestParameters.CODE_C
import static cz.muni.ics.openid.connect.request.ConnectRequestParameters.CODE_CHALLENGE_METHOD;
import static cz.muni.ics.openid.connect.request.ConnectRequestParameters.CODE_VERIFIER;
import static cz.muni.ics.openid.connect.request.ConnectRequestParameters.RESOURCE;
import static org.springframework.security.oauth2.provider.token.AccessTokenConverter.AUD;
/**
......@@ -241,12 +244,6 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
token.setAuthenticationHolder(authHolder);
// attach a refresh token, if this client is allowed to request them and the user gets the offline scope
if (client.isAllowRefresh() && token.getScope().contains(SystemScopeService.OFFLINE_ACCESS)) {
OAuth2RefreshTokenEntity savedRefreshToken = createRefreshToken(client, authHolder);
token.setRefreshToken(savedRefreshToken);
}
//Add approved site reference, if any
OAuth2Request originalAuthRequest = authHolder.getAuthentication().getOAuth2Request();
......@@ -273,6 +270,16 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
OAuth2AccessTokenEntity enhancedToken = (OAuth2AccessTokenEntity) tokenEnhancer.enhance(token, authentication);
// attach a refresh token, if this client is allowed to request them and the user gets the offline scope
if (client.isAllowRefresh() && token.getScope().contains(SystemScopeService.OFFLINE_ACCESS)) {
OAuth2RefreshTokenEntity savedRefreshToken = createRefreshToken(
client,
authHolder,
(Set<String>) token.getAdditionalInformation().getOrDefault(RESOURCE, new HashSet<>())
);
token.setRefreshToken(savedRefreshToken);
}
OAuth2AccessTokenEntity savedToken = saveAccessToken(enhancedToken);
if (savedToken.getRefreshToken() != null) {
tokenRepository.saveRefreshToken(savedToken.getRefreshToken()); // make sure we save any changes that might have been enhanced
......@@ -282,7 +289,9 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
}
private OAuth2RefreshTokenEntity createRefreshToken(ClientDetailsEntity client, AuthenticationHolderEntity authHolder) {
private OAuth2RefreshTokenEntity createRefreshToken(ClientDetailsEntity client,
AuthenticationHolderEntity authHolder,
Set<String> resources) {
OAuth2RefreshTokenEntity refreshToken = new OAuth2RefreshTokenEntity(); //refreshTokenFactory.createNewRefreshToken();
JWTClaimsSet.Builder refreshClaims = new JWTClaimsSet.Builder();
......@@ -296,10 +305,13 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
// set a random identifier
refreshClaims.jwtID(UUID.randomUUID().toString());
refreshClaims.issuer(configBean.getIssuer());
String audience = client.getClientId();
if (!Strings.isNullOrEmpty(audience)) {
refreshClaims.audience(Lists.newArrayList(audience));
if (resources == null || resources.isEmpty()) {
String audience = client.getClientId();
if (!Strings.isNullOrEmpty(audience)) {
refreshClaims.audience(Lists.newArrayList(audience));
}
} else {
refreshClaims.audience(new ArrayList<>(resources));
}
JWTClaimsSet claims = refreshClaims.build();
......@@ -365,15 +377,22 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
OAuth2AccessTokenEntity token = new OAuth2AccessTokenEntity();
// get the stored scopes from the authentication holder's authorization request; these are the scopes associated with the refresh token
Set<String> refreshScopesRequested = new HashSet<>(refreshToken.getAuthenticationHolder().getAuthentication().getOAuth2Request().getScope());
Set<String> refreshScopesRequested = new HashSet<>(
refreshToken.getAuthenticationHolder()
.getAuthentication()
.getOAuth2Request()
.getScope()
);
Set<SystemScope> refreshScopes = scopeService.fromStrings(refreshScopesRequested);
// remove any of the special system scopes
refreshScopes = scopeService.removeReservedScopes(refreshScopes);
Set<String> scopeRequested = authRequest.getScope() == null ? new HashSet<String>() : new HashSet<>(authRequest.getScope());
Set<SystemScope> scope = scopeService.fromStrings(scopeRequested);
Set<String> scopeRequested = new HashSet<>();
if (authRequest.getScope() != null && !authRequest.getScope().isEmpty()) {
scopeRequested.addAll(authRequest.getScope());
}
// remove any of the special system scopes
Set<SystemScope> scope = scopeService.fromStrings(scopeRequested);
scope = scopeService.removeReservedScopes(scope);
if (scope != null && !scope.isEmpty()) {
......@@ -398,12 +417,32 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
token.setExpiration(expiration);
}
Set<String> resources = new HashSet<>();
if (refreshToken.getJwt() != null) {
JWTClaimsSet claimsSet;
try {
claimsSet = refreshToken.getJwt().getJWTClaimsSet();
} catch (ParseException e) {
throw new RuntimeException(e);
}
if (claimsSet != null) {
List<String> audience = claimsSet.getAudience();
if (audience != null && !audience.isEmpty()) {
resources = new HashSet<>(audience);
token.getAdditionalInformation().put(AUD, audience.get(0));
if (audience.size() > 1) {
token.getAdditionalInformation().put(RESOURCE, resources);
}
}
}
}
if (client.isReuseRefreshToken()) {
// if the client re-uses refresh tokens, do that
token.setRefreshToken(refreshToken);
} else {
// otherwise, make a new refresh token
OAuth2RefreshTokenEntity newRefresh = createRefreshToken(client, authHolder);
OAuth2RefreshTokenEntity newRefresh = createRefreshToken(client, authHolder, resources);
token.setRefreshToken(newRefresh);
// clean up the old refresh token
......
......@@ -103,9 +103,9 @@ public class PerunAccessTokenEnhancer implements TokenEnhancer {
Set<String> audience = new HashSet<>();
audience.add(client.getClientId());
if (token.getAdditionalInformation().containsKey(RESOURCE)) {
audience.addAll((Set<String>) token.getAdditionalInformation().get(RESOURCE));
audience.addAll((Set<String>) token.getAdditionalInformation().getOrDefault(RESOURCE, new HashSet<>()));
}
String audExtension = (String) authentication.getOAuth2Request().getExtensions().get(AUD);
String audExtension = (String) authentication.getOAuth2Request().getExtensions().getOrDefault(AUD, null);
if (StringUtils.hasText(audExtension)) {
audience.add(audExtension);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment