From 40ca464b17a5dc0324d01b0510dac8b0beec9bd0 Mon Sep 17 00:00:00 2001 From: pujavs <43700552+pujavs@users.noreply.github.com> Date: Wed, 9 Feb 2022 21:53:21 +0530 Subject: [PATCH] feat(jans-config-api): organization configuration management endpoints (#790) * feat: support jansOrganization config * feat: jans org endpoint * feat: organization config endpoint * feat: jans org management endpoints * feat: jans orgnanization endpoints * feat: jans organization endpoint wip * feat: jans org functionality * feat: jans org functionality * feat: jans org manintenance endpoints - wip * feat: org endpoint * feat: org endpoints * feat: org management endpoints * feat: jans org endpoint management * feat: jans organization management endpoint --- .../configapi/util/ApiAccessConstants.java | 6 ++ .../io/jans/configapi/util/ApiConstants.java | 3 + .../docs/jans-config-api-swagger.yaml | 100 +++++++++++++++++- .../profiles/local/test.properties | 2 +- .../jans/configapi/rest/ApiApplication.java | 1 + .../rest/resource/auth/BaseResource.java | 8 +- .../resource/auth/OrganizationResource.java | 53 ++++++++++ .../java/io/jans/configapi/util/AuthUtil.java | 4 + .../main/resources/config-api-rs-protect.json | 17 +++ .../feature/config/org/org-config.feature | 45 ++++++++ .../test/resources/karate-config-jenkins.js | 1 + .../src/test/resources/karate-config.js | 1 + 12 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/OrganizationResource.java create mode 100644 jans-config-api/server/src/test/resources/feature/config/org/org-config.feature 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 29cfa3681b7..9e9fd5c1e95 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 @@ -2,6 +2,9 @@ public class ApiAccessConstants { + private ApiAccessConstants() { + } + public static final String JANS_AUTH_CONFIG_READ_ACCESS = "https://jans.io/oauth/jans-auth-server/config/properties.readonly"; public static final String JANS_AUTH_CONFIG_WRITE_ACCESS = "https://jans.io/oauth/jans-auth-server/config/properties.write"; @@ -59,4 +62,7 @@ public class ApiAccessConstants { public static final String STATS_USER_READ_ACCESS = "https://jans.io/oauth/config/stats.readonly"; public static final String JANS_STAT = "jans_stat"; + public static final String ORG_CONFIG_READ_ACCESS = "https://jans.io/oauth/config/organization.readonly"; + public static final String ORG_CONFIG_WRITE_ACCESS = "https://jans.io/oauth/config/organization.write"; + } diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java index 48a3e6a4a1d..12ed4df02f4 100644 --- a/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java +++ b/jans-config-api/common/src/main/java/io/jans/configapi/util/ApiConstants.java @@ -7,6 +7,8 @@ package io.jans.configapi.util; public class ApiConstants { + + private ApiConstants() {} public static final String BASE_API_URL = "/"; public static final String CONFIG = "/config"; @@ -69,6 +71,7 @@ public class ApiConstants { public static final String READY = "/ready"; public static final String STATISTICS = "/stat"; public static final String USER = "/user"; + public static final String ORG = "/org"; public static final String LIMIT = "limit"; public static final String START_INDEX = "startIndex"; diff --git a/jans-config-api/docs/jans-config-api-swagger.yaml b/jans-config-api/docs/jans-config-api-swagger.yaml index 02b8a114be8..fc03609f072 100644 --- a/jans-config-api/docs/jans-config-api-swagger.yaml +++ b/jans-config-api/docs/jans-config-api-swagger.yaml @@ -35,6 +35,7 @@ tags: - name: Health - Check - name: SCIM - User Management - name: SCIM - Config Management + - name: Organization Configuration - name: Auth Server Health - Check - name: Admin UI - Role - name: Admin UI - Permission @@ -2860,6 +2861,59 @@ paths: '500': $ref: '#/components/responses/InternalServerError' + /jans-config-api/api/v1/org: + get: + summary: Retrieves organization configuration. + description: Retrieves organization configuration. + operationId: get-organization-config + security: + - oauth2: [https://jans.io/oauth/config/organization.readonly] + tags: + - Organization Configuration + responses: + '200': + description: OK + content: + application/json: + schema: + title: Organization + description: Organization configuration. + $ref: '#/components/schemas/Organization' + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/InternalServerError' + patch: + summary: Partially modifies organization configuration. + description: Partially modifies organization configuration. + operationId: patch-organization-config + security: + - oauth2: [https://jans.io/oauth/config/organization.write] + tags: + - Organization Configuration + requestBody: + content: + application/json-patch+json: + schema: + type: array + items: + $ref: '#/components/schemas/PatchRequest' + description: String representing patch-document. + example: '[{"op": "add", "path": "/jsFaviconPath", "value": "/opt/jans/jetty/jans-auth/custom/static/"}]' + responses: + '200': + description: OK + content: + application/json: + schema: + title: Organization + description: Organization configuration. + $ref: '#/components/schemas/Organization' + '401': + $ref: '#/components/responses/Unauthorized' + '500': + $ref: '#/components/responses/InternalServerError' + /jans-config-api/api/v1/jans-auth-server/health: get: summary: Returns auth server health status. @@ -3336,6 +3390,8 @@ components: https://jans.io/oauth/config/scim/users.write: Manage scim user related information https://jans.io/scim/config.readonly: Vew SCIM App configuration https://jans.io/scim/config.write: Manage SCIM App configuration + https://jans.io/oauth/config/organization.readonly: View organization configuration information + https://jans.io/oauth/config/organization.write: Manage organization configuration information responses: Found: @@ -6543,4 +6599,46 @@ components: type: boolean description: Boolean value specifying whether to enable local in-memory cache. - \ No newline at end of file + Organization: + type: object + properties: + displayName: + type: string + description: Organization name + description: + type: string + description: Organization description + member: + type: string + description: String describing memberOf + countryName: + type: string + description: Organization country name + organization: + type: string + status: + type: string + managerGroup: + type: string + description: qualified id of the group + example: inum=60B7,ou=groups,o=jans + themeColor: + type: string + description: color of the theme + example: 166309 + shortName: + type: string + customMessages: + type: array + items: + type: string + title: + type: string + jsLogoPath: + type: string + description: Path to organization logo image + jsFaviconPath: + type: string + description: Path to organization favicon image + + diff --git a/jans-config-api/profiles/local/test.properties b/jans-config-api/profiles/local/test.properties index aded38d060b..3109daa325e 100644 --- a/jans-config-api/profiles/local/test.properties +++ b/jans-config-api/profiles/local/test.properties @@ -1,5 +1,5 @@ #LOCAL -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/database/couchbase.readonly https://jans.io/oauth/config/database/couchbase.write https://jans.io/oauth/config/database/couchbase.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/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 +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/database/couchbase.readonly https://jans.io/oauth/config/database/couchbase.write https://jans.io/oauth/config/database/couchbase.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/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 # Test env Setting #token.endpoint=https://jenkins-config-api.gluu.org/jans-auth/restv1/token diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/ApiApplication.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/ApiApplication.java index 019df3ff4e9..93f9342455e 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/ApiApplication.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/ApiApplication.java @@ -46,6 +46,7 @@ public Set> getClasses() { classes.add(UmaResourcesResource.class); classes.add(StatResource.class); classes.add(HealthCheckResource.class); + classes.add(OrganizationResource.class); return classes; } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/BaseResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/BaseResource.java index 0a6aa777dc0..073c14b6885 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/BaseResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/BaseResource.java @@ -94,9 +94,15 @@ protected static Response getNotAcceptableException(String msg) { protected static Response getBadRequestException(String msg) { ApiError error = new ApiError.ErrorBuilder() - .withCode(String.valueOf(Response.Status.NOT_ACCEPTABLE.getStatusCode())).withMessage(msg).build(); + .withCode(String.valueOf(Response.Status.BAD_REQUEST.getStatusCode())).withMessage(msg).build(); return Response.status(Response.Status.BAD_REQUEST).entity(error).build(); } + + protected static Response getInternalServerException(String msg) { + ApiError error = new ApiError.ErrorBuilder() + .withCode(String.valueOf(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode())).withMessage(msg).build(); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build(); + } protected SearchRequest createSearchRequest(String schemas, String filter, String sortBy, String sortOrder, Integer startIndex, Integer count, String attrsList, String excludedAttrsList) { 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 new file mode 100644 index 00000000000..6f1eaaf727f --- /dev/null +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/OrganizationResource.java @@ -0,0 +1,53 @@ +/* + * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Janssen Project + */ + +package io.jans.configapi.rest.resource.auth; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.fge.jsonpatch.JsonPatchException; + +import io.jans.as.persistence.model.GluuOrganization; +import io.jans.configapi.service.auth.OrganizationService; +import io.jans.configapi.core.rest.ProtectedApi; +import io.jans.configapi.service.auth.ConfigurationService; +import io.jans.configapi.util.ApiAccessConstants; +import io.jans.configapi.util.ApiConstants; +import io.jans.configapi.core.util.Jackson; + +import java.io.IOException; +import javax.inject.Inject; +import javax.validation.constraints.NotNull; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@Path(ApiConstants.ORG) +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public class OrganizationResource extends BaseResource { + + @Inject + OrganizationService organizationService; + + @GET + @ProtectedApi(scopes = { ApiAccessConstants.ORG_CONFIG_READ_ACCESS }) + public Response getOrganization() { + return Response.ok(organizationService.getOrganization()).build(); + } + + @PATCH + @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) + @ProtectedApi(scopes = { ApiAccessConstants.ORG_CONFIG_WRITE_ACCESS }) + public Response patchOrganization(@NotNull String pathString) throws JsonPatchException, IOException { + log.trace("Organization patch request - pathString:{} ", pathString); + GluuOrganization organization = organizationService.getOrganization(); + organization = Jackson.applyPatch(pathString, organization); + organizationService.updateOrganization(organization); + return Response.ok(organizationService.getOrganization()).build(); + } + +} \ No newline at end of file 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 77561a72f51..081a5420bfb 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 @@ -67,6 +67,10 @@ public String getIssuer() { return this.configurationService.find().getIssuer(); } + public String getServiceUrl(String url) { + return this.getIssuer() + url; + } + public String getClientId() { return this.configurationFactory.getApiClientId(); } 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 f3d1f1ca15c..34c6bc9f9b1 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 @@ -673,6 +673,23 @@ ] } ] + }, + { + "path":"/jans-config-api/api/v1/org", + "conditions":[ + { + "httpMethods":["GET"], + "scopes":[ + "https://jans.io/oauth/config/organization.readonly" + ] + }, + { + "httpMethods":["PATCH"], + "scopes":[ + "https://jans.io/oauth/config/organization.write" + ] + } + ] } ] } \ No newline at end of file diff --git a/jans-config-api/server/src/test/resources/feature/config/org/org-config.feature b/jans-config-api/server/src/test/resources/feature/config/org/org-config.feature new file mode 100644 index 00000000000..756025630fe --- /dev/null +++ b/jans-config-api/server/src/test/resources/feature/config/org/org-config.feature @@ -0,0 +1,45 @@ + +Feature: Verify Organization configuration endpoint + + Background: + * def mainUrl = org_configuration_url + + @auth-config-get-error + Scenario: Retrieve Organization configuration without bearer token + Given url mainUrl + When method GET + Then status 401 + And print response + + @auth-config-get + Scenario: Retrieve Organization configuration + Given url mainUrl + And header Authorization = 'Bearer ' + accessToken + When method GET + Then status 200 + And print response + And assert response.length != null + + @auth-config-patch + Scenario: Patch Organization configuration + Given url mainUrl + And header Authorization = 'Bearer ' + accessToken + When method GET + Then status 200 + And print response + And assert response.length != null + Given url mainUrl + And header Authorization = 'Bearer ' + accessToken + And header Content-Type = 'application/json-patch+json' + And header Accept = 'application/json' + And print response.description + #And def request_body = (response.description == null ? "[ {\"op\":\"add\", \"path\": \"/description\", \"value\":null } ]" : "[ {\"op\":\"replace\", \"path\": \"/description\", \"value\":"+response.description+" } ]") + And def request_body = (response.description == null ? "[ {\"op\":\"add\", \"path\": \"/description\", \"value\":null } ]" : "[ {\"op\":\"replace\", \"path\": \"/description\", \"value\":\""+response.description+"\" } ]") + And print request_body + And request request_body + Then print request + When method PATCH + Then status 200 + And print response + + \ No newline at end of file diff --git a/jans-config-api/server/src/test/resources/karate-config-jenkins.js b/jans-config-api/server/src/test/resources/karate-config-jenkins.js index 772a92a6884..137f9a93c5b 100644 --- a/jans-config-api/server/src/test/resources/karate-config-jenkins.js +++ b/jans-config-api/server/src/test/resources/karate-config-jenkins.js @@ -59,6 +59,7 @@ function() { smtp_url: baseUrl + '/jans-config-api/api/v1/config/smtp', logging_url: baseUrl + '/jans-config-api/api/v1/logging', auth_health_url: baseUrl + '/jans-config-api/api/v1/jans-auth-server/health', + org_configuration_url: baseUrl + '/jans-config-api/api/v1/org', }; karate.configure('connectTimeout', 30000); diff --git a/jans-config-api/server/src/test/resources/karate-config.js b/jans-config-api/server/src/test/resources/karate-config.js index 495875d5b92..5f26ec47ec2 100644 --- a/jans-config-api/server/src/test/resources/karate-config.js +++ b/jans-config-api/server/src/test/resources/karate-config.js @@ -59,6 +59,7 @@ function() { smtp_url: baseUrl + '/jans-config-api/api/v1/config/smtp', logging_url: baseUrl + '/jans-config-api/api/v1/logging', auth_health_url: baseUrl + '/jans-config-api/api/v1/jans-auth-server/health', + org_configuration_url: baseUrl + '/jans-config-api/api/v1/org', }; karate.configure('connectTimeout', 30000);