Skip to content

Commit

Permalink
feat(config-api): user mgt error handling (#8621)
Browse files Browse the repository at this point in the history
* fix(config-api): user attribute validation error handling

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): user attribute validation error handling

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): user attribute validation error handling

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix: added new IDP attributes

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix: added new IDP attributes

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): idp default values set

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): idp metadata default values issue#8384

Signed-off-by: pujavs <pujas.works@gmail.com>

* feat: idp metadata default value and removing filepath in document-store

Signed-off-by: pujavs <pujas.works@gmail.com>

* feat: idp metadata default value and removing filepath in document-store

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix: assetmgt and idp changes

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix: assetmgt and idp changes

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): validation for imp fields of asset mgt

Signed-off-by: pujavs <pujas.works@gmail.com>

* feat(config-api): pagination for get asset by name, asset filename and service validation

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): added asset validation, removed redundant fields for TR

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): agama swagger spec changes

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): agama swagger spec changes

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): added asset validation, removed redundant fields for TR

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): added asset validation, removed redundant fields for TR

Signed-off-by: pujavs <pujas.works@gmail.com>

* fix(config-api): added asset validation, removed redundant fields for TR

Signed-off-by: pujavs <pujas.works@gmail.com>

* feat(config-api): user mgt error handling

Signed-off-by: pujavs <pujas.works@gmail.com>

* feat(config-api): user mgt error handling

Signed-off-by: pujavs <pujas.works@gmail.com>

* feat(config-api): user mgt error handling

Signed-off-by: pujavs <pujas.works@gmail.com>

---------

Signed-off-by: pujavs <pujas.works@gmail.com>
  • Loading branch information
pujavs committed May 31, 2024
1 parent 5c59189 commit 8f05095
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 61 deletions.
12 changes: 5 additions & 7 deletions jans-config-api/docs/jans-config-api-swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8243,13 +8243,13 @@ components:
type: boolean
whitePagesCanView:
type: boolean
userCanEdit:
adminCanView:
type: boolean
adminCanEdit:
type: boolean
userCanView:
type: boolean
adminCanView:
userCanEdit:
type: boolean
userCanAccess:
type: boolean
Expand Down Expand Up @@ -8430,7 +8430,6 @@ components:
- password
- client_credentials
- refresh_token
- tx_token
- urn:ietf:params:oauth:grant-type:uma-ticket
- urn:ietf:params:oauth:grant-type:token-exchange
- urn:openid:params:grant-type:ciba
Expand Down Expand Up @@ -8743,7 +8742,6 @@ components:
- password
- client_credentials
- refresh_token
- tx_token
- urn:ietf:params:oauth:grant-type:uma-ticket
- urn:ietf:params:oauth:grant-type:token-exchange
- urn:openid:params:grant-type:ciba
Expand Down Expand Up @@ -9034,6 +9032,7 @@ components:
- INTROSPECTION
- REVOKE_TOKEN
- REVOKE_SESSION
- GLOBAL_TOKEN_REVOCATION
- ACTIVE_SESSION
- END_SESSION
- STATUS_SESSION
Expand Down Expand Up @@ -9538,7 +9537,6 @@ components:
- password
- client_credentials
- refresh_token
- tx_token
- urn:ietf:params:oauth:grant-type:uma-ticket
- urn:ietf:params:oauth:grant-type:token-exchange
- urn:openid:params:grant-type:ciba
Expand Down Expand Up @@ -10139,14 +10137,14 @@ components:
type: boolean
internal:
type: boolean
locationPath:
type: string
locationType:
type: string
enum:
- ldap
- db
- file
locationPath:
type: string
baseDn:
type: string
ScriptError:
Expand Down
10 changes: 5 additions & 5 deletions jans-config-api/plugins/docs/lock-plugin-swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ components:
type: string
externalLoggerConfiguration:
type: string
metricChannel:
type: string
metricReporterInterval:
type: integer
format: int32
Expand All @@ -130,17 +132,15 @@ components:
format: int32
opaConfiguration:
$ref: '#/components/schemas/OpaConfiguration'
messageConsumerType:
type: string
policyConsumerType:
pdpType:
type: string
policiesJsonUrisAccessToken:
policiesJsonUrisAuthorizationToken:
type: string
policiesJsonUris:
type: array
items:
type: string
policiesZipUrisAccessToken:
policiesZipUrisAuthorizationToken:
type: string
policiesZipUris:
type: array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.github.fge.jsonpatch.JsonPatchException;
import io.jans.as.common.model.common.User;
import io.jans.configapi.core.model.ApiError;
import io.jans.configapi.core.model.exception.ApiApplicationException;
import io.jans.configapi.core.util.ApiErrorResponse;
import io.jans.configapi.core.rest.BaseResource;
import io.jans.configapi.core.rest.ProtectedApi;
import io.jans.configapi.plugin.mgt.model.user.CustomUser;
Expand All @@ -18,7 +20,6 @@
import io.jans.util.StringHelper;
import io.jans.util.exception.InvalidAttributeException;


