From d8e97c4b47b1ff38d4a0207d3f07f461fb807630 Mon Sep 17 00:00:00 2001 From: pujavs <43700552+pujavs@users.noreply.github.com> Date: Wed, 6 Apr 2022 22:35:38 +0530 Subject: [PATCH] feat(jans-config-api): user-management endpoints (#1167) * feat(jans-config-api): user mgmt endpoint - wip * feat(jans-config-api): user mgmt endpoint -wip * feat(jans-auth-config): user mgmt endpoint - wip * feat(jans-config-api): user mgmt endpoint * feat(jans-config-api): user mgmt endpoint * feat(jans-config-api): user mgmt endpoint * feat(jans-config-api): user mgmt endpoint * feat(jans-config-api): user mgmt endpoint * feat(jans-config-api): user mgmt endpoint * feat(jans-config-api): user mgmt endpoint - wip * feat(jans-config-api): user mgmt endpoint - wip * feat(jans-config-api): user mgmt endpoints * feat(jans-config-api): user mgmt endpoints * feat(jans-config-api): user management api * feat(jans-config-api): user management api * feat(jans-config-api): user management api --- jans-cli/cli/jca.yaml | 258 ++++++++++++++++- .../configapi/util/ApiAccessConstants.java | 4 + .../docs/jans-config-api-swagger.yaml | 228 ++++++++++++++- .../default/config-api-test.properties | 2 +- .../profiles/jans-ui.jans.io/test.properties | 2 +- .../test.properties | 2 +- .../profiles/local/test.properties | 6 +- .../jans/configapi/rest/ApiApplication.java | 1 + .../rest/resource/auth/UserResource.java | 155 ++++++++++ .../configapi/service/auth/UserService.java | 75 +++++ .../main/resources/config-api-rs-protect.json | 23 ++ .../test/resources/feature/user/user-ref.json | 274 ++++++++++++++++++ .../test/resources/feature/user/user.feature | 46 +++ .../src/test/resources/feature/user/user.json | 262 +++++++++++++++++ .../test/resources/karate-config-jenkins.js | 1 + .../src/test/resources/karate-config.js | 1 + 16 files changed, 1322 insertions(+), 18 deletions(-) create mode 100644 jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UserResource.java create mode 100644 jans-config-api/server/src/main/java/io/jans/configapi/service/auth/UserService.java create mode 100644 jans-config-api/server/src/test/resources/feature/user/user-ref.json create mode 100644 jans-config-api/server/src/test/resources/feature/user/user.feature create mode 100644 jans-config-api/server/src/test/resources/feature/user/user.json diff --git a/jans-cli/cli/jca.yaml b/jans-cli/cli/jca.yaml index a564032eeea..30ba1f40938 100644 --- a/jans-cli/cli/jca.yaml +++ b/jans-cli/cli/jca.yaml @@ -34,6 +34,7 @@ tags: - name: Statistics - User - name: Health - Check - name: Server Stats + - name: User Management - name: SCIM - User Management - name: SCIM - Config Management - name: Organization Configuration @@ -2396,6 +2397,193 @@ paths: $ref: '#/components/schemas/StatsData' '500': description: Internal Server Error + + /jans-config-api/api/v1/user: + get: + tags: + - User Management + summary: Gets list of users + description: Gets list of users + operationId: get-user + responses: + '200': + description: OK + content: + application/json: + schema: + title: Users. + description: List of users. + items: + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/Unauthorized' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.readonly] + parameters: + - schema: + type: integer + default: 50 + in: query + name: limit + description: Search size - max size of the results to return. + - schema: + type: string + in: query + name: pattern + description: Search pattern. + - schema: + type: integer + default: 1 + in: query + name: startIndex + description: The 1-based index of the first query result. + - schema: + type: string + default: inum + in: query + name: sortBy + description: Attribute whose value will be used to order the returned response. + - schema: + type: string + default: ascending + enum: + - ascending + - descending + in: query + name: sortOrder + description: Order in which the sortBy param is applied. Allowed values are "ascending" and "descending". + post: + tags: + - User Management + summary: Create new User + description: Create new User + operationId: post-user + requestBody: + content: + application/json: + schema: + title: User Details. + description: User Details. + $ref: '#/components/schemas/User' + responses: + '201': + description: Created + content: + application/json: + schema: + title: User Details. + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/Unauthorized' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.write] + put: + tags: + - User Management + summary: Update User. + description: Update User. + operationId: put-user + requestBody: + content: + application/json: + schema: + title: User Details. + $ref: '#/components/schemas/User' + responses: + '200': + description: OK + content: + application/json: + schema: + title: User Details. + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.write] + /jans-config-api/api/v1/user/{inum}: + parameters: + - schema: + type: string + name: inum + in: path + description: User identifier + required: true + get: + tags: + - User Management + summary: Get User by Inum + description: Get User by Inum. + operationId: get-user-by-inum + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/Unauthorized' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.readonly] + delete: + tags: + - User Management + summary: Delete User. + description: Delete User. + operationId: delete-user + responses: + '204': + description: No Content + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.delete] + patch: + tags: + - User Management + summary: Update modified properties of user by Inum. + description: Update modified properties of user by Inum. + operationId: patch-user-by-inum + requestBody: + content: + application/json-patch+json: + schema: + type: array + items: + $ref: '#/components/schemas/PatchRequest' + description: String representing patch-document. + example: '[ {op:replace, path: userId, value: test_user_100 } ]' + responses: + '200': + description: OK + content: + application/json: + schema: + title: User Details. + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.write] /jans-config-api/scim/user: get: @@ -3433,6 +3621,10 @@ components: 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 + https://jans.io/oauth/config/user.readonly: View user related information + https://jans.io/oauth/config/user.write: Manage user related information + https://jans.io/oauth/config/user.delete: Delete user related information + responses: Found: @@ -6285,11 +6477,14 @@ components: type: object properties: value: + description: E-mail addresses for the user. type: string example: gossow@nsfw.com display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function; e.g., 'work' or 'home'. type: string example: work primary: @@ -6300,25 +6495,30 @@ components: type: object properties: value: + description: Phone number of the User type: string example: +1-555-555-8377 display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function; e.g., 'work' or 'home' or 'mobile' etc. type: string example: fax primary: + description: A Boolean value indicating the 'primary' or preferred attribute value for this attribute. type: boolean - description: Denotes if this is the preferred phone number among others, if any - description: See section 4.1.2 of RFC 7643 InstantMessagingAddress: type: object properties: value: + description: Instant messaging address for the User. type: string display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function; e.g., 'aim', 'gtalk', 'mobile' etc. type: string example: gtalk primary: @@ -6329,11 +6529,14 @@ components: type: object properties: value: + description: URI of a photo of the User. type: string example: https://pics.nsfw.com/gossow.png display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function; e.g., 'photo' or 'thumbnail'. type: string example: thumbnail primary: @@ -6345,8 +6548,9 @@ components: properties: formatted: type: string - description: Full mailing address, formatted for display or use with a mailing label + description: The full mailing address, formatted for display or use with a mailing label. streetAddress: + description: The full street address component, which may include house number, street name,PO BOX,etc. type: string example: 56 Acacia Avenue locality: @@ -6363,6 +6567,7 @@ components: description: Country expressed in ISO 3166-1 "alpha-2" code format example: UK type: + description: A label indicating the attribute's function; e.g., 'work' or 'home'. type: string example: home primary: @@ -6373,11 +6578,14 @@ components: type: object properties: value: + description: The value of a role type: string example: Project manager display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function. type: string primary: type: boolean @@ -6408,6 +6616,7 @@ components: description: URI associated to the group example: https://nsfw.com/scim/restv1/v2/Groups/180ee84f0671b1 display: + description: A human readable name, primarily used for display purposes. type: string example: Cult managers type: @@ -6419,11 +6628,14 @@ components: type: object properties: value: + description: The value of an entitlement. type: string example: Stakeholder display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function. type: string primary: type: boolean @@ -6433,11 +6645,13 @@ components: type: object properties: value: + description: The value of a X509 certificate. type: string - description: DER-encoded X.509 certificate display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function. type: string primary: type: boolean @@ -6743,5 +6957,37 @@ components: type: object $ref: '#/components/schemas/FacterData' description: Underlying Server stats - - + + User: + title: User object + description: User. + type: object + required: + - userId + properties: + dn: + type: string + description: Domain name. + userId: + description: A domain issued and managed identifier for the user. + type: string + createdAt: + description: User creation date. + type: string + format: date-time + updatedAt: + description: Time the information of the person was last updated. Seconds from 1970-01-01T0:0:0Z + type: string + format: date-time + oxAuthPersistentJwt: + description: Persistent JWT. + type: array + items: + type: string + customAttributes: + description: dn of associated clients with the user. + type: array + items: + $ref: '#/components/schemas/CustomAttribute' + + \ No newline at end of file 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 9e9fd5c1e95..f38f08c037a 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 @@ -65,4 +65,8 @@ private ApiAccessConstants() { 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"; + public static final String USER_READ_ACCESS = "https://jans.io/oauth/config/user.readonly"; + public static final String USER_WRITE_ACCESS = "https://jans.io/oauth/config/user.write"; + public static final String USER_DELETE_ACCESS = "https://jans.io/oauth/config/user.delete"; + } diff --git a/jans-config-api/docs/jans-config-api-swagger.yaml b/jans-config-api/docs/jans-config-api-swagger.yaml index a564032eeea..870e6c8c82d 100644 --- a/jans-config-api/docs/jans-config-api-swagger.yaml +++ b/jans-config-api/docs/jans-config-api-swagger.yaml @@ -34,6 +34,7 @@ tags: - name: Statistics - User - name: Health - Check - name: Server Stats + - name: User Management - name: SCIM - User Management - name: SCIM - Config Management - name: Organization Configuration @@ -2396,6 +2397,163 @@ paths: $ref: '#/components/schemas/StatsData' '500': description: Internal Server Error + + /jans-config-api/api/v1/user: + get: + tags: + - User Management + summary: Gets list of users + description: Gets list of users + operationId: get-user + responses: + '200': + description: OK + content: + application/json: + schema: + title: Users. + description: List of users. + items: + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/Unauthorized' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.readonly] + parameters: + - schema: + type: integer + default: 50 + in: query + name: limit + description: Search size - max size of the results to return. + - schema: + type: string + in: query + name: pattern + description: Search pattern. + - schema: + type: integer + default: 1 + in: query + name: startIndex + description: The 1-based index of the first query result. + - schema: + type: string + default: inum + in: query + name: sortBy + description: Attribute whose value will be used to order the returned response. + - schema: + type: string + default: ascending + enum: + - ascending + - descending + in: query + name: sortOrder + description: Order in which the sortBy param is applied. Allowed values are "ascending" and "descending". + post: + tags: + - User Management + summary: Create new User + description: Create new User + operationId: post-user + requestBody: + content: + application/json: + schema: + title: User Details. + description: User Details. + $ref: '#/components/schemas/User' + responses: + '201': + description: Created + content: + application/json: + schema: + title: User Details. + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/Unauthorized' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.write] + put: + tags: + - User Management + summary: Update User. + description: Update User. + operationId: put-user + requestBody: + content: + application/json: + schema: + title: User Details. + $ref: '#/components/schemas/User' + responses: + '200': + description: OK + content: + application/json: + schema: + title: User Details. + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.write] + /jans-config-api/api/v1/user/{inum}: + parameters: + - schema: + type: string + name: inum + in: path + description: User identifier + required: true + get: + tags: + - User Management + summary: Get User by Inum + description: Get User by Inum. + operationId: get-user-by-inum + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '401': + $ref: '#/components/responses/Unauthorized' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.readonly] + delete: + tags: + - User Management + summary: Delete User. + description: Delete User. + operationId: delete-user + responses: + '204': + description: No Content + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + description: Internal Server Error + security: + - oauth2: [https://jans.io/oauth/config/user.delete] + /jans-config-api/scim/user: get: @@ -3433,6 +3591,10 @@ components: 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 + https://jans.io/oauth/config/user.readonly: View user related information + https://jans.io/oauth/config/user.write: Manage user related information + https://jans.io/oauth/config/user.delete: Delete user related information + responses: Found: @@ -6285,11 +6447,14 @@ components: type: object properties: value: + description: E-mail addresses for the user. type: string example: gossow@nsfw.com display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function; e.g., 'work' or 'home'. type: string example: work primary: @@ -6300,25 +6465,30 @@ components: type: object properties: value: + description: Phone number of the User type: string example: +1-555-555-8377 display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function; e.g., 'work' or 'home' or 'mobile' etc. type: string example: fax primary: + description: A Boolean value indicating the 'primary' or preferred attribute value for this attribute. type: boolean - description: Denotes if this is the preferred phone number among others, if any - description: See section 4.1.2 of RFC 7643 InstantMessagingAddress: type: object properties: value: + description: Instant messaging address for the User. type: string display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function; e.g., 'aim', 'gtalk', 'mobile' etc. type: string example: gtalk primary: @@ -6329,11 +6499,14 @@ components: type: object properties: value: + description: URI of a photo of the User. type: string example: https://pics.nsfw.com/gossow.png display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function; e.g., 'photo' or 'thumbnail'. type: string example: thumbnail primary: @@ -6345,8 +6518,9 @@ components: properties: formatted: type: string - description: Full mailing address, formatted for display or use with a mailing label + description: The full mailing address, formatted for display or use with a mailing label. streetAddress: + description: The full street address component, which may include house number, street name,PO BOX,etc. type: string example: 56 Acacia Avenue locality: @@ -6363,6 +6537,7 @@ components: description: Country expressed in ISO 3166-1 "alpha-2" code format example: UK type: + description: A label indicating the attribute's function; e.g., 'work' or 'home'. type: string example: home primary: @@ -6373,11 +6548,14 @@ components: type: object properties: value: + description: The value of a role type: string example: Project manager display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function. type: string primary: type: boolean @@ -6408,6 +6586,7 @@ components: description: URI associated to the group example: https://nsfw.com/scim/restv1/v2/Groups/180ee84f0671b1 display: + description: A human readable name, primarily used for display purposes. type: string example: Cult managers type: @@ -6419,11 +6598,14 @@ components: type: object properties: value: + description: The value of an entitlement. type: string example: Stakeholder display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function. type: string primary: type: boolean @@ -6433,11 +6615,13 @@ components: type: object properties: value: + description: The value of a X509 certificate. type: string - description: DER-encoded X.509 certificate display: + description: A human readable name, primarily used for display purposes. type: string type: + description: A label indicating the attribute's function. type: string primary: type: boolean @@ -6743,5 +6927,37 @@ components: type: object $ref: '#/components/schemas/FacterData' description: Underlying Server stats - - + + User: + title: User object + description: User. + type: object + required: + - userId + properties: + dn: + type: string + description: Domain name. + userId: + description: A domain issued and managed identifier for the user. + type: string + createdAt: + description: User creation date. + type: string + format: date-time + updatedAt: + description: Time the information of the person was last updated. Seconds from 1970-01-01T0:0:0Z + type: string + format: date-time + oxAuthPersistentJwt: + description: Persistent JWT. + type: array + items: + type: string + customAttributes: + description: dn of associated clients with the user. + type: array + items: + $ref: '#/components/schemas/CustomAttribute' + + \ No newline at end of file diff --git a/jans-config-api/profiles/default/config-api-test.properties b/jans-config-api/profiles/default/config-api-test.properties index f31843b0563..2e700a452bf 100644 --- a/jans-config-api/profiles/default/config-api-test.properties +++ b/jans-config-api/profiles/default/config-api-test.properties @@ -1,7 +1,7 @@ # The URL of your Jans installation test.server=https://jenkins-config-api.gluu.org -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 https://jans.io/oauth/config/user.readonly https://jans.io/oauth/config/user.write https://jans.io/oauth/config/user.delete token.endpoint=https://jenkins-config-api.gluu.org/jans-auth/restv1/token token.grant.type=client_credentials diff --git a/jans-config-api/profiles/jans-ui.jans.io/test.properties b/jans-config-api/profiles/jans-ui.jans.io/test.properties index d2d4915e074..eb7108cfc2b 100644 --- a/jans-config-api/profiles/jans-ui.jans.io/test.properties +++ b/jans-config-api/profiles/jans-ui.jans.io/test.properties @@ -1,4 +1,4 @@ -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 https://jans.io/oauth/config/user.readonly https://jans.io/oauth/config/user.write https://jans.io/oauth/config/user.delete # Test env Setting token.endpoint=https://jans-ui.jans.io/jans-auth/restv1/token diff --git a/jans-config-api/profiles/jenkins-config-api.gluu.org/test.properties b/jans-config-api/profiles/jenkins-config-api.gluu.org/test.properties index b8bc8b1581d..65e505c94f1 100644 --- a/jans-config-api/profiles/jenkins-config-api.gluu.org/test.properties +++ b/jans-config-api/profiles/jenkins-config-api.gluu.org/test.properties @@ -1,6 +1,6 @@ test.server=https://jenkins-config-api.gluu.org -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 https://jans.io/oauth/config/user.readonly https://jans.io/oauth/config/user.write https://jans.io/oauth/config/user.delete token.endpoint=https://jenkins-config-api.gluu.org/jans-auth/restv1/token token.grant.type=client_credentials diff --git a/jans-config-api/profiles/local/test.properties b/jans-config-api/profiles/local/test.properties index bcad7a33e42..43b105ffc20 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 https://jans.io/oauth/config/organization.readonly https://jans.io/oauth/config/organization.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 https://jans.io/oauth/config/user.readonly https://jans.io/oauth/config/user.write https://jans.io/oauth/config/user.delete # Test env Setting #token.endpoint=https://jenkins-config-api.gluu.org/jans-auth/restv1/token @@ -70,6 +70,6 @@ test.scopes=https://jans.io/oauth/config/acrs.readonly https://jans.io/oauth/con # jans.server token.endpoint=https://jans.server/jans-auth/restv1/token token.grant.type=client_credentials -test.client.id=1800.77e9a8e6-8fee-4b86-b294-017ba6ab2112 -test.client.secret=dobHjXDhH6zh +test.client.id=1800.5cfac798-9a5d-4a92-8efe-4cecc4f0c196 +test.client.secret=SSj633EttZdV test.issuer=https://jans.server \ No newline at end of file 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 91638787dc4..6b49f3a553e 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 @@ -48,6 +48,7 @@ public Set> getClasses() { classes.add(HealthCheckResource.class); classes.add(OrganizationResource.class); classes.add(SqlConfigurationResource.class); + classes.add(UserResource.class); return classes; } diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UserResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UserResource.java new file mode 100644 index 00000000000..ad15da5d3f4 --- /dev/null +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/UserResource.java @@ -0,0 +1,155 @@ +/* + * 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.github.fge.jsonpatch.JsonPatchException; +import static io.jans.as.model.util.Util.escapeLog; +import io.jans.as.common.model.common.User; +import io.jans.configapi.core.rest.ProtectedApi; +import io.jans.configapi.rest.model.SearchRequest; +import io.jans.configapi.service.auth.UserService; +import io.jans.configapi.util.ApiAccessConstants; +import io.jans.configapi.util.ApiConstants; +import io.jans.configapi.core.util.Jackson; +import io.jans.orm.model.PagedResult; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.slf4j.Logger; + +@Path(ApiConstants.USER) +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +@ApplicationScoped +public class UserResource extends BaseResource { + + private static final String USER = "user"; + + @Inject + Logger logger; + + @Inject + UserService userSrv; + + @GET + @ProtectedApi(scopes = { ApiAccessConstants.USER_READ_ACCESS }) + public Response getUsers( + @DefaultValue(DEFAULT_LIST_SIZE) @QueryParam(value = ApiConstants.LIMIT) int limit, + @DefaultValue("") @QueryParam(value = ApiConstants.PATTERN) String pattern, + @DefaultValue(DEFAULT_LIST_START_INDEX) @QueryParam(value = ApiConstants.START_INDEX) int startIndex, + @QueryParam(value = ApiConstants.SORT_BY) String sortBy, + @QueryParam(value = ApiConstants.SORT_ORDER) String sortOrder) { + if (logger.isDebugEnabled()) { + logger.debug("User search param - limit:{}, pattern:{}, startIndex:{}, sortBy:{}, sortOrder:{}", + escapeLog(limit), escapeLog(pattern), escapeLog(startIndex), escapeLog(sortBy), + escapeLog(sortOrder)); + } + SearchRequest searchReq = createSearchRequest(userSrv.getPeopleBaseDn(), pattern, sortBy, sortOrder, startIndex, + limit, null, null); + + final List users = this.doSearch(searchReq); + logger.debug("User search result:{}", users); + return Response.ok(users).build(); + } + + @GET + @ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS }) + @Path(ApiConstants.INUM_PATH) + public Response getUserByInum(@PathParam(ApiConstants.INUM) @NotNull String inum) { + if (logger.isDebugEnabled()) { + logger.debug("User search by inum:{}", escapeLog(inum)); + } + User user = userSrv.getUserByInum(inum); + logger.debug("user:{}", user); + return Response.ok(user).build(); + } + + @POST + @ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS }) + public Response createUser(@Valid User user) { + if (logger.isDebugEnabled()) { + logger.debug("User details to be added - user:{}", escapeLog(user)); + } + user = userSrv.addUser(user, true); + logger.debug("User created {}", user); + return Response.status(Response.Status.CREATED).entity(user).build(); + } + + @PUT + @ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS }) + public Response updateUser(@Valid User user) { + if (logger.isDebugEnabled()) { + logger.debug("User details to be updated - user:{}", escapeLog(user)); + } + user = userSrv.updateUser((user)); + logger.debug("Updated user:{}", user); + + return Response.ok(user).build(); + } + + @PATCH + @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON) + @ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS }) + @Path(ApiConstants.INUM_PATH) + public Response patchUser(@PathParam(ApiConstants.INUM) @NotNull String inum, @NotNull String pathString) + throws JsonPatchException, IOException { + if (logger.isDebugEnabled()) { + logger.debug("User details to be patched - inum:{}, pathString:{}", escapeLog(inum), escapeLog(pathString)); + } + User existingUser = userSrv.getUserByInum(inum); + checkResourceNotNull(existingUser, USER); + + existingUser = Jackson.applyPatch(pathString, existingUser); + existingUser = userSrv.updateUser(existingUser); + logger.debug("Updated user:{}", existingUser); + return Response.ok(existingUser).build(); + } + + @DELETE + @Path(ApiConstants.INUM_PATH) + @ProtectedApi(scopes = { ApiAccessConstants.USER_DELETE_ACCESS }) + public Response deleteUser(@PathParam(ApiConstants.INUM) @NotNull String inum) { + if (logger.isDebugEnabled()) { + logger.debug("User to be deleted - inum:{} ", escapeLog(inum)); + } + User user = userSrv.getUserByInum(inum); + checkResourceNotNull(user, USER); + userSrv.removeUser(user); + return Response.noContent().build(); + } + + private List doSearch(SearchRequest searchReq) { + if (logger.isDebugEnabled()) { + logger.debug("User search params - searchReq:{} ", escapeLog(searchReq)); + } + + PagedResult pagedResult = userSrv.searchUsers(searchReq); + if (logger.isTraceEnabled()) { + logger.trace("PagedResult - pagedResult:{}", pagedResult); + } + + List users = new ArrayList<>(); + if (pagedResult != null) { + logger.trace("Users fetched - pagedResult.getEntries():{}", pagedResult.getEntries()); + users = pagedResult.getEntries(); + } + if (logger.isDebugEnabled()) { + logger.debug("Users fetched - users:{}", users); + } + return users; + } + +} diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/UserService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/UserService.java new file mode 100644 index 00000000000..1c9b5731694 --- /dev/null +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/UserService.java @@ -0,0 +1,75 @@ +/* + * 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.service.auth; + +import io.jans.as.common.model.common.User; +import io.jans.as.common.util.AttributeConstants; +import io.jans.as.model.config.StaticConfiguration; +import io.jans.as.model.configuration.AppConfiguration; +import io.jans.configapi.rest.model.SearchRequest; +import io.jans.orm.model.PagedResult; +import io.jans.orm.model.SortOrder; +import io.jans.orm.search.filter.Filter; +import static io.jans.as.model.util.Util.escapeLog; + +import java.util.List; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.inject.Named; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; + +@ApplicationScoped +@Named("userSrv") +public class UserService extends io.jans.as.common.service.common.UserService { + + @Inject + private Logger logger; + + @Inject + private StaticConfiguration staticConfiguration; + + @Inject + private AppConfiguration appConfiguration; + + @Override + public List getPersonCustomObjectClassList() { + return appConfiguration.getPersonCustomObjectClassList(); + } + + @Override + public String getPeopleBaseDn() { + return staticConfiguration.getBaseDn().getPeople(); + } + + public PagedResult searchUsers(SearchRequest searchRequest) { + if (logger.isDebugEnabled()) { + logger.debug("Search Users with searchRequest:{}", escapeLog(searchRequest)); + } + Filter searchFilter = null; + if (StringUtils.isNotEmpty(searchRequest.getFilter())) { + String[] targetArray = new String[] { searchRequest.getFilter() }; + Filter displayNameFilter = Filter.createSubstringFilter(AttributeConstants.DISPLAY_NAME, null, targetArray, + null); + Filter descriptionFilter = Filter.createSubstringFilter(AttributeConstants.DESCRIPTION, null, targetArray, + null); + Filter inumFilter = Filter.createSubstringFilter(AttributeConstants.INUM, null, targetArray, null); + searchFilter = Filter.createORFilter(displayNameFilter, descriptionFilter, inumFilter); + } + + return persistenceEntryManager.findPagedEntries(getPeopleBaseDn(), User.class, searchFilter, null, + searchRequest.getSortBy(), SortOrder.getByValue(searchRequest.getSortOrder()), + searchRequest.getStartIndex() - 1, searchRequest.getCount(), searchRequest.getMaxCount()); + + } + + public void removeUser(User user) { + persistenceEntryManager.removeRecursively(user.getDn(), User.class); + } + +} 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 34c6bc9f9b1..7534547dce5 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 @@ -690,6 +690,29 @@ ] } ] + }, + { + "path":"/jans-config-api/api/v1/user", + "conditions":[ + { + "httpMethods":["GET"], + "scopes":[ + "https://jans.io/oauth/config/user.readonly" + ] + }, + { + "httpMethods":["PATCH","POST","PUT"], + "scopes":[ + "https://jans.io/oauth/config/user.write" + ] + }, + { + "httpMethods":["DELETE"], + "scopes":[ + "https://jans.io/oauth/config/user.delete" + ] + } + ] } ] } \ No newline at end of file diff --git a/jans-config-api/server/src/test/resources/feature/user/user-ref.json b/jans-config-api/server/src/test/resources/feature/user/user-ref.json new file mode 100644 index 00000000000..97740843e29 --- /dev/null +++ b/jans-config-api/server/src/test/resources/feature/user/user-ref.json @@ -0,0 +1,274 @@ +{ + "dn": "inum=B1F3-AEAE-B799,ou=people,o=jans", + "userId": "admin_user21, + "updatedAt": "2017-02-13T19:25:12", + "customAttributes": [ + { + "name": "birthdate", + "multiValued": false, + "values": [ + "19830106010101.253Z" + ], + "value": "19830106010101.253Z", + "displayValue": "19830106010101.253Z" + }, + { + "name": "c", + "multiValued": false, + "values": [ + "US" + ], + "value": "US", + "displayValue": "US" + }, + { + "name": "cn", + "multiValued": false, + "values": [ + "Test User2" + ], + "value": "Test User2", + "displayValue": "Test User2" + }, + { + "name": "displayName", + "multiValued": false, + "values": [ + "Jans Auth Test User2" + ], + "value": "Jans Auth Test User2", + "displayValue": "Jans Auth Test User2" + }, + { + "name": "emailVerified", + "multiValued": false, + "values": [ + "TRUE" + ], + "value": "TRUE", + "displayValue": "TRUE" + }, + { + "name": "gender", + "multiValued": false, + "values": [ + "Male" + ], + "value": "Male", + "displayValue": "Male" + }, + { + "name": "givenName", + "multiValued": false, + "values": [ + "Test2" + ], + "value": "Test2", + "displayValue": "Test2" + }, + { + "name": "inum", + "multiValued": false, + "values": [ + "B1F3-AEAE-B799" + ], + "value": "B1F3-AEAE-B799", + "displayValue": "B1F3-AEAE-B799" + }, + { + "name": "jansPrefUsrName", + "multiValued": false, + "values": [ + "user2" + ], + "value": "user2", + "displayValue": "user2" + }, + { + "name": "jansStatus", + "multiValued": false, + "values": [ + "active" + ], + "value": "active", + "displayValue": "active" + }, + { + "name": "l", + "multiValued": false, + "values": [ + "Austin" + ], + "value": "Austin", + "displayValue": "Austin" + }, + { + "name": "locale", + "multiValued": false, + "values": [ + "en-US" + ], + "value": "en-US", + "displayValue": "en-US" + }, + { + "name": "mail", + "multiValued": false, + "values": [ + "test_user2@test.org" + ], + "value": "test_user2@test.org", + "displayValue": "test_user2@test.org" + }, + { + "name": "memberOf", + "multiValued": true, + "values": [ + "inum=7890,ou=groups,o=jans", + "inum=7891,ou=groups,o=jans" + ], + "value": "inum=7890,ou=groups,o=jans", + "displayValue": "inum=7890,ou=groups,o=jans, inum=7891,ou=groups,o=jans" + }, + { + "name": "middleName", + "multiValued": false, + "values": [ + "User2" + ], + "value": "User2", + "displayValue": "User2" + }, + { + "name": "mobile", + "multiValued": false, + "values": [ + "(512) 516-2414" + ], + "value": "(512) 516-2414", + "displayValue": "(512) 516-2414" + }, + { + "name": "nickname", + "multiValued": false, + "values": [ + "user2" + ], + "value": "user2", + "displayValue": "user2" + }, + { + "name": "o", + "multiValued": false, + "values": [ + "Test" + ], + "value": "Test", + "displayValue": "Test" + }, + { + "name": "phoneNumberVerified", + "multiValued": false, + "values": [ + "TRUE" + ], + "value": "TRUE", + "displayValue": "TRUE" + }, + { + "name": "picture", + "multiValued": false, + "values": [ + "http://www.jans.org/wp-content/uploads/2012/04/mike3.png" + ], + "value": "http://www.jans.org/wp-content/uploads/2012/04/mike3.png", + "displayValue": "http://www.jans.org/wp-content/uploads/2012/04/mike3.png" + }, + { + "name": "preferredLanguage", + "multiValued": false, + "values": [ + "en_US" + ], + "value": "en_US", + "displayValue": "en_US" + }, + { + "name": "profile", + "multiValued": false, + "values": [ + "http://www.mywebsite.com/profile" + ], + "value": "http://www.mywebsite.com/profile", + "displayValue": "http://www.mywebsite.com/profile" + }, + { + "name": "sn", + "multiValued": false, + "values": [ + "User2" + ], + "value": "User2", + "displayValue": "User2" + }, + { + "name": "st", + "multiValued": false, + "values": [ + "Texas" + ], + "value": "Texas", + "displayValue": "Texas" + }, + { + "name": "street", + "multiValued": false, + "values": [ + "622 East 6th Street" + ], + "value": "622 East 6th Street", + "displayValue": "622 East 6th Street" + }, + { + "name": "telephoneNumber", + "multiValued": false, + "values": [ + "(512) 516-2414" + ], + "value": "(512) 516-2414", + "displayValue": "(512) 516-2414" + }, + { + "name": "userPassword", + "multiValued": false, + "values": [ + "{SSHA512}gFcj2ucCCyO8NLN+IfBIbdzr3xjI7b07vAdwkJ8sw9Ynghj4uWPjfSHI2pHZ9dsyAdL3+mFl8g0ywxp6jcKs3exo/gRLQtre" + ], + "value": "{SSHA512}gFcj2ucCCyO8NLN+IfBIbdzr3xjI7b07vAdwkJ8sw9Ynghj4uWPjfSHI2pHZ9dsyAdL3+mFl8g0ywxp6jcKs3exo/gRLQtre", + "displayValue": "{SSHA512}gFcj2ucCCyO8NLN+IfBIbdzr3xjI7b07vAdwkJ8sw9Ynghj4uWPjfSHI2pHZ9dsyAdL3+mFl8g0ywxp6jcKs3exo/gRLQtre" + }, + { + "name": "website", + "multiValued": false, + "values": [ + "http://www.jans.io" + ], + "value": "http://www.jans.io", + "displayValue": "http://www.jans.io" + }, + { + "name": "zoneinfo", + "multiValued": false, + "values": [ + "America/Chicago" + ], + "value": "America/Chicago", + "displayValue": "America/Chicago" + } + ], + "customObjectClasses": [ + "top", + "jansCustomPerson" + ], + "baseDn": "inum=B1F3-AEAE-B799,ou=people,o=jans" +} \ No newline at end of file diff --git a/jans-config-api/server/src/test/resources/feature/user/user.feature b/jans-config-api/server/src/test/resources/feature/user/user.feature new file mode 100644 index 00000000000..dc045a067be --- /dev/null +++ b/jans-config-api/server/src/test/resources/feature/user/user.feature @@ -0,0 +1,46 @@ + +Feature: User endpoint + + Background: + * def mainUrl = user_url + +Scenario: Fetch all user without bearer token +Given url mainUrl +When method GET +Then status 401 + + +Scenario: Fetch all user +Given url mainUrl +And header Authorization = 'Bearer ' + accessToken +When method GET +Then status 200 +And print response +And assert response.length != null + + +Scenario: Fetch the first three users +Given url mainUrl +And header Authorization = 'Bearer ' + accessToken +And param limit = 3 +When method GET +Then status 200 +And print response +And assert response.length == 3 + +@ignore +Scenario: Get an user by inum(unexisting user) +Given url mainUrl + '/53553532727272772' +And header Authorization = 'Bearer ' + accessToken +When method GET +Then status 404 + +@ignore +Scenario: Delete a non-existion user by inum +Given url mainUrl + '/1402.66633-8675-473e-a749' +And header Authorization = 'Bearer ' + accessToken +When method GET +Then status 404 +And print response + + diff --git a/jans-config-api/server/src/test/resources/feature/user/user.json b/jans-config-api/server/src/test/resources/feature/user/user.json new file mode 100644 index 00000000000..d87fa615038 --- /dev/null +++ b/jans-config-api/server/src/test/resources/feature/user/user.json @@ -0,0 +1,262 @@ +{ + "userId": "config_test_user_1", + "customAttributes": [ + { + "name": "birthdate", + "multiValued": false, + "values": [ + "19830106010101.253Z" + ], + "value": "19830106010101.253Z", + "displayValue": "19830106010101.253Z" + }, + { + "name": "c", + "multiValued": false, + "values": [ + "US" + ], + "value": "US", + "displayValue": "US" + }, + { + "name": "cn", + "multiValued": false, + "values": [ + "Config Test User 1" + ], + "value": "Config Test User 1", + "displayValue": "Config Test User 1" + }, + { + "name": "displayName", + "multiValued": false, + "values": [ + "Config Test User" + ], + "value": "Config Test User", + "displayValue": "Config Test User" + }, + { + "name": "emailVerified", + "multiValued": false, + "values": [ + "TRUE" + ], + "value": "TRUE", + "displayValue": "TRUE" + }, + { + "name": "gender", + "multiValued": false, + "values": [ + "Male" + ], + "value": "Male", + "displayValue": "Male" + }, + { + "name": "givenName", + "multiValued": false, + "values": [ + "Test" + ], + "value": "Test", + "displayValue": "Test" + }, + { + "name": "jansPrefUsrName", + "multiValued": false, + "values": [ + "config_user_1" + ], + "value": "config_user_1", + "displayValue": "config_user_1" + }, + { + "name": "jansStatus", + "multiValued": false, + "values": [ + "active" + ], + "value": "active", + "displayValue": "active" + }, + { + "name": "l", + "multiValued": false, + "values": [ + "Austin" + ], + "value": "Austin", + "displayValue": "Austin" + }, + { + "name": "locale", + "multiValued": false, + "values": [ + "en-US" + ], + "value": "en-US", + "displayValue": "en-US" + }, + { + "name": "mail", + "multiValued": false, + "values": [ + "config_user_1@test.org" + ], + "value": "config_user_1@test.org", + "displayValue": "config_user_1@test.org" + }, + { + "name": "memberOf", + "multiValued": true, + "values": [ + "inum=7890,ou=groups,o=jans", + "inum=7891,ou=groups,o=jans" + ], + "value": "inum=7890,ou=groups,o=jans", + "displayValue": "inum=7890,ou=groups,o=jans, inum=7891,ou=groups,o=jans" + }, + { + "name": "middleName", + "multiValued": false, + "values": [ + "config_user_1" + ], + "value": "config_user_1", + "displayValue": "config_user_1" + }, + { + "name": "mobile", + "multiValued": false, + "values": [ + "(512) 516-2414" + ], + "value": "(512) 516-2414", + "displayValue": "(512) 516-2414" + }, + { + "name": "nickname", + "multiValued": false, + "values": [ + "user1" + ], + "value": "user1", + "displayValue": "user1" + }, + { + "name": "o", + "multiValued": false, + "values": [ + "Test" + ], + "value": "Test", + "displayValue": "Test" + }, + { + "name": "phoneNumberVerified", + "multiValued": false, + "values": [ + "TRUE" + ], + "value": "TRUE", + "displayValue": "TRUE" + }, + { + "name": "picture", + "multiValued": false, + "values": [ + "http://www.jans.org/wp-content/uploads/2012/04/mike3.png" + ], + "value": "http://www.jans.org/wp-content/uploads/2012/04/mike3.png", + "displayValue": "http://www.jans.org/wp-content/uploads/2012/04/mike3.png" + }, + { + "name": "preferredLanguage", + "multiValued": false, + "values": [ + "en_US" + ], + "value": "en_US", + "displayValue": "en_US" + }, + { + "name": "profile", + "multiValued": false, + "values": [ + "http://www.mywebsite.com/profile" + ], + "value": "http://www.mywebsite.com/profile", + "displayValue": "http://www.mywebsite.com/profile" + }, + { + "name": "sn", + "multiValued": false, + "values": [ + "User1" + ], + "value": "User1", + "displayValue": "User1" + }, + { + "name": "st", + "multiValued": false, + "values": [ + "Texas" + ], + "value": "Texas", + "displayValue": "Texas" + }, + { + "name": "street", + "multiValued": false, + "values": [ + "622 East 6th Street" + ], + "value": "622 East 6th Street", + "displayValue": "622 East 6th Street" + }, + { + "name": "telephoneNumber", + "multiValued": false, + "values": [ + "(512) 516-2414" + ], + "value": "(512) 516-2414", + "displayValue": "(512) 516-2414" + }, + { + "name": "userPassword", + "multiValued": false, + "values": [ + "{SSHA512}gFcj2ucCCyO8NLN+IfBIbdzr3xjI7b07vAdwkJ8sw9Ynghj4uWPjfSHI2pHZ9dsyAdL3+mFl8g0ywxp6jcKs3exo/gRLQtre" + ], + "value": "{SSHA512}gFcj2ucCCyO8NLN+IfBIbdzr3xjI7b07vAdwkJ8sw9Ynghj4uWPjfSHI2pHZ9dsyAdL3+mFl8g0ywxp6jcKs3exo/gRLQtre", + "displayValue": "{SSHA512}gFcj2ucCCyO8NLN+IfBIbdzr3xjI7b07vAdwkJ8sw9Ynghj4uWPjfSHI2pHZ9dsyAdL3+mFl8g0ywxp6jcKs3exo/gRLQtre" + }, + { + "name": "website", + "multiValued": false, + "values": [ + "http://www.jans.io" + ], + "value": "http://www.jans.io", + "displayValue": "http://www.jans.io" + }, + { + "name": "zoneinfo", + "multiValued": false, + "values": [ + "America/Chicago" + ], + "value": "America/Chicago", + "displayValue": "America/Chicago" + } + ], + "customObjectClasses": [ + "top", + "jansCustomPerson" + ] +} \ 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 137f9a93c5b..1e7158443ce 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 @@ -60,6 +60,7 @@ function() { 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', + user_url: baseUrl + '/jans-config-api/api/v1/user', }; 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 5f26ec47ec2..bfc916ad7b0 100644 --- a/jans-config-api/server/src/test/resources/karate-config.js +++ b/jans-config-api/server/src/test/resources/karate-config.js @@ -60,6 +60,7 @@ function() { 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', + user_url: baseUrl + '/jans-config-api/api/v1/user', }; karate.configure('connectTimeout', 30000);