Skip to content

Commit

Permalink
feat(jans-config-api): user mgmt patch endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
pujavs committed Apr 8, 2022
1 parent 0427186 commit 12a08e1
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 106 deletions.
30 changes: 22 additions & 8 deletions jans-cli/cli/jca.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2556,18 +2556,17 @@ paths:
patch:
tags:
- User Management
summary: Update modified properties of user by Inum.
description: Update modified properties of user by Inum.
summary: Patch user properties by Inum.
description: Patch user properties by Inum.
operationId: patch-user-by-inum
requestBody:
content:
application/json-patch+json:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/PatchRequest'
description: String representing patch-document.
example: '[ {op:replace, path: userId, value: test_user_100 } ]'
type: object
$ref: '#/components/schemas/UserPatchRequest'
description: Patch request object
example: '[ {"jsonPatchString": {"op": "add", "path": "userId","value": "test-user" }, "customAttributes": [{"name": "name, displayName, birthdate, email","multiValued": true,"values": ["string"]}]}]'
responses:
'200':
description: OK
Expand Down Expand Up @@ -6989,5 +6988,20 @@ components:
type: array
items:
$ref: '#/components/schemas/CustomAttribute'
UserPatchRequest:
title: User Patch Request object
description: UserPatchRequest.
type: object
properties:
jsonPatchString:
type: object
description: Possible errors assosiated with the script.
$ref: '#/components/schemas/PatchRequest'
customAttributes:
description: dn of associated clients with the user.
type: array
items:
$ref: '#/components/schemas/CustomAttribute'

