diff --git a/core/src/main/java/de/bstly/we/security/LocalAuthenticationProvider.java b/core/src/main/java/de/bstly/we/security/LocalAuthenticationProvider.java
index 0f2338d..c0c7380 100755
--- a/core/src/main/java/de/bstly/we/security/LocalAuthenticationProvider.java
+++ b/core/src/main/java/de/bstly/we/security/LocalAuthenticationProvider.java
@@ -86,8 +86,7 @@ public class LocalAuthenticationProvider extends DaoAuthenticationProvider imple
} else {
for (AdditionalAuthenticationProvider> provider : providers) {
if (provider.supports(auth.getClass())) {
- auth = provider.authenticate(auth);
- return this.secondFactorCheck(auth);
+ return provider.authenticate(auth);
}
}
}
diff --git a/pom.xml b/pom.xml
index 620d894..4cc0b91 100755
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
2.2
1.14.1
3.6.3
- 4.0.0
+ 4.0.1
diff --git a/webauthn/src/main/java/de/bstly/we/webauthn/businesslogic/WebAuthnManager.java b/webauthn/src/main/java/de/bstly/we/webauthn/businesslogic/WebAuthnManager.java
index 7164d87..458dc5a 100644
--- a/webauthn/src/main/java/de/bstly/we/webauthn/businesslogic/WebAuthnManager.java
+++ b/webauthn/src/main/java/de/bstly/we/webauthn/businesslogic/WebAuthnManager.java
@@ -253,12 +253,6 @@ public class WebAuthnManager implements UserDataProvider {
}
}
- /**
- * Creates a WebAuthn login request that does not depend on the username.
- *
- * This avoids username enumeration and allows resolving the user from the
- * returned credentialId during the finish step.
- */
public String createLoginRequest() {
try {
StartAssertionOptions.StartAssertionOptionsBuilder optionsBuilder = StartAssertionOptions.builder()
@@ -281,21 +275,14 @@ public class WebAuthnManager implements UserDataProvider {
}
}
- /**
- * Validates a WebAuthn login assertion where the user is resolved from the
- * credentialId contained in the assertion.
- *
- * @return the authenticated userId if successful, otherwise empty.
- */
public Optional validateLoginRequest(String assertionJson) {
try {
JsonNode assertionNode = objectMapper.readTree(assertionJson);
PublicKeyCredential pkc = PublicKeyCredential
.parseAssertionResponseJson(assertionJson);
-
- ByteArray credentialId = pkc.getId();
- WebAuthnCredential credential = credentialRepository.findByCredentialId(credentialId.getBase64Url());
- if (credential == null || !credential.isEnabled() || credential.getUsage() != WebAuthnUsage.LOGIN) {
+ WebAuthnCredential credential = credentialRepository.findByCredentialId(pkc.getId().getBase64Url());
+ if (credential == null || !credential.isEnabled() || credential.getUsage() != WebAuthnUsage.LOGIN
+ && credential.getUsage() != WebAuthnUsage.LOGIN_2FA) {
return Optional.empty();
}
@@ -337,12 +324,9 @@ public class WebAuthnManager implements UserDataProvider {
PublicKeyCredential pkc = PublicKeyCredential
.parseAssertionResponseJson(assertionJson);
+ WebAuthnCredential credential = credentialRepository.findByCredentialId(pkc.getId().getBase64Url());
- ByteArray credentialId = pkc.getId();
- WebAuthnCredential credential = credentialRepository.findByCredentialId(credentialId.getBase64Url());
-
- if (credential == null || !credential.isEnabled()
- || (credential.getUsage() != usage)) {
+ if (credential == null || !credential.isEnabled() || (credential.getUsage() != usage)) {
return false;
}
@@ -382,6 +366,16 @@ public class WebAuthnManager implements UserDataProvider {
return false;
}
+ public WebAuthnCredential getCredentialForAssertionJson(String assertionJson) {
+ try {
+ PublicKeyCredential pkc = PublicKeyCredential
+ .parseAssertionResponseJson(assertionJson);
+ return credentialRepository.findByCredentialId(pkc.getId().getBase64Url());
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
public ByteArray getUserHandle(Long userId) {
WebAuthnUserHandle webAuthnUserHandle = webAuthnUserHandleRepository.findByTarget(userId);
diff --git a/webauthn/src/main/java/de/bstly/we/webauthn/model/WebAuthnUsage.java b/webauthn/src/main/java/de/bstly/we/webauthn/model/WebAuthnUsage.java
index 853f97f..b854a71 100644
--- a/webauthn/src/main/java/de/bstly/we/webauthn/model/WebAuthnUsage.java
+++ b/webauthn/src/main/java/de/bstly/we/webauthn/model/WebAuthnUsage.java
@@ -1,5 +1,5 @@
package de.bstly.we.webauthn.model;
public enum WebAuthnUsage {
- NONE, TWO_FA, LOGIN
+ NONE, TWO_FA, LOGIN, LOGIN_2FA
}
diff --git a/webauthn/src/main/java/de/bstly/we/webauthn/security/WebAuthnAuthenticationProvider.java b/webauthn/src/main/java/de/bstly/we/webauthn/security/WebAuthnAuthenticationProvider.java
index 67d3881..fdc02b3 100644
--- a/webauthn/src/main/java/de/bstly/we/webauthn/security/WebAuthnAuthenticationProvider.java
+++ b/webauthn/src/main/java/de/bstly/we/webauthn/security/WebAuthnAuthenticationProvider.java
@@ -8,14 +8,19 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;
import de.bstly.we.businesslogic.UserManager;
import de.bstly.we.model.User;
import de.bstly.we.security.LocalUserDetailsService;
import de.bstly.we.security.businesslogic.AdditionalAuthenticationProvider;
+import de.bstly.we.security.businesslogic.SecondFactorProviderManager;
import de.bstly.we.webauthn.businesslogic.WebAuthnManager;
+import de.bstly.we.webauthn.model.WebAuthnCredential;
+import de.bstly.we.webauthn.model.WebAuthnUsage;
@Component
public class WebAuthnAuthenticationProvider implements AdditionalAuthenticationProvider {
@@ -26,6 +31,8 @@ public class WebAuthnAuthenticationProvider implements AdditionalAuthenticationP
private LocalUserDetailsService userDetailsService;
@Autowired
private WebAuthnManager webAuthnManager;
+ @Autowired
+ private SecondFactorProviderManager secondFactorProviderManager;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
@@ -48,6 +55,26 @@ public class WebAuthnAuthenticationProvider implements AdditionalAuthenticationP
UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUsername());
List authorities = List.copyOf(userDetails.getAuthorities());
+
+ WebAuthnCredential credential = webAuthnManager.getCredentialForAssertionJson(assertionJson);
+
+ if (credential == null) {
+ throw new BadCredentialsException("User not authenticated");
+ }
+
+ if (credential.getUsage() != WebAuthnUsage.LOGIN
+ && credential.getUsage() != WebAuthnUsage.LOGIN_2FA) {
+ throw new BadCredentialsException("User not authenticated");
+ }
+
+ if (credential.getUsage() != WebAuthnUsage.LOGIN_2FA
+ && !secondFactorProviderManager.getEnabled(userId).isEmpty()) {
+ PreAuthenticatedAuthenticationToken newAuth = new PreAuthenticatedAuthenticationToken(userDetails, "",
+ AuthorityUtils.createAuthorityList("ROLE_PRE_AUTH_USER"));
+ newAuth.setAuthenticated(false);
+ return newAuth;
+ }
+
return new UsernamePasswordAuthenticationToken(userDetails, assertionJson, authorities);
}