From 34bd41defb52c25f38a328ac6496ff9298cd15d8 Mon Sep 17 00:00:00 2001 From: pujavs <43700552+pujavs@users.noreply.github.com> Date: Wed, 30 Nov 2022 20:58:20 +0530 Subject: [PATCH] jans(config-api): static scope id and feature and admin level scopes (#3126) * fix(config-api): fix for swagger spec for scope creation and sessoin endpoint filter * ci: add yurem to linux setup codeowners * chore(image): sync missing localized attributes for sql and spanner (#2927) * chore(image): sync missing localized attributes for sql and spanner * chore(image): sync jans-schema.json template * Update restarting-services.md (#2941) Restart command and output were merged which made "copy" / "paste" hard.... * Update restarting-services.md (#2942) Removed "$" sign from command.... * Update restarting-services.md (#2943) Adding some other service related info... * feat: allow to use like with lower together (#2944) Co-authored-by: Yuriy Movchan * chore: remove unused merthod (#2945) Co-authored-by: Yuriy Movchan * feat(jans-auth-server): corrected GluuOrganization - refactor getOrganizationName() #2947 (#2948) * feat(config-api): super scope implementation * feat(config-api): static scope * feat(config-api): comprehensive claims for authurization * feat(config-api): endpoint group and admin scope * feat(config-api): sync with main * feat(config-api): endpoint group and admin scope * feat(config-api): scope change - wip * feat(config-api): scope change - wip * feat(config-api): scope enhancements * feat(config-api): scope enhancement * feat(config-api): scope enhancement wip * feat(config-api): scope enhancement- wip * feat(config-api): scope enhancement- wip * feat: jans-linux-setup config-api scope creation with static inum (ref: #3097) * feat(config-api): scope enhancement - wip * fix: jans-linux-setup create scope if inum exists (ref: #3097) * feat: jans-linux-setup config-api scope creation (ref: #3097) * feat(config-api): scope enhancement - wip * feat(config-api): scope enhancement Co-authored-by: moabu <47318409+moabu@users.noreply.github.com> Co-authored-by: Isman Firmansyah Co-authored-by: mzico Co-authored-by: Yuriy M <95305560+yuremm@users.noreply.github.com> Co-authored-by: Yuriy Movchan Co-authored-by: YuriyZ Co-authored-by: Mustafa Baser --- .../configapi/util/ApiAccessConstants.java | 15 +- .../docs/jans-config-api-swagger-auto.yaml | 46 +- .../profiles/local/test.properties | 8 +- .../configuration/AppInitializer.java | 2 +- .../rest/resource/auth/AcrsResource.java | 13 +- .../rest/resource/auth/AgamaResource.java | 27 +- .../resource/auth/AttributesResource.java | 34 +- .../auth/CacheConfigurationResource.java | 72 +- .../rest/resource/auth/ClientsResource.java | 22 +- .../rest/resource/auth/ConfigResource.java | 18 +- .../resource/auth/ConfigSmtpResource.java | 17 +- .../resource/auth/CustomScriptResource.java | 32 +- .../rest/resource/auth/JwksResource.java | 16 +- .../auth/LdapConfigurationResource.java | 16 +- .../rest/resource/auth/LoggingResource.java | 5 +- .../resource/auth/OrganizationResource.java | 5 +- .../rest/resource/auth/ScopesResource.java | 20 +- .../rest/resource/auth/SessionResource.java | 4 +- .../rest/resource/auth/StatResource.java | 2 +- .../resource/auth/UmaResourcesResource.java | 17 +- .../security/api/ApiProtectionCache.java | 131 +- .../security/api/ApiProtectionService.java | 167 +- .../service/AuthorizationService.java | 21 +- .../service/OpenIdAuthorizationService.java | 71 +- .../configapi/service/auth/ScopeService.java | 9 + .../java/io/jans/configapi/util/AuthUtil.java | 269 +-- .../main/resources/config-api-rs-protect.json | 1964 +++++++++++++---- .../configapi/core/protect/Condition.java | 59 + .../configapi/core/protect/RsResource.java | 96 + .../core/protect/RsResourceList.java | 37 + .../io/jans/configapi/core/protect/Scope.java | 36 + .../configapi/core/rest/ProtectedApi.java | 4 + .../core/util/ProtectionScopeType.java | 48 + .../setup_app/installers/config_api.py | 68 +- 34 files changed, 2488 insertions(+), 883 deletions(-) create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Condition.java create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResource.java create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResourceList.java create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Scope.java create mode 100644 jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScopeType.java diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiAccessConstants.java b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiAccessConstants.java index 1405a4288a6..fd8bacbb807 100644 --- a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiAccessConstants.java +++ b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiAccessConstants.java @@ -69,5 +69,18 @@ private ApiAccessConstants() { public static final String JANS_AUTH_SESSION_READ_ACCESS = "https://jans.io/oauth/jans-auth-server/session.readonly"; public static final String JANS_AUTH_SESSION_DELETE_ACCESS = "https://jans.io/oauth/jans-auth-server/session.delete"; public static final String JANS_AUTH_REVOKE_SESSION = "revoke_session"; - + + // Super Scopes + public static final String SUPER_ADMIN_READ_ACCESS = "https://jans.io/oauth/config/read-all"; + public static final String SUPER_ADMIN_WRITE_ACCESS = "https://jans.io/oauth/config/write-all"; + public static final String SUPER_ADMIN_DELETE_ACCESS = "https://jans.io/oauth/config/delete-all"; + + // Feature Scope + public static final String OPENID_READ_ACCESS = "https://jans.io/oauth/config/openid-read"; + public static final String OPENID_WRITE_ACCESS = "https://jans.io/oauth/config/openid/openid-write"; + public static final String OPENID_DELETE_ACCESS = "https://jans.io/oauth/config/openid/openid-delete"; + + public static final String UMA_READ_ACCESS = "https://jans.io/oauth/config/uma-read"; + public static final String UMA_WRITE_ACCESS = "https://jans.io/oauth/config/uma-write"; + public static final String UMA_DELETE_ACCESS = "https://jans.io/oauth/config/uma-delete"; } diff --git a/jans-config-api/docs/jans-config-api-swagger-auto.yaml b/jans-config-api/docs/jans-config-api-swagger-auto.yaml index 73d877bf0b0..2b3b83113f0 100644 --- a/jans-config-api/docs/jans-config-api-swagger-auto.yaml +++ b/jans-config-api/docs/jans-config-api-swagger-auto.yaml @@ -132,6 +132,8 @@ paths: security: - oauth2: - https://jans.io/oauth/config/acrs.readonly + - https://jans.io/oauth/config/acrs.write + - https://jans.io/oauth/config/read-all put: tags: - Default Authentication Method @@ -167,6 +169,7 @@ paths: security: - oauth2: - https://jans.io/oauth/config/acrs.write + - https://jans.io/oauth/config/write-all /api/v1/agama: get: tags: @@ -243,6 +246,8 @@ paths: security: - oauth2: - https://jans.io/oauth/config/agama.readonly + - https://jans.io/oauth/config/agama.write + - https://jans.io/oauth/config/read-all post: tags: - Configuration – Agama Flow @@ -333,6 +338,8 @@ paths: security: - oauth2: - https://jans.io/oauth/config/agama.readonly + - https://jans.io/oauth/config/agama.write + - https://jans.io/oauth/config/read-all post: tags: - Configuration – Agama Flow @@ -7178,19 +7185,19 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - whitePagesCanView: + adminCanEdit: type: boolean - adminCanAccess: + userCanEdit: type: boolean adminCanView: type: boolean - userCanAccess: + userCanView: type: boolean - adminCanEdit: + adminCanAccess: type: boolean - userCanView: + userCanAccess: type: boolean - userCanEdit: + whitePagesCanView: type: boolean baseDn: type: string @@ -7620,6 +7627,15 @@ components: format: int32 allowOfflineAccessWithoutConsent: type: boolean + minimumAcrLevel: + type: integer + format: int32 + minimumAcrLevelAutoresolve: + type: boolean + minimumAcrPriorityList: + type: array + items: + type: string CustomObjectAttribute: type: object properties: @@ -8334,6 +8350,15 @@ components: $ref: '#/components/schemas/EngineConfig' ssaConfiguration: $ref: '#/components/schemas/SsaConfiguration' + allResponseTypesSupported: + uniqueItems: true + type: array + items: + type: string + enum: + - code + - token + - id_token enabledFeatureFlags: uniqueItems: true type: array @@ -8361,15 +8386,6 @@ components: - STAT - PAR - SSA - allResponseTypesSupported: - uniqueItems: true - type: array - items: - type: string - enum: - - code - - token - - id_token fapi: type: boolean AuthenticationFilter: diff --git a/jans-config-api/profiles/local/test.properties b/jans-config-api/profiles/local/test.properties index a323fa7ea3e..af088ce1080 100644 --- a/jans-config-api/profiles/local/test.properties +++ b/jans-config-api/profiles/local/test.properties @@ -2,8 +2,8 @@ test.scopes=https://jans.io/oauth/config/acrs.readonly https://jans.io/oauth/config/acrs.write https://jans.io/oauth/config/attributes.readonly https://jans.io/oauth/config/attributes.write https://jans.io/oauth/config/attributes.delete https://jans.io/oauth/config/cache.readonly https://jans.io/oauth/config/cache.write https://jans.io/oauth/config/openid/clients.readonly https://jans.io/oauth/config/openid/clients.write https://jans.io/oauth/config/openid/clients.delete https://jans.io/oauth/jans-auth-server/config/properties.readonly https://jans.io/oauth/jans-auth-server/config/properties.write https://jans.io/oauth/config/smtp.readonly https://jans.io/oauth/config/smtp.write https://jans.io/oauth/config/smtp.delete https://jans.io/oauth/config/scripts.readonly https://jans.io/oauth/config/scripts.write https://jans.io/oauth/config/scripts.delete https://jans.io/oauth/config/fido2.readonly https://jans.io/oauth/config/fido2.write https://jans.io/oauth/config/jwks.readonly https://jans.io/oauth/config/jwks.write https://jans.io/oauth/config/jwks.delete https://jans.io/oauth/config/database/ldap.readonly https://jans.io/oauth/config/database/ldap.write https://jans.io/oauth/config/database/ldap.delete https://jans.io/oauth/config/logging.readonly https://jans.io/oauth/config/logging.write https://jans.io/oauth/config/scopes.readonly https://jans.io/oauth/config/scopes.write https://jans.io/oauth/config/scopes.delete https://jans.io/oauth/config/uma/resources.readonly https://jans.io/oauth/config/uma/resources.write https://jans.io/oauth/config/uma/resources.delete https://jans.io/oauth/config/database/sql.readonly https://jans.io/oauth/config/database/sql.write https://jans.io/oauth/config/database/sql.delete https://jans.io/oauth/config/stats.readonly jans_stat https://jans.io/scim/users.read https://jans.io/scim/users.write https://jans.io/oauth/config/scim/users.read https://jans.io/oauth/config/scim/users.write https://jans.io/scim/config.readonly https://jans.io/scim/config.write https://jans.io/oauth/config/organization.readonly https://jans.io/oauth/config/organization.write https://jans.io/oauth/config/user.readonly https://jans.io/oauth/config/user.write https://jans.io/oauth/config/user.delete https://jans.io/oauth/config/agama.readonly https://jans.io/oauth/config/agama.write https://jans.io/oauth/config/agama.delete https://jans.io/oauth/jans-auth-server/session.readonly https://jans.io/oauth/jans-auth-server/session.delete revoke_session # jans.server -token.endpoint=https://jans.server2/jans-auth/restv1/token +token.endpoint=https://jans.server1/jans-auth/restv1/token token.grant.type=client_credentials -test.client.id=1800.768b3d38-a6e8-4be4-93d1-72df33d34fd6 -test.client.secret=vA2TTjAOTfQY -test.issuer=https://jans.server2/ \ No newline at end of file +test.client.id=1800.5957dfad-b2cb-4764-85fe-841e6bc870ff +test.client.secret=ozu4fjIzoEbe +test.issuer=https://jans.server1/ \ No newline at end of file diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java b/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java index b848ea5989f..d80093d5928 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/configuration/AppInitializer.java @@ -153,7 +153,7 @@ public PersistenceEntryManager createPersistenceEntryManager() throws OxIntializ @ApplicationScoped @Named("authorizationService") private AuthorizationService createAuthorizationService() { - log.info( + log.error( "============= AppInitializer::createAuthorizationService() - configurationFactory.getApiProtectionType():{} ", configurationFactory.getApiProtectionType()); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AcrsResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AcrsResource.java index b3df69ddb29..cfcfc6b52b3 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AcrsResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AcrsResource.java @@ -48,13 +48,15 @@ public class AcrsResource extends ConfigBaseResource { @Operation(summary = "Gets default authentication method.", description = "Gets default authentication method.", operationId = "get-acrs", tags = { "Default Authentication Method" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.ACRS_READ_ACCESS })) + ApiAccessConstants.ACRS_READ_ACCESS, ApiAccessConstants.ACRS_WRITE_ACCESS, + ApiAccessConstants.SUPER_ADMIN_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuthenticationMethod.class) , examples = @ExampleObject(name = "Response example" , value = "example/acr/acr.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuthenticationMethod.class), examples = @ExampleObject(name = "Response example", value = "example/acr/acr.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.ACRS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ACRS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.ACRS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getDefaultAuthenticationMethod() { final GluuConfiguration gluuConfiguration = configurationService.findGluuConfiguration(); @@ -65,7 +67,7 @@ public Response getDefaultAuthenticationMethod() { @Operation(summary = "Updates default authentication method.", description = "Updates default authentication method.", operationId = "put-acrs", tags = { "Default Authentication Method" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.ACRS_WRITE_ACCESS })) + ApiAccessConstants.ACRS_WRITE_ACCESS, ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS })) @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuthenticationMethod.class), examples = @ExampleObject(name = "Request json example", value = "example/acr/acr.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuthenticationMethod.class))), @@ -73,7 +75,8 @@ public Response getDefaultAuthenticationMethod() { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.ACRS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ACRS_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateDefaultAuthenticationMethod(@NotNull AuthenticationMethod authenticationMethod) { log.debug("ACRS details to update - authenticationMethod:{}", authenticationMethod); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaResource.java index bb7a43d03c0..7e339b63f8d 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaResource.java @@ -61,13 +61,15 @@ public class AgamaResource extends ConfigBaseResource { @Operation(summary = "Fetches all agama flow.", description = "Fetches all agama flow.", operationId = "get-agama-flows", tags = { "Configuration – Agama Flow" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.AGAMA_READ_ACCESS })) + ApiAccessConstants.AGAMA_READ_ACCESS, ApiAccessConstants.AGAMA_WRITE_ACCESS, + ApiAccessConstants.SUPER_ADMIN_READ_ACCESS })) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Agama Flows", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response json example", value = "example/agama/agama-get-all.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }, groupScopes = { + ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getFlows(@DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue(ApiConstants.DEFAULT_LIST_START_INDEX) @QueryParam(value = ApiConstants.START_INDEX) int startIndex, @@ -90,13 +92,15 @@ public Response getFlows(@DefaultValue("") @QueryParam(value = ApiConstants.PATT @Operation(summary = "Gets an agama flow based on Qname.", description = "Gets an agama flow based on Qname.", operationId = "get-agama-flow", tags = { "Configuration – Agama Flow" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.AGAMA_READ_ACCESS })) + ApiAccessConstants.AGAMA_READ_ACCESS, ApiAccessConstants.AGAMA_WRITE_ACCESS, + ApiAccessConstants.SUPER_ADMIN_READ_ACCESS })) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Agama Flow", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = Flow.class), examples = @ExampleObject(name = "Response json example", value = "example/agama/agama-get.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }, groupScopes = { + ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.QNAME_PATH) public Response getFlowByName(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @DefaultValue("false") @QueryParam(value = ApiConstants.INCLUDE_SOURCE) boolean includeSource) { @@ -121,7 +125,8 @@ public Response getFlowByName(@PathParam(ApiConstants.QNAME) @NotNull String flo @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createFlow(@Valid Flow flow) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { logger.debug(" Flow to be added flow:{}, flow.getQName():{}, flow.getSource():{} ", flow, flow.getQname(), @@ -155,7 +160,8 @@ public Response createFlow(@Valid Flow flow) @POST @Consumes(MediaType.TEXT_PLAIN) @Path(ApiConstants.QNAME_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createFlowFromSource(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @Valid String source) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { logger.debug(" Flow to be created flowName:{}, source:{}", flowName, source); @@ -196,7 +202,8 @@ public Response createFlowFromSource(@PathParam(ApiConstants.QNAME) @NotNull Str @PUT @Consumes(MediaType.TEXT_PLAIN) @Path(ApiConstants.SOURCE + ApiConstants.QNAME_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateFlowSource(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @Valid String source) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { logger.debug(" Flow to be updated flowName:{}, source:{}", flowName, source); @@ -232,7 +239,8 @@ public Response updateFlowSource(@PathParam(ApiConstants.QNAME) @NotNull String @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) @Path(ApiConstants.QNAME_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchFlow(@PathParam(ApiConstants.QNAME) @NotNull String flowName, @NotNull JsonPatch jsonPatch) throws JsonPatchException, IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { @@ -267,7 +275,8 @@ public Response patchFlow(@PathParam(ApiConstants.QNAME) @NotNull String flowNam @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.QNAME_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_DELETE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response delete(@PathParam(ApiConstants.QNAME) @NotNull String flowName) { logger.debug(" Flow to delete - flowName:{}", flowName); String decodedFlowName = getURLDecodedValue(flowName); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java index b3d48969ef7..5fbeab63569 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java @@ -64,11 +64,12 @@ public class AttributesResource extends ConfigBaseResource { "Attribute" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response example" , value = "example/attribute/attribute-get-all.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute-get-all.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS }, groupScopes = { + ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getAttributes( @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -94,11 +95,12 @@ public Response getAttributes( "Attribute" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Response example" , value = "example/attribute/attribute-get.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute-get.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_READ_ACCESS }, groupScopes = { + ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response getAttributeByInum(@PathParam(ApiConstants.INUM) @NotNull String inum) { GluuAttribute attribute = attributeService.getAttributeByInum(inum); @@ -109,13 +111,14 @@ public Response getAttributeByInum(@PathParam(ApiConstants.INUM) @NotNull String @Operation(summary = "Adds a new attribute", description = "Adds a new attribute", operationId = "post-attributes", tags = { "Attribute" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS })) - @RequestBody(description = "GluuAttribute object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class) , examples = @ExampleObject(name = "Request example" , value = "example/attribute/attribute.json"))) + @RequestBody(description = "GluuAttribute object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Request example", value = "example/attribute/attribute.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class) , examples = @ExampleObject(name = "Response example" , value = "example/attribute/attribute.json"))), + @ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createAttribute(@Valid GluuAttribute attribute) { log.debug(" GluuAttribute details to add - attribute:{}", attribute); checkNotNull(attribute.getName(), AttributeNames.NAME); @@ -132,13 +135,14 @@ public Response createAttribute(@Valid GluuAttribute attribute) { @Operation(summary = "Updates an existing attribute", description = "Updates an existing attribute", operationId = "put-attributes", tags = { "Attribute" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS })) - @RequestBody(description = "GluuAttribute object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class) , examples = @ExampleObject(name = "Request example" , value = "example/attribute/attribute.json"))) + @RequestBody(description = "GluuAttribute object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Request example", value = "example/attribute/attribute.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class) , examples = @ExampleObject(name = "Response example" , value = "example/attribute/attribute.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateAttribute(@Valid GluuAttribute attribute) { log.debug(" GluuAttribute details to update - attribute:{}", attribute); String inum = attribute.getInum(); @@ -158,15 +162,16 @@ public Response updateAttribute(@Valid GluuAttribute attribute) { @Operation(summary = "Partially modify a GluuAttribute", description = "Partially modify a GluuAttribute", operationId = "patch-attributes-by-inum", tags = { "Attribute" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS })) - @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = PatchRequest.class)) , examples = @ExampleObject(name = "Patch request example" , value = "example/attribute/attribute-patch.json"))) + @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = PatchRequest.class)), examples = @ExampleObject(name = "Patch request example", value = "example/attribute/attribute-patch.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Updated GluuAttribute", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class) , examples = @ExampleObject(name = "Response example" , value = "example/attribute/attribute.json"))), + @ApiResponse(responseCode = "200", description = "Updated GluuAttribute", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GluuAttribute.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response patchAtribute(@PathParam(ApiConstants.INUM) @NotNull String inum, @NotNull String pathString) throws JsonPatchException, IOException { @@ -188,7 +193,8 @@ public Response patchAtribute(@PathParam(ApiConstants.INUM) @NotNull String inum @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.INUM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_DELETE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteAttribute(@PathParam(ApiConstants.INUM) @NotNull String inum) { log.debug(" GluuAttribute details to delete - inum:{}", inum); GluuAttribute attribute = attributeService.getAttributeByInum(inum); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CacheConfigurationResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CacheConfigurationResource.java index e538eeb23a0..4cf973f3c06 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CacheConfigurationResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CacheConfigurationResource.java @@ -70,11 +70,12 @@ private CacheConfiguration mergeModifiedCache(Function { @@ -111,7 +113,8 @@ public Response patchCacheConfiguration(@NotNull String requestString) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.REDIS) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }, groupScopes = { + ApiAccessConstants.CACHE_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getRedisConfiguration() { return Response.ok(loadCacheConfiguration().getRedisConfiguration()).build(); } @@ -119,14 +122,15 @@ public Response getRedisConfiguration() { @Operation(summary = "Updates Redis cache configuration.", description = "Updates Redis cache configuration", operationId = "put-config-cache-redis", tags = { "Cache Configuration – Redis" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS })) - @RequestBody(description = "RedisConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class) , examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-redis.json"))) + @RequestBody(description = "RedisConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class), examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-redis.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Redis cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-redis.json"))), + @ApiResponse(responseCode = "200", description = "Redis cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-redis.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @Path(ApiConstants.REDIS) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateRedisConfiguration(@NotNull RedisConfiguration redisConfiguration) { logger.debug("REDIS CACHE details to update - redisConfiguration:{}", redisConfiguration); final CacheConfiguration modifiedCache = mergeModifiedCache(cache -> { @@ -139,15 +143,16 @@ public Response updateRedisConfiguration(@NotNull RedisConfiguration redisConfig @Operation(summary = "Patch Redis cache configuration.", description = "Patch Redis cache configuration", operationId = "patch-config-cache-redis", tags = { "Cache Configuration – Redis" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS })) - @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)) , examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-redis-patch.json"))) + @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-redis-patch.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Redis cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-redis.json"))), + @ApiResponse(responseCode = "200", description = "Redis cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = RedisConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-redis.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Path(ApiConstants.REDIS) - @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchRedisConfiguration(@NotNull String requestString) { logger.debug("REDIS CACHE details to patch - requestString:{} ", requestString); mergeModifiedCache(cache -> { @@ -166,12 +171,13 @@ public Response patchRedisConfiguration(@NotNull String requestString) { "Cache Configuration – in-Memory" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "In-Memory configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), + @ApiResponse(responseCode = "200", description = "In-Memory configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.IN_MEMORY) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }, groupScopes = { + ApiAccessConstants.CACHE_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getInMemoryConfiguration() { return Response.ok(loadCacheConfiguration().getInMemoryConfiguration()).build(); } @@ -179,14 +185,15 @@ public Response getInMemoryConfiguration() { @Operation(summary = "Updates in-Memory cache configuration.", description = "Updates in-Memory cache configuration", operationId = "put-config-cache-in-memory", tags = { "Cache Configuration – in-Memory" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS })) - @RequestBody(description = "inMemoryConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class) , examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-in-memory.json"))) + @RequestBody(description = "inMemoryConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class), examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-in-memory.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "In-Memory cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), + @ApiResponse(responseCode = "200", description = "In-Memory cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @Path(ApiConstants.IN_MEMORY) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateInMemoryConfiguration(@NotNull InMemoryConfiguration inMemoryConfiguration) { logger.debug("IN_MEMORY CACHE details to update - inMemoryConfiguration:{}", inMemoryConfiguration); final CacheConfiguration modifiedCache = mergeModifiedCache(cache -> { @@ -200,15 +207,16 @@ public Response updateInMemoryConfiguration(@NotNull InMemoryConfiguration inMem @Operation(summary = "Patch In-Memory cache configuration.", description = "Patch In-Memory cache configuration", operationId = "patch-config-cache-in-memory", tags = { "Cache Configuration – in-Memory" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS })) - @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)) , examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-in-memory-patch.json"))) + @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-in-memory-patch.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "In-Memory cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), + @ApiResponse(responseCode = "200", description = "In-Memory cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = InMemoryConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-in-memory.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Path(ApiConstants.IN_MEMORY) @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchInMemoryConfiguration(@NotNull String requestString) { logger.debug("IN_MEMORY CACHE details to patch - requestString:{}", requestString); mergeModifiedCache(cache -> { @@ -231,7 +239,8 @@ public Response patchInMemoryConfiguration(@NotNull String requestString) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.NATIVE_PERSISTENCE) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }, groupScopes = { + ApiAccessConstants.CACHE_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getNativePersistenceConfiguration() { return Response.ok(loadCacheConfiguration().getNativePersistenceConfiguration()).build(); } @@ -241,12 +250,13 @@ public Response getNativePersistenceConfiguration() { ApiAccessConstants.CACHE_WRITE_ACCESS })) @RequestBody(description = "NativePersistenceConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = NativePersistenceConfiguration.class), examples = @ExampleObject(name = "Request json example", value = "example/cache/cache-native-persistence.json"))) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Native persistence cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = NativePersistenceConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-native-persistence.json"))), + @ApiResponse(responseCode = "200", description = "Native persistence cache configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = NativePersistenceConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-native-persistence.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @Path(ApiConstants.NATIVE_PERSISTENCE) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateNativePersistenceConfiguration( @NotNull NativePersistenceConfiguration nativePersistenceConfiguration) { logger.debug("NATIVE_PERSISTENCE CACHE details to update - nativePersistenceConfiguration:{}", @@ -269,7 +279,8 @@ public Response updateNativePersistenceConfiguration( @PATCH @Path(ApiConstants.NATIVE_PERSISTENCE) @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchNativePersistenceConfiguration(@NotNull String requestString) { logger.debug("NATIVE_PERSISTENCE CACHE details to patch - requestString:{} ", requestString); mergeModifiedCache(cache -> { @@ -288,12 +299,13 @@ public Response patchNativePersistenceConfiguration(@NotNull String requestStrin "Cache Configuration – Memcached" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.CACHE_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Memcached configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = MemcachedConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-memcached.json"))), + @ApiResponse(responseCode = "200", description = "Memcached configuration details", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = MemcachedConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/cache/cache-memcached.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.MEMCACHED) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_READ_ACCESS }, groupScopes = { + ApiAccessConstants.CACHE_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getMemcachedConfiguration() { return Response.ok(loadCacheConfiguration().getMemcachedConfiguration()).build(); } @@ -309,7 +321,8 @@ public Response getMemcachedConfiguration() { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @Path(ApiConstants.MEMCACHED) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateMemcachedConfiguration(@NotNull MemcachedConfiguration memcachedConfiguration) { logger.debug("MEMCACHED CACHE details to update - memcachedConfiguration:{} ", memcachedConfiguration); final CacheConfiguration modifiedCache = mergeModifiedCache(cache -> { @@ -330,7 +343,8 @@ public Response updateMemcachedConfiguration(@NotNull MemcachedConfiguration mem @PATCH @Path(ApiConstants.MEMCACHED) @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.CACHE_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchMemcachedConfiguration(@NotNull String requestString) { logger.debug("MEMCACHED CACHE details to patch - requestString:{} ", requestString); mergeModifiedCache(cache -> { diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ClientsResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ClientsResource.java index 1b7322563d7..ebea7e4f979 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ClientsResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ClientsResource.java @@ -86,11 +86,12 @@ public class ClientsResource extends ConfigBaseResource { "OAuth - OpenID Connect - Clients" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class) , examples = @ExampleObject(name = "Response json example", value = "example/openid-clients/openid-clients-get-all.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response json example", value = "example/openid-clients/openid-clients-get-all.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_READ_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getOpenIdConnectClients( @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -116,7 +117,8 @@ public Response getOpenIdConnectClients( @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_READ_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response getOpenIdClientByInum(@PathParam(ApiConstants.INUM) @NotNull String inum) { if (logger.isDebugEnabled()) { @@ -136,7 +138,8 @@ public Response getOpenIdClientByInum(@PathParam(ApiConstants.INUM) @NotNull Str @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createOpenIdConnect(@Valid Client client) throws EncryptionException { if (logger.isDebugEnabled()) { logger.debug("Client to be added - client:{}, client.getAttributes():{}, client.getCustomAttributes():{}", @@ -184,7 +187,8 @@ public Response createOpenIdConnect(@Valid Client client) throws EncryptionExcep @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateClient(@Valid Client client) throws EncryptionException { if (logger.isDebugEnabled()) { logger.debug("Client details to be updated - client:{}", escapeLog(client)); @@ -217,7 +221,7 @@ public Response updateClient(@Valid Client client) throws EncryptionException { @Operation(summary = "Patch OpenId Connect client", description = "Patch OpenId Connect client", operationId = "patch-oauth-openid-client-by-inum", tags = { "OAuth - OpenID Connect - Clients" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS })) - @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/openid-clients/openid-clients-patch.json") )) + @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/openid-clients/openid-clients-patch.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = Client.class), examples = @ExampleObject(name = "Response json example", value = "example/openid-clients/openid-clients-get.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @@ -225,7 +229,8 @@ public Response updateClient(@Valid Client client) throws EncryptionException { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_WRITE_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response patchClient(@PathParam(ApiConstants.INUM) @NotNull String inum, @NotNull String jsonPatchString) throws JsonPatchException, IOException { @@ -250,7 +255,8 @@ public Response patchClient(@PathParam(ApiConstants.INUM) @NotNull String inum, @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.INUM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.OPENID_CLIENTS_DELETE_ACCESS }, groupScopes = { + ApiAccessConstants.OPENID_DELETE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteClient(@PathParam(ApiConstants.INUM) @NotNull String inum) { if (logger.isDebugEnabled()) { logger.debug("Client to be deleted - inum:{} ", escapeLog(inum)); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigResource.java index 5a4e9de9ab4..a24286a23d4 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigResource.java @@ -34,7 +34,6 @@ import jakarta.ws.rs.core.Response; import java.io.IOException; -import org.json.JSONObject; import org.slf4j.Logger; @Path(ApiConstants.JANS_AUTH + ApiConstants.CONFIG) @@ -58,7 +57,9 @@ public class ConfigResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_READ_ACCESS }, groupScopes = { + ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getAppConfiguration() { AppConfiguration appConfiguration = configurationService.find(); log.debug("ConfigResource::getAppConfiguration() appConfiguration:{}", appConfiguration); @@ -67,15 +68,16 @@ public Response getAppConfiguration() { @Operation(summary = "Partially modifies Jans authorization server Application configuration properties.", description = "Partially modifies Jans authorization server AppConfiguration properties.", operationId = "patch-properties", tags = { "Configuration – Properties" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS})) - @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)) , examples = @ExampleObject(name = "Request json example", value = "example/auth/config/auth-config-patch.json"))) + ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS })) + @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/auth/config/auth-config-patch.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AppConfiguration.class))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchAppConfigurationProperty(@NotNull String jsonPatchString) throws JsonPatchException, IOException { log.debug("AUTH CONF details to patch - jsonPatchString:{} ", jsonPatchString); @@ -101,11 +103,13 @@ public Response patchAppConfigurationProperty(@NotNull String jsonPatchString) "Configuration – Properties" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Jans Authorization Server persistence type", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PersistenceConfiguration.class) , examples = @ExampleObject(name = "Response json example", value = "example/auth/config/auth-config-persistence.json"))), + @ApiResponse(responseCode = "200", description = "Jans Authorization Server persistence type", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PersistenceConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/config/auth-config-persistence.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_CONFIG_READ_ACCESS }, groupScopes = { + ApiAccessConstants.JANS_AUTH_CONFIG_WRITE_ACCESS }, superScopes = { + ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.PERSISTENCE) public Response getPersistenceDetails() { String persistenceType = configurationService.getPersistenceType(); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigSmtpResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigSmtpResource.java index aca1a9dd13f..18109bd996a 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigSmtpResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/ConfigSmtpResource.java @@ -65,7 +65,8 @@ public class ConfigSmtpResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SMTP_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SMTP_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SMTP_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getSmtpServerConfiguration() { SmtpConfiguration smtpConfiguration = configurationService.getConfiguration().getSmtpConfiguration(); log.debug(SMTP_CONFIGURATION + ":{}", smtpConfiguration); @@ -74,14 +75,15 @@ public Response getSmtpServerConfiguration() { @Operation(summary = "Adds SMTP server configuration", description = "Adds SMTP server configuration", operationId = "post-config-smtp", tags = { "Configuration – SMTP" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.SMTP_WRITE_ACCESS })) + ApiAccessConstants.SMTP_WRITE_ACCESS })) @RequestBody(description = "SmtpConfiguration object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = SmtpConfiguration.class), examples = @ExampleObject(name = "Request json example", value = "example/auth/smtp/smtp.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = SmtpConfiguration.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/smtp/smtp-get.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.SMTP_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SMTP_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response setupSmtpConfiguration(@Valid SmtpConfiguration smtpConfiguration) throws EncryptionException { log.debug(SMTP_CONFIGURATION + ":{}", smtpConfiguration); String password = smtpConfiguration.getPassword(); @@ -107,7 +109,8 @@ public Response setupSmtpConfiguration(@Valid SmtpConfiguration smtpConfiguratio @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.SMTP_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SMTP_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateSmtpConfiguration(@Valid SmtpConfiguration smtpConfiguration) throws EncryptionException { log.debug(SMTP_CONFIGURATION + ":{}", smtpConfiguration); String password = smtpConfiguration.getPassword(); @@ -131,7 +134,8 @@ public Response updateSmtpConfiguration(@Valid SmtpConfiguration smtpConfigurati @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST @Path(ApiConstants.TEST) - @ProtectedApi(scopes = { ApiAccessConstants.SMTP_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SMTP_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SMTP_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response testSmtpConfiguration() throws EncryptionException { SmtpConfiguration smtpConfiguration = configurationService.getConfiguration().getSmtpConfiguration(); @@ -152,7 +156,8 @@ public Response testSmtpConfiguration() throws EncryptionException { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE - @ProtectedApi(scopes = { ApiAccessConstants.SMTP_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SMTP_DELETE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response removeSmtpConfiguration() { GluuConfiguration configurationUpdate = configurationService.getConfiguration(); configurationUpdate.setSmtpConfiguration(new SmtpConfiguration()); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CustomScriptResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CustomScriptResource.java index 3fd789c4ec8..8a7dffc0d66 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CustomScriptResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/CustomScriptResource.java @@ -57,11 +57,12 @@ public class CustomScriptResource extends ConfigBaseResource { "Custom Scripts" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class) , examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-all.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-all.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getAllCustomScripts( @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -83,13 +84,14 @@ public Response getAllCustomScripts( "Custom Scripts" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS })) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "CustomScript", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class) , examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-by-name.json"))), + @ApiResponse(responseCode = "200", description = "CustomScript", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-by-name.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(PATH_SEPARATOR + ApiConstants.NAME + ApiConstants.NAME_PARAM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getCustomScriptByName(@PathParam(ApiConstants.NAME) @NotNull String name) { if (logger.isDebugEnabled()) { @@ -113,7 +115,8 @@ public Response getCustomScriptByName(@PathParam(ApiConstants.NAME) @NotNull Str @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(PATH_SEPARATOR + ApiConstants.TYPE + ApiConstants.TYPE_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getCustomScriptsByTypePattern(@PathParam(ApiConstants.TYPE) @NotNull String type, @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -142,7 +145,8 @@ public Response getCustomScriptsByTypePattern(@PathParam(ApiConstants.TYPE) @Not @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(PATH_SEPARATOR + ApiConstants.INUM + PATH_SEPARATOR + ApiConstants.INUM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getCustomScriptByInum(@PathParam(ApiConstants.INUM) @NotNull String inum) { if (logger.isDebugEnabled()) { logger.debug("Custom Script to be fetched - inum:{} ", escapeLog(inum)); @@ -163,13 +167,14 @@ public Response getCustomScriptByInum(@PathParam(ApiConstants.INUM) @NotNull Str @Operation(summary = "Adds a new custom script", description = "Adds a new custom script", operationId = "post-config-scripts", tags = { "Custom Scripts" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS })) - @RequestBody(description = "CustomScript object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class) , examples = @ExampleObject(name = "Request json example", value = "example/auth/scripts/scripts.json"))) + @RequestBody(description = "CustomScript object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class), examples = @ExampleObject(name = "Request json example", value = "example/auth/scripts/scripts.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-response.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createScript(@Valid CustomScript customScript) { logger.debug("Custom Script to create - customScript:{}", customScript); Objects.requireNonNull(customScript, "Attempt to create null custom script"); @@ -187,14 +192,15 @@ public Response createScript(@Valid CustomScript customScript) { @Operation(summary = "Updates a custom script", description = "Updates a custom script", operationId = "put-config-scripts", tags = { "Custom Scripts" }, security = @SecurityRequirement(name = "oauth2", scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS })) - @RequestBody(description = "CustomScript object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class) , examples = @ExampleObject(name = "Request json example", value = "example/auth/scripts/scripts.json"))) + @RequestBody(description = "CustomScript object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class), examples = @ExampleObject(name = "Request json example", value = "example/auth/scripts/scripts.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomScript.class), examples = @ExampleObject(name = "Response json example", value = "example/auth/scripts/scripts-response.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateScript(@Valid @NotNull CustomScript customScript) { logger.debug("Custom Script to update - customScript:{}", customScript); CustomScript existingScript = customScriptService.getScriptByInum(customScript.getInum()); @@ -214,7 +220,8 @@ public Response updateScript(@Valid @NotNull CustomScript customScript) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.INUM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_DELETE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteScript(@PathParam(ApiConstants.INUM) @NotNull String inum) { try { if (logger.isDebugEnabled()) { @@ -240,7 +247,8 @@ public Response deleteScript(@PathParam(ApiConstants.INUM) @NotNull String inum) @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCRIPTS_WRITE_ACCESS }, groupScopes = {}, superScopes = { + ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response patchAtribute(@PathParam(ApiConstants.INUM) @NotNull String inum, @NotNull String pathString) throws JsonPatchException, IOException { diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/JwksResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/JwksResource.java index ff1fd210881..2277f784771 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/JwksResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/JwksResource.java @@ -58,7 +58,8 @@ public class JwksResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_READ_ACCESS }, groupScopes = { + ApiAccessConstants.JWKS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response get() { final String json = configurationService.findConf().getWebKeys().toString(); log.debug("JWKS json :{}", json); @@ -74,7 +75,7 @@ public Response get() { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response put(WebKeysConfiguration webkeys) { log.debug("JWKS details to be updated - webkeys:{}", webkeys); final Conf conf = configurationService.findConf(); @@ -94,7 +95,7 @@ public Response put(WebKeysConfiguration webkeys) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patch(String requestString) throws JsonPatchException, IOException { log.debug("JWKS details to be patched - requestString:{}", requestString); final Conf conf = configurationService.findConf(); @@ -116,7 +117,7 @@ public Response patch(String requestString) throws JsonPatchException, IOExcepti @ApiResponse(responseCode = "406", description = "Not Acceptable"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.KEY_PATH) public Response getKeyById(@NotNull JSONWebKey jwk) { log.debug("Add a new Key to the JWKS:{}", jwk); @@ -145,7 +146,8 @@ public Response getKeyById(@NotNull JSONWebKey jwk) { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_READ_ACCESS } , groupScopes = { + ApiAccessConstants.JWKS_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.KID_PATH) public Response getKeyById(@PathParam(ApiConstants.KID) @NotNull String kid) { log.debug("Fetch JWK details by kid:{}", kid); @@ -166,7 +168,7 @@ public Response getKeyById(@PathParam(ApiConstants.KID) @NotNull String kid) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.KID_PATH) public Response patch(@PathParam(ApiConstants.KID) @NotNull String kid, @NotNull String requestString) throws JsonPatchException, IOException { @@ -201,7 +203,7 @@ public Response patch(@PathParam(ApiConstants.KID) @NotNull String kid, @NotNull @ApiResponse(responseCode = "406", description = "Not Acceptable"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE - @ProtectedApi(scopes = { ApiAccessConstants.JWKS_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JWKS_DELETE_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) @Path(ApiConstants.KID_PATH) public Response deleteKey(@PathParam(ApiConstants.KID) @NotNull String kid) { log.debug("Key to be to be deleted - kid:{}", kid); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LdapConfigurationResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LdapConfigurationResource.java index 70a34784847..c09729faf71 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LdapConfigurationResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LdapConfigurationResource.java @@ -55,7 +55,8 @@ public class LdapConfigurationResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS } , groupScopes = { + ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getLdapConfiguration() { List ldapConfigurationList = this.ldapConfigurationService.findLdapConfigurations(); return Response.ok(ldapConfigurationList).build(); @@ -70,7 +71,8 @@ public Response getLdapConfiguration() { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.NAME_PARAM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS } , groupScopes = { + ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getLdapConfigurationByName(@PathParam(ApiConstants.NAME) String name) { GluuLdapConfiguration ldapConfiguration = findLdapConfigurationByName(name); return Response.ok(ldapConfiguration).build(); @@ -86,7 +88,7 @@ public Response getLdapConfigurationByName(@PathParam(ApiConstants.NAME) String @ApiResponse(responseCode = "406", description = "Not Acceptable"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response addLdapConfiguration(@Valid @NotNull GluuLdapConfiguration ldapConfiguration) { logger.debug("LDAP configuration to be added - ldapConfiguration:{} ", ldapConfiguration); // Ensure that an LDAP server with same name does not exists. @@ -113,7 +115,7 @@ public Response addLdapConfiguration(@Valid @NotNull GluuLdapConfiguration ldapC @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateLdapConfiguration(@Valid @NotNull GluuLdapConfiguration ldapConfiguration) { logger.debug("LDAP configuration to be updated - ldapConfiguration:{}", ldapConfiguration); findLdapConfigurationByName(ldapConfiguration.getConfigId()); @@ -131,7 +133,7 @@ public Response updateLdapConfiguration(@Valid @NotNull GluuLdapConfiguration ld @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.NAME_PARAM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_DELETE_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteLdapConfigurationByName(@PathParam(ApiConstants.NAME) String name) { logger.debug("LDAP configuration to be deleted - name:{}", name); findLdapConfigurationByName(name); @@ -153,7 +155,7 @@ public Response deleteLdapConfigurationByName(@PathParam(ApiConstants.NAME) Stri @PATCH @Path(ApiConstants.NAME_PARAM_PATH) @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchLdapConfigurationByName(@PathParam(ApiConstants.NAME) String name, @NotNull String requestString) throws JsonPatchException, IOException { logger.debug("LDAP configuration to be patched - name:{}, requestString:{} ", name, requestString); @@ -175,7 +177,7 @@ public Response patchLdapConfigurationByName(@PathParam(ApiConstants.NAME) Strin @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST @Path(ApiConstants.TEST) - @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.DATABASE_LDAP_READ_ACCESS }, groupScopes = {ApiAccessConstants.DATABASE_LDAP_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response testLdapConfigurationByName(@Valid @NotNull GluuLdapConfiguration ldapConfiguration) { logger.debug("LDAP configuration to be tested - ldapConfiguration:{}", ldapConfiguration); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LoggingResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LoggingResource.java index 5f85a9e31e0..68717ee9a3e 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LoggingResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/LoggingResource.java @@ -51,7 +51,8 @@ public class LoggingResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.LOGGING_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.LOGGING_READ_ACCESS } , groupScopes = { + ApiAccessConstants.LOGGING_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getLogging() { return Response.ok(this.getLoggingConfiguration()).build(); } @@ -65,7 +66,7 @@ public Response getLogging() { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.LOGGING_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.LOGGING_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateLogConf(@Valid Logging logging) { log.debug("LOGGING configuration to be updated -logging:{}", logging); Conf conf = configurationService.findConf(); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/OrganizationResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/OrganizationResource.java index ca8f4718a7a..c878d482d11 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/OrganizationResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/OrganizationResource.java @@ -49,7 +49,8 @@ public class OrganizationResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.ORG_CONFIG_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ORG_CONFIG_READ_ACCESS } , groupScopes = { + ApiAccessConstants.ORG_CONFIG_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getOrganization() { return Response.ok(organizationService.getOrganization()).build(); } @@ -64,7 +65,7 @@ public Response getOrganization() { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.ORG_CONFIG_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.ORG_CONFIG_WRITE_ACCESS }, groupScopes = { }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response patchOrganization(@NotNull String pathString) throws JsonPatchException, IOException { logger.trace("Organization patch request - pathString:{} ", pathString); GluuOrganization organization = organizationService.getOrganization(); 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 16a74953142..f4845572e30 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 @@ -80,7 +80,8 @@ public class ScopesResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS } , groupScopes = { + ApiAccessConstants.SCOPES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getScopes(@DefaultValue("") @QueryParam(ApiConstants.TYPE) String type, @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -106,7 +107,8 @@ public Response getScopes(@DefaultValue("") @QueryParam(ApiConstants.TYPE) Strin @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS } , groupScopes = { + ApiAccessConstants.SCOPES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response getScopeById(@NotNull @PathParam(ApiConstants.INUM) String inum, @DefaultValue("false") @QueryParam(value = ApiConstants.WITH_ASSOCIATED_CLIENTS) boolean withAssociatedClients) { @@ -124,7 +126,8 @@ public Response getScopeById(@NotNull @PathParam(ApiConstants.INUM) String inum, @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }, groupScopes = { + ApiAccessConstants.SCOPES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.CREATOR + ApiConstants.CREATORID_PATH) public Response getScopeByClientId(@NotNull @PathParam(ApiConstants.CREATORID) String creatorId) { log.debug("SCOPES to be fetched by creatorId:{}", creatorId); @@ -144,7 +147,8 @@ public Response getScopeByClientId(@NotNull @PathParam(ApiConstants.CREATORID) S @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_READ_ACCESS } , groupScopes = { + ApiAccessConstants.SCOPES_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Path(ApiConstants.TYPE + ApiConstants.TYPE_PATH) public Response getScopeByType(@NotNull @PathParam(ApiConstants.TYPE) String type) { log.debug("SCOPES to be fetched by type:{}", type); @@ -164,7 +168,7 @@ public Response getScopeByType(@NotNull @PathParam(ApiConstants.TYPE) String typ @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createOpenidScope(@Valid Scope scope) { log.debug("SCOPE to be added - scope:{}", scope); @@ -195,7 +199,7 @@ public Response createOpenidScope(@Valid Scope scope) { @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateScope(@Valid Scope scope) { log.debug("SCOPE to be updated - scop:{}", scope.getId()); String inum = scope.getInum(); @@ -226,7 +230,7 @@ public Response updateScope(@Valid Scope scope) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.INUM_PATH) public Response patchScope(@PathParam(ApiConstants.INUM) @NotNull String inum, @NotNull String pathString) throws JsonPatchException, IOException { @@ -251,7 +255,7 @@ public Response patchScope(@PathParam(ApiConstants.INUM) @NotNull String inum, @ @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.INUM_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.SCOPES_DELETE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteScope(@PathParam(ApiConstants.INUM) @NotNull String inum) { log.debug("SCOPES to be deleted - inum:{}", inum); Scope scope = scopeService.getScopeByInum(inum); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/SessionResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/SessionResource.java index c6c86e9b702..1da2c0840aa 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/SessionResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/SessionResource.java @@ -49,7 +49,7 @@ public class SessionResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_SESSION_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_SESSION_READ_ACCESS } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getAllSessions() { final List sessions = sessionService.getSessions(); logger.debug("sessions:{}", sessions); @@ -66,7 +66,7 @@ public Response getAllSessions() { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST @ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_SESSION_DELETE_ACCESS, - ApiAccessConstants.JANS_AUTH_REVOKE_SESSION }) + ApiAccessConstants.JANS_AUTH_REVOKE_SESSION } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) @Path(ApiConstants.USERDN_PATH) public Response getAppConfiguration(@PathParam(ApiConstants.USERDN) @NotNull String userDn) { logger.debug("userDn:{}", userDn); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/StatResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/StatResource.java index 555870cf972..496c31f60ab 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/StatResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/StatResource.java @@ -46,7 +46,7 @@ public class StatResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.STATS_USER_READ_ACCESS, ApiAccessConstants.JANS_STAT }) + @ProtectedApi(scopes = { ApiAccessConstants.STATS_USER_READ_ACCESS, ApiAccessConstants.JANS_STAT } , groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Produces(MediaType.APPLICATION_JSON) public Response getStatistics(@HeaderParam("Authorization") String authorization, @QueryParam(value = "month") String month, @QueryParam(value = "start_month") String startMonth, diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UmaResourcesResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UmaResourcesResource.java index 00b29370e18..d01993838e2 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UmaResourcesResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UmaResourcesResource.java @@ -67,7 +67,8 @@ public class UmaResourcesResource extends ConfigBaseResource { @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS } , groupScopes = { + ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS, ApiAccessConstants.UMA_READ_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response fetchUmaResources( @DefaultValue(ApiConstants.DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, @@ -92,7 +93,8 @@ public Response fetchUmaResources( @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path(ApiConstants.ID_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS }, groupScopes = { + ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS, ApiAccessConstants.UMA_READ_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getUmaResourceByInum(@PathParam(value = ApiConstants.ID) @NotNull String id) { logger.debug("UMA_RESOURCE to fetch by id:{}", id); return Response.ok(findOrThrow(id)).build(); @@ -107,7 +109,8 @@ public Response getUmaResourceByInum(@PathParam(value = ApiConstants.ID) @NotNul @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path("/" + ApiConstants.CLIENTID + ApiConstants.CLIENTID_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_READ_ACCESS }, groupScopes = { + ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS, ApiAccessConstants.UMA_READ_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) public Response getUmaResourceByAssociatedClient( @PathParam(value = ApiConstants.CLIENTID) @NotNull String associatedClientId) { logger.debug("UMA_RESOURCE to fetch by associatedClientId:{} ", associatedClientId); @@ -124,7 +127,7 @@ public Response getUmaResourceByAssociatedClient( @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }, groupScopes = { ApiAccessConstants.UMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response createUmaResource(@Valid UmaResource umaResource) { logger.debug("UMA_RESOURCE to be added umaResource:{}", umaResource); checkNotNull(umaResource.getName(), AttributeNames.NAME); @@ -158,7 +161,7 @@ private UmaResource findOrThrow(String id) { @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }, groupScopes = { ApiAccessConstants.UMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response updateUmaResource(@Valid UmaResource resource) { logger.debug("UMA_RESOURCE to be upated - umaResource:{}", resource); String id = resource.getId(); @@ -182,7 +185,7 @@ public Response updateUmaResource(@Valid UmaResource resource) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_WRITE_ACCESS }, groupScopes = { ApiAccessConstants.UMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) @Path(ApiConstants.ID_PATH) public Response patchResource(@PathParam(ApiConstants.ID) @NotNull String id, @NotNull String pathString) throws JsonPatchException, IOException { @@ -203,7 +206,7 @@ public Response patchResource(@PathParam(ApiConstants.ID) @NotNull String id, @N @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE @Path(ApiConstants.ID_PATH) - @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_DELETE_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.UMA_RESOURCES_DELETE_ACCESS }, groupScopes = { ApiAccessConstants.UMA_DELETE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response deleteUmaResource(@PathParam(value = ApiConstants.ID) @NotNull String id) { logger.debug("UMA_RESOURCE to delete - id:{}", id); UmaResource umaResource = findOrThrow(id); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java index 45fe6bd1896..76b25a7898e 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionCache.java @@ -6,9 +6,12 @@ import com.google.common.cache.CacheBuilder; import com.google.common.collect.Maps; import io.jans.as.persistence.model.Scope; +import io.jans.configapi.core.util.ProtectionScopeType; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Named; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -22,9 +25,18 @@ public class ApiProtectionCache { private static final Cache scopeCache = CacheBuilder.newBuilder() .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); - private static final Cache> resourceCache = CacheBuilder.newBuilder() + private static final Cache groupScopeCache = CacheBuilder.newBuilder() .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); + private static final Cache superScopeCache = CacheBuilder.newBuilder() + .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); + + private static final Cache>> resourceCache = CacheBuilder.newBuilder() + .expireAfterWrite(CACHE_LIFETIME, TimeUnit.MINUTES).build(); + + ApiProtectionCache() { + } + // Scope public static void removeAllScopes() { scopeCache.invalidateAll(); @@ -39,35 +51,130 @@ public static Scope getScope(String scopeName) { public static void putScope(Scope scope) { Preconditions.checkNotNull(scope); - if (scopeCache.getIfPresent(scope.getId()) == null) { - scopeCache.put(scope.getId(), scope); + if (scopeCache.getIfPresent(scope.getInum()) == null) { + scopeCache.put(scope.getInum(), scope); } } - public static Map getAllScopes() { + public static Map getScopes() { return Maps.newHashMap(scopeCache.asMap()); } + // Group Scope + public static Scope getGroupScope(String scopeName) { + Preconditions.checkNotNull(scopeName); + Preconditions.checkState(!Strings.isNullOrEmpty(scopeName)); + return groupScopeCache.getIfPresent(scopeName); + + } + + public static void putGroupScope(Scope scope) { + Preconditions.checkNotNull(scope); + if (groupScopeCache.getIfPresent(scope.getInum()) == null) { + groupScopeCache.put(scope.getInum(), scope); + } + } + + public static void removeGroupScopes() { + groupScopeCache.invalidateAll(); + } + + public static Map getGroupScopes() { + return Maps.newHashMap(groupScopeCache.asMap()); + } + + // Super Scope + public static Scope getSuperScope(String scopeName) { + Preconditions.checkNotNull(scopeName); + Preconditions.checkState(!Strings.isNullOrEmpty(scopeName)); + return superScopeCache.getIfPresent(scopeName); + + } + + public static void putSuperScope(Scope scope) { + Preconditions.checkNotNull(scope); + if (superScopeCache.getIfPresent(scope.getInum()) == null) { + superScopeCache.put(scope.getInum(), scope); + } + } + + public static void removeSuperScopes() { + superScopeCache.invalidateAll(); + } + + public static Map getSuperScopes() { + return Maps.newHashMap(superScopeCache.asMap()); + } + + // All Scope + public static Map getAllTypesOfScopes() { + Map scopes = Maps.newHashMap(scopeCache.asMap()); + scopes.putAll(Maps.newHashMap(groupScopeCache.asMap())); + scopes.putAll(Maps.newHashMap(superScopeCache.asMap())); + return scopes; + } + // Resource - public static void removeAllResources() { + public static void raemoveAllResources() { resourceCache.invalidateAll(); } - public static List getResourceScopes(String resourceName) { + public static void putResource(String resourceName, Map> scopeMap) { Preconditions.checkNotNull(resourceName); - Preconditions.checkState(!Strings.isNullOrEmpty(resourceName)); - return resourceCache.getIfPresent(resourceName); + resourceCache.put(resourceName, scopeMap); + } + public static void putResourceScopeByType(String resourceName, ProtectionScopeType protectionScopeType, + List scopes) { + Preconditions.checkNotNull(resourceName); + Preconditions.checkNotNull(protectionScopeType); + Map> scopeMap = resourceCache.getIfPresent(resourceName); + if (scopeMap == null) { + scopeMap = new HashMap<>(); + } + scopeMap.put(protectionScopeType, scopes); + resourceCache.put(resourceName, scopeMap); + } + + public static Map>> getAllResources() { + return Maps.newHashMap(resourceCache.asMap()); } - public static void putResource(String resourceName, List scopeList) { + public static Map> getResourceScopes(String resourceName) { Preconditions.checkNotNull(resourceName); - resourceCache.put(resourceName, scopeList); + Preconditions.checkState(!Strings.isNullOrEmpty(resourceName)); + return resourceCache.getIfPresent(resourceName); } - public static Map> getAllResources() { - return Maps.newHashMap(resourceCache.asMap()); + public static List getResourceScopeByType(String resourceName, ProtectionScopeType protectionScopeType) { + Preconditions.checkNotNull(resourceName); + Preconditions.checkNotNull(protectionScopeType); + Map> scopeMap = resourceCache.getIfPresent(resourceName); + if (scopeMap == null) { + return Collections.emptyList(); + } + return scopeMap.get(protectionScopeType); } + public static void addScope(String resourceName, ProtectionScopeType protectionScopeType, Scope scope) { + Preconditions.checkNotNull(resourceName); + Preconditions.checkNotNull(protectionScopeType); + Preconditions.checkNotNull(scope); + + switch (protectionScopeType) { + case GROUP: + putGroupScope(scope); + break; + + case SUPER: + putSuperScope(scope); + break; + + default: + putScope(scope); + break; + + } + } } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java index 334e565cf2c..9df93750ce9 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/api/ApiProtectionService.java @@ -3,14 +3,15 @@ import com.google.common.base.Preconditions; import io.jans.as.common.model.registration.Client; import io.jans.as.model.common.ScopeType; -import io.jans.ca.rs.protect.Condition; -import io.jans.ca.rs.protect.RsResource; -import io.jans.ca.rs.protect.RsResourceList; +import io.jans.configapi.core.protect.Condition; +import io.jans.configapi.core.protect.RsResource; +import io.jans.configapi.core.protect.RsResourceList; import io.jans.as.persistence.model.Scope; import io.jans.configapi.configuration.ConfigurationFactory; import io.jans.configapi.service.auth.ClientService; import io.jans.configapi.service.auth.ScopeService; import io.jans.configapi.core.util.Jackson; +import io.jans.configapi.core.util.ProtectionScopeType; import java.io.IOException; import java.io.InputStream; @@ -18,10 +19,10 @@ import java.util.Collections; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.UUID; import java.util.stream.Collectors; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -68,8 +69,11 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO Preconditions.checkNotNull(rsResourceList, "Config Api Resource list cannot be null !!!"); createScopeIfNeeded(apiProtectionType); - log.trace("ApiProtectionService:::verifyResources() - allScopes:{}, allResources:{} ", - ApiProtectionCache.getAllScopes(), ApiProtectionCache.getAllResources()); + log.trace( + " *** ApiProtectionService:::verifyResources() - getAllResources:{}, getScopes():{}, getGroupScopes():{}, getSuperScopes():{}, getAllTypesOfScopes():{}", + ApiProtectionCache.getAllResources(), ApiProtectionCache.getScopes(), + ApiProtectionCache.getGroupScopes(), ApiProtectionCache.getSuperScopes(), + ApiProtectionCache.getAllTypesOfScopes()); updateScopeForClientIfNeeded(clientId); @@ -78,42 +82,34 @@ public void verifyResources(String apiProtectionType, String clientId) throws IO private void createScopeIfNeeded(String apiProtectionType) { log.debug("ApiProtectionService:::createScopeIfNeeded() - apiProtectionType:{}", apiProtectionType); - List rsScopes = null; List scopeList = new ArrayList<>(); for (RsResource rsResource : rsResourceList) { for (Condition condition : rsResource.getConditions()) { String resourceName = condition.getHttpMethods() + ":::" + rsResource.getPath(); - rsScopes = condition.getScopes(); - log.trace("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, rsScopes:{} ", resourceName, - rsScopes); + log.debug( + "ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, condition.getScopes():{}, condition.getGroupScopes():{}, condition.getSuperScopes():{}", + resourceName, condition.getScopes(), condition.getGroupScopes(), condition.getSuperScopes()); + + // Process Scopes // If no scopes for the path then skip validation - if (rsScopes == null || rsScopes.isEmpty()) { - break; + List rsScopes = condition.getScopes(); + if (rsScopes != null && !rsScopes.isEmpty()) { + processScope(resourceName, ProtectionScopeType.SCOPE, rsScopes); } - for (String scopeName : rsScopes) { - log.debug("ApiProtectionService:::createScopeIfNeeded() - scopeName:{} ", scopeName); - - // Check in cache - Scope scope = ApiProtectionCache.getScope(scopeName); - log.debug( - "ApiProtectionService:::createScopeIfNeeded() - ApiProtectionCache.getScope(scopeName):{}", - ApiProtectionCache.getScope(scopeName)); - - if (scope != null) { - log.debug("Scope - '{}' exists in cache.", scopeName); - scopeList.add(scope); - break; - } - - // validate scope - scopeList = validateScope(scopeName); + // If no group scopes for the path then skip validation + List groupScopes = condition.getGroupScopes(); + if (groupScopes != null && !groupScopes.isEmpty()) { + processScope(resourceName, ProtectionScopeType.GROUP, groupScopes); + } - } // for scopes + // If no super scopes for the path then skip validation + List superScopes = condition.getSuperScopes(); + if (superScopes != null && !superScopes.isEmpty()) { + processScope(resourceName, ProtectionScopeType.SUPER, superScopes); + } - // Add to resource cache - ApiProtectionCache.putResource(resourceName, scopeList); log.debug("ApiProtectionService:::createScopeIfNeeded() - resourceName:{}, scopeList:{}", resourceName, scopeList); @@ -121,59 +117,87 @@ private void createScopeIfNeeded(String apiProtectionType) { } } - private List validateScope(String scopeName) { - List scopeList = new ArrayList<>(); - Scope scope = null; + private void processScope(String resourceName, ProtectionScopeType protectionScopeType, + List scopeList) { + log.debug("ApiProtectionService:::processScope() - resourceName:{}, protectionScopeType:{}, scopeList:{}", + resourceName, protectionScopeType, scopeList); + + // return if no scopes + if (scopeList == null || scopeList.isEmpty()) { + return; + } + + for (io.jans.configapi.core.protect.Scope rsScope : scopeList) { + String inum = rsScope.getInum(); + String scopeName = rsScope.getName(); + log.debug("ApiProtectionService:::processScope() - resourceName:{}, inum:{}, scopeName:{}", resourceName, + inum, scopeName); + + // return if no scope details + if (StringUtils.isBlank(inum) || StringUtils.isBlank(scopeName)) { + return; + } + + List scopes = validateScope(resourceName, protectionScopeType, rsScope); + ApiProtectionCache.putResourceScopeByType(resourceName, protectionScopeType, scopes); + } + } + + private List validateScope(String resourceName, ProtectionScopeType protectionScopeType, + io.jans.configapi.core.protect.Scope rsScope) { + log.debug("Verify Scope in DB - protectionScopeType:{}, rsScope:{} ", protectionScopeType, rsScope); + Set scopeList = new HashSet<>(); + // Check in DB - log.debug("Verify Scope in DB - {} ", scopeName); - List scopes = scopeService.searchScopesById(scopeName); - log.debug("Scopes from DB - {}'", scopes); + Scope scope = scopeService.getScope(rsScope.getInum()); + log.debug("Scopes from DB - {}'", scope); - if (scopes != null && !scopes.isEmpty()) { + if (scope != null) { // Fetch existing scope to store in cache - scope = scopes.get(0); - log.debug("Scope from DB is - {}", scope.getId()); + log.debug("Scope from DB is not null scope.getInum():{}, scope.getId():{}", scope.getInum(), scope.getId()); scopeList.add(scope); } ScopeType scopeType = ScopeType.OAUTH; - log.trace("Scope details - scopes:{}, scopeName:{}, exclusiveAuthScopes:{}, isConfigApiScope(scopeName):{} '", - scopes, scopeName, configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes(), - isConfigApiScope(scopeName)); + log.debug( + "Scope details - scope:{}, rsScope.getName():{}, exclusiveAuthScopes:{}, isConfigApiScope(scopeName):{} '", + scope, rsScope.getName(), configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes(), + isConfigApiScope(rsScope.getName())); // Create/Update scope only if they are config-api-resource scopes - if (isConfigApiScope(scopeName)) { - - //ensure scope does not exists - scopes = scopeService.searchScopesById(scopeName); - log.debug("ConfigApiScope scopeName:{} in DB - scopes:{} ", scopeName, scopes); - if (scopes == null || scopes.isEmpty()) { - log.debug("Scope - '{}' does not exist, hence creating it.", scopeName); - // Scope does not exists hence create Scope - scope = new Scope(); - String inum = UUID.randomUUID().toString(); - scope.setId(scopeName); - scope.setDisplayName(scopeName); - scope.setInum(inum); - scope.setDn(scopeService.getDnForScope(inum)); - scope.setScopeType(scopeType); - scopeService.addScope(scope); - } - if (scope != null) { + if (isConfigApiScope(rsScope.getName())) { + + // ensure scope does not exists + scope = scopeService.getScope(rsScope.getInum()); + log.debug("Re-verify ConfigApiScope rsScope.getName():{} with rsScope.getInum():{} in DB - scope:{} ", + rsScope.getName(), rsScope.getInum(), scope); + if (scope == null) { + log.debug("Scope - '{}' does not exist, hence creating it.", scope); + // Scope does not exists hence create Scope + scope = new Scope(); + String inum = rsScope.getInum(); + scope.setId(rsScope.getName()); + scope.setDisplayName(rsScope.getName()); + scope.setInum(inum); + scope.setDn(scopeService.getDnForScope(inum)); + scope.setScopeType(scopeType); + scopeService.addScope(scope); + } else { // Update resource - log.debug("Scope - '{}' already exists, hence updating it.", scopeName); - scope.setId(scopeName); + log.debug("Scope - '{}' already exists, hence updating it.", rsScope.getName()); + scope.setId(rsScope.getName()); scope.setScopeType(scopeType); scopeService.updateScope(scope); } + } // Add to scope if not null if (scope != null) { scopeList.add(scope); - ApiProtectionCache.putScope(scope); + ApiProtectionCache.addScope(resourceName, protectionScopeType, scope); } - return scopeList; + return scopeList.stream().collect(Collectors.toList()); } private boolean isConfigApiScope(String scopeName) { @@ -196,11 +220,11 @@ private void updateScopeForClientIfNeeded(String clientId) { // Assign scope // Prepare scope array List scopes = getScopeWithDn(getAllScopes()); - log.trace("updateScopeForClientIfNeeded() - All scopes:{}", scopes); + log.debug("updateScopeForClientIfNeeded() - All scopes:{}", scopes); if (client.getScopes() != null) { List existingScopes = Arrays.asList(client.getScopes()); - log.trace("updateScopeForClientIfNeeded() - Clients existing scopes:{} ", existingScopes); + log.debug("updateScopeForClientIfNeeded() - Clients existing scopes:{} ", existingScopes); if (scopes == null) { scopes = new ArrayList<>(); } @@ -231,13 +255,16 @@ private List getAllScopes() { List scopes = new ArrayList<>(); // Verify in cache - Map scopeMap = ApiProtectionCache.getAllScopes(); + Map scopeMap = ApiProtectionCache.getAllTypesOfScopes(); Set keys = scopeMap.keySet(); + log.debug(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); for (String id : keys) { - Scope scope = ApiProtectionCache.getScope(id); + Scope scope = scopeMap.get(id); + log.trace(" All Scopes scopeMap:{}, keys:{}", scopeMap, keys); scopes.add(scope.getInum()); } + log.debug(" All Scopes being returned scopes:{}", scopes); return scopes; } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java index cc01f78ce1c..f2f7bfc3281 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/AuthorizationService.java @@ -8,13 +8,17 @@ import io.jans.configapi.util.AuthUtil; import io.jans.configapi.configuration.ConfigurationFactory; +import io.jans.configapi.core.util.ProtectionScopeType; + import org.slf4j.Logger; import jakarta.inject.Inject; +import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.container.ResourceInfo; import java.io.Serializable; import java.util.List; +import java.util.Map; public abstract class AuthorizationService implements Serializable { @@ -30,17 +34,13 @@ public abstract class AuthorizationService implements Serializable { transient AuthUtil authUtil; public abstract String processAuthorization(String token, String issuer, ResourceInfo resourceInfo, String method, - String path) throws Exception; + String path) throws WebApplicationException, Exception; protected Response getErrorResponse(Response.Status status, String detail) { return Response.status(status).entity(detail).build(); } - public List getRequestedScopes(String path) { - return authUtil.getRequestedScopes(path); - } - - public List getRequestedScopes(ResourceInfo resourceInfo) { + public Map> getRequestedScopes(ResourceInfo resourceInfo) { return authUtil.getRequestedScopes(resourceInfo); } @@ -48,6 +48,10 @@ public boolean validateScope(List authScopes, List resourceScope return authUtil.validateScope(authScopes, resourceScopes); } + public List getAllScopeList(Map> scopeMap) { + return authUtil.getAllScopeList(scopeMap); + } + public List getApiApprovedIssuer() { return this.configurationFactory.getApiApprovedIssuer(); } @@ -67,4 +71,9 @@ public List findMissingElements(List list1, List list2) public boolean isEqualCollection(List list1, List list2) { return authUtil.isEqualCollection(list1, list2); } + + public boolean containsAnyElement(List list1, List list2) { + return authUtil.containsAnyElement(list1, list2); + } + } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java index fca7abdd1a2..425a81b39d6 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/security/service/OpenIdAuthorizationService.java @@ -8,6 +8,7 @@ import io.jans.as.model.exception.InvalidJwtException; import io.jans.configapi.core.util.Jackson; +import io.jans.configapi.core.util.ProtectionScopeType; import io.jans.configapi.util.*; import io.jans.as.model.common.IntrospectionResponse; @@ -23,6 +24,7 @@ import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.Response; import java.io.Serializable; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -59,7 +61,7 @@ public class OpenIdAuthorizationService extends AuthorizationService implements ExternalInterceptionService externalInterceptionService; public String processAuthorization(String token, String issuer, ResourceInfo resourceInfo, String method, - String path) throws Exception { + String path) throws WebApplicationException, Exception { logger.debug("oAuth Authorization parameters , token:{}, issuer:{}, resourceInfo:{}, method: {}, path: {} ", token, issuer, resourceInfo, method, path); @@ -122,7 +124,14 @@ private String validateScope(String accessToken, List tokenScopes, Resou tokenScopes, resourceInfo, issuer); try { // Get resource scope - List resourceScopes = getRequestedScopes(resourceInfo); + Map> resourceScopesByType = getRequestedScopes(resourceInfo); + List resourceScopes = getAllScopeList(resourceScopesByType); + logger.debug("Validate scope, resourceScopesByType: {}, resourceScopes: {}", resourceScopesByType, + resourceScopes); + + // find missing scopes + List missingScopes = findMissingScopes(resourceScopesByType, tokenScopes); + logger.debug("missingScopes:{}", missingScopes); // Check if resource requires auth server specific scope List authSpecificScope = getAuthSpecificScopeRequired(resourceInfo); @@ -131,7 +140,7 @@ private String validateScope(String accessToken, List tokenScopes, Resou // If No auth scope required OR if token contains the authSpecificScope if ((authSpecificScope == null || authSpecificScope.isEmpty())) { logger.debug("Validating token scopes as no authSpecificScope required"); - if (!validateScope(tokenScopes, resourceScopes)) { + if ((missingScopes != null && !missingScopes.isEmpty())) { logger.error("Insufficient scopes! Required scope:{} - however token scopes:{}", resourceScopes, tokenScopes); throw new WebApplicationException("Insufficient scopes! , Required scope: " + resourceScopes @@ -141,10 +150,6 @@ private String validateScope(String accessToken, List tokenScopes, Resou return AUTHENTICATION_SCHEME + accessToken; } - // find missing scopes - List missingScopes = findMissingElements(resourceScopes, tokenScopes); - logger.debug("missingScopes:{}", missingScopes); - // If only authSpecificScope missing then proceed with token creation else throw // error if (missingScopes != null && !missingScopes.isEmpty() @@ -178,8 +183,8 @@ private String validateScope(String accessToken, List tokenScopes, Resou logger.info("Token scopes Valid Returning accessToken:{}", accessToken); return AUTHENTICATION_SCHEME + accessToken; } catch (Exception ex) { - if (log.isErrorEnabled()) { - log.error("oAuth authorization error:{} ", ex.getMessage()); + if (logger.isErrorEnabled()) { + logger.error("oAuth authorization error:{} ", ex.getMessage()); } throw new WebApplicationException("oAuth authorization error " + ex.getMessage(), Response.status(Response.Status.INTERNAL_SERVER_ERROR).build()); @@ -200,4 +205,52 @@ private boolean externalAuthorization(String token, String issuer, String method this.configurationFactory.getApiAppConfiguration(), requestParameters, responseAsJsonObject); } + private List findMissingScopes(Map> scopeMap, List tokenScopes) { + logger.debug("Check scopeMap:{}, tokenScopes:{}", scopeMap, tokenScopes); + List scopeList = new ArrayList<>(); + if (tokenScopes == null || tokenScopes.isEmpty() || scopeMap == null || scopeMap.isEmpty()) { + return scopeList; + } + + // Super scope + scopeList = scopeMap.get(ProtectionScopeType.SUPER); + logger.debug("SUPER Scopes:{}", scopeList); + List missingScopes = null; + boolean containsScope = false; + if (scopeList != null && !scopeList.isEmpty()) { + // check if token contains any of the super scopes + containsScope = containsAnyElement(scopeList, tokenScopes); + logger.debug("Token contains SUPER scopes?:{}", containsScope); + + // Super scope present so no need to check other types of scope + if (containsScope) { + return missingScopes; + } + } + + // Group scope present so no need to check normal scope presence + scopeList = scopeMap.get(ProtectionScopeType.GROUP); + logger.debug("GROUP Scopes:{}", scopeList); + if (scopeList != null && !scopeList.isEmpty()) { + // check if token contains any of the group scopes + containsScope = containsAnyElement(scopeList, tokenScopes); + logger.debug("Token contains GROUP scopes?:{}", containsScope); + + // Group scope present so no need to check normal scope + if (containsScope) { + return missingScopes; + } + } + + // Normal scope + scopeList = scopeMap.get(ProtectionScopeType.SCOPE); + logger.debug("SCOPE Scopes:{}", scopeList); + if (scopeList != null && !scopeList.isEmpty()) { + // check if token contains all the required scopes + missingScopes = findMissingElements(scopeList, tokenScopes); + logger.debug("SCOPE Missing Scopes:{}", missingScopes); + } + return missingScopes; + } + } \ No newline at end of file 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 c0a71d98b37..720a098ecba 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 @@ -88,6 +88,15 @@ public void updateScope(Scope scope) { persistenceEntryManager.merge(scope); } + public Scope getScope(String inum) { + try { + return persistenceEntryManager.find(Scope.class, getDnForScope(inum)); + } catch (Exception ex) { + logger.error("Error while finding scope with inum:{} is:{}", inum, ex); + } + return null; + } + public CustomScope getScopeByInum(String inum) { return getScopeByInum(inum, false); } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java index 9509d95fc69..ce28d113ca3 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/util/AuthUtil.java @@ -14,6 +14,7 @@ import io.jans.configapi.security.client.AuthClientFactory; import io.jans.configapi.configuration.ConfigurationFactory; import io.jans.configapi.core.rest.ProtectedApi; +import io.jans.configapi.core.util.ProtectionScopeType; import io.jans.configapi.service.auth.ConfigurationService; import io.jans.configapi.service.auth.ClientService; import io.jans.configapi.service.auth.ScopeService; @@ -22,8 +23,10 @@ import java.lang.reflect.Method; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.HashSet; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -31,9 +34,7 @@ import java.util.stream.Stream; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.container.ResourceInfo; -import jakarta.ws.rs.core.Response; import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; @@ -70,7 +71,7 @@ public String getAuthOpenidConfigurationUrl() { public String getIssuer() { return this.configurationService.find().getIssuer(); } - + public String getIntrospectionEndpoint() { return configurationService.find().getIntrospectionEndpoint(); } @@ -78,7 +79,7 @@ public String getIntrospectionEndpoint() { public String getTokenEndpoint() { return configurationService.find().getTokenEndpoint(); } - + public String getEndSessionEndpoint() { return this.configurationService.find().getEndSessionEndpoint(); } @@ -90,25 +91,24 @@ public String getServiceUrl(String url) { public String getClientId() { return this.configurationFactory.getApiClientId(); } - + public List getUserExclusionAttributes() { return this.configurationFactory.getApiAppConfiguration().getUserExclusionAttributes(); } - + public String getUserExclusionAttributesAsString() { List excludedAttributes = getUserExclusionAttributes(); return excludedAttributes == null ? null : excludedAttributes.stream().collect(Collectors.joining(",")); } - + public List getUserMandatoryAttributes() { return this.configurationFactory.getApiAppConfiguration().getUserMandatoryAttributes(); } - + public AgamaConfiguration getAgamaConfiguration() { return this.configurationFactory.getApiAppConfiguration().getAgamaConfiguration(); } - public String getTokenUrl() { return this.configurationService.find().getTokenEndpoint(); } @@ -153,120 +153,62 @@ public String encryptPassword(String clientPassword) { return encryptedPassword; } - public List getResourceScopeList(String method, String path) { - log.trace(" ResourceScopeList requested for method:{}, path:{}", method, path); + public Map> getRequestedScopes(ResourceInfo resourceInfo) { + log.info("Requested scopes for resourceInfo:{} ", resourceInfo); - // Verify in cache - Map> resources = ApiProtectionCache.getAllResources(); - - // Filter paths based on resource name - Set keys = resources.keySet(); - List filteredPaths = keys.stream().filter(k -> k.contains(path)).collect(Collectors.toList()); - - if (filteredPaths == null || filteredPaths.isEmpty()) { - throw new WebApplicationException("No matching resource found .", - Response.status(Response.Status.UNAUTHORIZED).build()); - } - - List scopeList = null; - for (String key : filteredPaths) { - String[] result = key.split(":::"); - if (result != null && result.length > 1) { - String httpmethod = result[0]; - String pathUrl = result[1]; - log.trace(" Resource Scopes - httpmethod:{} , pathUrl:{} ", httpmethod, pathUrl); - - if (pathUrl != null && pathUrl.contains(path)) { - // Matching url - log.trace(" Matching url with path:{} , pathUrl:{} ", path, pathUrl); - - // Verify Method - if (httpmethod.contains(method)) { - scopeList = ApiProtectionCache.getResourceScopes(key); - log.trace(" scopeList:{} for the method:{} ", scopeList, method); - break; - } - } - } - } - return scopeList; - } - - public List getAllResourceScopes() { - Map scopeMap = ApiProtectionCache.getAllScopes(); - log.trace("All Resource Scopes - scopeMap:{}", scopeMap); - - List scopeStrList = null; - if (scopeMap != null && !scopeMap.isEmpty()) { - Set scopeSet = scopeMap.keySet(); - scopeStrList = new ArrayList<>(scopeSet); - } - log.trace("All Resource Scopes - scopeStrList:{} ", scopeStrList); - return scopeStrList; - } - - public List getRequestedScopes(String path) { - List scopeList = ApiProtectionCache.getResourceScopes(path); - log.trace("Requested scopes:{} for path:{} ", scopeList, path); - - List scopeStrList = new ArrayList<>(); - if (scopeList != null && !scopeList.isEmpty()) { - for (Scope s : scopeList) { - scopeStrList.add(s.getId()); - } - } - log.trace("Requested scopeStrList:{} for path:{}", scopeStrList, path); - return scopeStrList; - } - - public List getRequestedScopes(String method, String path) { - log.trace("Requested scopes for path:{} and method:{} ", path, method); - List scopeList = this.getResourceScopeList(method, path); - log.trace("Requested scopeList:{} for path:{} and method:{} ", scopeList, path, method); - List scopeStrList = new ArrayList<>(); - if (scopeList != null && !scopeList.isEmpty()) { - for (Scope s : scopeList) { - scopeStrList.add(s.getId()); - } - } - log.trace("Final scopeStrList:{} for path:{} and method:{} ", scopeStrList, path, method); - return scopeStrList; - } - - public List getRequestedScopes(ResourceInfo resourceInfo) { - log.trace("Requested scopes for resourceInfo:{} ", resourceInfo); Class resourceClass = resourceInfo.getResourceClass(); ProtectedApi typeAnnotation = resourceClass.getAnnotation(ProtectedApi.class); - List scopes = new ArrayList<>(); + Map> scopes = new HashMap<>(); + log.debug("Requested scopes for resourceClass:{}, typeAnnotation:{} ", resourceClass, typeAnnotation); + if (typeAnnotation == null) { + log.debug("Requested scopes for resourceClass:{}, typeAnnotation == null ", resourceClass); addMethodScopes(resourceInfo, scopes); } else { - scopes.addAll(Stream.of(typeAnnotation.scopes()).collect(Collectors.toList())); + log.debug("Requested scopes for resourceClass:{}, typeAnnotation is not null ", resourceClass); + scopes.put(ProtectionScopeType.SCOPE, Stream.of(typeAnnotation.scopes()).collect(Collectors.toList())); + scopes.put(ProtectionScopeType.GROUP, Stream.of(typeAnnotation.groupScopes()).collect(Collectors.toList())); + scopes.put(ProtectionScopeType.SUPER, Stream.of(typeAnnotation.superScopes()).collect(Collectors.toList())); + + log.trace("ProtectionScopeType.SCOPE:{}, ProtectionScopeType.GROUP:{} , ProtectionScopeType.SUPER:{} ", + Stream.of(typeAnnotation.scopes()).collect(Collectors.toList()), + Stream.of(typeAnnotation.groupScopes()).collect(Collectors.toList()), + Stream.of(typeAnnotation.superScopes()).collect(Collectors.toList())); + + log.debug("All scopes:{} ", scopes); addMethodScopes(resourceInfo, scopes); } - log.trace("Requested scopes:{} for resourceInfo:{} ", scopes, resourceInfo); + log.info("*** Final Requested scopes:{} for resourceInfo:{} ", scopes, resourceInfo); return scopes; } public boolean validateScope(List authScopes, List resourceScopes) { + log.info("Validate Scopes for authScopes:{}, resourceScopes:{} ", authScopes, resourceScopes); Set authScopeSet = new HashSet<>(authScopes); Set resourceScopeSet = new HashSet<>(resourceScopes); return authScopeSet.containsAll(resourceScopeSet); } - private void addMethodScopes(ResourceInfo resourceInfo, List scopes) { + private void addMethodScopes(ResourceInfo resourceInfo, Map> scopes) { + log.info("Method Scopes for resourceInfo:{}, scopes:{} ", resourceInfo, scopes); Method resourceMethod = resourceInfo.getResourceMethod(); ProtectedApi methodAnnotation = resourceMethod.getAnnotation(ProtectedApi.class); + if (methodAnnotation != null) { - scopes.addAll(Stream.of(methodAnnotation.scopes()).collect(Collectors.toList())); + scopes.put(ProtectionScopeType.SCOPE, Stream.of(methodAnnotation.scopes()).collect(Collectors.toList())); + scopes.put(ProtectionScopeType.GROUP, + Stream.of(methodAnnotation.groupScopes()).collect(Collectors.toList())); + scopes.put(ProtectionScopeType.SUPER, + Stream.of(methodAnnotation.superScopes()).collect(Collectors.toList())); } + log.info("Final Method Scopes for resourceInfo:{}, scopes:{} ", resourceInfo, scopes); } - + public String requestAccessToken(final String clientId, final List scope) { log.info("Request for AccessToken - clientId:{}, scope:{} ", clientId, scope); String tokenUrl = getTokenEndpoint(); Token token = getAccessToken(tokenUrl, clientId, scope); - log.info("oAuth AccessToken response - token:{}", token); + log.debug("oAuth AccessToken response - token:{}", token); if (token != null) { return token.getAccessToken(); } @@ -274,7 +216,7 @@ public String requestAccessToken(final String clientId, final List scope } public Token getAccessToken(final String tokenUrl, final String clientId, final List scopes) { - log.debug("Access Token Request - tokenUrl:{}, clientId:{}, scopes:{}", tokenUrl, clientId, scopes); + log.info("Access Token Request - tokenUrl:{}, clientId:{}, scopes:{}", tokenUrl, clientId, scopes); // Get clientSecret String clientSecret = this.getClientDecryptPassword(clientId); @@ -305,7 +247,7 @@ public Token getAccessToken(final String tokenUrl, final String clientId, final } public void assignAllScope(final String clientId) { - log.trace("Client to be assigned all scope - {} ", clientId); + log.info("Client to be assigned all scope - {} ", clientId); // Get Client Client client = this.clientService.getClientByInum(clientId); @@ -329,7 +271,7 @@ public List getAllScopes() { List scopes = new ArrayList<>(); // Verify in cache - Map scopeMap = ApiProtectionCache.getAllScopes(); + Map scopeMap = ApiProtectionCache.getAllTypesOfScopes(); Set keys = scopeMap.keySet(); for (String id : keys) { @@ -369,10 +311,10 @@ public boolean isValidIssuer(String issuer) { } public List getAuthSpecificScopeRequired(ResourceInfo resourceInfo) { - log.debug("Fetch Auth server specific scope for resourceInfo:{} ", resourceInfo); + log.info("Fetch Auth server specific scope for resourceInfo:{} ", resourceInfo); // Get required oauth scopes for the endpoint - List resourceScopes = getRequestedScopes(resourceInfo); + List resourceScopes = getAllScopeList(getRequestedScopes(resourceInfo)); log.debug(" resource:{} has these scopes:{} and configured exclusiveAuthScopes are {}", resourceInfo, resourceScopes, this.configurationFactory.getApiAppConfiguration().getExclusiveAuthScopes()); @@ -386,67 +328,88 @@ public List getAuthSpecificScopeRequired(ResourceInfo resourceInfo) { .collect(Collectors.toList()); } - log.debug("Applicable exclusiveAuthScopes for resourceInfo:{} are {} ", resourceInfo, exclusiveAuthScopesToReq); + log.info("Applicable exclusiveAuthScopes for resourceInfo:{} are {} ", resourceInfo, exclusiveAuthScopesToReq); return exclusiveAuthScopesToReq; } public List findMissingElements(List list1, List list2) { + if (list1 == null || list1.isEmpty() || list2 == null || list2.isEmpty()) { + return Collections.emptyList(); + } return list1.stream().filter(e -> !list2.contains(e)).collect(Collectors.toList()); } + public boolean containsAnyElement(List list1, List list2) { + if (list1 == null || list1.isEmpty() || list2 == null || list2.isEmpty()) { + return false; + } + return list1.stream().anyMatch(list2::contains); + } + public boolean isEqualCollection(List list1, List list2) { + if (list1 == null || list1.isEmpty() || list2 == null || list2.isEmpty()) { + return false; + } return CollectionUtils.isEqualCollection(list1, list2); } - + public boolean containsField(List allFields, String attribute) { - log.debug("allFields:{}, attribute:{}, allFields.contains(attribute):{} ", allFields , attribute, allFields.stream().anyMatch(f -> f.getName().equals(attribute))); - + log.debug("allFields:{}, attribute:{}, allFields.contains(attribute):{} ", allFields, attribute, + allFields.stream().anyMatch(f -> f.getName().equals(attribute))); + return allFields.stream().anyMatch(f -> f.getName().equals(attribute)); - } - - public List getAllFields(Class type) { - List allFields = new ArrayList<>(); - allFields = getAllFields(allFields, type); - log.debug("Fields:{} of type:{} ", allFields, type); - - return allFields; - } - - public List getAllFields(List fields, Class type) { - log.debug("fields:{} of type:{} ", fields, type); - fields.addAll(Arrays.asList(type.getDeclaredFields())); - - if (type.getSuperclass() != null) { - getAllFields(fields, type.getSuperclass()); - } - log.debug("Final fields:{} of type:{} ", fields, type); - return fields; - } - - public boolean isValidDn(String dn) { - return isValidDn(dn, false); - } - - - public boolean isValidDn(String dn, boolean strictNameChecking) { - return DN.isValidDN(dn, strictNameChecking); - } - - - public RevokeSessionResponse revokeSession(final String url,final String token, final String userId) { - log.debug("Revoke session Request - url:{}, token:{}, userId:{}", url, token, userId); - - - - RevokeSessionResponse revokeSessionResponse = AuthClientFactory.revokeSession(url, token,userId); - log.debug("revokeSessionResponse:{}",revokeSessionResponse); - if (revokeSessionResponse != null) { - - log.debug("revokeSessionResponse.getEntity():{}, revokeSessionResponse.getStatus():{} ", revokeSessionResponse.getEntity(), revokeSessionResponse.getStatus()); - - - } - return revokeSessionResponse; - } + } + + public List getAllFields(Class type) { + List allFields = new ArrayList<>(); + allFields = getAllFields(allFields, type); + log.debug("Fields:{} of type:{} ", allFields, type); + + return allFields; + } + + public List getAllFields(List fields, Class type) { + log.debug("fields:{} of type:{} ", fields, type); + fields.addAll(Arrays.asList(type.getDeclaredFields())); + + if (type.getSuperclass() != null) { + getAllFields(fields, type.getSuperclass()); + } + log.debug("Final fields:{} of type:{} ", fields, type); + return fields; + } + + public boolean isValidDn(String dn) { + return isValidDn(dn, false); + } + + public boolean isValidDn(String dn, boolean strictNameChecking) { + return DN.isValidDN(dn, strictNameChecking); + } + + public RevokeSessionResponse revokeSession(final String url, final String token, final String userId) { + log.debug("Revoke session Request - url:{}, token:{}, userId:{}", url, token, userId); + + RevokeSessionResponse revokeSessionResponse = AuthClientFactory.revokeSession(url, token, userId); + log.debug("revokeSessionResponse:{}", revokeSessionResponse); + if (revokeSessionResponse != null) { + log.debug("revokeSessionResponse.getEntity():{}, revokeSessionResponse.getStatus():{} ", + revokeSessionResponse.getEntity(), revokeSessionResponse.getStatus()); + } + return revokeSessionResponse; + } + + public List getAllScopeList(Map> scopeMap) { + List scopeList = new ArrayList<>(); + log.debug("Get all scopeMap:{} ", scopeMap); + if (scopeMap == null || scopeMap.isEmpty()) { + return scopeList; + } + + scopeList = scopeMap.get(ProtectionScopeType.SCOPE); + log.debug("Get all scopeList:{} ", scopeList); + return scopeList; + + } } diff --git a/jans-config-api/server/src/main/resources/config-api-rs-protect.json b/jans-config-api/server/src/main/resources/config-api-rs-protect.json index dcacfbd867c..9b8561234c2 100644 --- a/jans-config-api/server/src/main/resources/config-api-rs-protect.json +++ b/jans-config-api/server/src/main/resources/config-api-rs-protect.json @@ -1,620 +1,1678 @@ -{"resources":[ +{ + "resources": [ { - "path":"/jans-config-api/api/v1/acrs", - "conditions":[ + "path": "/jans-config-api/api/v1/acrs", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.1", + "name": "https://jans.io/oauth/config/acrs.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/acrs.readonly" - ] - }, + "inum": "1800.01.2", + "name": "https://jans.io/oauth/config/acrs.write" + } + ], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.2", + "name": "https://jans.io/oauth/config/acrs.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/acrs.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/attributes", - "conditions":[ + "path": "/jans-config-api/api/v1/attributes", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.3", + "name": "https://jans.io/oauth/config/attributes.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/attributes.readonly" - ] - }, + "inum": "1800.01.4", + "name": "https://jans.io/oauth/config/attributes.write" + } + ], + "superScopes": [ { - "httpMethods":["PATCH","POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/attributes.write" - ] + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH", + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.4", + "name": "https://jans.io/oauth/config/attributes.write" } - , + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/attributes.delete" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.5", + "name": "https://jans.io/oauth/config/attributes.delete" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/cache", - "conditions":[ + "path": "/jans-config-api/api/v1/config/cache", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.6", + "name": "https://jans.io/oauth/config/cache.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/cache.readonly" - ] - }, + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/cache/redis", - "conditions":[ + "path": "/jans-config-api/api/v1/config/cache/redis", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.6", + "name": "https://jans.io/oauth/config/cache.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/cache.readonly" - ] - }, + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "superScopes": [ { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" } - ] + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/cache/in-memory", - "conditions":[ + "path": "/jans-config-api/api/v1/config/cache/in-memory", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.6", + "name": "https://jans.io/oauth/config/cache.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/cache.readonly" - ] - }, + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "superScopes": [ { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/cache/native-persistence", - "conditions":[ + "path": "/jans-config-api/api/v1/config/cache/native-persistence", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.6", + "name": "https://jans.io/oauth/config/cache.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/cache.readonly" - ] - }, + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "superScopes": [ { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" } - ] + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/cache/memcached", - "conditions":[ + "path": "/jans-config-api/api/v1/config/cache/memcached", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.6", + "name": "https://jans.io/oauth/config/cache.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/cache.readonly" - ] - }, + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "superScopes": [ { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.7", + "name": "https://jans.io/oauth/config/cache.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/cache.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/openid/clients", - "conditions":[ + "path": "/jans-config-api/api/v1/openid/clients", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.8", + "name": "https://jans.io/oauth/config/openid/clients.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/openid/clients.readonly" - ] - }, + "inum": "1800.02.1", + "name": "https://jans.io/oauth/config/openid-read" + } + ], + "superScopes": [ { - "httpMethods":["PATCH","POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/openid/clients.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH", + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.9", + "name": "https://jans.io/oauth/config/openid/clients.write" + } + ], + "groupScopes": [ + { + "inum": "1800.02.2", + "name": "https://jans.io/oauth/config/openid-write" + } + ], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.10", + "name": "https://jans.io/oauth/config/openid/clients.delete" + } + ], + "groupScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/openid/clients.delete" - ] + "inum": "1800.02.3", + "name": "https://jans.io/oauth/config/openid-delete" } - ] + ], + "superScopes": [ + { + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/jans-auth-server/config", - "conditions":[ + "path": "/jans-config-api/api/v1/jans-auth-server/config", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.11", + "name": "https://jans.io/oauth/jans-auth-server/config/properties.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/jans-auth-server/config/properties.readonly" - ] - }, + "inum": "1800.01.12", + "name": "https://jans.io/oauth/jans-auth-server/config/properties.write" + } + ], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/jans-auth-server/config/properties.write" - ] + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.12", + "name": "https://jans.io/oauth/jans-auth-server/config/properties.write" } - ] + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/jans-auth-server/config/persistence", - "conditions":[ + "path": "/jans-config-api/api/v1/jans-auth-server/config/persistence", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.11", + "name": "https://jans.io/oauth/jans-auth-server/config/properties.readonly" + } + ], + "groupScopes": [ + { + "inum": "1800.01.12", + "name": "https://jans.io/oauth/jans-auth-server/config/properties.write" + } + ], + "superScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/jans-auth-server/config/properties.readonly" - ] + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/smtp", - "conditions":[ + "path": "/jans-config-api/api/v1/config/smtp", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.13", + "name": "https://jans.io/oauth/config/smtp.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/smtp.readonly" - ] - }, + "inum": "1800.01.14", + "name": "https://jans.io/oauth/config/smtp.write" + } + ], + "superScopes": [ { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/smtp.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.14", + "name": "https://jans.io/oauth/config/smtp.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/smtp.delete" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.15", + "name": "https://jans.io/oauth/config/smtp.delete" } - ] + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/smtp/test", - "conditions":[ + "path": "/jans-config-api/api/v1/config/smtp/test", + "conditions": [ + { + "httpMethods": [ + "POST" + ], + "scopes": [ + { + "inum": "1800.01.13", + "name": "https://jans.io/oauth/config/smtp.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["POST"], - "scopes":[ - "https://jans.io/oauth/config/smtp.readonly" - ] + "inum": "1800.01.14", + "name": "https://jans.io/oauth/config/smtp.write" } - ] + ], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/scripts", - "conditions":[ + "path": "/jans-config-api/api/v1/config/scripts", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.16", + "name": "https://jans.io/oauth/config/scripts.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/scripts.readonly" - ] - }, + "inum": "1800.01.17", + "name": "https://jans.io/oauth/config/scripts.write" + } + ], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.17", + "name": "https://jans.io/oauth/config/scripts.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/scripts.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/scripts/type/{type}", - "conditions":[ + "path": "/jans-config-api/api/v1/config/scripts/type/{type}", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.16", + "name": "https://jans.io/oauth/config/scripts.readonly" + } + ], + "groupScopes": [ + { + "inum": "1800.01.17", + "name": "https://jans.io/oauth/config/scripts.write" + } + ], + "superScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/scripts.readonly" - ] + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/scripts/inum/{inum}", - "conditions":[ + "path": "/jans-config-api/api/v1/config/scripts/inum/{inum}", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.16", + "name": "https://jans.io/oauth/config/scripts.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/scripts.readonly" - ] + "inum": "1800.01.17", + "name": "https://jans.io/oauth/config/scripts.write" } - ] + ], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/scripts/{inum}", - "conditions":[ + "path": "/jans-config-api/api/v1/config/scripts/{inum}", + "conditions": [ + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.18", + "name": "https://jans.io/oauth/config/scripts.delete" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/scripts.delete" - ] - }, + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.17", + "name": "https://jans.io/oauth/config/scripts.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/scripts.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/fido2/config", - "conditions":[ + { + "path": "/jans-config-api/api/v1/fido2/config", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.19", + "name": "https://jans.io/oauth/config/fido2.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/fido2.readonly" - ] - }, + "inum": "1800.01.20", + "name": "https://jans.io/oauth/config/fido2.write" + } + ], + "superScopes": [ { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/fido2.write" - ] + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" } - ] + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.20", + "name": "https://jans.io/oauth/config/fido2.write" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/jwks", - "conditions":[ + "path": "/jans-config-api/api/v1/config/jwks", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.21", + "name": "https://jans.io/oauth/config/jwks.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/jwks.readonly" - ] - }, + "inum": "1800.01.22", + "name": "https://jans.io/oauth/config/jwks.write" + } + ], + "superScopes": [ { - "httpMethods":["PATCH","PUT"], - "scopes":[ - "https://jans.io/oauth/config/jwks.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.22", + "name": "https://jans.io/oauth/config/jwks.write" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.23", + "name": "https://jans.io/oauth/config/jwks.delete" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/jwks.delete" - ] + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/database/ldap", - "conditions":[ + "path": "/jans-config-api/api/v1/config/database/ldap", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.24", + "name": "https://jans.io/oauth/config/database/ldap.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.readonly" - ] - }, + "inum": "1800.01.25", + "name": "https://jans.io/oauth/config/database/ldap.write" + } + ], + "superScopes": [ { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.write" - ] + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" } - ] + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.25", + "name": "https://jans.io/oauth/config/database/ldap.write" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/database/ldap/{name}", - "conditions":[ + "path": "/jans-config-api/api/v1/config/database/ldap/{name}", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.24", + "name": "https://jans.io/oauth/config/database/ldap.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.readonly" - ] - }, + "inum": "1800.01.25", + "name": "https://jans.io/oauth/config/database/ldap.write" + } + ], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.25", + "name": "https://jans.io/oauth/config/database/ldap.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.delete" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.26", + "name": "https://jans.io/oauth/config/database/ldap.delete" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/config/database/ldap/test", - "conditions":[ + "path": "/jans-config-api/api/v1/config/database/ldap/test", + "conditions": [ + { + "httpMethods": [ + "POST" + ], + "scopes": [ + { + "inum": "1800.01.24", + "name": "https://jans.io/oauth/config/database/ldap.readonly" + } + ], + "groupScopes": [ + { + "inum": "1800.01.25", + "name": "https://jans.io/oauth/config/database/ldap.write" + } + ], + "superScopes": [ { - "httpMethods":["POST"], - "scopes":[ - "https://jans.io/oauth/config/database/ldap.readonly" - ] + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/logging", - "conditions":[ + "path": "/jans-config-api/api/v1/logging", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.27", + "name": "https://jans.io/oauth/config/logging.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/logging.readonly" - ] - }, + "inum": "1800.01.28", + "name": "https://jans.io/oauth/config/logging.write" + } + ], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.28", + "name": "https://jans.io/oauth/config/logging.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PUT"], - "scopes":[ - "https://jans.io/oauth/config/logging.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/scopes", - "conditions":[ + { + "path": "/jans-config-api/api/v1/scopes", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.29", + "name": "https://jans.io/oauth/config/scopes.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/scopes.readonly" - ] - }, + "inum": "1800.01.30", + "name": "https://jans.io/oauth/config/scopes.write" + } + ], + "superScopes": [ { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/scopes.write" - ] + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" } - ] + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.30", + "name": "https://jans.io/oauth/config/scopes.write" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/scopes/{inum}", - "conditions":[ + { + "path": "/jans-config-api/api/v1/scopes/{inum}", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.29", + "name": "https://jans.io/oauth/config/scopes.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/scopes.readonly" - ] - }, + "inum": "1800.01.30", + "name": "https://jans.io/oauth/config/scopes.write" + } + ], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/scopes.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.30", + "name": "https://jans.io/oauth/config/scopes.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/scopes.delete" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.31", + "name": "https://jans.io/oauth/config/scopes.delete" } - ] + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" + } + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/uma/resources", - "conditions":[ + { + "path": "/jans-config-api/api/v1/uma/resources", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.32", + "name": "https://jans.io/oauth/config/uma/resources.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/uma/resources.readonly" - ] + "inum": "1800.01.33", + "name": "https://jans.io/oauth/config/uma/resources.write" }, { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/uma/resources.write" - ] + "inum": "1800.02.4", + "name": "https://jans.io/oauth/config/uma-read" + } + ], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.33", + "name": "https://jans.io/oauth/config/uma/resources.write" + } + ], + "groupScopes": [ + { + "inum": "1800.02.5", + "name": "https://jans.io/oauth/config/uma-write" + } + ], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/uma/resources/{id}", - "conditions":[ + { + "path": "/jans-config-api/api/v1/uma/resources/{id}", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.32", + "name": "https://jans.io/oauth/config/uma/resources.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/uma/resources.readonly" - ] + "inum": "1800.01.33", + "name": "https://jans.io/oauth/config/uma/resources.write" }, { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/uma/resources.write" - ] - }, + "inum": "1800.02.4", + "name": "https://jans.io/oauth/config/uma-read" + } + ], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.33", + "name": "https://jans.io/oauth/config/uma/resources.write" + } + ], + "groupScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/uma/resources.delete" - ] + "inum": "1800.02.5", + "name": "https://jans.io/oauth/config/uma-write" } - - ] + ], + "superScopes": [ + { + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" + } + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.34", + "name": "https://jans.io/oauth/config/uma/resources.delete" + } + ], + "groupScopes": [ + { + "inum": "1800.02.6", + "name": "https://jans.io/oauth/config/uma-delete" + } + ], + "superScopes": [ + { + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/stat", - "conditions":[ + "path": "/jans-config-api/api/v1/stat", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.35", + "name": "https://jans.io/oauth/config/stats.readonly" + }, { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/stats.readonly", - "jans_stat" - ] - } - ] + "inum": "", + "name": "jans_stat" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + } + ] }, { - "path":"/jans-config-api/api/v1/health", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ ] - } - ] + "path": "/jans-config-api/api/v1/health", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [], + "groupScopes": [], + "superScopes": [] + } + ] }, { - "path":"/jans-config-api/api/v1/health/live", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ ] - } - ] + "path": "/jans-config-api/api/v1/health/live", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [] + } + ] }, { - "path":"/jans-config-api/api/v1/health/ready", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ ] - } - ] + "path": "/jans-config-api/api/v1/health/ready", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [], + "groupScopes": [], + "superScopes": [] + } + ] }, { - "path":"/jans-config-api/scim/scim-config", - "conditions":[ + "path": "/jans-config-api/scim/scim-config", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.36", + "name": "https://jans.io/scim/config.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/scim/config.readonly" - ] - }, + "inum": "1800.01.37", + "name": "https://jans.io/scim/config.write" + } + ], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.37", + "name": "https://jans.io/scim/config.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/scim/config.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, { - "path":"/jans-config-api/api/v1/org", - "conditions":[ + "path": "/jans-config-api/api/v1/org", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.38", + "name": "https://jans.io/oauth/config/organization.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/organization.readonly" - ] - }, + "inum": "1800.01.39", + "name": "https://jans.io/oauth/config/organization.write" + } + ], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH" + ], + "scopes": [ + { + "inum": "1800.01.39", + "name": "https://jans.io/oauth/config/organization.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["PATCH"], - "scopes":[ - "https://jans.io/oauth/config/organization.write" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + } + ] }, - { - "path":"/jans-config-api/mgt/configuser", - "conditions":[ + { + "path": "/jans-config-api/mgt/configuser", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.40", + "name": "https://jans.io/oauth/config/user.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/user.readonly" - ] - }, + "inum": "1800.01.41", + "name": "https://jans.io/oauth/config/user.write" + } + ], + "superScopes": [ { - "httpMethods":["PATCH","POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/user.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "PATCH", + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.41", + "name": "https://jans.io/oauth/config/user.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/user.delete" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.42", + "name": "https://jans.io/oauth/config/user.delete" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" + } + ] + } + ] }, - { - "path":"/jans-config-api/api/v1/agama", - "conditions":[ + { + "path": "/jans-config-api/api/v1/agama", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.43", + "name": "https://jans.io/oauth/config/agama.readonly" + } + ], + "groupScopes": [ { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/config/agama.readonly" - ] - }, + "inum": "1800.01.44", + "name": "https://jans.io/oauth/config/agama.write" + } + ], + "superScopes": [ { - "httpMethods":["POST","PUT"], - "scopes":[ - "https://jans.io/oauth/config/agama.write" - ] - }, + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST", + "PUT" + ], + "scopes": [ + { + "inum": "1800.01.44", + "name": "https://jans.io/oauth/config/agama.write" + } + ], + "groupScopes": [], + "superScopes": [ { - "httpMethods":["DELETE"], - "scopes":[ - "https://jans.io/oauth/config/agama.delete" - ] + "inum": "1800.03.2", + "name": "https://jans.io/oauth/config/write-all" } - ] - } - , - { - "path":"/jans-config-api/api/v1/jans-auth-server/session", - "conditions":[ - { - "httpMethods":["GET"], - "scopes":[ - "https://jans.io/oauth/jans-auth-server/session.readonly" - ] + ] + }, + { + "httpMethods": [ + "DELETE" + ], + "scopes": [ + { + "inum": "1800.01.45", + "name": "https://jans.io/oauth/config/agama.delete" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" + } + ] + } + ] + }, + { + "path": "/jans-config-api/api/v1/jans-auth-server/session", + "conditions": [ + { + "httpMethods": [ + "GET" + ], + "scopes": [ + { + "inum": "1800.01.46", + "name": "https://jans.io/oauth/jans-auth-server/session.readonly" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.1", + "name": "https://jans.io/oauth/config/read-all" + } + ] + }, + { + "httpMethods": [ + "POST" + ], + "scopes": [ + { + "inum": "1800.01.47", + "name": "https://jans.io/oauth/jans-auth-server/session.delete" }, { - "httpMethods":["POST"], - "scopes":[ - "https://jans.io/oauth/jans-auth-server/session.delete" - ] + "inum": "", + "name": "revoke_session" + } + ], + "groupScopes": [], + "superScopes": [ + { + "inum": "1800.03.3", + "name": "https://jans.io/oauth/config/delete-all" } - ] + ] + } + ] } -] + ] } \ No newline at end of file diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Condition.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Condition.java new file mode 100644 index 00000000000..a1bcfdd48da --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Condition.java @@ -0,0 +1,59 @@ +package io.jans.configapi.core.protect; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Condition { + + @JsonProperty(value = "httpMethods") + List httpMethods; + @JsonProperty(value = "scopes") + List scopes; + @JsonProperty(value = "groupScopes") + List groupScopes; + @JsonProperty(value = "superScopes") + List superScopes; + + public List getHttpMethods() { + return httpMethods; + } + + public void setHttpMethods(List httpMethods) { + this.httpMethods = httpMethods; + } + + public List getScopes() { + return scopes; + } + + public void setScopes(List scopes) { + this.scopes = scopes; + } + + public List getGroupScopes() { + return groupScopes; + } + + public void setGroupScopes(List groupScopes) { + this.groupScopes = groupScopes; + } + + public List getSuperScopes() { + return superScopes; + } + + public void setSuperScopes(List superScopes) { + this.superScopes = superScopes; + } + + @Override + public String toString() { + return "Condition [httpMethods=" + httpMethods + ", scopes=" + scopes + ", groupScopes=" + groupScopes + + ", superScopes=" + superScopes + "]"; + } + + } diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResource.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResource.java new file mode 100644 index 00000000000..b697ee8eca6 --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResource.java @@ -0,0 +1,96 @@ +package io.jans.configapi.core.protect; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.Maps; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + + +@JsonIgnoreProperties(ignoreUnknown = true) +public class RsResource implements Serializable { + + @JsonProperty(value = "path") + String path; + @JsonProperty(value = "conditions") + List conditions; + @JsonProperty(value = "iat") + private Integer iat; + @JsonProperty(value = "exp") + private Integer exp; + + private Map httpMethodToCondition = null; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public List getConditions() { + return conditions; + } + + public void setConditions(List conditions) { + this.conditions = conditions; + } + + public List scopes(String httpMethod) { + return getConditionMap().get(httpMethod).getScopes(); + } + + public Integer getIat() { + return iat; + } + + public void setIat(Integer iat) { + this.iat = iat; + } + + public Integer getExp() { + return exp; + } + + public void setExp(Integer exp) { + this.exp = exp; + } + + + + public Map getConditionMap() { + if (httpMethodToCondition == null) { + initMap(); + } + return httpMethodToCondition; + } + + private void initMap() { + httpMethodToCondition = Maps.newHashMap(); + if (conditions != null) { + for (Condition condition : conditions) { + if (condition.getHttpMethods() != null) { + for (String httpMethod : condition.getHttpMethods()) { + httpMethodToCondition.put(httpMethod, condition); + } + } + } + } + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("RsResource"); + sb.append("{path='").append(path).append('\''); + sb.append(", conditions=").append(conditions); + sb.append(", httpMethodToCondition=").append(httpMethodToCondition); + sb.append(", iat=").append(iat); + sb.append(", exp=").append(exp); + sb.append('}'); + return sb.toString(); + } +} diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResourceList.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResourceList.java new file mode 100644 index 00000000000..af61652f335 --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/RsResourceList.java @@ -0,0 +1,37 @@ +package io.jans.configapi.core.protect; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.Lists; + +import java.io.Serializable; +import java.util.List; + +public class RsResourceList implements Serializable { + + @JsonProperty(value = "resources") + private List resources = Lists.newArrayList(); + + public RsResourceList() { + } + + public RsResourceList(List resources) { + this.resources = resources; + } + + public List getResources() { + return resources; + } + + public void setResources(List resources) { + this.resources = resources; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("RsResourceList"); + sb.append("{resources=").append(resources); + sb.append('}'); + return sb.toString(); + } +} diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Scope.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Scope.java new file mode 100644 index 00000000000..3bdc29c61a8 --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/protect/Scope.java @@ -0,0 +1,36 @@ +package io.jans.configapi.core.protect; + + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Scope { + + @JsonProperty(value = "inum") + private String inum; + @JsonProperty(value = "name") + private String name; + + public String getInum() { + return inum; + } + + public void setInum(String inum) { + this.inum = inum; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Scope [inum=" + inum + ", name=" + name + "]"; + } + + } diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/ProtectedApi.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/ProtectedApi.java index ea252b7c7d1..3ad1ec0be54 100644 --- a/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/ProtectedApi.java +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/ProtectedApi.java @@ -18,5 +18,9 @@ public @interface ProtectedApi { String[] scopes() default {}; + + String[] groupScopes() default {}; + + String[] superScopes() default {}; } diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScopeType.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScopeType.java new file mode 100644 index 00000000000..085e49b852c --- /dev/null +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/ProtectionScopeType.java @@ -0,0 +1,48 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.configapi.core.util; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import org.apache.commons.lang.StringUtils; + +public enum ProtectionScopeType { + + SCOPE("scope"), GROUP("group"), SUPER("super"); + + private final String scopeName; + + ProtectionScopeType(String scopeName) { + this.scopeName = scopeName; + } + + String getValue() { + return toString().toLowerCase(); + } + + @JsonCreator + public static ProtectionScopeType fromString(String scopeType) { + if (StringUtils.isNotBlank(scopeType)) { + for (ProtectionScopeType type : ProtectionScopeType.values()) { + if (scopeType.equalsIgnoreCase(type.getValue())) { + return type; + } + } + } + return null; + } + + @Override + @JsonValue + public String toString() { + return scopeName; + } + + public String getScopeName() { + return scopeName; + } +} diff --git a/jans-linux-setup/jans_setup/setup_app/installers/config_api.py b/jans-linux-setup/jans_setup/setup_app/installers/config_api.py index 40c470cb2dd..0904179da7a 100644 --- a/jans-linux-setup/jans_setup/setup_app/installers/config_api.py +++ b/jans-linux-setup/jans_setup/setup_app/installers/config_api.py @@ -77,7 +77,7 @@ def install(self): def extract_files(self): base.extract_file(base.current_app.jans_zip, 'jans-config-api/server/src/main/resources/log4j2.xml', self.custom_config_dir) base.extract_file(base.current_app.jans_zip, 'jans-config-api/docs/jans-config-api-swagger.yaml', Config.data_dir) - + base.extract_file(base.current_app.jans_zip, 'jans-config-api/server/src/main/resources/config-api-rs-protect.json', Config.data_dir) def create_folders(self): for d in (self.output_folder, self.custom_config_dir): @@ -96,11 +96,9 @@ def read_config_api_swagger(self): def generate_configuration(self): - try: - cfg_yml = self.read_config_api_swagger() - scopes_def = cfg_yml['components']['securitySchemes']['oauth2']['flows']['clientCredentials']['scopes'] - except: - scopes_def = {} + + config_api_rs_protect_fn = os.path.join(Config.data_dir, 'config-api-rs-protect.json') + scopes_def = base.readJsonFile(config_api_rs_protect_fn) scope_type = 'oauth' self.check_clients([('jca_client_id', '1800.')]) @@ -109,7 +107,6 @@ def generate_configuration(self): Config.jca_client_pw = self.getPW() Config.jca_client_encoded_pw = self.obscure(Config.jca_client_pw) - scopes = '' scope_ldif_fd = open(self.scope_ldif_fn, 'wb') ldif_scopes_writer = LDIFWriter(scope_ldif_fd, cols=1000) scopes = {} @@ -119,32 +116,37 @@ def generate_configuration(self): scim_scopes = base.current_app.ScimInstaller.create_user_scopes() jansUmaScopes_all += scim_scopes - for scope in scopes_def: - - jansUmaScopes = [] - - if Config.installed_instance and self.dbUtils.search('ou=scopes,o=jans', search_filter='(&(jansId={})(objectClass=jansScope))'.format(scope)): - continue - - if not scope in scopes: - inum = '1800.' + os.urandom(3).hex().upper() - scope_dn = 'inum={},ou=scopes,o=jans'.format(inum) - scopes[scope] = {'dn': scope_dn} - display_name = 'Config API scope {}'.format(scope) - ldif_scopes_writer.unparse( - scope_dn, { - 'objectclass': ['top', 'jansScope'], - 'description': [scopes_def[scope]], - 'displayName': [display_name], - 'inum': [inum], - 'jansDefScope': ['false'], - 'jansId': [scope], - 'jansScopeTyp': [scope_type], - 'jansAttrs': [json.dumps({"spontaneousClientId":None, "spontaneousClientScopes":[], "showInConfigurationEndpoint": False})], - }) - - jansUmaScopes.append(scopes[scope]['dn']) - jansUmaScopes_all.append(scopes[scope]['dn']) + scope_levels = {'scopes':'1', 'groupScopes':'2', 'superScopes':'3'} + + for resource in scopes_def['resources']: + + for condition in resource.get('conditions', []): + for scope_level in scope_levels: + for scope in (condition.get(scope_level, [])): + + if not scope.get('inum'): + continue + + if Config.installed_instance and self.dbUtils.search('ou=scopes,o=jans', search_filter='(&(jansId={})(objectClass=jansScope))'.format(scope['name'])): + continue + + if not scope['name'] in scopes: + scope_dn = 'inum={},ou=scopes,o=jans'.format(scope['inum']) + scopes[scope['name']] = {'dn': scope_dn} + display_name = 'Config API scope {}'.format(scope['name']) + description = 'Config API {} scope {}'.format(scope_level, scope['name']) + ldif_dict = { + 'objectclass': ['top', 'jansScope'], + 'description': [description], + 'displayName': [display_name], + 'inum': [scope['inum']], + 'jansDefScope': ['false'], + 'jansId': [scope['name']], + 'jansScopeTyp': [scope_type], + 'jansAttrs': [json.dumps({"spontaneousClientId":None, "spontaneousClientScopes":[], "showInConfigurationEndpoint": False})], + } + ldif_scopes_writer.unparse(scope_dn, ldif_dict) + jansUmaScopes_all.append(scope_dn) scope_ldif_fd.close()