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 b6f770e645b..ab3ec3c0e59 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 @@ -12,6 +12,7 @@ private ApiConstants() {} public static final String BASE_API_URL = "/"; public static final String CONFIG = "/config"; + public static final String CONFIGS = "/configs"; public static final String API_CONFIG = "/api-config"; public static final String JWKS = "/jwks"; public static final String JANS_AUTH = "/jans-auth-server"; @@ -113,6 +114,7 @@ private ApiConstants() {} public static final String ACTIVE = "active"; public static final String INACTIVE = "inactive"; public static final String ADD_SCRIPT_TEMPLATE = "addScriptTemplate"; + public static final String REMOVE_NON_LDAP_ATTRIBUTES = "removeNonLDAPAttributes"; // API Protection public static final String PROTECTION_TYPE_OAUTH2 = "oauth2"; diff --git a/jans-config-api/docs/jans-config-api-swagger.yaml b/jans-config-api/docs/jans-config-api-swagger.yaml index 275f0e5007d..739324c6aeb 100644 --- a/jans-config-api/docs/jans-config-api-swagger.yaml +++ b/jans-config-api/docs/jans-config-api-swagger.yaml @@ -209,8 +209,6 @@ 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: - Agama - Developer Studio @@ -252,7 +250,6 @@ paths: security: - oauth2: - https://jans.io/oauth/config/agama.write - - https://jans.io/oauth/config/write-all delete: tags: - Agama - Developer Studio @@ -282,19 +279,40 @@ paths: - https://jans.io/oauth/config/agama.delete /api/v1/agama-deployment/configs: get: - operationId: getConfigs + tags: + - Agama - Developer Studio + summary: Retrieve the list of configs based on name. + description: Retrieve the list of configs based on name. + operationId: get-agama-dev-prj-configs parameters: - name: name in: query schema: type: string responses: - default: - description: default response + "200": + description: Agama projects configs content: - application/json: {} + application/json: + schema: + type: string + examples: + Response json example: + description: Response json example + value: "" + "401": + description: Unauthorized + "500": + description: InternalServerError + security: + - oauth2: + - https://jans.io/oauth/config/agama.readonly put: - operationId: setConfigs + tags: + - Agama - Developer Studio + summary: Update an Agama project. + description: Update an Agama project. + operationId: put-agama-dev-studio-prj parameters: - name: name in: query @@ -310,10 +328,27 @@ paths: additionalProperties: type: object responses: - default: - description: default response + "202": + description: Agama project accepted content: - application/json: {} + application/json: + schema: + type: string + examples: + Response json example: + description: Response json example + value: "" + "400": + description: Bad Request + "401": + description: Unauthorized + "409": + description: Conflict + "500": + description: InternalServerError + security: + - oauth2: + - https://jans.io/oauth/config/agama.write /api/v1/agama-deployment/list: get: tags: @@ -350,8 +385,6 @@ paths: security: - oauth2: - https://jans.io/oauth/config/agama.readonly - - https://jans.io/oauth/config/agama.write - - https://jans.io/oauth/config/read-all /api/v1/agama: get: tags: @@ -7573,20 +7606,20 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - adminCanAccess: + whitePagesCanView: type: boolean adminCanView: type: boolean - adminCanEdit: - type: boolean userCanAccess: type: boolean userCanView: type: boolean - whitePagesCanView: - type: boolean userCanEdit: type: boolean + adminCanAccess: + type: boolean + adminCanEdit: + type: boolean baseDn: type: string PatchRequest: @@ -8975,10 +9008,10 @@ components: type: array items: type: object - displayValue: - type: string value: type: object + displayValue: + type: string LocalizedString: type: object properties: diff --git a/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml b/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml index 98076264e6d..762ce2dd8e9 100644 --- a/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml +++ b/jans-config-api/plugins/docs/user-mgt-plugin-swagger.yaml @@ -121,6 +121,15 @@ paths: summary: Update User description: Update User operationId: put-user + parameters: + - name: removeNonLDAPAttributes + in: query + description: "Boolean flag to indicate if attributes to be removed for non-LDAP\ + \ DB. Default value is true, indicating non-LDAP attributes will be removed\ + \ from request." + schema: + type: boolean + default: true requestBody: description: User object content: @@ -302,6 +311,8 @@ paths: "givenName": "Test3", "baseDn": "inum=559a7e26-7a33-4e11-9d42-13266d33261e,ou=people,o=jans" } + "400": + description: Bad Request "401": description: Unauthorized "404": @@ -317,6 +328,15 @@ paths: summary: Create new User description: Create new User operationId: post-user + parameters: + - name: removeNonLDAPAttributes + in: query + description: "Boolean flag to indicate if attributes to be removed for non-LDAP\ + \ DB. Default value is true, indicating non-LDAP attributes will be removed\ + \ from request." + schema: + type: boolean + default: true requestBody: description: User object content: @@ -495,6 +515,8 @@ paths: "givenName": "Test3", "baseDn": "inum=559a7e26-7a33-4e11-9d42-13266d33261e,ou=people,o=jans" } + "400": + description: Bad Request "401": description: Unauthorized "500": @@ -654,6 +676,14 @@ paths: required: true schema: type: string + - name: removeNonLDAPAttributes + in: query + description: "Boolean flag to indicate if attributes to be removed for non-LDAP\ + \ DB. Default value is true, indicating non-LDAP attributes will be removed\ + \ from request." + schema: + type: boolean + default: true requestBody: description: UserPatchRequest content: @@ -772,6 +802,8 @@ paths: "givenName": "Test3", "baseDn": "inum=559a7e26-7a33-4e11-9d42-13266d33261e,ou=people,o=jans" } + "400": + description: Bad Request "401": description: Unauthorized "404": @@ -794,10 +826,10 @@ components: type: array items: type: object - displayValue: - type: string value: type: object + displayValue: + type: string CustomUser: type: object properties: diff --git a/jans-config-api/plugins/user-mgt-plugin/src/main/java/io/jans/configapi/plugin/mgt/rest/UserResource.java b/jans-config-api/plugins/user-mgt-plugin/src/main/java/io/jans/configapi/plugin/mgt/rest/UserResource.java index 6ba10d39923..b395c34f8d1 100644 --- a/jans-config-api/plugins/user-mgt-plugin/src/main/java/io/jans/configapi/plugin/mgt/rest/UserResource.java +++ b/jans-config-api/plugins/user-mgt-plugin/src/main/java/io/jans/configapi/plugin/mgt/rest/UserResource.java @@ -54,7 +54,9 @@ public class UserResource extends BaseResource { private static final String GIVEN_NAME = "givenName"; private static final String USER_PWD = "userPassword"; private static final String INUM = "inum"; - private class UserPagedResult extends PagedResult{}; + + private class UserPagedResult extends PagedResult { + }; @Inject Logger logger; @@ -89,7 +91,7 @@ public Response getUsers( SearchRequest searchReq = createSearchRequest(userMgmtSrv.getPeopleBaseDn(), pattern, sortBy, sortOrder, startIndex, limit, null, userMgmtSrv.getUserExclusionAttributesAsString(), mgtUtil.getRecordMaxCount()); - return Response.ok(this.doSearch(searchReq)).build(); + return Response.ok(this.doSearch(searchReq, true)).build(); } @Operation(summary = "Get User by Inum", description = "Get User by Inum", operationId = "get-user-by-inum", tags = { @@ -103,7 +105,8 @@ public Response getUsers( @GET @ProtectedApi(scopes = { ApiAccessConstants.USER_READ_ACCESS }) @Path(ApiConstants.INUM_PATH) - public Response getUserByInum(@Parameter(description = "User identifier") @PathParam(ApiConstants.INUM) @NotNull String inum) + public Response getUserByInum( + @Parameter(description = "User identifier") @PathParam(ApiConstants.INUM) @NotNull String inum) throws IllegalAccessException, InvocationTargetException { if (logger.isDebugEnabled()) { logger.debug("User search by inum:{}", escapeLog(inum)); @@ -117,7 +120,7 @@ public Response getUserByInum(@Parameter(description = "User identifier") @PathP logger.debug("user:{}", user); // get custom user - CustomUser customUser = getCustomUser(user); + CustomUser customUser = getCustomUser(user, true); logger.debug("customUser:{}", customUser); return Response.ok(customUser).build(); @@ -129,14 +132,17 @@ public Response getUserByInum(@Parameter(description = "User identifier") @PathP @RequestBody(description = "User object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class), examples = @ExampleObject(name = "Request json example", value = "example/user/user-post.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class, description = "Created Object"), examples = @ExampleObject(name = "Response json example", value = "example/user/user.json"))), + @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST @ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS }) - public Response createUser(@Valid CustomUser customUser) + public Response createUser(@Valid CustomUser customUser, + @Parameter(description = "Boolean flag to indicate if attributes to be removed for non-LDAP DB. Default value is true, indicating non-LDAP attributes will be removed from request.") @DefaultValue("true") @QueryParam(value = ApiConstants.REMOVE_NON_LDAP_ATTRIBUTES) boolean removeNonLDAPAttributes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (logger.isDebugEnabled()) { - logger.debug("User details to be added - customUser:{}", escapeLog(customUser)); + logger.debug("User details to be added - customUser:{}, removeNonLDAPAttributes:{}", escapeLog(customUser), + removeNonLDAPAttributes); } // get User object @@ -148,7 +154,7 @@ public Response createUser(@Valid CustomUser customUser) // checking mandatory attributes checkMissingAttributes(user, null); - ignoreCustomObjectClassesForNonLDAP(user); + ignoreCustomAttributes(user, removeNonLDAPAttributes); user = userMgmtSrv.addUser(user, true); logger.debug("User created {}", user); @@ -157,7 +163,7 @@ public Response createUser(@Valid CustomUser customUser) user = excludeUserAttributes(user); // get custom user - customUser = getCustomUser(user); + customUser = getCustomUser(user, removeNonLDAPAttributes); logger.debug("newly created customUser:{}", customUser); return Response.status(Response.Status.CREATED).entity(customUser).build(); @@ -169,15 +175,18 @@ public Response createUser(@Valid CustomUser customUser) @RequestBody(description = "User object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class), examples = @ExampleObject(name = "Request json example", value = "example/user/user.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class), examples = @ExampleObject(name = "Response json example", value = "example/user/user.json"))), + @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS }) - public Response updateUser(@Valid CustomUser customUser) + public Response updateUser(@Valid CustomUser customUser, + @Parameter(description = "Boolean flag to indicate if attributes to be removed for non-LDAP DB. Default value is true, indicating non-LDAP attributes will be removed from request.") @DefaultValue("true") @QueryParam(value = ApiConstants.REMOVE_NON_LDAP_ATTRIBUTES) boolean removeNonLDAPAttributes) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (logger.isDebugEnabled()) { - logger.debug("User details to be updated - customUser:{}", escapeLog(customUser)); + logger.debug("User details to be updated - customUser:{}, removeNonLDAPAttributes:{}", + escapeLog(customUser), removeNonLDAPAttributes); } // get User object @@ -190,7 +199,8 @@ public Response updateUser(@Valid CustomUser customUser) // checking mandatory attributes List excludeAttributes = List.of(USER_PWD); checkMissingAttributes(user, excludeAttributes); - ignoreCustomObjectClassesForNonLDAP(user); + ignoreCustomAttributes(user, removeNonLDAPAttributes); + try { user = userMgmtSrv.updateUser(user); logger.debug("Updated user:{}", user); @@ -203,7 +213,7 @@ public Response updateUser(@Valid CustomUser customUser) user = excludeUserAttributes(user); // get custom user - customUser = getCustomUser(user); + customUser = getCustomUser(user, removeNonLDAPAttributes); logger.debug("updated customUser:{}", customUser); return Response.ok(customUser).build(); @@ -216,17 +226,21 @@ public Response updateUser(@Valid CustomUser customUser) @RequestBody(description = "UserPatchRequest", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = UserPatchRequest.class), examples = @ExampleObject(name = "Request json example", value = "example/user/user-patch.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class, description = "Patched CustomUser Object"), examples = @ExampleObject(name = "Response json example", value = "example/user/user.json"))), + @ApiResponse(responseCode = "400", description = "Bad Request"), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PATCH @ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS }) @Path(ApiConstants.INUM_PATH) - public Response patchUser(@Parameter(description = "User identifier") @PathParam(ApiConstants.INUM) @NotNull String inum, - @NotNull UserPatchRequest userPatchRequest) + public Response patchUser( + @Parameter(description = "User identifier") @PathParam(ApiConstants.INUM) @NotNull String inum, + @NotNull UserPatchRequest userPatchRequest, + @Parameter(description = "Boolean flag to indicate if attributes to be removed for non-LDAP DB. Default value is true, indicating non-LDAP attributes will be removed from request.") @DefaultValue("true") @QueryParam(value = ApiConstants.REMOVE_NON_LDAP_ATTRIBUTES) boolean removeNonLDAPAttributes) throws IllegalAccessException, InvocationTargetException, JsonPatchException, IOException { if (logger.isDebugEnabled()) { - logger.debug("User:{} to be patched with :{} ", escapeLog(inum), escapeLog(userPatchRequest)); + logger.debug("User:{} to be patched with :{}, removeNonLDAPAttributes:{} ", escapeLog(inum), + escapeLog(userPatchRequest), removeNonLDAPAttributes); } // check if user exists User existingUser = userMgmtSrv.getUserBasedOnInum(inum); @@ -234,7 +248,7 @@ public Response patchUser(@Parameter(description = "User identifier") @PathParam // parse birthdate if present userMgmtSrv.parseBirthDateAttribute(existingUser); checkResourceNotNull(existingUser, USER); - ignoreCustomObjectClassesForNonLDAP(existingUser); + ignoreCustomAttributes(existingUser, removeNonLDAPAttributes); // patch user existingUser = userMgmtSrv.patchUser(inum, userPatchRequest); @@ -244,7 +258,7 @@ public Response patchUser(@Parameter(description = "User identifier") @PathParam existingUser = excludeUserAttributes(existingUser); // get custom user - CustomUser customUser = getCustomUser(existingUser); + CustomUser customUser = getCustomUser(existingUser, removeNonLDAPAttributes); logger.debug("patched customUser:{}", customUser); return Response.ok(customUser).build(); @@ -260,7 +274,8 @@ public Response patchUser(@Parameter(description = "User identifier") @PathParam @DELETE @Path(ApiConstants.INUM_PATH) @ProtectedApi(scopes = { ApiAccessConstants.USER_DELETE_ACCESS }) - public Response deleteUser(@Parameter(description = "User identifier") @PathParam(ApiConstants.INUM) @NotNull String inum) { + public Response deleteUser( + @Parameter(description = "User identifier") @PathParam(ApiConstants.INUM) @NotNull String inum) { if (logger.isDebugEnabled()) { logger.debug("User to be deleted - inum:{} ", escapeLog(inum)); } @@ -270,9 +285,11 @@ public Response deleteUser(@Parameter(description = "User identifier") @PathPara return Response.noContent().build(); } - private UserPagedResult doSearch(SearchRequest searchReq) throws IllegalAccessException, InvocationTargetException { + private UserPagedResult doSearch(SearchRequest searchReq, Boolean removeNonLDAPAttributes) + throws IllegalAccessException, InvocationTargetException { if (logger.isDebugEnabled()) { - logger.debug("User search params - searchReq:{} ", escapeLog(searchReq)); + logger.debug("User search params - searchReq:{}, removeNonLDAPAttributes:{} ", escapeLog(searchReq), + removeNonLDAPAttributes); } PagedResult pagedResult = userMgmtSrv.searchUsers(searchReq); @@ -293,7 +310,7 @@ private UserPagedResult doSearch(SearchRequest searchReq) throws IllegalAccessEx users = users.stream().map(user -> userMgmtSrv.parseBirthDateAttribute(user)).collect(Collectors.toList()); // get customUser() - List customUsers = getCustomUserList(users); + List customUsers = getCustomUserList(users, removeNonLDAPAttributes); pagedCustomUser.setStart(pagedResult.getStart()); pagedCustomUser.setEntriesCount(pagedResult.getEntriesCount()); pagedCustomUser.setTotalEntriesCount(pagedResult.getTotalEntriesCount()); @@ -321,7 +338,7 @@ private void checkMissingAttributes(User user, List excludeAttributes) throwMissingAttributeError(missingAttributes); } - private List getCustomUserList(List users) { + private List getCustomUserList(List users, Boolean removeNonLDAPAttributes) { List customUserList = new ArrayList<>(); if (users == null || users.isEmpty()) { return customUserList; @@ -329,25 +346,25 @@ private List getCustomUserList(List users) { for (User user : users) { CustomUser customUser = new CustomUser(); - setParentAttributes(customUser, user); + setParentAttributes(customUser, user, removeNonLDAPAttributes); customUserList.add(customUser); - ignoreCustomObjectClassesForNonLDAP(customUser); + ignoreCustomAttributes(customUser, removeNonLDAPAttributes); } logger.debug("Custom Users - customUserList:{}", customUserList); return customUserList; } - private CustomUser getCustomUser(User user) { + private CustomUser getCustomUser(User user, Boolean ignoreCustomAttributes) { CustomUser customUser = new CustomUser(); if (user == null) { return customUser; } - setParentAttributes(customUser, user); + setParentAttributes(customUser, user, ignoreCustomAttributes); logger.debug("Custom User - customUser:{}", customUser); return customUser; } - public CustomUser setParentAttributes(CustomUser customUser, User user) { + public CustomUser setParentAttributes(CustomUser customUser, User user, Boolean removeNonLDAPAttributes) { customUser.setBaseDn(user.getBaseDn()); customUser.setCreatedAt(user.getCreatedAt()); customUser.setCustomAttributes(user.getCustomAttributes()); @@ -357,7 +374,7 @@ public CustomUser setParentAttributes(CustomUser customUser, User user) { customUser.setUpdatedAt(user.getUpdatedAt()); customUser.setUserId(user.getUserId()); - ignoreCustomObjectClassesForNonLDAP(customUser); + ignoreCustomAttributes(customUser, removeNonLDAPAttributes); return setCustomUserAttributes(customUser, user); } @@ -404,8 +421,21 @@ private User setUserCustomAttributes(CustomUser customUser, User user) { return user; } - private User ignoreCustomObjectClassesForNonLDAP(User user) { - return userMgmtSrv.ignoreCustomObjectClassesForNonLDAP(user); + private User ignoreCustomAttributes(User user, Boolean removeNonLDAPAttributes) { + logger.info("validate User CustomObjectClasses - User user:{}, removeNonLDAPAttributes:{}", user, + removeNonLDAPAttributes); + if (user == null || (user.getCustomObjectClasses() == null || user.getCustomObjectClasses().length == 0)) { + return user; + } + + logger.trace("user.getCustomObjectClasses():{}, userMgmtSrv.getPersistenceType():{}, userMgmtSrv.isLDAP():?{}", + user.getCustomObjectClasses(), userMgmtSrv.getPersistenceType(), userMgmtSrv.isLDAP()); + + if (removeNonLDAPAttributes) { + return userMgmtSrv.ignoreCustomObjectClassesForNonLDAP(user); + } + return user; + } } \ No newline at end of file diff --git a/jans-config-api/plugins/user-mgt-plugin/src/main/java/io/jans/configapi/plugin/mgt/service/UserMgmtService.java b/jans-config-api/plugins/user-mgt-plugin/src/main/java/io/jans/configapi/plugin/mgt/service/UserMgmtService.java index 39248893166..7b6f03dc57e 100644 --- a/jans-config-api/plugins/user-mgt-plugin/src/main/java/io/jans/configapi/plugin/mgt/service/UserMgmtService.java +++ b/jans-config-api/plugins/user-mgt-plugin/src/main/java/io/jans/configapi/plugin/mgt/service/UserMgmtService.java @@ -319,8 +319,8 @@ public User parseBirthDateAttribute(User user) { public User ignoreCustomObjectClassesForNonLDAP(User user) { String persistenceType = configurationService.getPersistenceType(); - logger.debug("persistenceType: {}", persistenceType); - if (!PersistenceEntryManager.PERSITENCE_TYPES.ldap.name().equals(persistenceType)) { + logger.debug("persistenceType: {}, isLDAP?:{}", persistenceType, isLDAP()); + if (!isLDAP()) { logger.debug( "Setting CustomObjectClasses :{} to null as its used only for LDAP and current persistenceType is {} ", user.getCustomObjectClasses(), persistenceType); @@ -329,6 +329,19 @@ public User ignoreCustomObjectClassesForNonLDAP(User user) { return user; } + public boolean isLDAP() { + String persistenceType = getPersistenceType(); + logger.debug("persistenceType: {}", persistenceType); + if (PersistenceEntryManager.PERSITENCE_TYPES.ldap.name().equals(persistenceType)) { + return true; + } + return false; + } + + public String getPersistenceType() { + return configurationService.getPersistenceType(); + } + public User addUser(User user, boolean active) { return userService.addUser(user, active); } diff --git a/jans-config-api/profiles/local/test.properties b/jans-config-api/profiles/local/test.properties index fbb95638a40..d7fe54e2e6d 100644 --- a/jans-config-api/profiles/local/test.properties +++ b/jans-config-api/profiles/local/test.properties @@ -1,9 +1,9 @@ #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/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 https://jans.io/oauth/config/read-all https://jans.io/oauth/config/write-all https://jans.io/oauth/config/delete-all https://jans.io/oauth/config/openid-read https://jans.io/oauth/config/openid-write https://jans.io/oauth/config/openid-delete https://jans.io/oauth/config/uma-read https://jans.io/oauth/config/uma-write https://jans.io/oauth/config/uma-delete https://jans.io/oauth/jans-auth-server/config/adminui/user/role.readonly https://jans.io/oauth/jans-auth-server/config/adminui/user/role.write https://jans.io/oauth/jans-auth-server/config/adminui/read-all https://jans.io/oauth/jans-auth-server/config/adminui/write-all https://jans.io/oauth/jans-auth-server/config/adminui/user/role.delete https://jans.io/oauth/jans-auth-server/config/adminui/delete-all https://jans.io/oauth/jans-auth-server/config/adminui/user/permission.readonly https://jans.io/oauth/jans-auth-server/config/adminui/user/permission.write https://jans.io/oauth/jans-auth-server/config/adminui/user/permission.write https://jans.io/oauth/jans-auth-server/config/adminui/user/permission.delete https://jans.io/oauth/jans-auth-server/config/adminui/user/rolePermissionMapping.readonly https://jans.io/oauth/jans-auth-server/config/adminui/user/rolePermissionMapping.write https://jans.io/oauth/jans-auth-server/config/adminui/user/rolePermissionMapping.delete https://jans.io/oauth/jans-auth-server/config/adminui/license.readonly https://jans.io/oauth/jans-auth-server/config/adminui/license.write https://jans.io/oauth/config/plugin.readonly +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 https://jans.io/oauth/config/read-all https://jans.io/oauth/config/write-all https://jans.io/oauth/config/delete-all https://jans.io/oauth/config/openid-read https://jans.io/oauth/config/openid-write https://jans.io/oauth/config/openid-delete https://jans.io/oauth/config/uma-read https://jans.io/oauth/config/uma-write https://jans.io/oauth/config/uma-delete https://jans.io/oauth/jans-auth-server/config/adminui/user/role.readonly https://jans.io/oauth/jans-auth-server/config/adminui/user/role.write https://jans.io/oauth/jans-auth-server/config/adminui/read-all https://jans.io/oauth/jans-auth-server/config/adminui/write-all https://jans.io/oauth/jans-auth-server/config/adminui/user/role.delete https://jans.io/oauth/jans-auth-server/config/adminui/delete-all https://jans.io/oauth/jans-auth-server/config/adminui/user/permission.readonly https://jans.io/oauth/jans-auth-server/config/adminui/user/permission.write https://jans.io/oauth/jans-auth-server/config/adminui/user/permission.write https://jans.io/oauth/jans-auth-server/config/adminui/user/permission.delete https://jans.io/oauth/jans-auth-server/config/adminui/user/rolePermissionMapping.readonly https://jans.io/oauth/jans-auth-server/config/adminui/user/rolePermissionMapping.write https://jans.io/oauth/jans-auth-server/config/adminui/user/rolePermissionMapping.delete https://jans.io/oauth/jans-auth-server/config/adminui/license.readonly https://jans.io/oauth/jans-auth-server/config/adminui/license.write https://jans.io/oauth/config/plugin.readonly https://jans.io/oauth/client/authorizations.readonly https://jans.io/oauth/client/authorizations.delete # 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.17bb80e1-2e30-40a9-b52c-be882f304f22 -test.client.secret=g7RbK1zVnejt -test.issuer=https://jans.server2/ \ No newline at end of file +test.client.id=1800.bf52932e-6f81-4a1b-be78-ccc0147f2a32 +test.client.secret=WBvBJiWJnfbh +test.issuer=https://jans.server1/ \ No newline at end of file diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaDeploymentsResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaDeploymentsResource.java index 1273b9536a0..229e79135bf 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaDeploymentsResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AgamaDeploymentsResource.java @@ -44,18 +44,15 @@ public class AgamaDeploymentsResource extends ConfigBaseResource { private ObjectMapper mapper; @Operation(summary = "Retrieve the list of projects deployed currently.", description = "Retrieve the list of projects deployed currently.", operationId = "get-agama-dev-prj", tags = { - "Agama - Developer Studio" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.AGAMA_READ_ACCESS, ApiAccessConstants.AGAMA_WRITE_ACCESS, - ApiAccessConstants.SUPER_ADMIN_READ_ACCESS })) + "Agama - Developer Studio" }, security = @SecurityRequirement(name = "oauth2", scopes = {ApiAccessConstants.AGAMA_READ_ACCESS})) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Agama projects", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = PagedResult.class), examples = @ExampleObject(name = "Response json example", value = "example/agama/agama-dev-prj-get-all.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @Path("list") - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }, groupScopes = { - ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }, groupScopes = {ApiAccessConstants.AGAMA_WRITE_ACCESS}, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Produces(MediaType.APPLICATION_JSON) + @Path("list") public Response getDeployments(@QueryParam("start") int start, @QueryParam("count") int count) { // this is NOT a search but a paged listing @@ -67,9 +64,7 @@ public Response getDeployments(@QueryParam("start") int start, @QueryParam("coun } @Operation(summary = "Fetches deployed Agama project based on name.", description = "Fetches deployed Agama project based on name.", operationId = "get-agama-dev-studio-prj-by-name", tags = { - "Agama - Developer Studio" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.AGAMA_READ_ACCESS, ApiAccessConstants.AGAMA_WRITE_ACCESS, - ApiAccessConstants.SUPER_ADMIN_READ_ACCESS })) + "Agama - Developer Studio" }, security = @SecurityRequirement(name = "oauth2", scopes = {ApiAccessConstants.AGAMA_READ_ACCESS} )) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Agama project", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = Deployment.class), examples = @ExampleObject(name = "Response json example", value = "example/agama/agama-dev-prj-get.json"))), @ApiResponse(responseCode = "204", description = "No Content"), @@ -78,8 +73,7 @@ public Response getDeployments(@QueryParam("start") int start, @QueryParam("coun @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }, groupScopes = { - ApiAccessConstants.AGAMA_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }, groupScopes = {ApiAccessConstants.AGAMA_WRITE_ACCESS}, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS }) @Produces(MediaType.APPLICATION_JSON) public Response getDeployment(@QueryParam("name") String projectName) { @@ -103,9 +97,7 @@ public Response getDeployment(@QueryParam("name") String projectName) { } @Operation(summary = "Deploy an Agama project.", description = "Deploy an Agama project.", operationId = "post-agama-dev-studio-prj", tags = { - "Agama - Developer Studio" }, security = @SecurityRequirement(name = "oauth2", scopes = { - ApiAccessConstants.AGAMA_WRITE_ACCESS, - ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS })) + "Agama - Developer Studio" }, security = @SecurityRequirement(name = "oauth2", scopes = {ApiAccessConstants.AGAMA_WRITE_ACCESS})) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Agama project accepted", content = @Content(mediaType = "application/zip", schema = @Schema(implementation = String.class), examples = @ExampleObject(name = "Response json example", value = "example/agama/agama-dev-prj-post.json"))), @ApiResponse(responseCode = "400", description = "Bad Request"), @@ -114,7 +106,7 @@ public Response getDeployment(@QueryParam("name") String projectName) { @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST @Consumes("application/zip") - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response deploy(@QueryParam("name") String projectName, byte[] gamaBinary) { @@ -143,7 +135,7 @@ public Response deploy(@QueryParam("name") String projectName, byte[] gamaBinary @ApiResponse(responseCode = "409", description = "Conflict"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @DELETE - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_DELETE_ACCESS }, + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_DELETE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_DELETE_ACCESS }) public Response undeploy(@QueryParam("name") String projectName) { @@ -165,6 +157,12 @@ public Response undeploy(@QueryParam("name") String projectName) { } + @Operation(summary = "Retrieve the list of configs based on name.", description = "Retrieve the list of configs based on name.", operationId = "get-agama-dev-prj-configs", tags = { + "Agama - Developer Studio" }, security = @SecurityRequirement(name = "oauth2", scopes = {ApiAccessConstants.AGAMA_READ_ACCESS})) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Agama projects configs", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = Map.class), examples = @ExampleObject(name = "Response json example", value = "example/agama/agama-dev-prj-get-configs-all.json"))), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "500", description = "InternalServerError") }) @GET @Path("configs") @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_READ_ACCESS }, groupScopes = { @@ -193,10 +191,18 @@ public Response getConfigs(@QueryParam("name") String projectName) throws JsonPr } + @Operation(summary = "Update an Agama project.", description = "Update an Agama project.", operationId = "put-agama-dev-studio-prj", tags = { + "Agama - Developer Studio" }, security = @SecurityRequirement(name = "oauth2", scopes = {ApiAccessConstants.AGAMA_WRITE_ACCESS})) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", description = "Agama project accepted", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = Map.class), examples = @ExampleObject(name = "Response json example", value = "example/agama/agama-dev-prj-post.json"))), + @ApiResponse(responseCode = "400", description = "Bad Request"), + @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "409", description = "Conflict"), + @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @Path("configs") @Consumes(MediaType.APPLICATION_JSON) - @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, + @ProtectedApi(scopes = { ApiAccessConstants.AGAMA_WRITE_ACCESS }, groupScopes = {}, superScopes = { ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS }) public Response setConfigs(@QueryParam("name") String projectName, Map> flowsConfigs) { diff --git a/jans-config-api/server/src/test/resources/feature/agama/agama-deployment.feature b/jans-config-api/server/src/test/resources/feature/agama/agama-deployment.feature new file mode 100644 index 00000000000..df830d55fd9 --- /dev/null +++ b/jans-config-api/server/src/test/resources/feature/agama/agama-deployment.feature @@ -0,0 +1,46 @@ + +Feature: Agama Deployment + +Background: +* def mainUrl = agama_deployment_url +* def funGetEncodedValue = +""" +function(strValue) { +print(' strValue = '+strValue); +if(strValue == null || strValue.length==0){ +return strValue; +} +var URLEncoder = Java.type('java.net.URLEncoder'); +var encodedStrValue = URLEncoder.encode(strValue, "UTF-8"); +print(' encodedStrValue = '+encodedStrValue); +return encodedStrValue; +} +""" + +Scenario: Fetch all Agama deployment without bearer token + Given url mainUrl + '/list' + When method GET + Then status 401 + And print response + + +Scenario: Fetch all Agama deployment + Given url mainUrl + '/list' + And print 'accessToken = '+accessToken + And header Authorization = 'Bearer ' + accessToken + When method GET + Then status 200 + And print response + +Scenario: Fetch all Agama deployment + Given url mainUrl + '/list' + And print 'accessToken = '+accessToken + And header Authorization = 'Bearer ' + accessToken + And param start = 0 + And param count = 3 + When method GET + Then status 200 + And print response + + + 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 260a59998f8..3e71531a1fc 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 @@ -64,6 +64,7 @@ function() { session_url: baseUrl + '/jans-config-api/api/v1/jans-auth-server/session', plugin_url: baseUrl + '/jans-config-api/api/v1/plugin', api_config_url: baseUrl + '/jans-config-api/api/v1/api-config', + agama_deployment_url: baseUrl + '/jans-config-api/api/v1/agama-deployment', }; 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 8c51ff66d96..1604201d52f 100644 --- a/jans-config-api/server/src/test/resources/karate-config.js +++ b/jans-config-api/server/src/test/resources/karate-config.js @@ -64,6 +64,7 @@ function() { session_url: baseUrl + '/jans-config-api/api/v1/jans-auth-server/session', plugin_url: baseUrl + '/jans-config-api/api/v1/plugin', api_config_url: baseUrl + '/jans-config-api/api/v1/api-config', + agama_deployment_url: baseUrl + '/jans-config-api/api/v1/agama-deployment', }; karate.configure('connectTimeout', 30000);