This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new dd2109374f Checking ClientApp's Realm for authorization, when set
dd2109374f is described below
commit dd2109374f0e1a80aeadbdfaae7ea553082a170a
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Thu Aug 20 17:31:22 2026 +0200
Checking ClientApp's Realm for authorization, when set
---
.../syncope/common/lib/types/AMEntitlement.java | 2 +-
.../apache/syncope/core/logic/ClientAppLogic.java | 101 +++++++++++++++++----
.../apache/syncope/core/logic/ResourceLogic.java | 4 +-
3 files changed, 88 insertions(+), 19 deletions(-)
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
index 69c5fa0a03..e0af286d41 100644
---
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/AMEntitlement.java
@@ -44,7 +44,7 @@ public final class AMEntitlement {
public static final String CLIENTAPP_CREATE = "CLIENTAPP_CREATE";
- public static final String CLIENTAPP_UPDATE = "CLIENTAPP_CREATE";
+ public static final String CLIENTAPP_UPDATE = "CLIENTAPP_UPDATE";
public static final String CLIENTAPP_DELETE = "CLIENTAPP_DELETE";
diff --git
a/core/am/logic/src/main/java/org/apache/syncope/core/logic/ClientAppLogic.java
b/core/am/logic/src/main/java/org/apache/syncope/core/logic/ClientAppLogic.java
index d0ac97f257..9901b9e105 100644
---
a/core/am/logic/src/main/java/org/apache/syncope/core/logic/ClientAppLogic.java
+++
b/core/am/logic/src/main/java/org/apache/syncope/core/logic/ClientAppLogic.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.logic;
import java.lang.reflect.Method;
import java.util.List;
+import java.util.Set;
import java.util.stream.Stream;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.syncope.common.keymaster.client.api.ServiceOps;
@@ -38,7 +39,10 @@ import
org.apache.syncope.core.persistence.api.entity.am.ClientAppUtils;
import org.apache.syncope.core.persistence.api.entity.am.ClientAppUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.am.OIDCRPClientApp;
import org.apache.syncope.core.persistence.api.entity.am.SAML2SPClientApp;
+import org.apache.syncope.core.persistence.api.utils.RealmUtils;
import org.apache.syncope.core.provisioning.api.data.ClientAppDataBinder;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import
org.apache.syncope.core.spring.security.DelegatedAdministrationException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
@@ -88,10 +92,19 @@ public class ClientAppLogic extends
AbstractTransactionalLogic<ClientAppTO> {
stream =
saml2SPClientAppDAO.findAll().stream().map(binder::getClientAppTO);
}
- return stream.toList();
+ return stream.filter(clientApp -> {
+ if (clientApp.getRealm() == null) {
+ return true;
+ }
+
+ Set<String> authRealms = RealmUtils.getEffective(
+
AuthContextUtils.getAuthorizations().get(AMEntitlement.CLIENTAPP_LIST),
+ clientApp.getRealm());
+ return
RealmUtils.SubtreePredicate.of(authRealms).test(clientApp.getRealm());
+ }).toList();
}
- protected void checkType(final ClientAppType type, final ClientAppUtils
clientAppUtils) {
+ protected void typeCheck(final ClientAppType type, final ClientAppUtils
clientAppUtils) {
if (clientAppUtils.getType() != type) {
SyncopeClientException sce =
SyncopeClientException.build(ClientExceptionType.InvalidRequest);
sce.getElements().add("Found " + type + ", expected " +
clientAppUtils.getType());
@@ -99,70 +112,110 @@ public class ClientAppLogic extends
AbstractTransactionalLogic<ClientAppTO> {
}
}
+ protected void securityChecks(
+ final Set<String> realms,
+ final String realm,
+ final ClientAppType type,
+ final String key) {
+
+ if (!RealmUtils.SubtreePredicate.of(realms).test(realm)) {
+ throw new DelegatedAdministrationException(realm, type.name(),
key);
+ }
+ }
+
@PreAuthorize("hasRole('" + AMEntitlement.CLIENTAPP_READ + "')")
@Transactional(readOnly = true)
public <T extends ClientAppTO> T read(final ClientAppType type, final
String key) {
+ T clientApp;
switch (type) {
case OIDCRP:
OIDCRPClientApp oidcrp = oidcRPClientAppDAO.findById(key).
orElseThrow(() -> new
NotFoundException("OIDCRPClientApp " + key));
- checkType(type, clientAppUtilsFactory.getInstance(oidcrp));
+ typeCheck(type, clientAppUtilsFactory.getInstance(oidcrp));
- return binder.getClientAppTO(oidcrp);
+ clientApp = binder.getClientAppTO(oidcrp);
+ break;
case CASSP:
CASSPClientApp cassp = casSPClientAppDAO.findById(key).
orElseThrow(() -> new
NotFoundException("CASSPClientApp " + key));
- checkType(type, clientAppUtilsFactory.getInstance(cassp));
+ typeCheck(type, clientAppUtilsFactory.getInstance(cassp));
- return binder.getClientAppTO(cassp);
+ clientApp = binder.getClientAppTO(cassp);
+ break;
case SAML2SP:
default:
SAML2SPClientApp saml2sp = saml2SPClientAppDAO.findById(key).
orElseThrow(() -> new
NotFoundException("SAML2SPClientApp " + key));
- checkType(type, clientAppUtilsFactory.getInstance(saml2sp));
+ typeCheck(type, clientAppUtilsFactory.getInstance(saml2sp));
+
+ clientApp = binder.getClientAppTO(saml2sp);
+ }
- return binder.getClientAppTO(saml2sp);
+ if (clientApp.getRealm() != null) {
+ Set<String> authRealms = RealmUtils.getEffective(
+
AuthContextUtils.getAuthorizations().get(AMEntitlement.CLIENTAPP_READ),
+ clientApp.getRealm());
+ securityChecks(authRealms, clientApp.getRealm(), type, key);
}
+
+ return clientApp;
}
@PreAuthorize("hasRole('" + AMEntitlement.CLIENTAPP_CREATE + "')")
public <T extends ClientAppTO> T create(final ClientAppType type, final
ClientAppTO clientAppTO) {
- checkType(type, clientAppUtilsFactory.getInstance(clientAppTO));
+ typeCheck(type, clientAppUtilsFactory.getInstance(clientAppTO));
+ T clientApp;
switch (type) {
case OIDCRP:
- return
binder.getClientAppTO(oidcRPClientAppDAO.save(binder.create(clientAppTO)));
+ clientApp =
binder.getClientAppTO(oidcRPClientAppDAO.save(binder.create(clientAppTO)));
+ break;
+
case CASSP:
- return
binder.getClientAppTO(casSPClientAppDAO.save(binder.create(clientAppTO)));
+ clientApp =
binder.getClientAppTO(casSPClientAppDAO.save(binder.create(clientAppTO)));
+ break;
+
case SAML2SP:
default:
- return
binder.getClientAppTO(saml2SPClientAppDAO.save(binder.create(clientAppTO)));
+ clientApp =
binder.getClientAppTO(saml2SPClientAppDAO.save(binder.create(clientAppTO)));
+ }
+
+ if (clientApp.getRealm() != null) {
+ Set<String> authRealms = RealmUtils.getEffective(
+
AuthContextUtils.getAuthorizations().get(AMEntitlement.CLIENTAPP_CREATE),
+ clientApp.getRealm());
+ securityChecks(authRealms, clientApp.getRealm(), type, null);
}
+
+ return clientApp;
}
@PreAuthorize("hasRole('" + AMEntitlement.CLIENTAPP_UPDATE + "')")
public <T extends ClientAppTO> T update(final ClientAppType type, final
ClientAppTO clientAppTO) {
- checkType(type, clientAppUtilsFactory.getInstance(clientAppTO));
+ typeCheck(type, clientAppUtilsFactory.getInstance(clientAppTO));
+ T clientApp;
switch (type) {
case OIDCRP:
OIDCRPClientApp oidcrp =
oidcRPClientAppDAO.findById(clientAppTO.getKey()).
orElseThrow(() -> new
NotFoundException("OIDCRPClientApp " + clientAppTO.getKey()));
binder.update(oidcrp, clientAppTO);
- return binder.getClientAppTO(oidcRPClientAppDAO.save(oidcrp));
+ clientApp =
binder.getClientAppTO(oidcRPClientAppDAO.save(oidcrp));
+ break;
case CASSP:
CASSPClientApp cassp =
casSPClientAppDAO.findById(clientAppTO.getKey()).
orElseThrow(() -> new
NotFoundException("CASSPClientApp " + clientAppTO.getKey()));
binder.update(cassp, clientAppTO);
- return binder.getClientAppTO(casSPClientAppDAO.save(cassp));
+ clientApp =
binder.getClientAppTO(casSPClientAppDAO.save(cassp));
+ break;
case SAML2SP:
default:
@@ -170,8 +223,17 @@ public class ClientAppLogic extends
AbstractTransactionalLogic<ClientAppTO> {
orElseThrow(() -> new
NotFoundException("SAML2SPClientApp " + clientAppTO.getKey()));
binder.update(saml2sp, clientAppTO);
- return
binder.getClientAppTO(saml2SPClientAppDAO.save(saml2sp));
+ clientApp =
binder.getClientAppTO(saml2SPClientAppDAO.save(saml2sp));
+ }
+
+ if (clientApp.getRealm() != null) {
+ Set<String> authRealms = RealmUtils.getEffective(
+
AuthContextUtils.getAuthorizations().get(AMEntitlement.CLIENTAPP_UPDATE),
+ clientApp.getRealm());
+ securityChecks(authRealms, clientApp.getRealm(), type, null);
}
+
+ return clientApp;
}
@PreAuthorize("hasRole('" + AMEntitlement.CLIENTAPP_DELETE + "')")
@@ -203,6 +265,13 @@ public class ClientAppLogic extends
AbstractTransactionalLogic<ClientAppTO> {
deleted = binder.getClientAppTO(saml2sp);
}
+ if (deleted.getRealm() != null) {
+ Set<String> authRealms = RealmUtils.getEffective(
+
AuthContextUtils.getAuthorizations().get(AMEntitlement.CLIENTAPP_DELETE),
+ deleted.getRealm());
+ securityChecks(authRealms, deleted.getRealm(), type, null);
+ }
+
return deleted;
}
diff --git
a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index 1b77821b5f..c0f6177c21 100644
---
a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++
b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -112,9 +112,9 @@ public class ResourceLogic extends
AbstractTransactionalLogic<ResourceTO> {
return merged;
}
- protected void securityChecks(final Set<String> realms, final String
realm, final String resourceKey) {
+ protected void securityChecks(final Set<String> realms, final String
realm, final String key) {
if (!RealmUtils.SubtreePredicate.of(realms).test(realm)) {
- throw new DelegatedAdministrationException(realm,
ExternalResource.class.getSimpleName(), resourceKey);
+ throw new DelegatedAdministrationException(realm,
ExternalResource.class.getSimpleName(), key);
}
}