webauthn registerCredential returns transports
The webauthn support previously did not pass the transports to webauthn4j. This meant that the result of Webauthn4jRelyingPartyOperations.registerCredential did not have any transports either. This commit ensures that the transports are passed to the webauth4j lib and then returned in the result of registerCredential. Closes gh-16084
This commit is contained in:
		
							parent
							
								
									cc2506b0c1
								
							
						
					
					
						commit
						9c3b11914d
					
				| 
						 | 
				
			
			@ -20,6 +20,7 @@ import java.time.Duration;
 | 
			
		|||
import java.time.Instant;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
| 
						 | 
				
			
			@ -254,7 +255,9 @@ public class Webauthn4JRelyingPartyOperations implements WebAuthnRelyingPartyOpe
 | 
			
		|||
		boolean userPresenceRequired = true;
 | 
			
		||||
		List<com.webauthn4j.data.PublicKeyCredentialParameters> pubKeyCredParams = convertCredentialParamsToWebauthn4j(
 | 
			
		||||
				creationOptions.getPubKeyCredParams());
 | 
			
		||||
		RegistrationRequest webauthn4jRegistrationRequest = new RegistrationRequest(attestationObject, clientDataJSON);
 | 
			
		||||
		Set<String> transports = convertTransportsToString(response);
 | 
			
		||||
		RegistrationRequest webauthn4jRegistrationRequest = new RegistrationRequest(attestationObject, clientDataJSON,
 | 
			
		||||
				transports);
 | 
			
		||||
		RegistrationParameters registrationParameters = new RegistrationParameters(serverProperty, pubKeyCredParams,
 | 
			
		||||
				userVerificationRequired, userPresenceRequired);
 | 
			
		||||
		RegistrationData registrationData = this.webAuthnManager.validate(webauthn4jRegistrationRequest,
 | 
			
		||||
| 
						 | 
				
			
			@ -283,6 +286,17 @@ public class Webauthn4JRelyingPartyOperations implements WebAuthnRelyingPartyOpe
 | 
			
		|||
		return userCredential;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static Set<String> convertTransportsToString(AuthenticatorAttestationResponse response) {
 | 
			
		||||
		if (response.getTransports() == null) {
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
		Set<String> transports = new HashSet<>(response.getTransports().size());
 | 
			
		||||
		for (AuthenticatorTransport transport : response.getTransports()) {
 | 
			
		||||
			transports.add(transport.getValue());
 | 
			
		||||
		}
 | 
			
		||||
		return transports;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private List<com.webauthn4j.data.PublicKeyCredentialParameters> convertCredentialParamsToWebauthn4j(
 | 
			
		||||
			List<PublicKeyCredentialParameters> parameters) {
 | 
			
		||||
		return parameters.stream().map(this::convertParamToWebauthn4j).collect(Collectors.toUnmodifiableList());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,7 @@ import org.springframework.security.core.authority.AuthorityUtils;
 | 
			
		|||
import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse;
 | 
			
		||||
import org.springframework.security.web.webauthn.api.AuthenticatorAttestationResponse.AuthenticatorAttestationResponseBuilder;
 | 
			
		||||
import org.springframework.security.web.webauthn.api.AuthenticatorSelectionCriteria;
 | 
			
		||||
import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
 | 
			
		||||
import org.springframework.security.web.webauthn.api.Bytes;
 | 
			
		||||
import org.springframework.security.web.webauthn.api.CredentialRecord;
 | 
			
		||||
import org.springframework.security.web.webauthn.api.PublicKeyCredential;
 | 
			
		||||
| 
						 | 
				
			
			@ -224,6 +225,47 @@ class Webauthn4jRelyingPartyOperationsTests {
 | 
			
		|||
		assertThatIllegalArgumentException().isThrownBy(() -> this.rpOperations.registerCredential(null));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void registerCredentialWhenDefaultTransportsThenSuccess() {
 | 
			
		||||
		PublicKeyCredentialCreationOptions creationOptions = TestPublicKeyCredentialCreationOptions
 | 
			
		||||
			.createPublicKeyCredentialCreationOptions()
 | 
			
		||||
			.build();
 | 
			
		||||
		PublicKeyCredential<AuthenticatorAttestationResponse> publicKeyCredential = TestPublicKeyCredential
 | 
			
		||||
			.createPublicKeyCredential()
 | 
			
		||||
			.build();
 | 
			
		||||
		RelyingPartyPublicKey rpPublicKey = new RelyingPartyPublicKey(publicKeyCredential, this.label);
 | 
			
		||||
 | 
			
		||||
		ImmutableRelyingPartyRegistrationRequest rpRegistrationRequest = new ImmutableRelyingPartyRegistrationRequest(
 | 
			
		||||
				creationOptions, rpPublicKey);
 | 
			
		||||
		CredentialRecord credentialRecord = this.rpOperations.registerCredential(rpRegistrationRequest);
 | 
			
		||||
		assertThat(credentialRecord).isNotNull();
 | 
			
		||||
		assertThat(credentialRecord.getCredentialId()).isNotNull();
 | 
			
		||||
		assertThat(credentialRecord.getTransports()).containsExactlyInAnyOrder(AuthenticatorTransport.INTERNAL,
 | 
			
		||||
				AuthenticatorTransport.HYBRID);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void registerCredentialWhenInternalTransportThenCredentialRecordHasTransport() {
 | 
			
		||||
		PublicKeyCredentialCreationOptions creationOptions = TestPublicKeyCredentialCreationOptions
 | 
			
		||||
			.createPublicKeyCredentialCreationOptions()
 | 
			
		||||
			.build();
 | 
			
		||||
		AuthenticatorAttestationResponse response = TestAuthenticatorAttestationResponse
 | 
			
		||||
			.createAuthenticatorAttestationResponse()
 | 
			
		||||
			.transports(AuthenticatorTransport.INTERNAL)
 | 
			
		||||
			.build();
 | 
			
		||||
		PublicKeyCredential<AuthenticatorAttestationResponse> publicKeyCredential = TestPublicKeyCredential
 | 
			
		||||
			.createPublicKeyCredential()
 | 
			
		||||
			.response(response)
 | 
			
		||||
			.build();
 | 
			
		||||
		RelyingPartyPublicKey rpPublicKey = new RelyingPartyPublicKey(publicKeyCredential, this.label);
 | 
			
		||||
 | 
			
		||||
		ImmutableRelyingPartyRegistrationRequest rpRegistrationRequest = new ImmutableRelyingPartyRegistrationRequest(
 | 
			
		||||
				creationOptions, rpPublicKey);
 | 
			
		||||
		CredentialRecord credentialRecord = this.rpOperations.registerCredential(rpRegistrationRequest);
 | 
			
		||||
		assertThat(credentialRecord).isNotNull();
 | 
			
		||||
		assertThat(credentialRecord.getTransports()).containsExactlyInAnyOrder(AuthenticatorTransport.INTERNAL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void registerCredentialWhenExistsThenException() {
 | 
			
		||||
		PublicKeyCredentialCreationOptions creationOptions = TestPublicKeyCredentialCreationOptions
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue