Skip to content

Commit

Permalink
Merge pull request #1711 from wultra/develop
Browse files Browse the repository at this point in the history
Merge develop to master
  • Loading branch information
banterCZ authored Oct 25, 2024
2 parents f334918 + cac0c52 commit 3e3391b
Show file tree
Hide file tree
Showing 45 changed files with 416 additions and 94 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/scp-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ jobs:
- name: Deploy powerauth-webflow.war
shell: bash
run: |
scp -i ~/.ssh/id_rsa **/target/powerauth-webflow-*.war ${{ secrets.SCP_USERNAME }}@${{ secrets.SCP_HOST }}:/opt/apache-tomcat/webapps/powerauth-webflow.war
scp -i ~/.ssh/id_rsa powerauth-webflow/target/powerauth-webflow-*.war ${{ secrets.SCP_USERNAME }}@${{ secrets.SCP_HOST }}:/opt/apache-tomcat/webapps/powerauth-webflow.war
- name: Deploy powerauth-nextstep.war
shell: bash
run: |
scp -i ~/.ssh/id_rsa **/target/powerauth-nextstep-*.war ${{ secrets.SCP_USERNAME }}@${{ secrets.SCP_HOST }}:/opt/apache-tomcat/webapps/powerauth-nextstep.war
scp -i ~/.ssh/id_rsa powerauth-nextstep/target/powerauth-nextstep-*.war ${{ secrets.SCP_USERNAME }}@${{ secrets.SCP_HOST }}:/opt/apache-tomcat/webapps/powerauth-nextstep.war
- name: Deploy powerauth-webflow-client.war
shell: bash
run: |
scp -i ~/.ssh/id_rsa **/target/webflow-client-*.war ${{ secrets.SCP_USERNAME }}@${{ secrets.SCP_HOST }}:/opt/apache-tomcat/webapps/webflow-client.war
scp -i ~/.ssh/id_rsa powerauth-webflow-client/target/powerauth-webflow-client-*.war ${{ secrets.SCP_USERNAME }}@${{ secrets.SCP_HOST }}:/opt/apache-tomcat/webapps/powerauth-webflow-client.war
- name: Deploy powerauth-tpp-engine.war
shell: bash
run: |
scp -i ~/.ssh/id_rsa **/target/powerauth-tpp-engine-*.war ${{ secrets.SCP_USERNAME }}@${{ secrets.SCP_HOST }}:/opt/apache-tomcat/webapps/powerauth-tpp-engine.war
scp -i ~/.ssh/id_rsa powerauth-tpp-engine/target/powerauth-tpp-engine-*.war ${{ secrets.SCP_USERNAME }}@${{ secrets.SCP_HOST }}:/opt/apache-tomcat/webapps/powerauth-tpp-engine.war
2 changes: 1 addition & 1 deletion docs/Basic-Definitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ When the user identity is managed by the Next Step application, Next Step provid

### Next Step -- credential hashing

Next Step application hashes the user credentials using the Argon2 hashing algorithm. The credential verification is performed by comparing the hash of the credential with the stored hash. The hashing algorithm parameters can be changed and in this case the credential hash is recreated with new parameters during the next user authentication and stored in the database.
Next Step application hashes the user credentials using the Argon2 or Bcrypt hashing algorithms. The credential verification is performed by comparing the hash of the credential with the stored hash. For Argon2, the hashing algorithm parameters can be changed to provide strong hashing. In this case the credential hash is recreated with new parameters during the next user authentication and stored in the database. We recommend to use Argon2 instead of Bcrypt, which was added mainly for compatibility reasons and does not support hashing strength configuration.

### Next Step -- database record encryption

Expand Down
1 change: 1 addition & 0 deletions docs/Migration-Instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

This page contains PowerAuth Web Flow migration instructions.

