From 9783b1143da6576028de23e15a1f198b1f937b82 Mon Sep 17 00:00:00 2001 From: "Khaled Y.M" Date: Tue, 5 Oct 2021 21:53:55 +0100 Subject: [PATCH 1/2] Prevent authentication with inactive identifiers --- .../authguard/basic/BasicAuthProvider.java | 37 +++++++++++++++++-- .../basic/BasicAuthProviderTest.java | 22 +++++++++++ .../service/exceptions/codes/ErrorCode.java | 1 + .../service/model/UserIdentifier.java | 6 ++- 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/basic-auth/src/main/java/com/nexblocks/authguard/basic/BasicAuthProvider.java b/basic-auth/src/main/java/com/nexblocks/authguard/basic/BasicAuthProvider.java index d27c325f..fc4908c6 100644 --- a/basic-auth/src/main/java/com/nexblocks/authguard/basic/BasicAuthProvider.java +++ b/basic-auth/src/main/java/com/nexblocks/authguard/basic/BasicAuthProvider.java @@ -7,10 +7,7 @@ import com.nexblocks.authguard.service.exceptions.ServiceAuthorizationException; import com.nexblocks.authguard.service.exceptions.ServiceException; import com.nexblocks.authguard.service.exceptions.codes.ErrorCode; -import com.nexblocks.authguard.service.model.AccountBO; -import com.nexblocks.authguard.service.model.AuthRequestBO; -import com.nexblocks.authguard.service.model.CredentialsBO; -import com.nexblocks.authguard.service.model.EntityType; +import com.nexblocks.authguard.service.model.*; import com.google.inject.Inject; import io.vavr.control.Either; import org.slf4j.Logger; @@ -86,7 +83,14 @@ private Either handleBasicAuthenticationNoPassword(final S private Either verifyCredentialsAndGetAccount(final String username, final String password) { final Optional credentials = credentialsService.getByUsernameUnsafe(username); + // TODO replace this with Either mapping if (credentials.isPresent()) { + final Optional validationError = checkIdentifier(credentials.get(), username); + + if (validationError.isPresent()) { + return Either.left(validationError.get()); + } + if (securePassword.verify(password, credentials.get().getHashedPassword())) { return getAccountById(credentials.get().getAccountId()); } else { @@ -103,6 +107,12 @@ private Either verifyCredentialsAndGetAccount(final String final Optional credentials = credentialsService.getByUsernameUnsafe(username); if (credentials.isPresent()) { + final Optional validationError = checkIdentifier(credentials.get(), username); + + if (validationError.isPresent()) { + return Either.left(validationError.get()); + } + return getAccountById(credentials.get().getAccountId()); } else { return Either.left(new ServiceAuthorizationException(ErrorCode.CREDENTIALS_DOES_NOT_EXIST, @@ -110,6 +120,25 @@ private Either verifyCredentialsAndGetAccount(final String } } + private Optional checkIdentifier(final CredentialsBO credentials, + final String identifier) { + final Optional matchedIdentifier = credentials.getIdentifiers() + .stream() + .filter(existing -> identifier.equals(existing.getIdentifier())) + .findFirst(); + + if (matchedIdentifier.isEmpty()) { + return Optional.of(new IllegalStateException("No identifier matched but credentials were returned")); + } + + if (!matchedIdentifier.get().isActive()) { + return Optional.of(new ServiceAuthorizationException(ErrorCode.INACTIVE_IDENTIFIER, + "Identifier is not active", EntityType.ACCOUNT, credentials.getAccountId())); + } + + return Optional.empty(); + } + private Either getAccountById(final String accountId) { final Optional account = accountsService.getById(accountId); diff --git a/basic-auth/src/test/java/com/nexblocks/authguard/basic/BasicAuthProviderTest.java b/basic-auth/src/test/java/com/nexblocks/authguard/basic/BasicAuthProviderTest.java index 34d1df7f..f21e5748 100644 --- a/basic-auth/src/test/java/com/nexblocks/authguard/basic/BasicAuthProviderTest.java +++ b/basic-auth/src/test/java/com/nexblocks/authguard/basic/BasicAuthProviderTest.java @@ -64,6 +64,7 @@ void authenticate() { .withIdentifiers(UserIdentifierBO.builder() .identifier(username) .type(UserIdentifier.Type.USERNAME) + .active(true) .build()); final HashedPasswordBO hashedPasswordBO = HashedPasswordBO.builder() .password(credentials.getHashedPassword().getPassword()) @@ -79,6 +80,27 @@ void authenticate() { assertThat(result.get()).isEqualTo(account); } + @Test + void authenticateInactiveIdentifier() { + final String username = "username"; + final String password = "password"; + final String authorization = Base64.getEncoder().encodeToString((username + ":" + password).getBytes()); + + final CredentialsBO credentials = RANDOM.nextObject(CredentialsBO.class) + .withIdentifiers(UserIdentifierBO.builder() + .identifier(username) + .type(UserIdentifier.Type.USERNAME) + .active(false) + .build()); + + Mockito.when(credentialsService.getByUsernameUnsafe(username)).thenReturn(Optional.of(credentials)); + + final Either result = basicAuth.authenticateAndGetAccount(authorization); + + assertThat(result.isLeft()).isTrue(); + assertThat(result.getLeft()).isInstanceOf(ServiceAuthorizationException.class); + } + @Test void authenticateNotFound() { final String username = "username"; diff --git a/service-api/src/main/java/com/nexblocks/authguard/service/exceptions/codes/ErrorCode.java b/service-api/src/main/java/com/nexblocks/authguard/service/exceptions/codes/ErrorCode.java index 30bf4c04..262ddd5a 100644 --- a/service-api/src/main/java/com/nexblocks/authguard/service/exceptions/codes/ErrorCode.java +++ b/service-api/src/main/java/com/nexblocks/authguard/service/exceptions/codes/ErrorCode.java @@ -33,6 +33,7 @@ public enum ErrorCode { TOKEN_EXPIRED_OR_DOES_NOT_EXIST("AT.025"), TOKEN_GENERATION_FAILED("AT.031"), ACCOUNT_IS_LOCKED("AT.032"), + INACTIVE_IDENTIFIER("AT.033"), GENERIC_AUTH_FAILURE("AT.039"), UNSUPPORTED_JWT_ALGORITHM("JT.021"), diff --git a/service-api/src/main/java/com/nexblocks/authguard/service/model/UserIdentifier.java b/service-api/src/main/java/com/nexblocks/authguard/service/model/UserIdentifier.java index 605a4811..6a5d76ae 100644 --- a/service-api/src/main/java/com/nexblocks/authguard/service/model/UserIdentifier.java +++ b/service-api/src/main/java/com/nexblocks/authguard/service/model/UserIdentifier.java @@ -8,7 +8,11 @@ public interface UserIdentifier { Long getId(); // only useful for relational DBs Type getType(); String getIdentifier(); - boolean isActive(); + + @Value.Default + default boolean isActive() { + return true; + } enum Type { USERNAME, From 4972af9e74db3daabe4735d2886edb9fba94bad4 Mon Sep 17 00:00:00 2001 From: "Khaled Y.M" Date: Wed, 6 Oct 2021 19:52:15 +0100 Subject: [PATCH 2/2] Update some dependencies --- pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index a96d41c3..00a13677 100644 --- a/pom.xml +++ b/pom.xml @@ -50,17 +50,17 @@ 2.12.3 2.7.4 13.0 - 3.12.0 + 3.16.0 3.12.0 1.7 1.4 1.3.0.Final - 1.62 + 1.68 0.9.12 - 4.2.3 + 5.0.0 3.0.12 - 3.9.4 - 4.9.0 + 3.9.7 + 4.9.1 5.1.4 2.2 0.9.0