Skip to content

Commit

Permalink
Use BCrypt encryption for password encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
besidev committed Jan 3, 2024
1 parent 5ad2f28 commit 227354e
Show file tree
Hide file tree
Showing 19 changed files with 1,671 additions and 30 deletions.
2 changes: 1 addition & 1 deletion jpro-auth/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ dependencies {
implementation "com.auth0:java-jwt:$AUTH0_JAVAJWT_VERSION"
implementation "com.auth0:jwks-rsa:$AUTH0_JWKSRSA_VERSION"
implementation "org.jetbrains:annotations:$JETBRAINS_ANNOTATIONS_VERSION"
// api "jakarta.inject:jakarta.inject-api:$JAKARTA_INJECT_VERSION"
api "org.slf4j:slf4j-api:$SLF4J_API_VERSION"
api "org.json:json:$JSON_VERSION"

testImplementation "org.junit.jupiter:junit-jupiter-api:$JUNIT_VERSION"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$JUNIT_VERSION"
testImplementation "org.assertj:assertj-core:$ASSERTJ_VERSION"
testRuntimeOnly "ch.qos.logback:logback-classic:$LOGBACK_VERSION"
}

Expand Down
3 changes: 3 additions & 0 deletions jpro-auth/core/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@
exports one.jpro.platform.auth.core.oauth2.provider;
exports one.jpro.platform.auth.core.http;
exports one.jpro.platform.auth.core.utils;
exports one.jpro.platform.auth.core.crypto;
exports one.jpro.platform.auth.core.crypto.bcrypt;
exports one.jpro.platform.auth.core.basic.provider;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface AuthAPI {
/**
* Configure and create a basic (username and password) authentication provider.
*
* @return fluent style api.
* @return fluent style api
*/
static FluentBasicAuth basicAuth() {
return new FluentBasicAuthAPI();
Expand All @@ -21,7 +21,7 @@ static FluentBasicAuth basicAuth() {
/**
* Configure and create a Google authentication provider.
*
* @return fluent style api.
* @return fluent style api
*/
static FluentGoogleAuth googleAuth() {
return new FluentGoogleAuthAPI();
Expand All @@ -30,7 +30,7 @@ static FluentGoogleAuth googleAuth() {
/**
* Configure and create a Keycloak authentication provider.
*
* @return fluent style api.
* @return fluent style api
*/
static FluentKeycloakAuth keycloakAuth() {
return new FluentKeycloakAuthAPI();
Expand All @@ -39,7 +39,7 @@ static FluentKeycloakAuth keycloakAuth() {
/**
* Configure and create a Microsoft authentication provider.
*
* @return fluent style api.
* @return fluent style api
*/
static FluentMicrosoftAuth microsoftAuth() {
return new FluentMicrosoftAuthAPI();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package one.jpro.platform.auth.core.api;

import one.jpro.platform.auth.core.basic.BasicAuthenticationProvider;
import one.jpro.platform.auth.core.basic.provider.BasicAuthenticationProvider;

import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -39,7 +39,7 @@ public interface FluentBasicAuth {
/**
* Create a simple authentication provider.
*
* @return a {@link BasicAuthenticationProvider} instance.
* @return a {@link BasicAuthenticationProvider} instance
*/
BasicAuthenticationProvider create();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package one.jpro.platform.auth.core.api;

import one.jpro.platform.auth.core.basic.BasicAuthenticationProvider;
import one.jpro.platform.auth.core.basic.provider.BasicAuthenticationProvider;

import java.util.Map;
import java.util.Set;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public interface FluentGoogleAuth {
* Create a Google authentication provider.
*
* @param stage the stage
* @return a {@link GoogleAuthenticationProvider} instance.
* @return a {@link GoogleAuthenticationProvider} instance
*/
GoogleAuthenticationProvider create(Stage stage);
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public interface FluentKeycloakAuth {
* Create a Keycloak authentication provider.
*
* @param stage the stage
* @return a {@link KeycloakAuthenticationProvider} instance.
* @return a {@link KeycloakAuthenticationProvider} instance
*/
KeycloakAuthenticationProvider create(Stage stage);
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public interface FluentMicrosoftAuth {
* Create a Microsoft authentication provider.
*
* @param stage the stage
* @return a {@link MicrosoftAuthenticationProvider} instance.
* @return a {@link MicrosoftAuthenticationProvider} instance
*/
MicrosoftAuthenticationProvider create(Stage stage);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@

import one.jpro.platform.auth.core.authentication.CredentialValidationException;
import one.jpro.platform.auth.core.authentication.Credentials;
import one.jpro.platform.auth.core.utils.AuthUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.json.JSONObject;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Objects;
import java.util.Optional;

import static one.jpro.platform.auth.core.utils.AuthUtils.BASE64_ENCODER;
import static one.jpro.platform.auth.core.utils.AuthUtils.BCRYPT_PASSWORD_ENCODER;

/**
* Username and password credentials holder.
*
* @author Besmir Beqiri
*/
public class UsernamePasswordCredentials implements Credentials {

private static final Base64.Encoder BASE64_ENCODER = AuthUtils.BASE64_ENCODER;

@Nullable
private String username;

Expand All @@ -36,8 +35,8 @@ public UsernamePasswordCredentials() {
/**
* Constructor with username and password.
*
* @param username User's name
* @param password User's password
* @param username the user's name
* @param password the user's password
*/
public UsernamePasswordCredentials(@NotNull String username, @NotNull String password) {
this.username = username;
Expand Down Expand Up @@ -112,7 +111,8 @@ public String toHttpAuthorization() {
public JSONObject toJSON() {
JSONObject json = new JSONObject();
Optional.ofNullable(getUsername()).ifPresent(username -> json.put("username", username));
Optional.ofNullable(getPassword()).ifPresent(password -> json.put("password", password));
Optional.ofNullable(getPassword())
.ifPresent(password -> json.put("password", BCRYPT_PASSWORD_ENCODER.encode(password)));
return json;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package one.jpro.platform.auth.core.basic;
package one.jpro.platform.auth.core.basic.provider;

import one.jpro.platform.auth.core.authentication.*;
import one.jpro.platform.auth.core.basic.UsernamePasswordCredentials;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.json.JSONArray;
Expand All @@ -12,6 +13,8 @@
import java.util.Set;
import java.util.concurrent.CompletableFuture;

import static one.jpro.platform.auth.core.utils.AuthUtils.BCRYPT_PASSWORD_ENCODER;

/**
* The {@code BasicAuthenticationProvider} class implements the {@code AuthenticationProvider} interface
* to provide basic authentication using username and password credentials.
Expand All @@ -34,8 +37,8 @@ public class BasicAuthenticationProvider implements AuthenticationProvider<Usern
/**
* Constructs a new {@code BasicAuthenticationProvider} with specified roles and attributes.
*
* @param roles the set of roles to be associated with the authenticated user, may be {@code null}.
* @param attributes the map of attributes to be associated with the authenticated user, may be {@code null}.
* @param roles the set of roles to be associated with the authenticated user, may be {@code null}
* @param attributes the map of attributes to be associated with the authenticated user, may be {@code null}
*/
public BasicAuthenticationProvider(@Nullable final Set<String> roles,
@Nullable final Map<String, Object> attributes) {
Expand All @@ -47,7 +50,7 @@ public BasicAuthenticationProvider(@Nullable final Set<String> roles,
* Authenticates the user based on the provided {@code UsernamePasswordCredentials}.
*
* @param credentials the credentials containing the username and password
* @return a {@code CompletableFuture} that, when completed, provides the authenticated {@code User}.
* @return a {@code CompletableFuture} that, when completed, provides the authenticated {@code User}
* @throws CredentialValidationException if the credentials are not valid
*/
@NotNull
Expand All @@ -66,7 +69,7 @@ public CompletableFuture<User> authenticate(@NotNull final UsernamePasswordCrede
userJSON.put(User.KEY_ROLES, new JSONArray(roles));

JSONObject authJSON = new JSONObject();
authJSON.put("password", credentials.getPassword());
authJSON.put("password", BCRYPT_PASSWORD_ENCODER.encode(credentials.getPassword()));
userJSON.put(User.KEY_ATTRIBUTES, new JSONObject(attributes).put("auth", authJSON));

final User user = Authentication.create(userJSON);
Expand Down Expand Up @@ -97,7 +100,7 @@ public void setAuthorizationPath(@NotNull String authorizationPath) {
/**
* Gets the set of roles associated with this authentication provider.
*
* @return The set of roles, may be {@code null}.
* @return the set of roles, may be {@code null}
*/
@Nullable
public Set<String> getRoles() {
Expand All @@ -107,7 +110,7 @@ public Set<String> getRoles() {
/**
* Sets the roles to be associated with this authentication provider.
*
* @param roles The set of roles, may be {@code null}.
* @param roles the set of roles, may be {@code null}
*/
public void setRoles(@Nullable Set<String> roles) {
this.roles = roles;
Expand All @@ -116,7 +119,7 @@ public void setRoles(@Nullable Set<String> roles) {
/**
* Gets the attributes associated with this authentication provider.
*
* @return The attributes, may be {@code null}.
* @return the attributes, may be {@code null}
*/
@Nullable
public Map<String, Object> getAttributes() {
Expand All @@ -126,7 +129,7 @@ public Map<String, Object> getAttributes() {
/**
* Sets the attributes to be associated with this authentication provider.
*
* @param attributes The map of attributes, may be {@code null}.
* @param attributes the map of attributes, may be {@code null}
*/
public void setAttributes(@Nullable Map<String, Object> attributes) {
this.attributes = attributes;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package one.jpro.platform.auth.core.crypto;

/**
* Password encoder interface.
*
* @author Besmir Beqiri
*/
public interface PasswordEncoder {

/**
* Encode the raw password. Generally, a good encoding algorithm applies an SHA-1 or
* greater hash combined with an 8-byte or greater randomly generated salt.
*
* @param rawPassword the raw password to encode
* @return encoded password string
*/
String encode(CharSequence rawPassword);

/**
* Verify the encoded password obtained from storage matches the submitted raw
* password after it too is encoded. Returns true if the passwords match, false if
* they do not. The stored password itself is never decoded.
*
* @param rawPassword the raw password to encode and match
* @param encodedPassword the encoded password from storage to compare with
* @return true if the raw password, after encoding, matches the encoded password from
* storage
*/
boolean matches(CharSequence rawPassword, String encodedPassword);

/**
* Returns true if the encoded password should be encoded again for better security,
* else false. The default implementation always returns false.
*
* @param encodedPassword the encoded password to check
* @return true if the encoded password should be encoded again for better security,
* else false.
*/
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
Loading

0 comments on commit 227354e

Please sign in to comment.