- [PowerAuth Web Flow 1.9.0](./Web-Flow-1.9.0.md)
- [PowerAuth Web Flow 1.8.0](./Web-Flow-1.8.0.md)
- [PowerAuth Web Flow 1.7.0](./Web-Flow-1.7.0.md)
- [PowerAuth Web Flow 1.6.0](./Web-Flow-1.6.0.md)
Expand Down
2 changes: 2 additions & 0 deletions docs/Next-Step-Server-REST-API-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -5701,6 +5701,8 @@ The list of expected status codes:
}
```

Possible algorithm names: `ARGON_2D`, `ARGON_2I`, `ARGON_2ID`, `BCRYPT`. For `BCRYPT` empty parameters should be used as this algorithm does not support hashing algorithm parameterization.

#### Response 200

- Headers:
Expand Down
5 changes: 5 additions & 0 deletions docs/Web-Flow-1.9.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Migration from 1.8.0 to 1.9.0

This guide contains instructions for migration from PowerAuth WebFlow version `1.8.x` to version `1.9.0`.

There are no database changes needed for this version.
20 changes: 10 additions & 10 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

<groupId>io.getlime.security</groupId>
<artifactId>powerauth-webflow-parent</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
<packaging>pom</packaging>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.2</version>
<version>3.3.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

Expand Down Expand Up @@ -93,21 +93,21 @@
<maven.compiler.target>17</maven.compiler.target>
<bcprov-jdk18on.version>1.78.1</bcprov-jdk18on.version>
<zxing.version>3.5.3</zxing.version>
<passay.version>1.6.4</passay.version>
<passay.version>1.6.6</passay.version>

<!-- Documentation Dependencies -->
<springdoc-openapi-starter-webmvc-ui.version>2.6.0</springdoc-openapi-starter-webmvc-ui.version>
<swagger-annotations-jakarta.version>2.2.22</swagger-annotations-jakarta.version>
<swagger-annotations-jakarta.version>2.2.25</swagger-annotations-jakarta.version>

<moneta.version>1.4.4</moneta.version>
<owasp-java-html-sanitizer.version>20240325.1</owasp-java-html-sanitizer.version>
<logstash.version>7.4</logstash.version>
<logstash.version>8.0</logstash.version>

<!-- Wultra dependencies -->
<wultra-core.version>1.10.0</wultra-core.version>
<powerauth.version>1.8.0</powerauth.version>
<powerauth-crypto.version>1.8.0</powerauth-crypto.version>
<powerauth-push.version>1.8.0</powerauth-push.version>
<wultra-core.version>1.11.0</wultra-core.version>
<powerauth.version>1.9.0</powerauth.version>
<powerauth-crypto.version>1.9.0</powerauth-crypto.version>
<powerauth-push.version>1.9.0</powerauth-push.version>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -345,7 +345,7 @@
<dependency>
<groupId>de.skuzzle.enforcer</groupId>
<artifactId>restrict-imports-enforcer-rule</artifactId>
<version>2.5.0</version>
<version>2.6.0</version>
</dependency>
</dependencies>
<executions>
Expand Down
2 changes: 1 addition & 1 deletion powerauth-data-adapter-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<parent>
<artifactId>powerauth-webflow-parent</artifactId>
<groupId>io.getlime.security</groupId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>

<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion powerauth-data-adapter-model/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<parent>
<artifactId>powerauth-webflow-parent</artifactId>
<groupId>io.getlime.security</groupId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>

<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion powerauth-mtoken-model/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<parent>
<artifactId>powerauth-webflow-parent</artifactId>
<groupId>io.getlime.security</groupId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>

<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion powerauth-nextstep-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<parent>
<artifactId>powerauth-webflow-parent</artifactId>
<groupId>io.getlime.security</groupId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>

<artifactId>powerauth-nextstep-client</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion powerauth-nextstep-model/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<parent>
<groupId>io.getlime.security</groupId>
<artifactId>powerauth-webflow-parent</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@
*/
package io.getlime.security.powerauth.lib.nextstep.model.entity.enumeration;

import lombok.Getter;

/**
* Enumeration representing hashing algorithms.
*
* @author Roman Strobl, [email protected]
*/
@Getter
public enum HashAlgorithm {

/**
Expand All @@ -37,35 +40,30 @@ public enum HashAlgorithm {
/**
* Algorithm argon2id.
*/
ARGON_2ID("argon2id", 2);
ARGON_2ID("argon2id", 2),

BCRYPT("bcrypt");

private final String name;
private final int id;
private final Integer id;

/**
* Hash algorithm constructor.
* @param name Algorithm name for Modular Crypt Format.
* @param id Algorithm ID in Bouncy Castle library.
* @param name Algorithm name.
*/
HashAlgorithm(String name, int id) {
HashAlgorithm(String name) {
this.name = name;
this.id = id;
this.id = null;
}

/**
* Get algorithm name for Modular Crypt Format.
* @return Algorithm name.
*/
public String getName() {
return name;
}

/**
* Get algorithm ID in Bouncy Castle library.
* @return Algorithm ID.
* Hash algorithm constructor for Argon family of algorithms.
* @param name Algorithm name for Modular Crypt Format.
* @param id Algorithm ID in Bouncy Castle library (Argon algorithms only).
*/
public int getId() {
return id;
HashAlgorithm(String name, int id) {
this.name = name;
this.id = id;
}

}
2 changes: 1 addition & 1 deletion powerauth-nextstep/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<parent>
<groupId>io.getlime.security</groupId>
<artifactId>powerauth-webflow-parent</artifactId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;

import java.io.IOException;
Expand Down Expand Up @@ -100,6 +101,10 @@ public CredentialValue protectCredential(String credentialValue, CredentialEntit
final String hashedValue = argon2Hash.toString();
return credentialValueConverter.toDBValue(hashedValue, userId, credentialDefinition);
}
case BCRYPT -> {
String hashedValue = BCrypt.hashpw(credentialValue, BCrypt.gensalt());
return credentialValueConverter.toDBValue(hashedValue, userId, credentialDefinition);
}
default -> throw new InvalidConfigurationException("Unsupported hashing algorithm: " + algorithm);
}
}
Expand Down Expand Up @@ -132,6 +137,13 @@ public boolean verifyCredential(String credentialValue, CredentialEntity credent
}
return succeeded;
}
case BCRYPT -> {
boolean succeeded = BCrypt.checkpw(credentialValue, decryptedCredentialValue);
if (succeeded) {
updateStoredCredentialValueIfRequired(credentialValue, credential);
}
return succeeded;
}
default -> throw new InvalidConfigurationException("Unsupported hashing algorithm: " + algorithm);
}
}
Expand All @@ -154,6 +166,7 @@ public boolean verifyCredentialHistory(String credentialValue, CredentialHistory
final HashAlgorithm algorithm = hashingConfig.getAlgorithm();
return switch (algorithm) {
case ARGON_2I, ARGON_2D, ARGON_2ID -> verifyCredentialUsingArgon2(credentialValue, algorithm, decryptedCredentialValue);
case BCRYPT -> BCrypt.checkpw(credentialValue, decryptedCredentialValue);
};
}

Expand Down Expand Up @@ -335,7 +348,7 @@ private void updateStoredCredentialValueIfRequired(String credentialValue, Crede
updateRequired = true;
} else {
// Check actual argon2 parameters from the hash in the database and compare them with credential definition
updateRequired = updateRequired || !argon2ParamMatch(extractCredentialValue(credential), credentialDefinition.getHashingConfig().getAlgorithm(), credential.getHashingConfig().getParameters());
updateRequired = updateRequired || (credentialDefinition.getHashingConfig().getAlgorithm() != HashAlgorithm.BCRYPT && !argon2ParamMatch(extractCredentialValue(credential), credentialDefinition.getHashingConfig().getAlgorithm(), credential.getHashingConfig().getParameters()));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* PowerAuth Web Flow and related software components
* Copyright (C) 2024 Wultra s.r.o.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.getlime.security.powerauth.app.nextstep.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.getlime.security.powerauth.app.nextstep.NextStepTest;
import io.getlime.security.powerauth.app.nextstep.repository.model.entity.CredentialDefinitionEntity;
import io.getlime.security.powerauth.app.nextstep.repository.model.entity.CredentialEntity;
import io.getlime.security.powerauth.app.nextstep.repository.model.entity.HashConfigEntity;
import io.getlime.security.powerauth.app.nextstep.repository.model.entity.UserIdentityEntity;
import io.getlime.security.powerauth.lib.nextstep.model.entity.CredentialValue;
import io.getlime.security.powerauth.lib.nextstep.model.entity.enumeration.EncryptionAlgorithm;
import io.getlime.security.powerauth.lib.nextstep.model.entity.enumeration.HashAlgorithm;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;

/**
* Tests for password hashing.
*
* @author Roman Strobl, [email protected]
*/
class CredentialProtectionServiceTest extends NextStepTest {

@Autowired
private CredentialProtectionService credentialProtectionService;

@Test
void testBcrypt() throws Exception {
final CredentialEntity credentialEntity = new CredentialEntity();
final UserIdentityEntity user = new UserIdentityEntity();
final HashConfigEntity hashConfig = new HashConfigEntity();
final CredentialDefinitionEntity credentialDefinition = new CredentialDefinitionEntity();
credentialDefinition.setEncryptionAlgorithm(EncryptionAlgorithm.NO_ENCRYPTION);
credentialDefinition.setHashingConfig(hashConfig);
hashConfig.setAlgorithm(HashAlgorithm.BCRYPT);
hashConfig.setParameters("{}");
user.setUserId("test");
credentialEntity.setUser(user);
credentialEntity.setCredentialDefinition(credentialDefinition);
credentialEntity.setHashingConfig(hashConfig);
final CredentialValue hashed = credentialProtectionService.protectCredential("test", credentialEntity);
credentialEntity.setValue(hashed.getValue());
assertEquals(EncryptionAlgorithm.NO_ENCRYPTION, hashed.getEncryptionAlgorithm());
assertNotEquals("test", hashed.getValue());
assertTrue(hashed.getValue().startsWith("$2a$10$"));
assertTrue(credentialProtectionService.verifyCredential("test", credentialEntity));
}

@Test
void testArgon2() throws Exception {
final CredentialEntity credentialEntity = new CredentialEntity();
final UserIdentityEntity user = new UserIdentityEntity();
final HashConfigEntity hashConfig = new HashConfigEntity();
final CredentialDefinitionEntity credentialDefinition = new CredentialDefinitionEntity();
credentialDefinition.setEncryptionAlgorithm(EncryptionAlgorithm.NO_ENCRYPTION);
credentialDefinition.setHashingConfig(hashConfig);
hashConfig.setAlgorithm(HashAlgorithm.ARGON_2I);
final Map<String, String> params = Map.of(
"version", "19",
"iterations", "4",
"memory", "16",
"parallelism", "2",
"outputLength", "32"
);
hashConfig.setParameters(new ObjectMapper().writeValueAsString(params));
user.setUserId("test");
credentialEntity.setUser(user);
credentialEntity.setCredentialDefinition(credentialDefinition);
credentialEntity.setHashingConfig(hashConfig);
final CredentialValue hashed = credentialProtectionService.protectCredential("test", credentialEntity);
credentialEntity.setValue(hashed.getValue());
assertEquals(EncryptionAlgorithm.NO_ENCRYPTION, hashed.getEncryptionAlgorithm());
assertNotEquals("test", hashed.getValue());
assertTrue(hashed.getValue().startsWith("$argon2i$v=19$m=65536,t=4,p=2$"));
assertTrue(credentialProtectionService.verifyCredential("test", credentialEntity));
}

}
2 changes: 1 addition & 1 deletion powerauth-tpp-engine-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<parent>
<artifactId>powerauth-webflow-parent</artifactId>
<groupId>io.getlime.security</groupId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>

<name>powerauth-tpp-engine-client</name>
Expand Down
2 changes: 1 addition & 1 deletion powerauth-tpp-engine-model/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<parent>
<artifactId>powerauth-webflow-parent</artifactId>
<groupId>io.getlime.security</groupId>
<version>1.8.0</version>
<version>1.9.0</version>
</parent>

<name>powerauth-tpp-engine-model</name>
Expand Down
Loading

0 comments on commit 3e3391b

Please sign in to comment.