Allow token exchange when subjec_token is not associated with a session
Closes #12596
This commit is contained in:
parent
4fd3049c85
commit
3631a413d2
2 changed files with 39 additions and 0 deletions
|
@ -29,6 +29,7 @@ import org.keycloak.broker.provider.IdentityProviderFactory;
|
|||
import org.keycloak.broker.provider.IdentityProviderMapper;
|
||||
import org.keycloak.broker.provider.IdentityProviderMapperSyncModeDelegate;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.constants.ServiceAccountConstants;
|
||||
import org.keycloak.common.util.Base64Url;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
|
@ -370,6 +371,13 @@ public class DefaultTokenExchangeProvider implements TokenExchangeProvider {
|
|||
authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
|
||||
authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
|
||||
|
||||
if (targetUserSession == null) {
|
||||
// if no session is associated with a subject_token, a stateless session is created to only allow building a token to the audience
|
||||
targetUserSession = session.sessions().createUserSession(authSession.getParentSession().getId(), realm, targetUser, targetUser.getUsername(),
|
||||
clientConnection.getRemoteAddr(), ServiceAccountConstants.CLIENT_AUTH, false, null, null, UserSessionModel.SessionPersistenceState.PERSISTENT);
|
||||
|
||||
}
|
||||
|
||||
event.session(targetUserSession);
|
||||
|
||||
AuthenticationManager.setClientScopesInSession(authSession);
|
||||
|
|
|
@ -209,6 +209,15 @@ public class ClientTokenExchangeTest extends AbstractKeycloakTest {
|
|||
noRefreshToken.setFullScopeAllowed(false);
|
||||
noRefreshToken.getAttributes().put(OIDCConfigAttributes.USE_REFRESH_TOKEN, "false");
|
||||
|
||||
ClientModel serviceAccount = realm.addClient("my-service-account");
|
||||
serviceAccount.setClientId("my-service-account");
|
||||
serviceAccount.setPublicClient(false);
|
||||
serviceAccount.setServiceAccountsEnabled(true);
|
||||
serviceAccount.setEnabled(true);
|
||||
serviceAccount.setSecret("secret");
|
||||
serviceAccount.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
serviceAccount.setFullScopeAllowed(false);
|
||||
|
||||
// permission for client to client exchange to "target" client
|
||||
ClientPolicyRepresentation clientRep = new ClientPolicyRepresentation();
|
||||
clientRep.setName("to");
|
||||
|
@ -216,6 +225,7 @@ public class ClientTokenExchangeTest extends AbstractKeycloakTest {
|
|||
clientRep.addClient(legal.getId());
|
||||
clientRep.addClient(directLegal.getId());
|
||||
clientRep.addClient(noRefreshToken.getId());
|
||||
clientRep.addClient(serviceAccount.getId());
|
||||
|
||||
ResourceServer server = management.realmResourceServer();
|
||||
Policy clientPolicy = management.authz().getStoreFactory().getPolicyStore().create(server, clientRep);
|
||||
|
@ -305,6 +315,27 @@ public class ClientTokenExchangeTest extends AbstractKeycloakTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@UncaughtServerErrorExpected
|
||||
public void testExchangeUsingServiceAccount() throws Exception {
|
||||
testingClient.server().run(ClientTokenExchangeTest::setupRealm);
|
||||
|
||||
oauth.realm(TEST);
|
||||
oauth.clientId("my-service-account");
|
||||
OAuthClient.AccessTokenResponse response = oauth.doClientCredentialsGrantAccessTokenRequest("secret");
|
||||
String accessToken = response.getAccessToken();
|
||||
|
||||
{
|
||||
response = oauth.doTokenExchange(TEST, accessToken, "target", "my-service-account", "secret");
|
||||
String exchangedTokenString = response.getAccessToken();
|
||||
TokenVerifier<AccessToken> verifier = TokenVerifier.create(exchangedTokenString, AccessToken.class);
|
||||
AccessToken exchangedToken = verifier.parse().getToken();
|
||||
Assert.assertEquals("my-service-account", exchangedToken.getIssuedFor());
|
||||
Assert.assertEquals("target", exchangedToken.getAudience()[0]);
|
||||
Assert.assertEquals(exchangedToken.getPreferredUsername(), "service-account-my-service-account");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@UncaughtServerErrorExpected
|
||||
public void testExchangeFromPublicClient() throws Exception {
|
||||
|
|
Loading…
Reference in a new issue