diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/rest/model/CustomScope.java b/jans-config-api/common/src/main/java/io/jans/configapi/rest/model/CustomScope.java new file mode 100644 index 00000000000..f07e3e57b5b --- /dev/null +++ b/jans-config-api/common/src/main/java/io/jans/configapi/rest/model/CustomScope.java @@ -0,0 +1,21 @@ +package io.jans.configapi.rest.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.jans.as.common.model.registration.Client; +import io.jans.as.persistence.model.Scope; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CustomScope extends Scope { + public List getClients() { + return clients; + } + + public void setClients(List clients) { + this.clients = clients; + } + + private List clients; + +} diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java index 7ca7dc2a3ea..47a1c776905 100644 --- a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java +++ b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java @@ -75,7 +75,7 @@ private ApiConstants() {} public static final String SERVER_STAT = "/server-stat"; public static final String USERNAME_PATH = "/{username}"; public static final String CLIENTID_PATH = "/{clientId}"; - public static final String AGAMA = "/agama"; + public static final String AGAMA = "/agama"; public static final String QNAME_PATH = "{qname}"; public static final String ENABLED = "enabled"; public static final String QNAME = "qname"; @@ -83,6 +83,7 @@ private ApiConstants() {} public static final String LIMIT = "limit"; public static final String START_INDEX = "startIndex"; public static final String PATTERN = "pattern"; + public static final String WITH_ASSOCIATED_CLIENTS = "withAssociatedClients"; public static final String STATUS = "status"; public static final String INUM = "inum"; public static final String ID = "id"; diff --git a/jans-config-api/docs/jans-config-api-swagger.yaml b/jans-config-api/docs/jans-config-api-swagger.yaml index 0da0993ef39..3da59e4e857 100644 --- a/jans-config-api/docs/jans-config-api-swagger.yaml +++ b/jans-config-api/docs/jans-config-api-swagger.yaml @@ -2295,6 +2295,12 @@ paths: in: query name: pattern description: Search pattern. + - schema: + type: boolean + default: false + in: query + name: withAssociatedClients + description: Also fetch associated clients with scopes. post: tags: - OAuth - Scopes @@ -2353,6 +2359,12 @@ paths: name: inum in: path required: true + - schema: + type: boolean + default: false + in: query + name: withAssociatedClients + description: Also fetch associated clients with scopes. get: tags: - OAuth - Scopes diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ScopesResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ScopesResource.java index 8d44443e312..19b39fed0bb 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ScopesResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ScopesResource.java @@ -10,6 +10,7 @@ import io.jans.as.model.common.ScopeType; import io.jans.as.persistence.model.Scope; import io.jans.configapi.core.rest.ProtectedApi; +import io.jans.configapi.rest.model.CustomScope; import io.jans.configapi.service.auth.ScopeService; import io.jans.configapi.util.ApiAccessConstants; import io.jans.configapi.util.ApiConstants; @@ -58,13 +59,14 @@ public class ScopesResource extends ConfigBaseResource { @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }) public Response getScopes(@DefaultValue("") @QueryParam(ApiConstants.TYPE) String type, @DefaultValue(DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, - @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern) { + @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, + @DefaultValue("false") @QueryParam(value = ApiConstants.WITH_ASSOCIATED_CLIENTS) boolean withAssociatedClients) { log.debug("SCOPES to be fetched type = " + type + " , limit = " + limit + " , pattern = " + pattern); - final List scopes; + final List scopes; if (StringHelper.isNotEmpty(pattern)) { - scopes = scopeService.searchScopes(pattern, limit, type); + scopes = scopeService.searchScopes(pattern, limit, type, withAssociatedClients); } else { - scopes = scopeService.getAllScopesList(limit, type); + scopes = scopeService.getAllScopesList(limit, type, withAssociatedClients); } return Response.ok(scopes).build(); } @@ -72,9 +74,10 @@ public Response getScopes(@DefaultValue("") @QueryParam(ApiConstants.TYPE) Strin @GET @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }) @Path(ApiConstants.INUM_PATH) - public Response getScopeById(@NotNull @PathParam(ApiConstants.INUM) String inum) { + public Response getScopeById(@NotNull @PathParam(ApiConstants.INUM) String inum, + @DefaultValue("false") @QueryParam(value = ApiConstants.WITH_ASSOCIATED_CLIENTS) boolean withAssociatedClients) { log.debug("SCOPES to be fetched - inum = " + inum); - Scope scope = scopeService.getScopeByInum(inum); + CustomScope scope = scopeService.getScopeByInum(inum, withAssociatedClients); checkResourceNotNull(scope, SCOPE); return Response.ok(scope).build(); } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java index b0183f372ae..012e163dbea 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/ScopeService.java @@ -6,20 +6,28 @@ package io.jans.configapi.service.auth; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.api.client.util.Lists; +import io.jans.as.common.model.registration.Client; import io.jans.as.common.service.OrganizationService; import io.jans.as.common.util.AttributeConstants; +import io.jans.as.model.common.ScopeType; import io.jans.as.model.config.StaticConfiguration; +import io.jans.as.model.uma.persistence.UmaResource; import io.jans.as.persistence.model.Scope; +import io.jans.configapi.rest.model.CustomScope; import io.jans.orm.PersistenceEntryManager; import io.jans.orm.search.filter.Filter; import io.jans.util.StringHelper; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; /** * Responsible for OpenID Connect, OAuth2 and UMA scopes. (Type is defined by @@ -42,6 +50,12 @@ public class ScopeService { @Inject OrganizationService organizationService; + @Inject + ClientService clientService; + + @Inject + UmaResourceService umaResourceService; + public String baseDn() { return staticConfiguration.getBaseDn().getScopes(); } @@ -70,9 +84,19 @@ public void updateScope(Scope scope) { persistenceEntryManager.merge(scope); } - public Scope getScopeByInum(String inum) { + public CustomScope getScopeByInum(String inum){ + return getScopeByInum(inum, false); + } + + public CustomScope getScopeByInum(String inum, boolean withAssociatedClients) { try { - return persistenceEntryManager.find(Scope.class, getDnForScope(inum)); + CustomScope scope = persistenceEntryManager.find(CustomScope.class, getDnForScope(inum)); + if (withAssociatedClients) { + List clients = clientService.getAllClients(); + List umaResources = umaResourceService.getAllResources(); + return setClients(scope, clients, umaResources); + } + return scope; } catch (Exception e) { return null; } @@ -86,7 +110,7 @@ public String getDnForScope(String inum) { return String.format("inum=%s,ou=scopes,%s", inum, orgDn); } - public List searchScopes(String pattern, int sizeLimit) { + public List searchScopes(String pattern, int sizeLimit) { return searchScopes(pattern, sizeLimit, null); } @@ -99,13 +123,17 @@ public List searchScopesById(String jsId) { return new ArrayList<>(); } } - + public Scope getScopeByDn(String dn) { return persistenceEntryManager.find(Scope.class, dn); } - public List searchScopes(String pattern, int sizeLimit, String scopeType) { - String[] targetArray = new String[] { pattern }; + public List searchScopes(String pattern, int sizeLimit, String scopeType) { + return searchScopes(pattern, sizeLimit, scopeType, false); + } + + public List searchScopes(String pattern, int sizeLimit, String scopeType, boolean withAssociatedClients) { + String[] targetArray = new String[]{pattern}; Filter displayNameFilter = Filter.createSubstringFilter(AttributeConstants.DISPLAY_NAME, null, targetArray, null); Filter descriptionFilter = Filter.createSubstringFilter(AttributeConstants.DESCRIPTION, null, targetArray, @@ -115,22 +143,70 @@ public List searchScopes(String pattern, int sizeLimit, String scopeType) searchFilter = Filter.createANDFilter(Filter.createEqualityFilter("jansScopeTyp", scopeType), searchFilter); } try { - return persistenceEntryManager.findEntries(getDnForScope(null), Scope.class, searchFilter, sizeLimit); + List scopes = persistenceEntryManager.findEntries(getDnForScope(null), CustomScope.class, searchFilter, sizeLimit); + + if (withAssociatedClients) { + List clients = clientService.getAllClients(); + List umaResources = umaResourceService.getAllResources(); + List custScopes = scopes.stream().map(scope -> setClients(scope, clients, umaResources)).collect(Collectors.toList()); + return custScopes; + } + + return scopes; } catch (Exception e) { logger.error("No scopes found by pattern: " + pattern, e); return new ArrayList<>(); } } - public List getAllScopesList(int size) { + public List getAllScopesList(int size) { return getAllScopesList(size, null); } - public List getAllScopesList(int size, String scopeType) { + public List getAllScopesList(int size, String scopeType) { + return getAllScopesList(size, scopeType, false); + } + + public List getAllScopesList(int size, String scopeType, boolean withAssociatedClients) { Filter searchFilter = null; if (StringHelper.isNotEmpty(scopeType)) { searchFilter = Filter.createEqualityFilter("jansScopeTyp", scopeType); } - return persistenceEntryManager.findEntries(getDnForScope(null), Scope.class, searchFilter, size); + List scopes = persistenceEntryManager.findEntries(getDnForScope(null), CustomScope.class, searchFilter, size); + + if (withAssociatedClients) { + List clients = clientService.getAllClients(); + List umaResources = umaResourceService.getAllResources(); + List custScopes = scopes.stream().map(scope -> setClients(scope, clients, umaResources)).collect(Collectors.toList()); + return custScopes; + } + return scopes; + } + + private CustomScope setClients(Scope scope, List clients, List umaResources) { + ObjectMapper mapper = new ObjectMapper(); + CustomScope customScope = mapper.convertValue(scope, CustomScope.class); + customScope.setClients(Lists.newArrayList()); + + for (Client client : clients) { + if (client.getScopes() == null) { + continue; + } + if (scope.getScopeType() == ScopeType.OPENID || scope.getScopeType() == ScopeType.OAUTH || scope.getScopeType() == ScopeType.DYNAMIC) { + if (Arrays.asList(client.getScopes()).contains(getDnForScope(scope.getInum()))) { + customScope.getClients().add(client); + } + } else if (scope.getScopeType() == ScopeType.UMA) { + List umaRes = umaResources.stream().filter(umaResource -> (umaResource.getScopes() != null && umaResource.getScopes().contains(getDnForScope(scope.getInum())))).collect(Collectors.toList()); + if (umaRes.stream().anyMatch(ele -> ele.getClients().contains(clientService.getDnForClient(client.getClientId())))) { + customScope.getClients().add(client); + } + } else if (scope.getScopeType() == ScopeType.SPONTANEOUS) { + if (client.getClientId().equals(customScope.getAttributes().getSpontaneousClientId())) { + customScope.getClients().add(client); + } + } + } + return customScope; } } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/UmaResourceService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/UmaResourceService.java index 5f1a25b9ab5..032a8d3b93e 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/UmaResourceService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/UmaResourceService.java @@ -69,6 +69,10 @@ public List getAllResources(int sizeLimit) { return persistenceEntryManager.findEntries(getDnForResource(null), UmaResource.class, null, sizeLimit); } + public List getAllResources() { + return persistenceEntryManager.findEntries(getDnForResource(null), UmaResource.class, null); + } + public void addResource(UmaResource resource) { persistenceEntryManager.persist(resource); }