Skip to content

Commit

Permalink
Add support to filter by the account state disabled
Browse files Browse the repository at this point in the history
  • Loading branch information
KaveeshaPiumini committed Jan 7, 2025
1 parent 557496e commit 735591f
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com).
* Copyright (c) 2023-2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand Down Expand Up @@ -28,6 +28,9 @@ public class IdleAccountIdentificationConstants {
public static final String DATE_INACTIVE_AFTER = "inactiveAfter";
public static final String DATE_EXCLUDE_BEFORE = "excludeBefore";
public static final String DATE_FORMAT_REGEX = "^\\d{4}-\\d{2}-\\d{2}$";
public static final String IS_DISABLED = "isDisabled";
public static final String TRUE_VALUE = "true";
public static final String FALSE_VALUE = "false";

/**
* Enums for error messages.
Expand All @@ -51,6 +54,10 @@ public enum ErrorMessage {
"Invalid date combination is provided.",
"The inactive after date must be before the exclude after date."),

ERROR_INVALID_FILTER("60005",
"Invalid filter value provided.",
"The filter value provided is invalid"),

// Server errors 650xx.
ERROR_RETRIEVING_INACTIVE_USERS("65001",
"Error while retrieving inactive users.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com).
* Copyright (c) 2023-2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand Down Expand Up @@ -33,6 +33,7 @@
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import io.swagger.annotations.*;
import org.wso2.carbon.identity.idle.account.identification.exception.IdleAccountIdentificationClientException;

import javax.validation.constraints.*;

Expand All @@ -57,8 +58,12 @@ public class InactiveUsersApi {
@ApiResponse(code = 403, message = "Resource Forbidden", response = Void.class),
@ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public Response getInactiveUsers( @Valid@ApiParam(value = "Latest active date of login.") @QueryParam("inactiveAfter") String inactiveAfter, @Valid@ApiParam(value = "Date to exclude the oldest inactive users.") @QueryParam("excludeBefore") String excludeBefore) {
public Response getInactiveUsers(
@Valid @ApiParam(value = "Latest active date of login.") @QueryParam("inactiveAfter") String inactiveAfter,
@Valid @ApiParam(value = "Date to exclude the oldest inactive users.") @QueryParam("excludeBefore") String excludeBefore,
@Valid @ApiParam(value = "Filter inactive users by account state disabled.") @QueryParam("filter") String filter)
throws IdleAccountIdentificationClientException {

return delegate.getInactiveUsers(inactiveAfter, excludeBefore );
return delegate.getInactiveUsers(inactiveAfter, excludeBefore, filter);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com).
* Copyright (c) 2023-2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand Down Expand Up @@ -27,9 +27,23 @@
import org.wso2.carbon.identity.api.idle.account.identification.v1.model.Error;
import org.wso2.carbon.identity.api.idle.account.identification.v1.model.InactiveUser;
import org.wso2.carbon.identity.api.idle.account.identification.v1.model.Unauthorized;
import org.wso2.carbon.identity.idle.account.identification.exception.IdleAccountIdentificationClientException;

import javax.ws.rs.core.Response;

public interface InactiveUsersApiService {

public Response getInactiveUsers(String inactiveAfter, String excludeBefore);

/**
* Get inactive users list for a specified period.
*
* @param inactiveAfter The date after which the users are considered as inactive.
* @param excludeBefore The date before which the users are considered as inactive. (optional)
* @param filter Filter inactive users based isDisabled attribute. (optional)
* @return InactiveUser
* @throws IdleAccountIdentificationClientException If an error occurs while retrieving inactive users.
*/
Response getInactiveUsers(String inactiveAfter, String excludeBefore, String filter)
throws IdleAccountIdentificationClientException;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com).
* Copyright (c) 2023-2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand All @@ -26,11 +26,16 @@
import org.wso2.carbon.identity.api.idle.account.identification.v1.model.InactiveUser;
import org.wso2.carbon.identity.api.server.common.error.APIError;
import org.wso2.carbon.identity.api.server.common.error.ErrorResponse;
import org.wso2.carbon.identity.base.IdentityException;
import org.wso2.carbon.identity.core.model.ExpressionNode;
import org.wso2.carbon.identity.core.model.FilterTreeBuilder;
import org.wso2.carbon.identity.core.model.Node;
import org.wso2.carbon.identity.idle.account.identification.exception.IdleAccountIdentificationClientException;
import org.wso2.carbon.identity.idle.account.identification.exception.IdleAccountIdentificationException;
import org.wso2.carbon.identity.idle.account.identification.exception.IdleAccountIdentificationServerException;
import org.wso2.carbon.identity.idle.account.identification.models.InactiveUserModel;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
Expand All @@ -44,6 +49,9 @@
import static org.wso2.carbon.identity.api.idle.account.identification.common.util.IdleAccountIdentificationConstants.DATE_FORMAT_REGEX;
import static org.wso2.carbon.identity.api.idle.account.identification.common.util.IdleAccountIdentificationConstants.DATE_INACTIVE_AFTER;
import static org.wso2.carbon.identity.api.idle.account.identification.common.util.IdleAccountIdentificationConstants.ErrorMessage;
import static org.wso2.carbon.identity.api.idle.account.identification.common.util.IdleAccountIdentificationConstants.FALSE_VALUE;
import static org.wso2.carbon.identity.api.idle.account.identification.common.util.IdleAccountIdentificationConstants.IS_DISABLED;
import static org.wso2.carbon.identity.api.idle.account.identification.common.util.IdleAccountIdentificationConstants.TRUE_VALUE;

