This repository has been archived by the owner on Aug 2, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Stephane Segning
committed
Sep 13, 2020
0 parents
commit e846c1e
Showing
6 changed files
with
1,038 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.idea | ||
*.iml | ||
*.log | ||
*.class | ||
target | ||
.code | ||
*.zip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Keycloak Bcrypt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>com.bayamsell.keycloak</groupId> | ||
<artifactId>keycloak-bcrypt</artifactId> | ||
<version>1.0.0</version> | ||
|
||
<properties> | ||
<java.version>11</java.version> | ||
<lombock.version>1.18.10</lombock.version> | ||
<keycloak.version>11.0.2</keycloak.version> | ||
</properties> | ||
|
||
<dependencyManagement> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-parent</artifactId> | ||
<version>${keycloak.version}</version> | ||
<type>pom</type> | ||
<scope>import</scope> | ||
</dependency> | ||
</dependencies> | ||
</dependencyManagement> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-server-spi</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-server-spi-private</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-services</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-core</artifactId> | ||
</dependency> | ||
|
||
<!-- lombock --> | ||
<dependency> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<scope>provided</scope> | ||
<version>${lombock.version}</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<version>4.12</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<finalName>${artifactId}-${project.version}</finalName> | ||
|
||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<version>3.8.0</version> | ||
<configuration> | ||
<verbose>false</verbose> | ||
<release>${java.version}</release> | ||
<source>${java.version}</source> | ||
<target>${java.version}</target> | ||
<annotationProcessorPaths> | ||
<path> | ||
<groupId>org.projectlombok</groupId> | ||
<artifactId>lombok</artifactId> | ||
<version>${lombock.version}</version> | ||
</path> | ||
</annotationProcessorPaths> | ||
</configuration> | ||
</plugin> | ||
|
||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-ear-plugin</artifactId> | ||
<version>3.0.1</version> | ||
<configuration> | ||
<defaultLibBundleDir>lib</defaultLibBundleDir> | ||
<outputFileNameMapping>@{artifactId}@.@{extension}@</outputFileNameMapping> | ||
</configuration> | ||
</plugin> | ||
|
||
<plugin> | ||
<groupId>org.wildfly.plugins</groupId> | ||
<artifactId>wildfly-maven-plugin</artifactId> | ||
<version>2.0.1.Final</version> | ||
</plugin> | ||
|
||
<!-- Maven Assembly Plugin --> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-assembly-plugin</artifactId> | ||
<version>3.1.1</version> | ||
<configuration> | ||
<!-- get all project dependencies --> | ||
<descriptorRefs> | ||
<descriptorRef>jar-with-dependencies</descriptorRef> | ||
</descriptorRefs> | ||
</configuration> | ||
<executions> | ||
<execution> | ||
<id>make-assembly</id> | ||
<!-- bind to the packaging phase --> | ||
<phase>package</phase> | ||
<goals> | ||
<goal>single</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
|
||
</plugins> | ||
</build> | ||
</project> |
65 changes: 65 additions & 0 deletions
65
src/main/java/com/bayamsell/keycloak/BCryptPasswordHashProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package com.bayamsell.keycloak; | ||
|
||
import com.bayamsell.keycloak.helper.BCrypt; | ||
import lombok.AllArgsConstructor; | ||
import org.keycloak.credential.hash.PasswordHashProvider; | ||
import org.keycloak.models.PasswordPolicy; | ||
import org.keycloak.models.credential.PasswordCredentialModel; | ||
import org.keycloak.models.credential.dto.PasswordCredentialData; | ||
import org.keycloak.models.credential.dto.PasswordSecretData; | ||
|
||
/** | ||
* @author <a href="mailto:pro.guillaume.leroy@gmail.com">Guillaume Leroy</a> | ||
*/ | ||
@AllArgsConstructor | ||
public class BCryptPasswordHashProvider implements PasswordHashProvider { | ||
// BCrypt uses min of 4 and max of 30 2**log_rounds | ||
private final int MAX_BCRYPT_LOG_ROUNDS = 30; | ||
private final int MIN_BCRYPT_LOG_ROUNDS = 4; | ||
|
||
private final String providerId; | ||
private final int defaultIterations; | ||
|
||
@Override | ||
public boolean policyCheck(PasswordPolicy policy, PasswordCredentialModel passwordCredentialModel) { | ||
int policyHashIterations = policy.getHashIterations(); | ||
if (policyHashIterations == -1) { | ||
policyHashIterations = defaultIterations; | ||
} | ||
|
||
PasswordCredentialData passwordCredentialData = passwordCredentialModel.getPasswordCredentialData(); | ||
return passwordCredentialData.getHashIterations() == policyHashIterations && providerId.equals(passwordCredentialData.getAlgorithm()); | ||
} | ||
|
||
@Override | ||
public PasswordCredentialModel encodedCredential(String rawPassword, int iterations) { | ||
int logRounds = iterations == -1 ? iterationsToLogRounds(defaultIterations) : iterationsToLogRounds(iterations); | ||
String salt = BCrypt.gensalt(logRounds); | ||
String hash = BCrypt.hashpw(rawPassword, salt); | ||
return PasswordCredentialModel.createFromValues(providerId, new byte[0], iterations, hash); | ||
} | ||
|
||
@Override | ||
public boolean verify(String rawPassword, PasswordCredentialModel passwordCredentialModel) { | ||
PasswordSecretData passwordSecretData = passwordCredentialModel.getPasswordSecretData(); | ||
return BCrypt.checkpw(rawPassword, passwordSecretData.getValue()); | ||
} | ||
|
||
@Override | ||
public String encode(String rawPassword, int iterations) { | ||
int logRounds = iterations == -1 ? iterationsToLogRounds(defaultIterations) : iterationsToLogRounds(iterations); | ||
String salt = BCrypt.gensalt(logRounds); | ||
return BCrypt.hashpw(rawPassword, salt); | ||
} | ||
|
||
@Override | ||
public void close() { | ||
|
||
} | ||
|
||
private int iterationsToLogRounds(int iterations) { | ||
// bcrypt uses 2**log2_rounds with a min of 4 and max of 30 log rounds | ||
return Math.max(MIN_BCRYPT_LOG_ROUNDS, Math.min(MAX_BCRYPT_LOG_ROUNDS, | ||
(int) Math.round(Math.log(iterations) / Math.log(2) + 1))); | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
src/main/java/com/bayamsell/keycloak/BCryptPasswordHashProviderFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package com.bayamsell.keycloak; | ||
|
||
import org.keycloak.Config; | ||
import org.keycloak.credential.hash.PasswordHashProvider; | ||
import org.keycloak.credential.hash.PasswordHashProviderFactory; | ||
import org.keycloak.models.KeycloakSession; | ||
import org.keycloak.models.KeycloakSessionFactory; | ||
import org.keycloak.provider.ServerInfoAwareProviderFactory; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
/** | ||
* @author <a href="mailto:pro.guillaume.leroy@gmail.com">Guillaume Leroy</a> | ||
*/ | ||
public class BCryptPasswordHashProviderFactory implements PasswordHashProviderFactory, ServerInfoAwareProviderFactory { | ||
public static final String ID = "bcrypt"; | ||
public static final int DEFAULT_ITERATIONS = 8192; | ||
|
||
private static final Map<String, String> infos = new HashMap<>(); | ||
|
||
static { | ||
infos.put("version", "1.0.0"); | ||
} | ||
|
||
@Override | ||
public PasswordHashProvider create(KeycloakSession session) { | ||
return new BCryptPasswordHashProvider(ID, DEFAULT_ITERATIONS); | ||
} | ||
|
||
@Override | ||
public void init(Config.Scope config) { | ||
} | ||
|
||
@Override | ||
public void postInit(KeycloakSessionFactory factory) { | ||
} | ||
|
||
@Override | ||
public String getId() { | ||
return ID; | ||
} | ||
|
||
@Override | ||
public void close() { | ||
} | ||
|
||
/** | ||
* Return actual info about the provider. This info contains informations about providers configuration and operational conditions (eg. errors in connection to remote systems etc) which is | ||
* shown on "Server Info" page then. | ||
* | ||
* @return Map with keys describing value and relevant values itself | ||
*/ | ||
@Override | ||
public Map<String, String> getOperationalInfo() { | ||
return infos; | ||
} | ||
} |
Oops, something went wrong.