import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.validation.Valid;
Expand Down Expand Up @@ -60,6 +61,7 @@ public class UserResource extends BaseResource {
private static final String GIVEN_NAME = "givenName";
private static final String USER_PWD = "userPassword";
private static final String INUM = "inum";
private static final String USER_PLACEHOLDER = "user:{}";

private class UserPagedResult extends PagedResult<CustomUser> {
};
Expand Down Expand Up @@ -91,13 +93,15 @@ public Response getUsers(
@Parameter(description = "Field and value pair for seraching", examples = @ExampleObject(name = "Field value example", value = "mail=abc@mail.com,jansStatus=true")) @DefaultValue("") @QueryParam(value = ApiConstants.FIELD_VALUE_PAIR) String fieldValuePair)
throws IllegalAccessException, InvocationTargetException {
if (logger.isInfoEnabled()) {
logger.info("User search param - limit:{}, pattern:{}, startIndex:{}, sortBy:{}, sortOrder:{}, fieldValuePair:{}",
logger.info(
"User search param - limit:{}, pattern:{}, startIndex:{}, sortBy:{}, sortOrder:{}, fieldValuePair:{}",
escapeLog(limit), escapeLog(pattern), escapeLog(startIndex), escapeLog(sortBy),
escapeLog(sortOrder),escapeLog(fieldValuePair));
escapeLog(sortOrder), escapeLog(fieldValuePair));
}

SearchRequest searchReq = createSearchRequest(userMgmtSrv.getPeopleBaseDn(), pattern, sortBy, sortOrder,
startIndex, limit, null, userMgmtSrv.getUserExclusionAttributesAsString(), mgtUtil.getRecordMaxCount(), fieldValuePair, CustomUser.class);
startIndex, limit, null, userMgmtSrv.getUserExclusionAttributesAsString(), mgtUtil.getRecordMaxCount(),
fieldValuePair, CustomUser.class);

return Response.ok(this.doSearch(searchReq, true)).build();
}
Expand All @@ -121,11 +125,11 @@ public Response getUserByInum(
}
User user = userMgmtSrv.getUserBasedOnInum(inum);
checkResourceNotNull(user, USER);
logger.debug("user:{}", user);
logger.debug(USER_PLACEHOLDER, user);

// excludedAttributes
user = excludeUserAttributes(user);
logger.debug("user:{}", user);
logger.debug(USER_PLACEHOLDER, user);