/**
* Calls internal osgi services to perform idle account identification management related operations.
Expand Down Expand Up @@ -83,6 +91,41 @@ public List<InactiveUser> getInactiveUsers(String inactiveAfter, String excludeB
}
}

/**
* Get inactive users.
*
* @param inactiveAfter Latest active date of login.
* @param excludeBefore Date to exclude the oldest inactive users.
* @param tenantDomain Tenant domain.
* @return List of inactive users.
* @throws IdleAccountIdentificationClientException If an error occurs while retrieving inactive users.
*/
public List<InactiveUser> getInactiveUsers(String inactiveAfter, String excludeBefore, String tenantDomain,
String filter) throws IdleAccountIdentificationClientException {

List<ExpressionNode> expressionNodes = getExpressionNodes(filter);
if (validateExpressionNodes(expressionNodes)) {
boolean isDisabled = Boolean.parseBoolean(expressionNodes.get(0).getValue());
List<InactiveUserModel> inactiveUsers;
try {
validateDates(inactiveAfter, excludeBefore);
LocalDateTime inactiveAfterDate = convertToDateObject(inactiveAfter, DATE_INACTIVE_AFTER);
LocalDateTime excludeBeforeDate = convertToDateObject(excludeBefore, DATE_EXCLUDE_BEFORE);

validateDatesCombination(inactiveAfterDate, excludeBeforeDate);

inactiveUsers = IdleAccountIdentificationServiceHolder.getIdleAccountIdentificationService()
.filterInactiveUsersIfDisabled(inactiveAfterDate, excludeBeforeDate, tenantDomain, isDisabled);

return buildResponse(inactiveUsers);
} catch (IdleAccountIdentificationException e) {
throw handleIdleAccIdentificationException(e, ErrorMessage.ERROR_RETRIEVING_INACTIVE_USERS,
tenantDomain);
}
}
return getInactiveUsers(inactiveAfter, excludeBefore, tenantDomain);
}

