Skip to content

Commit

Permalink
fix: fix the default and optional scopes on update state (#23)
Browse files Browse the repository at this point in the history
Co-authored-by: milan.horvath <[email protected]>
  • Loading branch information
milanhorvath and milan.horvath authored Jun 19, 2024
1 parent 0cfc806 commit 94a62f7
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ public int createClient(KeycloakClient keycloakClient) {
}

// check scopes if they exist and create them if necessary
checkAndCreateScopes(client, realm);

var scopeNametoIdMap = checkAndCreateScopes(client, realm);
if (Boolean.TRUE.equals(clientDefaultConfig.addDefaultScopes())) {
var defaultScopesKC = keycloak.realm(realm).getDefaultDefaultClientScopes().stream()
.filter(csr -> csr.getProtocol().equals(PROTOCOL_OPENID_CONNECT)).map(ClientScopeRepresentation::getName)
Expand All @@ -77,25 +76,27 @@ public int createClient(KeycloakClient keycloakClient) {
}
} else {
// do update
var defaultClientScopes = client.getDefaultClientScopes();
var optionalClientScopes = client.getOptionalClientScopes();
var defaultClientScopeNames = client.getDefaultClientScopes();
var optionalClientScopeNames = client.getOptionalClientScopes();
var clientToUpdate = keycloak.realm(realm).clients().get(clients.get(0).getId());
clientToUpdate.update(client);
// update default client scopes
var toRemove = clientToUpdate.getDefaultClientScopes().stream()
.filter(rep -> !defaultClientScopes.contains(rep.getName())).map(ClientScopeRepresentation::getId)
.filter(rep -> !defaultClientScopeNames.contains(rep.getName())).map(ClientScopeRepresentation::getId)
.collect(Collectors.toSet());
var toAdd = new ArrayList<>(client.getDefaultClientScopes());
toAdd.removeAll(clientToUpdate.getDefaultClientScopes().stream().map(ClientScopeRepresentation::getName)
var toAdd = client.getDefaultClientScopes().stream().map(scopeNametoIdMap::get)
.collect(Collectors.toCollection(ArrayList::new));
toAdd.removeAll(clientToUpdate.getDefaultClientScopes().stream().map(ClientScopeRepresentation::getId)
.collect(Collectors.toSet()));
toRemove.forEach(scope -> removeDefaultClientScope(clientToUpdate, scope));
toAdd.forEach(scope -> addDefaultClientScope(clientToUpdate, scope));
// update optional client scopes
var toRemoveOpt = clientToUpdate.getOptionalClientScopes().stream()
.filter(rep -> !optionalClientScopes.contains(rep.getName())).map(ClientScopeRepresentation::getId)
.filter(rep -> !optionalClientScopeNames.contains(rep.getName())).map(ClientScopeRepresentation::getId)
.collect(Collectors.toSet());
var toAddOpt = new ArrayList<>(client.getOptionalClientScopes());
toAddOpt.removeAll(clientToUpdate.getOptionalClientScopes().stream().map(ClientScopeRepresentation::getName)
var toAddOpt = client.getOptionalClientScopes().stream().map(scopeNametoIdMap::get)
.collect(Collectors.toCollection(ArrayList::new));
toAddOpt.removeAll(clientToUpdate.getOptionalClientScopes().stream().map(ClientScopeRepresentation::getId)
.collect(Collectors.toSet()));
toRemoveOpt.forEach(scope -> removeOptClientScope(clientToUpdate, scope));
toAddOpt.forEach(scope -> addOptClientScope(clientToUpdate, scope));
Expand Down Expand Up @@ -148,8 +149,10 @@ void removeOptClientScope(ClientResource cr, String clientScope) {
}
}

private void checkAndCreateScopes(ClientRepresentation clientRepresentation, String realm) {
private Map<String, String> checkAndCreateScopes(ClientRepresentation clientRepresentation, String realm) {
var kcScopes = keycloak.realm(realm).clientScopes().findAll();
var kcScopesMap = kcScopes.stream()
.collect(Collectors.toMap(ClientScopeRepresentation::getName, ClientScopeRepresentation::getId));
var scopeNames = kcScopes.stream().map(ClientScopeRepresentation::getName).collect(Collectors.toSet());

var scopesToAdd = new HashSet<String>();
Expand All @@ -165,8 +168,14 @@ private void checkAndCreateScopes(ClientRepresentation clientRepresentation, Str

// add all missing scopes to keycloak
if (!scopesToAdd.isEmpty()) {
scopesToAdd.forEach(scopeName -> createClientScope(scopeName, realm));
scopesToAdd.forEach(scopeName -> {
createClientScope(scopeName, realm);
kcScopesMap.put(scopeName, scopeName);
});

}

return kcScopesMap;
}

private void createClientScope(String clientScopeName, String realm) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
import static org.awaitility.Awaitility.await;

import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jakarta.inject.Inject;
import jakarta.ws.rs.core.Response;

import org.apache.groovy.util.Maps;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.*;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.representations.idm.ClientScopeRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tkit.onecx.iam.kc.client.operator.service.KeycloakAdminService;
Expand Down Expand Up @@ -87,6 +91,8 @@ void createUIClient() {
assertThat(clientRep.getDescription()).isEqualTo(kcConfig.getDescription());
// validate that attributes are all in
assertThat(clientRep.getAttributes()).containsAllEntriesOf(kcConfig.getAttributes());
// test Organization_ID should not be the part of the default scopes at this point
assertThat(clientRep.getDefaultClientScopes()).doesNotContain("Organization_ID");
assertThat(clientRep.getOptionalClientScopes()).containsAll(kcConfig.getOptionalClientScopes());

var token = keycloakClient.getAccessToken(USER_ALICE, CLIENT_ID);
Expand Down Expand Up @@ -165,6 +171,8 @@ void createUIClientAllOptionsFilled() {
@Test
@Order(2)
void updateUIClient() {
// create Organization_ID as default scope
createOrgIdScope();
var CLIENT_ID = "test-ui-client";
operator.start();

Expand Down Expand Up @@ -199,6 +207,8 @@ void updateUIClient() {
assertThat(clientRep.getDescription()).isEqualTo(kcConfig.getDescription());
// validate that attributes are all in
assertThat(clientRep.getAttributes()).containsAllEntriesOf(kcConfig.getAttributes());
// test if the new default scope for Realm Organization_ID was added correctly
assertThat(clientRep.getDefaultClientScopes()).contains("Organization_ID");
assertThat(clientRep.getOptionalClientScopes()).containsAll(kcConfig.getOptionalClientScopes());

var token = keycloakClient.getAccessToken(USER_ALICE, CLIENT_ID);
Expand Down Expand Up @@ -363,6 +373,7 @@ void createMachineClient() {
kcClientSpec.setKcConfig(kcConfig);
kcConfig.setClientId(CLIENT_ID);
kcConfig.setPassword(CLIENT_SECRET);

kcConfig.setDefaultClientScopes(List.of("create-scope-1", "create-scope-2"));
kcConfig.setAttributes(Maps.of("create.attr.1", "create.values.1", "create.attr.2", "create.values.2"));
data.setSpec(kcClientSpec);
Expand Down Expand Up @@ -396,6 +407,32 @@ void createMachineClient() {
assertThat(scopes).containsAll(kcConfig.getDefaultClientScopes());
}

void createOrgIdScope() {
ClientScopeRepresentation orgIdScope = new ClientScopeRepresentation();
orgIdScope.setId("test-id-12345");
orgIdScope.setName("Organization_ID");
orgIdScope.setDescription("Tenant organization ID");
orgIdScope.setProtocol("openid-connect");
ProtocolMapperRepresentation pmr = new ProtocolMapperRepresentation();
pmr.setId("pmr-test-1234");
pmr.setName("OrgIdMapper");
pmr.setProtocol("openid-connect");
pmr.setProtocolMapper("oidc-usermodel-attribute-mapper");
Map<String, String> mapperConfig = new HashMap<>();
mapperConfig.put("userinfo.token.claim", "true");
mapperConfig.put("multivalued", "false");
mapperConfig.put("user.attribute", "orgId");
mapperConfig.put("id.token.claim", "true");
mapperConfig.put("access.token.claim", "true");
mapperConfig.put("claim.name", "orgId");
mapperConfig.put("jsonType.label", "String");
pmr.setConfig(mapperConfig);
orgIdScope.setProtocolMappers(List.of(pmr));
try (Response res = keycloak.realm(REALM_QUARKUS).clientScopes().create(orgIdScope)) {
keycloak.realm(REALM_QUARKUS).addDefaultDefaultClientScope(orgIdScope.getId());
}
}

@Test
@Order(11)
void updateMachineClient() {
Expand Down

0 comments on commit 94a62f7

Please sign in to comment.