// get custom user
CustomUser customUser = getCustomUser(user, true);
Expand All @@ -140,11 +144,10 @@ public Response getUserByInum(
@RequestBody(description = "User object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class), examples = @ExampleObject(name = "Request json example", value = "example/user/user-post.json")))
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class, description = "Created Object"), examples = @ExampleObject(name = "Response json example", value = "example/user/user.json"))),
@ApiResponse(responseCode = "400", description = "Bad Request" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "BadRequestException"))),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "BadRequestException"))),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Not Found" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "NotFoundException"))),
@ApiResponse(responseCode = "500", description = "InternalServerError", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "InternalServerError"))),
})
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "NotFoundException"))),
@ApiResponse(responseCode = "500", description = "InternalServerError", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "InternalServerError"))), })
@POST
@ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS })
public Response createUser(@Valid CustomUser customUser,
Expand All @@ -154,7 +157,7 @@ public Response createUser(@Valid CustomUser customUser,
logger.info("User details to be added - customUser:{}, removeNonLDAPAttributes:{}", escapeLog(customUser),
removeNonLDAPAttributes);
}

try {
// get User object
User user = setUserAttributes(customUser);
Expand All @@ -166,6 +169,7 @@ public Response createUser(@Valid CustomUser customUser,
// checking mandatory attributes
checkMissingAttributes(user, null);
ignoreCustomAttributes(user, removeNonLDAPAttributes);
validateUser(user, false);
validateAttributes(user);

logger.info("Service call to create user:{}", user);
Expand All @@ -179,10 +183,13 @@ public Response createUser(@Valid CustomUser customUser,
// get custom user
customUser = getCustomUser(user, removeNonLDAPAttributes);
logger.info("newly created customUser:{}", customUser);
}catch(InvalidAttributeException iae) {
} catch (ApiApplicationException ae) {
logger.error(ApiErrorResponse.CREATE_USER_ERROR.getDescription(), ae);
throwBadRequestException("USER_CREATION_ERROR", ae.getMessage());
} catch (InvalidAttributeException iae) {
logger.error("InvalidAttributeException while creating user is:{}, cause:{}", iae, iae.getCause());
throwBadRequestException("USER_CREATION_ERROR", iae.getMessage());
}catch(Exception ex) {
} catch (Exception ex) {
logger.error("Exception while creating user is:{}, cause:{}", ex, ex.getCause());
throwInternalServerException(ex);
}
Expand All @@ -195,11 +202,10 @@ public Response createUser(@Valid CustomUser customUser,
@RequestBody(description = "User object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class), examples = @ExampleObject(name = "Request json example", value = "example/user/user.json")))
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = CustomUser.class), examples = @ExampleObject(name = "Response json example", value = "example/user/user.json"))),
@ApiResponse(responseCode = "400", description = "Bad Request" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "BadRequestException"))),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "BadRequestException"))),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Not Found" , content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "NotFoundException"))),
@ApiResponse(responseCode = "500", description = "InternalServerError", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "InternalServerError"))),
})
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "NotFoundException"))),
@ApiResponse(responseCode = "500", description = "InternalServerError", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ApiError.class, description = "InternalServerError"))), })
@PUT
@ProtectedApi(scopes = { ApiAccessConstants.USER_WRITE_ACCESS })
public Response updateUser(@Valid CustomUser customUser,
Expand All @@ -222,6 +228,7 @@ public Response updateUser(@Valid CustomUser customUser,
List<String> excludeAttributes = List.of(USER_PWD);
checkMissingAttributes(user, excludeAttributes);
ignoreCustomAttributes(user, removeNonLDAPAttributes);
validateUser(user, true);
validateAttributes(user);

logger.info("Call update user:{}", user);
Expand All @@ -235,11 +242,13 @@ public Response updateUser(@Valid CustomUser customUser,
// get custom user
customUser = getCustomUser(user, removeNonLDAPAttributes);
logger.info("updated customUser:{}", customUser);
} catch (ApiApplicationException ae) {
logger.error(ApiErrorResponse.UPDATE_USER_ERROR.getDescription(), ae);
throwBadRequestException("USER_UPDATE_ERROR", ae.getMessage());
} catch (InvalidAttributeException iae) {
logger.error("InvalidAttributeException while updating user is:{}, cause:{}", iae, iae.getCause());
throwBadRequestException("USER_UPDATE_ERROR", iae.getMessage());
}
catch (Exception ex) {
} catch (Exception ex) {
logger.error("Exception while updating user is:{}, cause:{}", ex, ex.getCause());
throwInternalServerException(ex);
}
Expand Down Expand Up @@ -354,17 +363,105 @@ private User excludeUserAttributes(User user) throws IllegalAccessException, Inv
}

private void checkMissingAttributes(User user, List<String> excludeAttributes)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ApiApplicationException {
String missingAttributes = userMgmtSrv.checkMandatoryFields(user, excludeAttributes);
logger.debug("missingAttributes:{}", missingAttributes);

if (StringHelper.isEmpty(missingAttributes)) {
return;
}

throwMissingAttributeError(missingAttributes);
throw new ApiApplicationException(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(),
String.format(ApiErrorResponse.MISSING_ATTRIBUTES.getDescription(), missingAttributes));
}


private void validateUser(User user, boolean isUpdate) throws ApiApplicationException {
logger.info(USER_PLACEHOLDER, user);

if (user == null) {
return;
}
StringBuilder sb = new StringBuilder();

// check if user with same name and email already exists
String msg = this.validateUserName(user, isUpdate);
if (StringUtils.isNotBlank(msg)) {
sb.append(msg);
}
msg = this.validateUserEmail(user, isUpdate);
if (StringUtils.isNotBlank(msg)) {
sb.append(msg);
}

if (sb.length() > 0) {
throw new ApiApplicationException(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(),
String.format(ApiErrorResponse.GENERAL_ERROR.getDescription(), sb.toString()));
}
}

private String validateUserName(User user, boolean isUpdate) throws ApiApplicationException {
logger.info(USER_PLACEHOLDER, " isUpdate:{}", user, isUpdate);

String msg = null;

if (user == null) {
return msg;
}

// check if user with same name already exists
final String inum = user.getAttribute("inum");
final String name = user.getUserId();

List<User> sameNameUser = userMgmtSrv.getUserByName(name);
logger.info(" sameNameUser:{}", sameNameUser);

// name validation
if (sameNameUser != null && !sameNameUser.isEmpty()) {

List<User> users = null;
if (isUpdate) {
users = sameNameUser.stream().filter(e -> !e.getAttribute("inum").equalsIgnoreCase(inum))
.collect(Collectors.toList());
}

if (!isUpdate || (users != null && !users.isEmpty())) {
msg = String.format(ApiErrorResponse.SAME_NAME_USER_EXISTS_ERROR.getDescription(), name);
}
}
return msg;
}

private String validateUserEmail(User user, boolean isUpdate) throws ApiApplicationException {
logger.info(USER_PLACEHOLDER, " isUpdate:{}", user, isUpdate);

String msg = null;

if (user == null) {
return msg;
}
// check if user with same email already exists
final String inum = user.getAttribute("inum");
final String email = user.getAttribute(MAIL);
List<User> sameEmailUser = userMgmtSrv.getUserByEmail(email);
logger.info(" sameEmailUser:{}", sameEmailUser);

// email validation
if (sameEmailUser != null && !sameEmailUser.isEmpty()) {

List<User> usersList = null;
if (isUpdate) {
usersList = sameEmailUser.stream().filter(e -> !e.getAttribute("inum").equalsIgnoreCase(inum))
.collect(Collectors.toList());
}

if (!isUpdate || (usersList != null && !usersList.isEmpty())) {
msg = String.format(ApiErrorResponse.SAME_NAME_EMAIL_EXISTS_ERROR.getDescription(), email);
}
}

return msg;
}

private void validateAttributes(User user) {
userMgmtSrv.validateAttributes(user.getCustomAttributes());
}
Expand Down Expand Up @@ -436,25 +533,25 @@ private User setUserAttributes(CustomUser customUser) {
user.setOxAuthPersistentJwt(customUser.getOxAuthPersistentJwt());
user.setUpdatedAt(customUser.getUpdatedAt());
user.setUserId(customUser.getUserId());
user.setStatus((customUser.getStatus()!=null?customUser.getStatus() : GluuStatus.ACTIVE));
user.setStatus((customUser.getStatus() != null ? customUser.getStatus() : GluuStatus.ACTIVE));

return setUserCustomAttributes(customUser, user);
}

private User setUserCustomAttributes(CustomUser customUser, User user) {
if(StringUtils.isNotBlank(customUser.getMail())) {
if (StringUtils.isNotBlank(customUser.getMail())) {
user.setAttribute(MAIL, customUser.getMail(), false);
}

user.setAttribute(DISPLAY_NAME, customUser.getDisplayName(), false);
user.setAttribute(GIVEN_NAME, customUser.getGivenName(), false);
if(StringUtils.isNotBlank(customUser.getUserPassword())) {
if (StringUtils.isNotBlank(customUser.getUserPassword())) {
user.setAttribute(USER_PWD, customUser.getUserPassword(), false);
}
if(StringUtils.isNotBlank(customUser.getInum())) {
if (StringUtils.isNotBlank(customUser.getInum())) {
user.setAttribute(INUM, customUser.getInum(), false);
}

return user;
}

Expand Down
Loading

0 comments on commit 8f05095

Please sign in to comment.