From ad66713700b6988378c4e3c603fb3518f8ade247 Mon Sep 17 00:00:00 2001 From: Puja Sharma Date: Thu, 31 Mar 2022 21:22:45 +0530 Subject: [PATCH] feat(jans-config-api): user mgmt endpoint --- jans-cli/cli/jca.yaml | 513 +++++++++++++++++- .../rest/resource/auth/UserResource.java | 24 +- 2 files changed, 524 insertions(+), 13 deletions(-) diff --git a/jans-cli/cli/jca.yaml b/jans-cli/cli/jca.yaml index a564032eeea..cad2d7b753b 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 @@ -6744,4 +6958,293 @@ components: $ref: '#/components/schemas/FacterData' description: Underlying Server stats - + User: + title: User object + description: User. + type: object + required: + - displayName + properties: + inum: + description: XRI i-number. Identifier to uniquely identify the user. + type: string + associatedClient: + description: dn of associated clients with the person. + type: array + items: + type: string + countryName: + description: county name. + type: string + displayName: + description: Name of the user suitable for display to end-users + type: string + givenName: + description: Given name(s) or first name(s) of the End-User. + type: string + managedOrganizations: + description: Organizations with which a person is associated. + type: array + items: + type: string + optOuts: + description: White pages attributes restricted by person in exclude profile management. + type: array + items: + type: string + status: + description: Status of the entry. + type: string + mail: + description: Primary Email Address. + type: string + memberOf: + description: Groups with which a person is associated. + type: array + items: + type: string + organization: + description: Users organization. + type: string + oxAuthPersistentJwt: + description: Persistent JWT. + type: array + items: + type: string + createdAt: + description: User creation date. + type: string + format: date-time + externalUid: + description: List of associated external uid. + type: array + items: + type: string + otpCache: + description: List of used OTP to prevent a hacker from using it again. Complementary to jansExtUid attribute. + type: array + items: + type: string + lastLogonTime: + description: 'Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating last login time.' + type: string + format: date-time + active: + type: boolean + description: boolean value indicating if user is active. + default: true + addres: + description: List of users address. + type: array + items: + $ref: '#/components/schemas/Address' + email: + description: List of users email address. + type: array + items: + $ref: '#/components/schemas/Email' + entitlements: + description: List of users entitlement. + type: array + items: + $ref: '#/components/schemas/Entitlement' + extId: + description: User's external id. + type: string + imsValue: + description: Instant messaging address value. + type: array + items: + $ref: '#/components/schemas/InstantMessagingAddress' + created: + description: Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating creation time. + type: string + format: date-time + lastModified: + description: Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating last modified time. + type: string + format: date-time + location: + description: The location (URI) of the user + type: string + version: + description: The version of the user data + type: string + nameFormatted: + description: The full name, including all middle names, titles, and suffixes as appropriate, formatted. + type: string + phoneValue: + description: Phone numbers of the user + type: array + items: + $ref: '#/components/schemas/PhoneNumber' + photos: + description: User's photos + type: array + items: + $ref: '#/components/schemas/Photo' + profileURL: + description: URI pointing to a location representing the User's online profile + type: string + roles: + description: Users various roles + type: array + items: + $ref: '#/components/schemas/Role' + title: + description: Users titles + type: string + example: Vice President + userType: + description: Used to identify the relationship between the organization and the user + type: string + example: Contractor + honorificPrefix: + description: The honorific prefix(es) of the User, or Title in most Western languages (for example, Ms. given the full name Ms. Barbara J Jensen, III.) + type: string + example: Ms.,Mr.,Miss. + honorificSuffix: + description: The honorific suffix(es) of the User, or Suffix in most Western languages (for example,III. given the full name Ms. Barbara J Jensen, III.) + type: string + x509Certificates: + description: List of public certificate of the user + type: array + items: + $ref: '#/components/schemas/X509Certificate' + passwordExpirationDate: + description: 'Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating password expiration date.' + type: string + format: date-time + persistentId: + description: Persistent Id of the user + type: string + middleName: + type: string + description: Middle name of the user. + nickName: + type: string + description: Casual way to address the user in real life + preferredUsername: + type: string + description: Preferred name of the user. + profile: + type: string + description: Profile page URL of the user + picture: + type: string + description: Profile picture URL of the user + website: + type: string + description: Web page or blog URL of the person + emailVerified: + type: boolean + description: True if the e-mail address of the person has been verified; otherwise false + gender: + type: boolean + description: Gender of the person + birthdate: + description: Date of birth of the user. Year of birth (four digits),Month of birth (1-12),Day of birth + type: string + format: date-time + timezone: + description: Time zone database representing the End-Usrs time zone. For example, Europe/Paris or America/Los_Angeles + type: string + example: America/Los_Angeles + locale: + description: Locale of the person, represented as a BCP47 [RFC5646] language tag. Used for purposes of localizing items such as currency and dates. + type: string + example: en-US + phoneNumberVerified: + type: boolean + description: True if the phone number of the person has been verified, otherwise false + address: + description: OpenID Connect formatted JSON object representing the address of the person + type: array + items: + $ref: '#/components/schemas/Address' + updatedAt: + description: Time the information of the person was last updated. Seconds from 1970-01-01T0:0:0Z + type: string + format: date-time + preferredLanguage: + description: Preferred language as used in the Accept-Language HTTP header + type: string + example: en + secretAnswer: + description: Secret Answer + type: string + secretQuestion: + description: Secret Question + type: string + seeAlso: + type: string + sn: + description: This would be referred to as last name or surname. + type: string + cn: + description: Common Name + type: string + transientId: + description: Transient Id + type: string + uid: + description: A domain issued and managed identifier for the person.Subject - Identifier for the End-User at the Issuer. + type: string + userPassword: + description: user password + type: string + state: + description: State or Province + type: string + street: + type: string + city: + description: Locality Name or city + type: string + countInvalidLogin: + description: Invalid login attempts count + type: integer + enrollmentCode: + description: Users enrollment code + type: string + imapData: + description: This data has information about your imap connection + type: string + ppid: + description: Persistent Pairwise ID for OpenID Connect + type: array + items: + type: string + guid: + description: A random string to mark temporary tokens + type: string + preferredMethod: + description: Casa - Preferred method to use for user authentication + type: string + userCertificate: + description: Casa - Preferred method to use for user authentication + type: string + otpDevices: + description: Casa - Json representation of OTP devices. Complementary to jansExtUid attribute + type: string + mobileDevices: + description: Casa - Json representation of mobile devices. Complementary to mobile attribute + type: string + trustedDevices: + description: Casa - Devices with which strong authentication may be skipped + type: string + strongAuthPolicy: + description: Casa - 2FA Enforcement Policy for User + type: string + unlinkedExternalUids: + description: Casa - List of unlinked social accounts (ie disabled jansExtUids) + type: array + items: + type: string + backchannelDeviceRegistrationTkn: + description: Backchannel Device Registration Tkn + type: string + backchannelUsrCode: + description: jans Backchannel User Code + type: string + \ No newline at end of file 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 index b2946115d52..59f02e5ea00 100644 --- 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 @@ -79,13 +79,13 @@ public Response getOpenIdConnectClients( @GET @ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS }) @Path(ApiConstants.INUM_PATH) - public Response getUserByInum(@PathParam(ApiConstants.INUM) @NotNull String inum) { + public Response getUserByInum(@PathParam(ApiConstants.INUM) @NotNull String inum) throws EncryptionException { if (logger.isDebugEnabled()) { logger.debug("User serach by inum:{}", escapeLog(inum)); } User user = userSrv.getUserByInum(inum); logger.error("Based on inum:{}, user:{}", inum, user); - return Response.ok(user).build(); + return Response.ok(decryptUserPassword(user)).build(); } @POST @@ -96,7 +96,7 @@ public Response createOpenIdConnect(@Valid User user) throws EncryptionException } user = userSrv.addUser(encryptUserPassword(user), true); logger.error("User created {}", user); - return Response.status(Response.Status.CREATED).entity(user).build(); + return Response.status(Response.Status.CREATED).entity(decryptUserPassword(user)).build(); } @PUT @@ -106,9 +106,9 @@ public Response updateUser(@Valid User user) throws EncryptionException { logger.debug("User details to be updated - user:{}", escapeLog(user)); } user = userSrv.updateUser(encryptUserPassword(user)); - logger.debug("Updated user:{}", user); + logger.error("Updated user:{}", user); - return Response.ok(user).build(); + return Response.ok(decryptUserPassword(user)).build(); } @PATCH @@ -116,7 +116,7 @@ public Response updateUser(@Valid User user) throws EncryptionException { @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 { + throws EncryptionException, JsonPatchException, IOException { if (logger.isDebugEnabled()) { logger.debug("User details to be patched - inum:{}, pathString:{}", escapeLog(inum), escapeLog(pathString)); } @@ -124,8 +124,9 @@ public Response patchUser(@PathParam(ApiConstants.INUM) @NotNull String inum, @N checkResourceNotNull(existingUser, USER); existingUser = Jackson.applyPatch(pathString, existingUser); - userSrv.updateUser(existingUser); - return Response.ok(existingUser).build(); + existingUser = userSrv.updateUser(existingUser); + logger.error("Updated user:{}", existingUser); + return Response.ok(decryptUserPassword(existingUser)).build(); } @DELETE @@ -181,4 +182,11 @@ private User encryptUserPassword(User user) throws EncryptionException { return user; } + private User decryptUserPassword(User user) throws EncryptionException { + if (StringUtils.isNotBlank(user.getAttribute("userPassword"))) { + user.setAttribute("userPassword", encryptionService.decrypt(user.getAttribute("userPassword")), false); + } + return user; + } + }