46 changes: 45 additions & 1 deletion jans-config-api/docs/jans-config-api-swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2553,7 +2553,36 @@ paths:
description: Internal Server Error
security:
- oauth2: [https://jans.io/oauth/config/user.delete]

patch:
tags:
- User Management
summary: Patch user properties by Inum.
description: Patch user properties by Inum.
operationId: patch-user-by-inum
requestBody:
content:
application/json:
schema:
type: object
$ref: '#/components/schemas/UserPatchRequest'
description: Patch request object
example: '[ {"jsonPatchString": {"op": "add", "path": "userId","value": "test-user" }, "customAttributes": [{"name": "name, displayName, birthdate, email","multiValued": true,"values": ["string"]}]}]'
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:
Expand Down Expand Up @@ -6959,5 +6988,20 @@ components:
type: array
items:
$ref: '#/components/schemas/CustomAttribute'
UserPatchRequest:
title: User Patch Request object
description: UserPatchRequest.
type: object
properties:
jsonPatchString:
type: object
description: Possible errors assosiated with the script.
$ref: '#/components/schemas/PatchRequest'
customAttributes:
description: dn of associated clients with the user.
type: array
items:
$ref: '#/components/schemas/CustomAttribute'

Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public Response getUsers(@DefaultValue(DEFAULT_LIST_SIZE) @QueryParam(value = Ap
@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) throws IllegalAccessException, InvocationTargetException {
@QueryParam(value = ApiConstants.SORT_ORDER) String sortOrder)
throws IllegalAccessException, InvocationTargetException {
if (logger.isDebugEnabled()) {
logger.debug("User search param - limit:{}, pattern:{}, startIndex:{}, sortBy:{}, sortOrder:{}",
escapeLog(limit), escapeLog(pattern), escapeLog(startIndex), escapeLog(sortBy),
Expand All @@ -61,24 +62,26 @@ public Response getUsers(@DefaultValue(DEFAULT_LIST_SIZE) @QueryParam(value = Ap
limit, null, ApiConstants.USER_EXCLUDED_ATTRIBUTES);

List<User> users = this.doSearch(searchReq);
logger.debug("User search result:{}", users);
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) throws IllegalAccessException, InvocationTargetException {
public Response getUserByInum(@PathParam(ApiConstants.INUM) @NotNull String inum)
throws IllegalAccessException, InvocationTargetException {
if (logger.isDebugEnabled()) {
logger.debug("User search by inum:{}", escapeLog(inum));
}
User user = userSrv.getUserByInum(inum);
User user = userSrv.getUserBasedOnInum(inum);
checkResourceNotNull(user, USER);
logger.debug("user:{}", user);
//excludedAttributes

// excludedAttributes
user = userSrv.excludedAttributes(user, ApiConstants.USER_EXCLUDED_ATTRIBUTES);

return Response.ok(user).build();
}

Expand Down Expand Up @@ -106,41 +109,38 @@ public Response updateUser(@Valid User user) {
}

@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 UserPatchRequest userPatchRequest) throws JsonPatchException, IOException {
public Response patchUser(@PathParam(ApiConstants.INUM) @NotNull String inum,
@NotNull UserPatchRequest userPatchRequest) throws JsonPatchException, IOException {
if (logger.isDebugEnabled()) {
logger.debug("User:{} to be patched with :{} ", escapeLog(inum),escapeLog(userPatchRequest));
logger.debug("User:{} to be patched with :{} ", escapeLog(inum), escapeLog(userPatchRequest));
}
logger.error("User:{} to be patched with :{} ", escapeLog(inum),escapeLog(userPatchRequest));

//check if user exists
User existingUser = userSrv.getUserByInum(inum);
// check if user exists
User existingUser = userSrv.getUserBasedOnInum(inum);
checkResourceNotNull(existingUser, USER);

//patch user
// patch user
existingUser = userSrv.patchUser(inum, userPatchRequest);
logger.error("Patched 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);
User user = userSrv.getUserBasedOnInum(inum);
checkResourceNotNull(user, USER);
userSrv.removeUser(user);
return Response.noContent().build();
}

private List<User> doSearch(SearchRequest searchReq) throws IllegalAccessException, InvocationTargetException{
private List<User> doSearch(SearchRequest searchReq) throws IllegalAccessException, InvocationTargetException {
if (logger.isDebugEnabled()) {
logger.debug("User search params - searchReq:{} ", escapeLog(searchReq));
}
Expand All @@ -158,14 +158,11 @@ private List<User> doSearch(SearchRequest searchReq) throws IllegalAccessExcepti
if (logger.isDebugEnabled()) {
logger.debug("Users fetched - users:{}", users);
}
//excludedAttributes

// excludedAttributes
users = userSrv.excludedAttributes(users, searchReq.getExcludedAttributesStr());

return users;
}




}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class UserService extends io.jans.as.common.service.common.UserService {

@Inject
private AppConfiguration appConfiguration;

@Inject
AuthUtil authUtil;

Expand Down Expand Up @@ -86,10 +86,11 @@ public void removeUser(User user) {
persistenceEntryManager.removeRecursively(user.getDn(), User.class);
}

public User patchUser(String inum, UserPatchRequest userPatchRequest)
throws JsonPatchException, IOException {

logger.error("Details to patch user inum:{}, UserPatchRequest:{} ", escapeLog(inum), escapeLog(userPatchRequest));
public User patchUser(String inum, UserPatchRequest userPatchRequest) throws JsonPatchException, IOException {
if (logger.isDebugEnabled()) {
logger.debug("Details to patch user inum:{}, UserPatchRequest:{} ", escapeLog(inum),
escapeLog(userPatchRequest));
}
if (StringHelper.isEmpty(inum)) {
return null;
}
Expand All @@ -99,41 +100,51 @@ public User patchUser(String inum, UserPatchRequest userPatchRequest)
return null;
}

logger.error("User to be patched- user:{}", user);
logger.debug("User to be patched- user:{}", user);
// apply direct patch for basic attributes
if( StringUtils.isNotEmpty(userPatchRequest.getJsonPatchString())) {
logger.error("Patch basic attributes");
if (StringUtils.isNotEmpty(userPatchRequest.getJsonPatchString())) {
logger.debug("Patch basic attributes");
user = Jackson.applyPatch(userPatchRequest.getJsonPatchString(), user);
logger.error("User after patching basic attributes - user:{}", user);
logger.debug("User after patching basic attributes - user:{}", user);
}

// patch for customAttributes
if (userPatchRequest.getCustomAttributes() != null && !userPatchRequest.getCustomAttributes().isEmpty()) {
user = updateCustomAttributes(user, userPatchRequest.getCustomAttributes());
updateCustomAttributes(user, userPatchRequest.getCustomAttributes());
}

logger.error("User before patch user:{}", user);
logger.debug("User before patch user:{}", user);

// persist user
user = updateUser(user);
logger.error("User after patch user:{}", user);
logger.debug("User after patch user:{}", user);
return user;

}

public User getUserBasedOnInum(String inum) {
User result = null;
try {
result = getUserByInum(inum);
} catch (Exception ex) {
logger.error("Failed to load user entry", ex);
}
return result;
}

private User updateCustomAttributes(User user, List<CustomObjectAttribute> customAttributes) {
logger.error("Custom Attributes to update for - user:{}, customAttributes:{} ", user, customAttributes);
logger.debug("Custom Attributes to update for - user:{}, customAttributes:{} ", user, customAttributes);

if (customAttributes != null && !customAttributes.isEmpty()) {
for (CustomObjectAttribute attribute : customAttributes) {
CustomObjectAttribute existingAttribute = getCustomAttribute(user, attribute.getName());
logger.error("Existing CustomAttributes with existingAttribute:{} ", existingAttribute);
logger.debug("Existing CustomAttributes with existingAttribute:{} ", existingAttribute);

// add
if (existingAttribute == null) {
boolean result = addUserAttribute(user, attribute.getName(), attribute.getValues(),
attribute.isMultiValued());
logger.error("Result of adding CustomAttributes attribute:{} , result:{} ", attribute, result);
logger.debug("Result of adding CustomAttributes attribute:{} , result:{} ", attribute, result);
}
// remove attribute
else if (attribute.getValue() == null || attribute.getValues() == null) {
Expand All @@ -146,44 +157,46 @@ else if (attribute.getValue() == null || attribute.getValues() == null) {
existingAttribute.setValues(attribute.getValues());
}
// Final attribute
logger.error("Finally user CustomAttributes user.getCustomAttributes:{} ", user.getCustomAttributes());
logger.debug("Finally user CustomAttributes user.getCustomAttributes:{} ", user.getCustomAttributes());

}
}

return user;
}

public List<User> excludedAttributes(List<User> users, String commaSeparatedString) throws IllegalAccessException, InvocationTargetException {
logger.error("Attributes:{} to be excluded from users:{} ", commaSeparatedString, users);
for(User user: users) {
user = excludedAttributes(user, commaSeparatedString);

public List<User> excludedAttributes(List<User> users, String commaSeparatedString)
throws IllegalAccessException, InvocationTargetException {
logger.debug("Attributes:{} to be excluded from users:{} ", commaSeparatedString, users);
for (User user : users) {
excludedAttributes(user, commaSeparatedString);
}
logger.error("Users:{} after excluding attribute:{} ", users, commaSeparatedString);
logger.debug("Users:{} after excluding attribute:{} ", users, commaSeparatedString);

return users;
}

public User excludedAttributes(User user, String commaSeparatedString) throws IllegalAccessException, InvocationTargetException {
logger.error("Attributes:{} to be excluded from user:{} ", commaSeparatedString, user);
if(user == null || StringUtils.isEmpty(commaSeparatedString)) {

public User excludedAttributes(User user, String commaSeparatedString)
throws IllegalAccessException, InvocationTargetException {
logger.debug("Attributes:{} to be excluded from user:{} ", commaSeparatedString, user);
if (user == null || StringUtils.isEmpty(commaSeparatedString)) {
return user;
}
List<String> excludedAttributes = Arrays.asList(commaSeparatedString.split(","));
logger.error("Attributes List:{} to be excluded ", excludedAttributes);

for(String attribute : excludedAttributes) {
logger.error("User class conatins attribute:{} ? :{} ", attribute, authUtil.doesObjectContainField(user,attribute));
if(authUtil.doesObjectContainField(user,attribute)) {
BeanUtils.setProperty(user,attribute,null);
logger.debug("Attributes List:{} to be excluded ", excludedAttributes);

}
else {
logger.error("Removing custom attribute:{} from user:{} ", attribute, user);
for (String attribute : excludedAttributes) {
logger.debug("User class conatins attribute:{} ? :{} ", attribute,
authUtil.doesObjectContainField(user, attribute));
if (authUtil.doesObjectContainField(user, attribute)) {
BeanUtils.setProperty(user, attribute, null);

} else {
logger.debug("Removing custom attribute:{} from user:{} ", attribute, user);
user.removeAttribute(attribute);
}
}
}

return user;
}

Expand Down
Loading

0 comments on commit 12a08e1

Please sign in to comment.