Skip to content

Commit

Permalink
update to user management
Browse files Browse the repository at this point in the history
  • Loading branch information
cometbid-project committed May 8, 2024
1 parent e55e644 commit b17edb4
Show file tree
Hide file tree
Showing 15 changed files with 487 additions and 44 deletions.
1 change: 1 addition & 0 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: "adopt"
java-version: 17
cache: maven
- run: mvn -B test -P coverage --no-transfer-progress
Expand Down
61 changes: 54 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<version>0.1.1</version>
<packaging>jar</packaging>

<name>${project.groupId}:${project.artifactId}</name>
<name>${project.artifactId}</name>
<description>Keycloak admin client adapter</description>
<url>https://cometbid.org/kc-iam-connector</url>

Expand Down Expand Up @@ -328,18 +328,19 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.release>17</maven.compiler.release>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.release>21</maven.compiler.release>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>

<java.version>17</java.version>
<java.version>21</java.version>
<junit.version>5.10.1</junit.version>
<jacoco.version>0.8.11</jacoco.version>
<lombok.version>1.18.30</lombok.version>
<log4j2.version>2.22.0</log4j2.version>
<mapstruct.version>1.6.0.Beta1</mapstruct.version>
<samstevens.totp.version>1.7.1</samstevens.totp.version>
<keycloak.admin.version>23.0.3</keycloak.admin.version>
<keycloak.admin.version>24.0.1</keycloak.admin.version>
<test-container-version>1.19.7</test-container-version>
<keycloak-test-container-version>3.3.0</keycloak-test-container-version>
<jacoco.version>0.8.11</jacoco.version>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
Expand All @@ -349,6 +350,18 @@
<exec.mainClass>org.cometbid.integration.kc.iam.connector.KcIamConnector</exec.mainClass>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${test-container-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
Expand Down Expand Up @@ -402,6 +415,34 @@
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>com.github.dasniko</groupId>
<artifactId>testcontainers-keycloak</artifactId>
<version>${keycloak-test-container-version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
Expand All @@ -414,6 +455,12 @@
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.2.3</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@
*/
package org.cometbid.integration.kc.iam.connector.config;

import lombok.Builder;

/**
*
* @author samueladebowale
*/
@Builder
public record KeycloakConfigProperties(String serverUrl, String realmName,
String clientId, String clientSecret) {

Expand All @@ -37,4 +40,23 @@ public String getRealmUrl() {
public String getRealmCertsUrl() {
return getRealmUrl() + "/protocol/openid-connect/certs";
}

public static KeycloakConfigProperties create(String serverUrl, String realmName) {

return KeycloakConfigProperties.builder()
.serverUrl(serverUrl)
.realmName(realmName)
.build();
}

public static KeycloakConfigProperties create(String serverUrl, String realmName,
String clientId, String clientSecret) {

return KeycloakConfigProperties.builder()
.serverUrl(serverUrl)
.realmName(realmName)
.clientId(clientId)
.clientSecret(clientSecret)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,8 @@ public record PasswordConfigProperties(Integer numberOfPastPassword, Boolean all
.orElseGet(() -> Constants.ALLOW_PASSWORD_REUSE);
}

public static PasswordConfigProperties create(Integer numberOfPastPassword, Boolean allowPasswordReuse) {
return new PasswordConfigProperties(numberOfPastPassword, allowPasswordReuse);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
*/
public enum SocialProvider {

FACEBOOK("facebook"), TWITTER("twitter"), LINKEDIN("linkedin"), GOOGLE("google"), GITHUB("github"), LOCAL("local");
FACEBOOK("facebook"),
TWITTER("twitter"),
LINKEDIN("linkedin"),
GOOGLE("google"),
GITHUB("github"),
LOCAL("local");

private String providerType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,16 @@
*/
public record Role(String id, String name, String description) {

public static Role create(String id, String name, String description) {
return new Role(id, name, description);
}

public static Role create(String name, String description) {
return new Role(null, name, description);
}

public static Role create(String name) {
return new Role(null, name, null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package org.cometbid.integration.kc.iam.connector.resource;

import java.util.Set;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
Expand All @@ -33,6 +34,10 @@
public class KeycloakPasswordResource {

private final PasswordEncoder passwordEncoder;

public KeycloakPasswordResource() {
this.passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

public KeycloakPasswordResource(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,24 @@
*/
package org.cometbid.integration.kc.iam.connector.totp;

import dev.samstevens.totp.code.CodeGenerator;
import dev.samstevens.totp.code.CodeVerifier;
import dev.samstevens.totp.code.DefaultCodeGenerator;
import dev.samstevens.totp.code.DefaultCodeVerifier;
import dev.samstevens.totp.code.HashingAlgorithm;
import dev.samstevens.totp.exceptions.QrGenerationException;
import dev.samstevens.totp.qr.QrData;
import dev.samstevens.totp.qr.QrDataFactory;
//import dev.samstevens.totp.qr.QrDataFactory;
import dev.samstevens.totp.qr.QrGenerator;
import dev.samstevens.totp.qr.ZxingPngQrGenerator;
import dev.samstevens.totp.secret.SecretGenerator;
import lombok.RequiredArgsConstructor;
import static dev.samstevens.totp.util.Utils.getDataUriForImage;

import java.util.SplittableRandom;
import dev.samstevens.totp.recovery.RecoveryCodeGenerator;
import dev.samstevens.totp.secret.DefaultSecretGenerator;
import dev.samstevens.totp.time.SystemTimeProvider;
import dev.samstevens.totp.time.TimeProvider;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.cometbid.integration.kc.iam.connector.util.Constants;
Expand All @@ -42,18 +49,33 @@
*
* @author samueladebowale
*/
@RequiredArgsConstructor
public class TotpManagerImpl implements TotpManager {
public final class TotpManagerImpl implements TotpManager {

private static TotpManagerImpl INSTANCE = new TotpManagerImpl();

// @Value("totp.code.length")
private final String configOtpLength;
private final Integer configOtpLength;
// @Value("totp.qrCode.issuer")
private final String configIssuer;
private final CodeVerifier codeVerifier;
private final QrDataFactory qrDataFactory;
private final QrGenerator qrGenerator;
private final SecretGenerator secretGenerator;

private TotpManagerImpl() {
this.configOtpLength = Constants.OTP_LENGTH;

// this.configIssuer = Optional.ofNullable(configIssuer)
// .filter(StringUtils::isNotBlank).orElse(Constants.ISSUER);
this.configIssuer = Constants.ISSUER;
this.secretGenerator = new DefaultSecretGenerator();
this.qrGenerator = new ZxingPngQrGenerator();
this.codeVerifier = myCodeVerifier();
}

public static TotpManager getInstance() {
return INSTANCE;
}

/**
*
* @return
Expand Down Expand Up @@ -86,10 +108,17 @@ public String generateQrImage(String email, String secret) throws RuntimeExcepti
// String secret = secretGenerator.generate();
String qrCodeImage = null;
try {
String totpIssuer = Optional.ofNullable(configIssuer)
.filter(StringUtils::isNotBlank).orElse(Constants.ISSUER);

QrData data = qrDataFactory.newBuilder().label(email).secret(secret).issuer(totpIssuer).build();
//String totpIssuer = Optional.ofNullable(configIssuer)
// .filter(StringUtils::isNotBlank).orElse(Constants.ISSUER);

QrData data = new QrData.Builder()
.label(email)
.secret(secret)
.issuer(this.configIssuer)
.digits(6)
.period(30)
.algorithm(HashingAlgorithm.SHA512)
.build();

byte[] imageData = qrGenerator.generate(data);
String mimeType = qrGenerator.getImageMimeType();
Expand All @@ -112,7 +141,6 @@ public String generateOtp() {

//Optional.ofNullable(configOtpLength).map(Ints::tryParse).orElse(Constants.OTP_LENGTH);
int otpLength = Optional.ofNullable(configOtpLength)
.filter(StringUtils::isNotBlank)
.map(Integer::valueOf).orElse(Constants.OTP_LENGTH);

SplittableRandom splittableRandom = new SplittableRandom();
Expand All @@ -136,4 +164,15 @@ public String[] generateRecoveryCodes() {
return codes;
}

private CodeVerifier myCodeVerifier() {
// Time
TimeProvider timeProvider = new SystemTimeProvider();

// Code Generator
CodeGenerator codeGenerator = new DefaultCodeGenerator(HashingAlgorithm.SHA512, 6);
DefaultCodeVerifier localCodeVerifier = new DefaultCodeVerifier(codeGenerator, timeProvider);
localCodeVerifier.setTimePeriod(30);
localCodeVerifier.setAllowedTimePeriodDiscrepancy(2);
return localCodeVerifier;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@
package org.cometbid.integration.kc.iam.connector.user;

import java.util.List;
import java.util.Set;
import org.cometbid.integration.kc.iam.connector.enums.ProfileStatus;
import org.cometbid.integration.kc.iam.connector.realm.role.Role;

/**
*
* @author samueladebowale
*/
public record CreateUserRequest(KeycloakUser keycloakUser, ProfileStatus profileStatus,
List<Role> roles, String plainPassword, List<String> recoveryCodelist) {
Set<String> roles, String plainPassword, List<String> recoveryCodelist) {

public static CreateUserRequest createRequest(KeycloakUser keycloakUser, ProfileStatus profileStatus,
Set<String> roles, String plainPassword, List<String> recoveryCodelist) {

return new CreateUserRequest(keycloakUser, profileStatus, roles, plainPassword, recoveryCodelist);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
*
* @author samueladebowale
*/
public record CreateUserResponse(ProcessStatus status, String totpSecret) {
public record CreateUserResponse(ProcessStatus status, MfaToken token) {

static CreateUserResponse createSuccessResponse(String totpSecret) {
return new CreateUserResponse(ProcessStatus.SUCCESS, totpSecret);
static CreateUserResponse createSuccessResponse(MfaToken token) {
return new CreateUserResponse(ProcessStatus.SUCCESS, token);
}

static CreateUserResponse createFailedResponse() {
Expand Down
Loading

0 comments on commit b17edb4

Please sign in to comment.