/**
* Validate the dates.
*
Expand Down Expand Up @@ -257,4 +300,80 @@ private void validateDatesCombination(LocalDateTime inactiveAfterDate, LocalDate
String.format(error.getDescription()));
}
}

/**
* Get the filter node as a list.
*
* @param filter value of the filter.
* @return node tree.
* @throws IdleAccountIdentificationClientException Error when validate filters.
*/
private List<ExpressionNode> getExpressionNodes(String filter) throws IdleAccountIdentificationClientException {

// Filter example : isDisabled eq true.
List<ExpressionNode> expressionNodes = new ArrayList<>();
FilterTreeBuilder filterTreeBuilder;
try {
if (StringUtils.isNotBlank(filter)) {
filterTreeBuilder = new FilterTreeBuilder(filter);
Node rootNode = filterTreeBuilder.buildTree();
setExpressionNodeList(rootNode, expressionNodes);
}
} catch (IOException | IdentityException e) {
ErrorMessage error = ErrorMessage.ERROR_INVALID_FILTER;
throw new IdleAccountIdentificationClientException(error.getCode(), error.getMessage(),
String.format(error.getDescription()));
}
return expressionNodes;
}

/**
* Set the node values as list of expression.
*
* @param node filter node.
* @param expression list of expression.
* @throws IdleAccountIdentificationClientException Error when passing invalid filter.
*/
private void setExpressionNodeList(Node node, List<ExpressionNode> expression)
throws IdleAccountIdentificationClientException {

if (node instanceof ExpressionNode) {
if (StringUtils.isNotBlank(((ExpressionNode) node).getAttributeValue())) {
if (((ExpressionNode) node).getAttributeValue().contains(IS_DISABLED)) {
if (TRUE_VALUE.contains(((ExpressionNode) node).getValue())) {
((ExpressionNode) node).setValue(TRUE_VALUE);
} else if (FALSE_VALUE.contains(((ExpressionNode) node).getValue())) {
((ExpressionNode) node).setValue(FALSE_VALUE);
} else {
String message = "Invalid value: " + ((ExpressionNode) node).getValue() + "is passed for '" +
IS_DISABLED + "' attribute in the filter. It should be '" + TRUE_VALUE + "' or '" +
FALSE_VALUE + "'";
ErrorMessage error = ErrorMessage.ERROR_INVALID_FILTER;
throw new IdleAccountIdentificationClientException(error.getCode(), error.getMessage(),
message);
}
}
}
expression.add((ExpressionNode) node);
}
}

/**
* Validate the expression nodes.
*
* @param expressionNodes List of expression nodes.
* @return boolean.
* @throws IdleAccountIdentificationClientException Error when validate filters.
*/
private boolean validateExpressionNodes(List<ExpressionNode> expressionNodes)
throws IdleAccountIdentificationClientException {

if (expressionNodes.get(0).getAttributeValue().equals(IS_DISABLED)) {
return true;
}

ErrorMessage error = ErrorMessage.ERROR_INVALID_FILTER;
throw new IdleAccountIdentificationClientException(error.getCode(), error.getMessage(),
String.format(error.getDescription()));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com).
* Copyright (c) 2023-2025, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
Expand All @@ -22,6 +22,7 @@
import org.wso2.carbon.identity.api.idle.account.identification.common.ContextLoader;
import org.wso2.carbon.identity.api.idle.account.identification.v1.InactiveUsersApiService;
import org.wso2.carbon.identity.api.idle.account.identification.v1.core.InactiveUsersManagementApiService;
import org.wso2.carbon.identity.idle.account.identification.exception.IdleAccountIdentificationClientException;

import javax.ws.rs.core.Response;

Expand All @@ -40,4 +41,18 @@ public Response getInactiveUsers(String inactiveAfter, String excludeBefore) {
return Response.ok().entity(
inactiveUsersManagementApiService.getInactiveUsers(inactiveAfter, excludeBefore, tenantDomain)).build();
}

@Override
public Response getInactiveUsers(String inactiveAfter, String excludeBefore, String filter)
throws IdleAccountIdentificationClientException {

String tenantDomain = ContextLoader.getTenantDomainFromContext();

if (filter != null) {
return Response.ok().entity(
inactiveUsersManagementApiService.getInactiveUsers(inactiveAfter, excludeBefore, tenantDomain,
filter)).build();
}
return getInactiveUsers(inactiveAfter, excludeBefore);
}
}

0 comments on commit 735591f

Please sign in to comment.