Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public class RealmRepresentation {
@Deprecated
protected List<String> defaultRoles;
protected RoleRepresentation defaultRole;
protected ClientRepresentation adminPermissionsClient;
protected List<String> defaultGroups;
@Deprecated
protected Set<String> requiredCredentials;
Expand Down Expand Up @@ -553,6 +554,14 @@ public void setDefaultRole(RoleRepresentation defaultRole) {
this.defaultRole = defaultRole;
}

public ClientRepresentation getAdminPermissionsClient() {
return adminPermissionsClient;
}

public void setAdminPermissionsClient(ClientRepresentation adminPermissionsClient) {
this.adminPermissionsClient = adminPermissionsClient;
}

public List<String> getDefaultGroups() {
return defaultGroups;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,18 @@ public RoleModel getDefaultRole() {
return cached.getDefaultRoleId() == null ? null : cacheSession.getRoleById(this, cached.getDefaultRoleId());
}

@Override
public void setAdminPermissionsClient(ClientModel client) {
getDelegateForUpdate();
updated.setAdminPermissionsClient(client);
}

@Override
public ClientModel getAdminPermissionsClient() {
if (isUpdated()) return updated.getAdminPermissionsClient();
return cached.getAdminPermissionsClientId() == null ? null : cacheSession.getClientById(this, cached.getAdminPermissionsClientId());
}

@Override
public RoleModel getRole(String name) {
return cacheSession.getRealmRole(this, name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ public class CachedRealm extends AbstractExtendableRevisioned {
protected boolean adminEventsEnabled;
protected boolean adminEventsDetailsEnabled;
protected String defaultRoleId;
protected String adminPermissionsClientId;
private boolean allowUserManagedAccess;

protected List<String> defaultGroups;
Expand Down Expand Up @@ -257,6 +258,7 @@ public CachedRealm(Long revision, RealmModel model) {

adminEventsEnabled = model.isAdminEventsEnabled();
adminEventsDetailsEnabled = model.isAdminEventsDetailsEnabled();
adminPermissionsClientId = model.getAdminPermissionsClient() == null ? null : model.getAdminPermissionsClient().getId();

if(Objects.isNull(model.getDefaultRole())) {
throw new ModelException("Default Role is null for Realm " + name);
Expand Down Expand Up @@ -339,6 +341,10 @@ public String getDefaultRoleId() {
return defaultRoleId;
}

public String getAdminPermissionsClientId() {
return adminPermissionsClientId;
}

public String getName() {
return name;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,23 @@
package org.keycloak.models.jpa;

import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.models.ClientProvider;
import org.keycloak.models.ClientProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.jpa.entities.RealmAttributes;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.saml.SamlConfigAttributes;

import jakarta.persistence.EntityManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static org.keycloak.models.jpa.JpaRealmProviderFactory.PROVIDER_ID;
import static org.keycloak.models.jpa.JpaRealmProviderFactory.PROVIDER_PRIORITY;
Expand Down Expand Up @@ -59,7 +64,20 @@ public void init(Config.Scope config) {

@Override
public void postInit(KeycloakSessionFactory factory) {
if (Profile.isFeatureEnabled(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ_V2)) {
factory.register(event -> {
if (event instanceof RealmModel.RealmAttributeUpdateEvent attrUpdateEvent) {
if (Objects.equals(attrUpdateEvent.getAttributeName(), RealmAttributes.ADMIN_PERMISSIONS_ENABLED) && Boolean.parseBoolean(attrUpdateEvent.getAttributeValue())) {
KeycloakSession keycloakSession = attrUpdateEvent.getKeycloakSession();
RealmModel realm = attrUpdateEvent.getRealm();

if (realm.getAdminPermissionsClient() != null) return;

KeycloakModelUtils.setupAdminPermissionsClient(keycloakSession, realm);
}
}
});
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,34 @@ public boolean isAdminPermissionsEnabled() {

@Override
public void setAdminPermissionsEnabled(boolean adminPermissionsEnabled) {
boolean isAdminPermissionsAlreadyEnabled = getAdminPermissionsClient() != null;
setAttribute(RealmAttributes.ADMIN_PERMISSIONS_ENABLED, adminPermissionsEnabled);

// sending an event if we are enabling the permissions and it was not enabled already
if (adminPermissionsEnabled && !isAdminPermissionsAlreadyEnabled) {
session.getKeycloakSessionFactory().publish(new RealmModel.RealmAttributeUpdateEvent() {

@Override
public RealmModel getRealm() {
return RealmAdapter.this;
}

@Override
public String getAttributeName() {
return RealmAttributes.ADMIN_PERMISSIONS_ENABLED;
}

@Override
public String getAttributeValue() {
return String.valueOf(adminPermissionsEnabled);
}

@Override
public KeycloakSession getKeycloakSession() {
return session;
}
});
}
}

@Override
Expand Down Expand Up @@ -1251,6 +1278,19 @@ public RoleModel getDefaultRole() {
return session.roles().getRoleById(this, realm.getDefaultRoleId());
}

@Override
public void setAdminPermissionsClient(ClientModel client) {
setAttribute(RealmAttributes.ADMIN_PERMISSIONS_CLIENT_ID, client.getId());
}

@Override
public ClientModel getAdminPermissionsClient() {
if (getAttribute(RealmAttributes.ADMIN_PERMISSIONS_CLIENT_ID) == null) {
return null;
}
return session.clients().getClientById(this, getAttribute(RealmAttributes.ADMIN_PERMISSIONS_CLIENT_ID));
}

@Override
public Stream<IdentityProviderModel> getIdentityProvidersStream() {
return session.identityProviders().getAllStream();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@ public interface RealmAttributes {

String ORGANIZATIONS_ENABLED = "organizationsEnabled";
String ADMIN_PERMISSIONS_ENABLED = "adminPermissionsEnabled";
String ADMIN_PERMISSIONS_CLIENT_ID = "adminPermissionsClientId";
}
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,13 @@ private static RoleModel getOrAddClientRole(ClientModel client, String name) {
}

private static Map<String, ClientModel> createClients(KeycloakSession session, RealmRepresentation rep, RealmModel realm, Map<String, String> mappedFlows) {
Map<String, ClientModel> appMap = new HashMap<String, ClientModel>();
Map<String, ClientModel> appMap = new HashMap<>();
for (ClientRepresentation resourceRep : rep.getClients()) {
if (Profile.isFeatureEnabled(Feature.ADMIN_FINE_GRAINED_AUTHZ_V2)) {
if (realm.getAdminPermissionsClient() != null && realm.getAdminPermissionsClient().getClientId().equals(resourceRep.getClientId())) {
continue; // admin-permission-client is already imported at this point
}
}
ClientModel app = RepresentationToModel.createClient(session, realm, resourceRep, mappedFlows);
String postLogoutRedirectUris = app.getAttribute(OIDCConfigAttributes.POST_LOGOUT_REDIRECT_URIS);
if (postLogoutRedirectUris == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,6 @@ public final class Constants {

//attribute name used to mark a temporary admin user/service account as temporary
public static final String IS_TEMP_ADMIN_ATTR_NAME = "is_temporary_admin";

public static final String ADMIN_PERMISSIONS_CLIENT_ID = "admin-permissions";
}
Original file line number Diff line number Diff line change
Expand Up @@ -1188,4 +1188,11 @@ public static void setDefaultGroups(KeycloakSession session, RealmModel realm, S
public static boolean isAdminPermissionsEnabled(RealmModel realm) {
return Profile.isFeatureEnabled(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ_V2) && realm.isAdminPermissionsEnabled();
}

public static void setupAdminPermissionsClient(KeycloakSession session, RealmModel realm) {
ClientModel client = session.clients().addClient(realm, Constants.ADMIN_PERMISSIONS_CLIENT_ID);
realm.setAdminPermissionsClient(client);
RepresentationToModel.createResourceServer(client, session, false);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ public class ModelToRepresentation {
REALM_EXCLUDED_ATTRIBUTES.add("organizationsEnabled");
REALM_EXCLUDED_ATTRIBUTES.add("verifiableCredentialsEnabled");
REALM_EXCLUDED_ATTRIBUTES.add("adminPermissionsEnabled");
REALM_EXCLUDED_ATTRIBUTES.add("adminPermissionsClientId");
}

public static Set<String> CLIENT_EXCLUDED_ATTRIBUTES = new HashSet<>();
Expand Down Expand Up @@ -509,6 +510,14 @@ public static RealmRepresentation toRepresentation(KeycloakSession session, Real

rep.setDefaultRole(toBriefRepresentation(realm.getDefaultRole()));

if (realm.getAdminPermissionsClient() != null) {
ClientModel adminPermissionsClient = realm.getAdminPermissionsClient();
ClientRepresentation clientRep = new ClientRepresentation();
clientRep.setId(adminPermissionsClient.getId());
clientRep.setClientId(adminPermissionsClient.getClientId());
rep.setAdminPermissionsClient(clientRep);
}

List<String> defaultGroups = realm.getDefaultGroupsStream()
.map(ModelToRepresentation::buildGroupPath).collect(Collectors.toList());
if (!defaultGroups.isEmpty()) {
Expand Down Expand Up @@ -1037,8 +1046,6 @@ public static ScopeRepresentation toRepresentation(Scope model) {
}

public static ResourceServerRepresentation toRepresentation(ResourceServer model, ClientModel client) {
RealmModel realm = client.getRealm();

ResourceServerRepresentation server = new ResourceServerRepresentation();

server.setId(model.getId());
Expand All @@ -1047,11 +1054,22 @@ public static ResourceServerRepresentation toRepresentation(ResourceServer model
server.setAllowRemoteResourceManagement(model.isAllowRemoteResourceManagement());
server.setPolicyEnforcementMode(model.getPolicyEnforcementMode());
server.setDecisionStrategy(model.getDecisionStrategy());
server.setAuthorizationSchema(KeycloakModelUtils.isAdminPermissionsEnabled(realm) ? AdminPermissionsAuthorizationSchema.INSTANCE : null);
server.setAuthorizationSchema(getAuthorizationSchema(client));

return server;
}

private static AuthorizationSchema getAuthorizationSchema(ClientModel client) {
if (!KeycloakModelUtils.isAdminPermissionsEnabled(client.getRealm())) {
return null;
}
ClientModel adminPermissionsClient = client.getRealm().getAdminPermissionsClient();
if (adminPermissionsClient == null || ! client.getClientId().equals(adminPermissionsClient.getClientId())) {
return null;
}
return AdminPermissionsAuthorizationSchema.INSTANCE;
}

public static <R extends AbstractPolicyRepresentation> R toRepresentation(Policy policy, AuthorizationProvider authorization) {
return toRepresentation(policy, authorization, false, true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,16 @@ public void setDefaultRole(RoleModel role) {
delegate.setDefaultRole(role);
}

@Override
public ClientModel getAdminPermissionsClient() {
return delegate.getAdminPermissionsClient();
}

@Override
public void setAdminPermissionsClient(ClientModel client) {
delegate.setAdminPermissionsClient(client);
}

public boolean isIdentityFederationEnabled() {
return delegate.isIdentityFederationEnabled();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1620,6 +1620,15 @@ public void setDefaultRole(RoleModel role) {

}

@Override
public ClientModel getAdminPermissionsClient() {
return null;
}

@Override
public void setAdminPermissionsClient(ClientModel client) {
}

@Override
public boolean isIdentityFederationEnabled() {
return false;
Expand Down
11 changes: 11 additions & 0 deletions server-spi/src/main/java/org/keycloak/models/RealmModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ interface IdentityProviderRemovedEvent extends ProviderEvent {
KeycloakSession getKeycloakSession();
}

interface RealmAttributeUpdateEvent extends ProviderEvent {
RealmModel getRealm();
String getAttributeName();
String getAttributeValue();
KeycloakSession getKeycloakSession();
}

@Override
String getId();

Expand Down Expand Up @@ -677,6 +684,10 @@ default Stream<ComponentModel> getStorageProviders(Class<? extends Provider> sto
*/
void setDefaultRole(RoleModel role);

ClientModel getAdminPermissionsClient();

void setAdminPermissionsClient(ClientModel client);

/**
* @deprecated use {@link IdentityProviderStorageProvider#isIdentityFederationEnabled()} instead.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,16 @@ public RealmModel importRealm(RealmRepresentation rep, boolean skipUserDependent
realm.setDefaultRole(RepresentationToModel.createRole(realm, rep.getDefaultRole()));
}

if (Profile.isFeatureEnabled(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ_V2)) {
if (rep.getAdminPermissionsClient() != null) {
ClientModel client = RepresentationToModel.createClient(session, realm, rep.getAdminPermissionsClient());
realm.setAdminPermissionsClient(client);
RepresentationToModel.createResourceServer(client, session, false);
} else if (Boolean.TRUE.equals(rep.isAdminPermissionsEnabled())) {
KeycloakModelUtils.setupAdminPermissionsClient(session, realm);
}
}

boolean postponeMasterClientSetup = postponeMasterClientSetup(rep);
if (!postponeMasterClientSetup) {
setupMasterAdminManagement(realm);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.authz.admin;
package org.keycloak.testsuite.authz.admin.permissions;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
Expand Down Expand Up @@ -73,13 +73,24 @@ public void authorizationSchemaAvailableFeatureV2Enabled() throws Exception {
assertThat(clients, hasSize(1));
ResourceServerRepresentation authorizationSettings = testRealm().clients().get(clients.get(0).getId()).authorization().getSettings();
assertThat(authorizationSettings, notNullValue());

//admin permissions not enabled for the realm
assertThat(authorizationSettings.getAuthorizationSchema(), nullValue());

try (RealmAttributeUpdater rau = new RealmAttributeUpdater(testRealm()).setAdminPermissionsEnabled(Boolean.TRUE).update()) {
authorizationSettings = testRealm().clients().get(clients.get(0).getId()).authorization().getSettings();
assertThat(authorizationSettings, notNullValue());

//schema should be available only for admin-permissions client
assertThat(authorizationSettings.getAuthorizationSchema(), nullValue());

//get the admin-permissions client
ClientRepresentation adminPermissionsClient = testRealm().toRepresentation().getAdminPermissionsClient();
assertThat(adminPermissionsClient, notNullValue());

authorizationSettings = testRealm().clients().get(adminPermissionsClient.getId()).authorization().getSettings();
assertThat(authorizationSettings.getAuthorizationSchema(), notNullValue());
}
}

}
Loading
Loading