mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-22 12:02:14 +00:00
Merge branch '6.4.x'
- Fix WebAuthn saves Anonymous PublicKeyCredentialUserEntity Closes gh-16821
This commit is contained in:
commit
491d28b6bb
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -333,9 +333,7 @@ public class Webauthn4JRelyingPartyOperations implements WebAuthnRelyingPartyOpe
|
|||||||
public PublicKeyCredentialRequestOptions createCredentialRequestOptions(
|
public PublicKeyCredentialRequestOptions createCredentialRequestOptions(
|
||||||
PublicKeyCredentialRequestOptionsRequest request) {
|
PublicKeyCredentialRequestOptionsRequest request) {
|
||||||
Authentication authentication = request.getAuthentication();
|
Authentication authentication = request.getAuthentication();
|
||||||
// FIXME: do not load credentialRecords if anonymous
|
List<CredentialRecord> credentialRecords = findCredentialRecords(authentication);
|
||||||
PublicKeyCredentialUserEntity userEntity = findUserEntityOrCreateAndSave(authentication.getName());
|
|
||||||
List<CredentialRecord> credentialRecords = this.userCredentials.findByUserId(userEntity.getId());
|
|
||||||
return PublicKeyCredentialRequestOptions.builder()
|
return PublicKeyCredentialRequestOptions.builder()
|
||||||
.allowCredentials(credentialDescriptors(credentialRecords))
|
.allowCredentials(credentialDescriptors(credentialRecords))
|
||||||
.challenge(Bytes.random())
|
.challenge(Bytes.random())
|
||||||
@ -346,6 +344,17 @@ public class Webauthn4JRelyingPartyOperations implements WebAuthnRelyingPartyOpe
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<CredentialRecord> findCredentialRecords(Authentication authentication) {
|
||||||
|
if (!this.trustResolver.isAuthenticated(authentication)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
PublicKeyCredentialUserEntity userEntity = this.userEntities.findByUsername(authentication.getName());
|
||||||
|
if (userEntity == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return this.userCredentials.findByUserId(userEntity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PublicKeyCredentialUserEntity authenticate(RelyingPartyAuthenticationRequest request) {
|
public PublicKeyCredentialUserEntity authenticate(RelyingPartyAuthenticationRequest request) {
|
||||||
PublicKeyCredentialRequestOptions requestOptions = request.getRequestOptions();
|
PublicKeyCredentialRequestOptions requestOptions = request.getRequestOptions();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2024 the original author or authors.
|
* Copyright 2002-2025 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -42,6 +42,8 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
|||||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
|
import org.springframework.security.core.userdetails.PasswordEncodedUser;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse;
|
import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse;
|
||||||
import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse.AuthenticatorAttestationResponseBuilder;
|
import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse.AuthenticatorAttestationResponseBuilder;
|
||||||
import org.springframework.security.web.webauthn.api.AuthenticatorSelectionCriteria;
|
import org.springframework.security.web.webauthn.api.AuthenticatorSelectionCriteria;
|
||||||
@ -66,6 +68,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
import static org.assertj.core.api.Assertions.assertThatRuntimeException;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
class Webauthn4jRelyingPartyOperationsTests {
|
class Webauthn4jRelyingPartyOperationsTests {
|
||||||
@ -536,6 +539,50 @@ class Webauthn4jRelyingPartyOperationsTests {
|
|||||||
.isEqualTo(creationOptions.getAuthenticatorSelection().getUserVerification());
|
.isEqualTo(creationOptions.getAuthenticatorSelection().getUserVerification());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createCredentialRequestOptionsWhenAnonymousAuthentication() {
|
||||||
|
AnonymousAuthenticationToken authentication = new AnonymousAuthenticationToken("key", "anonymousUser",
|
||||||
|
Set.of(() -> "ROLE_ANONYMOUS"));
|
||||||
|
PublicKeyCredentialRequestOptionsRequest createRequest = new ImmutablePublicKeyCredentialRequestOptionsRequest(
|
||||||
|
authentication);
|
||||||
|
PublicKeyCredentialRequestOptions credentialRequestOptions = this.rpOperations
|
||||||
|
.createCredentialRequestOptions(createRequest);
|
||||||
|
|
||||||
|
assertThat(credentialRequestOptions.getAllowCredentials()).isEmpty();
|
||||||
|
// verify anonymous user not saved
|
||||||
|
verifyNoInteractions(this.userEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createCredentialRequestOptionsWhenNullAuthentication() {
|
||||||
|
PublicKeyCredentialRequestOptionsRequest createRequest = new ImmutablePublicKeyCredentialRequestOptionsRequest(
|
||||||
|
null);
|
||||||
|
PublicKeyCredentialRequestOptions credentialRequestOptions = this.rpOperations
|
||||||
|
.createCredentialRequestOptions(createRequest);
|
||||||
|
|
||||||
|
assertThat(credentialRequestOptions.getAllowCredentials()).isEmpty();
|
||||||
|
// verify anonymous user not saved
|
||||||
|
verifyNoInteractions(this.userEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createCredentialRequestOptionsWhenAuthenticated() {
|
||||||
|
UserDetails user = PasswordEncodedUser.user();
|
||||||
|
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, null,
|
||||||
|
user.getAuthorities());
|
||||||
|
PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity().build();
|
||||||
|
CredentialRecord credentialRecord = TestCredentialRecord.userCredential().build();
|
||||||
|
given(this.userEntities.findByUsername(user.getUsername())).willReturn(userEntity);
|
||||||
|
given(this.userCredentials.findByUserId(userEntity.getId())).willReturn(Arrays.asList(credentialRecord));
|
||||||
|
PublicKeyCredentialRequestOptionsRequest createRequest = new ImmutablePublicKeyCredentialRequestOptionsRequest(
|
||||||
|
auth);
|
||||||
|
PublicKeyCredentialRequestOptions credentialRequestOptions = this.rpOperations
|
||||||
|
.createCredentialRequestOptions(createRequest);
|
||||||
|
|
||||||
|
assertThat(credentialRequestOptions.getAllowCredentials()).extracting(PublicKeyCredentialDescriptor::getId)
|
||||||
|
.containsExactly(credentialRecord.getCredentialId());
|
||||||
|
}
|
||||||
|
|
||||||
private static AuthenticatorAttestationResponse setFlag(byte... flags) throws Exception {
|
private static AuthenticatorAttestationResponse setFlag(byte... flags) throws Exception {
|
||||||
AuthenticatorAttestationResponseBuilder authAttResponseBldr = TestAuthenticatorAttestationResponse
|
AuthenticatorAttestationResponseBuilder authAttResponseBldr = TestAuthenticatorAttestationResponse
|
||||||
.createAuthenticatorAttestationResponse();
|
.createAuthenticatorAttestationResponse();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user