Skip to content

Commit 08e2d9f

Browse files
authored
Added search users by createdTime and modifiedTime and a simple example of checking password policy (#150)
1 parent 579d753 commit 08e2d9f

7 files changed

Lines changed: 247 additions & 2 deletions

File tree

examples/check-pwd-policy/pom.xml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xmlns="http://maven.apache.org/POM/4.0.0"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.descope</groupId>
8+
<artifactId>check-pwd-policy</artifactId>
9+
<version>1.0</version>
10+
11+
<properties>
12+
<maven.compiler.release>17</maven.compiler.release>
13+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14+
<org.projectlombok.version>1.18.36</org.projectlombok.version>
15+
</properties>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>com.descope</groupId>
20+
<artifactId>java-sdk</artifactId>
21+
<version>[1.0.0,)</version>
22+
</dependency>
23+
<dependency>
24+
<artifactId>jackson-databind</artifactId>
25+
<groupId>com.fasterxml.jackson.core</groupId>
26+
<version>2.18.1</version>
27+
</dependency>
28+
<dependency>
29+
<artifactId>jackson-datatype-jsr310</artifactId>
30+
<groupId>com.fasterxml.jackson.datatype</groupId>
31+
<version>2.18.1</version>
32+
</dependency>
33+
<dependency>
34+
<artifactId>commons-lang3</artifactId>
35+
<groupId>org.apache.commons</groupId>
36+
<version>3.17.0</version>
37+
</dependency>
38+
39+
<!-- LOMBOK -->
40+
<dependency>
41+
<artifactId>lombok</artifactId>
42+
<groupId>org.projectlombok</groupId>
43+
<scope>provided</scope>
44+
<version>${org.projectlombok.version}</version>
45+
</dependency>
46+
</dependencies>
47+
<build>
48+
<plugins>
49+
<plugin>
50+
<artifactId>maven-compiler-plugin</artifactId>
51+
<groupId>org.apache.maven.plugins</groupId>
52+
<version>3.13.0</version>
53+
<configuration>
54+
<source>${maven.compiler.source}</source>
55+
<target>${maven.compiler.target}</target>
56+
<annotationProcessorPaths>
57+
<path>
58+
<groupId>org.projectlombok</groupId>
59+
<artifactId>lombok</artifactId>
60+
<version>${org.projectlombok.version}</version>
61+
</path>
62+
</annotationProcessorPaths>
63+
</configuration>
64+
</plugin>
65+
<plugin>
66+
<groupId>org.springframework.boot</groupId>
67+
<artifactId>spring-boot-maven-plugin</artifactId>
68+
<version>3.3.5</version>
69+
<configuration>
70+
<mainClass>com.descope.CheckPwdPolicy</mainClass>
71+
<layout>JAR</layout>
72+
</configuration>
73+
<executions>
74+
<execution>
75+
<goals>
76+
<goal>repackage</goal>
77+
</goals>
78+
</execution>
79+
</executions>
80+
</plugin>
81+
</plugins>
82+
</build>
83+
</project>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.descope;
2+
3+
import com.descope.client.DescopeClient;
4+
import com.descope.exception.DescopeException;
5+
import com.descope.model.passwordsettings.PasswordSettings;
6+
7+
public class CheckPwdPolicy {
8+
public static void main(String[] args) {
9+
if (args.length != 2) {
10+
System.err.println("Usage: CheckPwdPolicy <loginId> <password>");
11+
System.exit(1);
12+
}
13+
try {
14+
var client = new DescopeClient();
15+
var userService = client.getManagementServices().getUserService();
16+
var pwdPolicyService = client.getManagementServices().getPasswordSettingsService();
17+
var res = userService.load(args[0]);
18+
var commonPasswordSettings = PasswordSettings.builder()
19+
.enabled(true)
20+
.minLength(Integer.MIN_VALUE)
21+
.expirationWeeks(Integer.MAX_VALUE)
22+
.reuseAmount(Integer.MIN_VALUE)
23+
.lockAttempts(Integer.MAX_VALUE)
24+
.build();
25+
if (res.getUser() != null && res.getUser().getUserTenants() != null) {
26+
for (var tenant : res.getUser().getUserTenants()) {
27+
var policy = pwdPolicyService.getSettings(tenant.getTenantId());
28+
if (policy != null && policy.getEnabled()) {
29+
if (policy.getMinLength() != null && policy.getMinLength() > commonPasswordSettings.getMinLength()) {
30+
commonPasswordSettings.setMinLength(policy.getMinLength());
31+
}
32+
if (policy.getLowercase() != null && policy.getLowercase()) {
33+
commonPasswordSettings.setLowercase(policy.getLowercase());
34+
}
35+
if (policy.getUppercase() != null && policy.getUppercase()) {
36+
commonPasswordSettings.setUppercase(policy.getUppercase());
37+
}
38+
if (policy.getNumber() != null && policy.getNumber()) {
39+
commonPasswordSettings.setNumber(policy.getNumber());
40+
}
41+
if (policy.getNonAlphanumeric() != null && policy.getNonAlphanumeric()) {
42+
commonPasswordSettings.setNonAlphanumeric(policy.getNonAlphanumeric());
43+
}
44+
if (policy.getExpiration() != null && policy.getExpiration()) {
45+
commonPasswordSettings.setExpiration(policy.getExpiration());
46+
if (policy.getExpirationWeeks() != null
47+
&& policy.getExpirationWeeks() < commonPasswordSettings.getExpirationWeeks()) {
48+
commonPasswordSettings.setExpirationWeeks(policy.getExpirationWeeks());
49+
}
50+
}
51+
if (policy.getReuse() != null && policy.getReuse()) {
52+
commonPasswordSettings.setReuse(policy.getReuse());
53+
if (policy.getReuseAmount() != null
54+
&& policy.getReuseAmount() > commonPasswordSettings.getReuseAmount()) {
55+
commonPasswordSettings.setReuseAmount(policy.getReuseAmount());
56+
}
57+
}
58+
if (policy.getLock() != null && policy.getLock()) {
59+
commonPasswordSettings.setLock(policy.getLock());
60+
if (policy.getLockAttempts() != null
61+
&& policy.getLockAttempts() < commonPasswordSettings.getLockAttempts()) {
62+
commonPasswordSettings.setLockAttempts(policy.getLockAttempts());
63+
}
64+
}
65+
}
66+
}
67+
if (args[1].length() < commonPasswordSettings.getMinLength()) {
68+
System.out.println("Password does not meet the minimum length requirement");
69+
}
70+
if (commonPasswordSettings.getLowercase() && !args[1].matches(".*[a-z].*")) {
71+
System.out.println("Password does not contain lowercase characters");
72+
}
73+
if (commonPasswordSettings.getUppercase() && !args[1].matches(".*[A-Z].*")) {
74+
System.out.println("Password does not contain uppercase characters");
75+
}
76+
if (commonPasswordSettings.getNumber() && !args[1].matches(".*[0-9].*")) {
77+
System.out.println("Password does not contain numeric characters");
78+
}
79+
if (commonPasswordSettings.getNonAlphanumeric() && args[1].matches("[a-zA-Z0-9]*")) {
80+
System.out.println("Password does not contain non-alphanumeric characters");
81+
}
82+
}
83+
} catch (DescopeException de) {
84+
System.err.println(String.format("%s - %s", de.getCode(), de.getMessage()));
85+
}
86+
}
87+
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<groupId>com.descope</groupId>
55
<artifactId>java-sdk</artifactId>
66
<modelVersion>4.0.0</modelVersion>
7-
<version>1.0.31</version>
7+
<version>1.0.32</version>
88
<name>${project.groupId}:${project.artifactId}</name>
99
<description>Java library used to integrate with Descope.</description>
1010
<url>https://github.com/descope/descope-java</url>

src/main/java/com/descope/model/user/request/UserSearchRequest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.descope.model.user.request;
22

33
import com.descope.enums.UserStatus;
4+
import com.descope.utils.InstantToMillisSerializer;
5+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
6+
import java.time.Instant;
47
import java.util.List;
58
import java.util.Map;
69
import lombok.AllArgsConstructor;
@@ -27,4 +30,16 @@ public class UserSearchRequest {
2730
List<String> phones;
2831
List<String> loginIds;
2932
List<String> ssoAppIds;
33+
/** Retrieve only users created after the given time. */
34+
@JsonSerialize(using = InstantToMillisSerializer.class)
35+
Instant fromCreatedTime;
36+
/** Retrieve only users created before the given time. */
37+
@JsonSerialize(using = InstantToMillisSerializer.class)
38+
Instant toCreatedTime;
39+
/** Retrieve only users updated after the given time. */
40+
@JsonSerialize(using = InstantToMillisSerializer.class)
41+
Instant fromModifiedTime;
42+
/** Retrieve only users updated before the given time. */
43+
@JsonSerialize(using = InstantToMillisSerializer.class)
44+
Instant toModifiedTime;
3045
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.descope.utils;
2+
3+
import com.fasterxml.jackson.core.JsonGenerator;
4+
import com.fasterxml.jackson.databind.SerializerProvider;
5+
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
6+
import java.io.IOException;
7+
import java.time.Instant;
8+
9+
public class InstantToMillisSerializer extends StdSerializer<Instant> {
10+
11+
public InstantToMillisSerializer() {
12+
super(Instant.class);
13+
}
14+
15+
@Override
16+
public void serialize(Instant value, JsonGenerator gen, SerializerProvider provider) throws IOException {
17+
gen.writeNumber(value.toEpochMilli());
18+
}
19+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.descope.model.user.request;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import com.fasterxml.jackson.core.JsonProcessingException;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import java.time.Instant;
8+
import java.util.Collections;
9+
import org.junit.jupiter.api.Test;
10+
11+
12+
public class UserSearchRequestTest {
13+
14+
@Test
15+
public void testInstantSerialization() throws JsonProcessingException {
16+
ObjectMapper mapper = new ObjectMapper();
17+
Instant now = Instant.now();
18+
UserSearchRequest request = UserSearchRequest.builder()
19+
.fromCreatedTime(now)
20+
.toCreatedTime(now)
21+
.fromModifiedTime(now)
22+
.toModifiedTime(now)
23+
.tenantIds(Collections.singletonList("tenant1"))
24+
.roles(Collections.singletonList("role1"))
25+
.build();
26+
27+
String json = mapper.writeValueAsString(request);
28+
29+
long expectedMillis = now.toEpochMilli();
30+
String expectedJson = String.format(
31+
"{\"tenantIds\":[\"tenant1\"],\"roles\":[\"role1\"],\"limit\":0,\"page\":0,\"withTestUser\":null,"
32+
+ "\"testUsersOnly\":null,\"customAttributes\":null,\"statuses\":null,\"emails\":null,\"phones\":null,"
33+
+ "\"loginIds\":null,\"ssoAppIds\":null,\"fromCreatedTime\":%d,\"toCreatedTime\":%d,\"fromModifiedTime\":%d,"
34+
+ "\"toModifiedTime\":%d}", expectedMillis, expectedMillis, expectedMillis, expectedMillis);
35+
36+
assertEquals(expectedJson, json);
37+
}
38+
}

src/test/java/com/descope/sdk/mgmt/impl/UserServiceImplTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
import com.descope.sdk.mgmt.UserService;
5555
import java.security.SecureRandom;
5656
import java.security.spec.KeySpec;
57+
import java.time.Duration;
58+
import java.time.Instant;
5759
import java.util.Arrays;
5860
import java.util.List;
5961
import java.util.Map;
@@ -902,7 +904,8 @@ void testFunctionalFullCycle() {
902904
assertEquals(true, user.getVerifiedPhone());
903905
assertEquals("Testing Test", user.getName());
904906
assertEquals("enabled", user.getStatus());
905-
AllUsersResponseDetails searchResponse = userService.searchAll(null);
907+
AllUsersResponseDetails searchResponse = userService.searchAll(
908+
UserSearchRequest.builder().fromCreatedTime(Instant.now().minus(Duration.ofMinutes(5))).build());
906909
boolean found = false;
907910
for (UserResponse u : searchResponse.getUsers()) {
908911
if (u.getUserId().equals(createResponse.getUser().getUserId())) {

0 commit comments

Comments
 (0)