Skip to content

Commit 6a3c8e4

Browse files
Add more missing mixins and deserializers
1 parent ec2a416 commit 6a3c8e4

9 files changed

+95
-44
lines changed

web/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputDeserializer.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,8 @@ class AuthenticationExtensionsClientInputDeserializer extends StdDeserializer<Au
4040

4141
@Override
4242
public AuthenticationExtensionsClientInput deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
43-
// if (parser.currentToken() != JsonToken.START_OBJECT) {
44-
// ctxt.reportInputMismatch(this, "Expected START_OBJECT token");
45-
// }
46-
//
4743
while (parser.nextToken() != JsonToken.END_OBJECT) {
4844
String extensionId = parser.currentName();
49-
parser.nextToken();
50-
5145
Object value = parser.readValueAs(Object.class);
5246
return new ImmutableAuthenticationExtensionsClientInput(extensionId, value);
5347
}

web/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticationExtensionsClientInputsDeserializer.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@ class AuthenticationExtensionsClientInputsDeserializer extends StdDeserializer<A
4545

4646
@Override
4747
public AuthenticationExtensionsClientInputs deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
48-
// if (p.currentToken() != JsonToken.START_OBJECT) {
49-
// ctxt.reportInputMismatch(this, "Expected START_OBJECT token for AuthenticationExtensionsClientInputs");
50-
// }
51-
//
5248
final AuthenticationExtensionsClientInputDeserializer authenticationExtensionsClientInputDeserializer = new AuthenticationExtensionsClientInputDeserializer();
5349

5450
final List<AuthenticationExtensionsClientInput> extensions = new ArrayList<>();

web/src/main/java/org/springframework/security/web/webauthn/jackson/AuthenticatorSelectionCriteriaDeserializer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ public AuthenticatorSelectionCriteria deserialize(JsonParser parser, Deserializa
5151
if ("authenticatorAttachment".equals(fieldName)) {
5252
parser.nextToken(); // Move to value
5353
builder.authenticatorAttachment(AuthenticatorAttachment.valueOf(parser.getText()));
54-
} else if ("requireResidentKey".equals(fieldName)) {
54+
} else if ("residentKey".equals(fieldName)) {
5555
parser.nextToken(); // Move to value
5656
builder.residentKey(ResidentKeyRequirement.valueOf(parser.getText()));
5757
} else if ("userVerification".equals(fieldName)) {
5858
parser.nextToken(); // Move to value
5959
builder.userVerification(UserVerificationRequirement.valueOf(parser.getText()));
6060
} else {
61-
parser.skipChildren(); // Ignore unknown fields
61+
throw new IOException("Unsupported field name: " + fieldName);
6262
}
6363
}
6464
return builder.build();

web/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialDescriptorDeserializer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public PublicKeyCredentialDescriptor deserialize(JsonParser p, DeserializationCo
4343
}
4444
builder.transports(transports.toArray(new AuthenticatorTransport[0]));
4545
} else {
46-
p.skipChildren();
46+
throw new IOException("Unsupported field name: " + fieldName);
4747
}
4848
}
4949

web/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialParametersDeserializer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public PublicKeyCredentialParameters deserialize(JsonParser p, DeserializationCo
2929
p.nextToken();
3030
alg = COSEAlgorithmIdentifier.valueOf(p.getLongValue());
3131
} else {
32-
p.skipChildren();
32+
throw new IOException("Unsupported field name: " + fieldName);
3333
}
3434
}
3535

web/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialRequestOptionsDeserializer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public PublicKeyCredentialRequestOptions deserialize(JsonParser parser, Deserial
7474
parser.nextToken();
7575
builder.extensions(parser.readValueAs(AuthenticationExtensionsClientInputs.class));
7676
} else {
77-
parser.skipChildren();
77+
throw new IOException("Unsupported field name: " + fieldName);
7878
}
7979
}
8080

web/src/main/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialUserEntityDeserializer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public PublicKeyCredentialUserEntity deserialize(JsonParser p, DeserializationCo
3333
p.nextToken();
3434
builder.displayName(p.getText());
3535
} else {
36-
p.skipChildren();
36+
throw new IOException("Unsupported field name: " + fieldName);
3737
}
3838
}
3939

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.springframework.security.web.webauthn.jackson;
22

33
import org.springframework.security.web.webauthn.api.AttestationConveyancePreference;
4+
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInput;
45
import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
56
import org.springframework.security.web.webauthn.api.AuthenticatorSelectionCriteria;
67
import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
@@ -19,7 +20,6 @@
1920
import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
2021

2122
import java.time.Duration;
22-
import java.util.Collections;
2323
import java.util.List;
2424
import java.util.Set;
2525

@@ -31,30 +31,102 @@
3131
*/
3232
public final class PublicKeyCredentialCreationOptionsGivens {
3333
private PublicKeyCredentialCreationOptionsGivens() {}
34+
3435
public static PublicKeyCredentialCreationOptions create() {
3536
return PublicKeyCredentialCreationOptions.builder()
36-
.rp(PublicKeyCredentialRpEntity.builder().id("example.com").name("Example RP").build())
37-
.user(ImmutablePublicKeyCredentialUserEntity.builder().name("name").id(Bytes.random()).displayName("displayName").build())
37+
.rp(
38+
PublicKeyCredentialRpEntity.builder()
39+
.id("example.com")
40+
.name("Example RP")
41+
.build()
42+
)
43+
.user(
44+
ImmutablePublicKeyCredentialUserEntity.builder()
45+
.name("name")
46+
.id(Bytes.random())
47+
.displayName("displayName")
48+
.build()
49+
)
3850
.challenge(Bytes.random())
39-
.pubKeyCredParams(List.of(PublicKeyCredentialParameters.ES384, PublicKeyCredentialParameters.EdDSA, PublicKeyCredentialParameters.RS512))
51+
.pubKeyCredParams(
52+
List.of(
53+
PublicKeyCredentialParameters.EdDSA,
54+
PublicKeyCredentialParameters.ES256,
55+
PublicKeyCredentialParameters.ES384,
56+
PublicKeyCredentialParameters.ES512,
57+
PublicKeyCredentialParameters.RS256,
58+
PublicKeyCredentialParameters.RS384,
59+
PublicKeyCredentialParameters.RS512,
60+
PublicKeyCredentialParameters.RS1
61+
)
62+
)
4063
.timeout(Duration.ofSeconds(60))
41-
.excludeCredentials(Collections.singletonList(
42-
PublicKeyCredentialDescriptor.builder()
43-
.id(Bytes.random())
44-
.type(PublicKeyCredentialType.PUBLIC_KEY)
45-
.transports(Set.of(AuthenticatorTransport.INTERNAL, AuthenticatorTransport.HYBRID))
64+
.excludeCredentials(
65+
List.of(
66+
PublicKeyCredentialDescriptor.builder()
67+
.id(Bytes.random())
68+
.type(PublicKeyCredentialType.PUBLIC_KEY)
69+
.transports(Set.of(AuthenticatorTransport.USB))
70+
.build(),
71+
PublicKeyCredentialDescriptor.builder()
72+
.id(Bytes.random())
73+
.type(PublicKeyCredentialType.PUBLIC_KEY)
74+
.transports(Set.of(AuthenticatorTransport.NFC))
75+
.build(),
76+
PublicKeyCredentialDescriptor.builder()
77+
.id(Bytes.random())
78+
.type(PublicKeyCredentialType.PUBLIC_KEY)
79+
.transports(Set.of(AuthenticatorTransport.BLE))
80+
.build(),
81+
PublicKeyCredentialDescriptor.builder()
82+
.id(Bytes.random())
83+
.type(PublicKeyCredentialType.PUBLIC_KEY)
84+
.transports(Set.of(AuthenticatorTransport.SMART_CARD))
85+
.build(),
86+
PublicKeyCredentialDescriptor.builder()
87+
.id(Bytes.random())
88+
.type(PublicKeyCredentialType.PUBLIC_KEY)
89+
.transports(Set.of(AuthenticatorTransport.HYBRID))
90+
.build(),
91+
PublicKeyCredentialDescriptor.builder()
92+
.id(Bytes.random())
93+
.type(PublicKeyCredentialType.PUBLIC_KEY)
94+
.transports(Set.of(AuthenticatorTransport.INTERNAL))
95+
.build()
96+
)
97+
)
98+
.authenticatorSelection(
99+
AuthenticatorSelectionCriteria.builder()
100+
.userVerification(UserVerificationRequirement.PREFERRED)
101+
.residentKey(ResidentKeyRequirement.REQUIRED)
102+
.authenticatorAttachment(AuthenticatorAttachment.PLATFORM)
46103
.build()
47-
))
48-
.authenticatorSelection(AuthenticatorSelectionCriteria.builder()
49-
.userVerification(UserVerificationRequirement.PREFERRED)
50-
.residentKey(ResidentKeyRequirement.REQUIRED)
51-
.authenticatorAttachment(AuthenticatorAttachment.PLATFORM)
52-
.build()
53104
)
54105
.attestation(AttestationConveyancePreference.DIRECT)
55106
.extensions(
56-
new ImmutableAuthenticationExtensionsClientInputs(new CredProtectAuthenticationExtensionsClientInput(new CredProtect(ProtectionPolicy.USER_VERIFICATION_REQUIRED, true)))
107+
new ImmutableAuthenticationExtensionsClientInputs(
108+
new CredProtectAuthenticationExtensionsClientInput(new CredProtect(ProtectionPolicy.USER_VERIFICATION_REQUIRED, true)),
109+
new MinPinLengthAuthenticationExtensionsClientInput(true)
110+
)
57111
)
58112
.build();
59113
}
114+
115+
// ImmutableAuthenticationExtensionsClientInputs wraps a List<AuthenticationExtensionsClientInput<T>>.
116+
// Since only CredProtectAuthenticationExtensionsClientInput implements AuthenticationExtensionsClientInput<T>,
117+
// a second class is needed to help test with two extensions.
118+
/**
119+
* Implements <a href=
120+
* "https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#sctn-minpinlength-extension">
121+
* Minimum PIN Length Extension (minPinLength)</a>.
122+
*
123+
* @author Justin Cranford
124+
* @since 6.5
125+
*/
126+
record MinPinLengthAuthenticationExtensionsClientInput(Boolean getInput) implements AuthenticationExtensionsClientInput<Boolean> {
127+
@Override
128+
public String getExtensionId() {
129+
return "minPinLength";
130+
}
131+
}
60132
}

web/src/test/java/org/springframework/security/web/webauthn/jackson/PublicKeyCredentialCreationOptionsTests.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,9 @@ class PublicKeyCredentialCreationOptionsTests {
4040
@BeforeEach
4141
void setup() {
4242
this.mapper = new ObjectMapper();
43-
// this.mapper.enable(SerializationFeature.INDENT_OUTPUT);
43+
this.mapper.enable(SerializationFeature.INDENT_OUTPUT);
4444
// this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
4545
this.mapper.registerModule(new WebauthnJackson2Module());
46-
// this.mapper.addMixIn(
47-
// ImmutablePublicKeyCredentialUserEntity.class,
48-
// PublicKeyCredentialUserEntityMixin.class
49-
// );
50-
// this.mapper.addMixin(PublicKeyCredentialCreationOptions.class, PublicKeyCredentialCreationOptionsMixin.class);
51-
// this.mapper.addMixin(ImmutablePublicKeyCredentialUserEntity.class, PublicKeyCredentialUserEntityMixin.class);
52-
// this.mapper.addMixin(PublicKeyCredentialUserEntity.class, PublicKeyCredentialUserEntityMixin.class);
53-
// this.mapper.addMixin(PublicKeyCredentialRpEntity.class, PublicKeyCredentialRpEntityMixin.class);
54-
// this.mapper.addMixin(PublicKeyCredentialParameters.class, PublicKeyCredentialParametersMixin.class);
55-
// this.mapper.addMixin(AuthenticatorSelectionCriteria.class, AuthenticatorSelectionCriteriaMixin.class);
56-
//
5746
// this.mapper.addMixin(PublicKeyCredentialRequestOptions.class, PublicKeyCredentialRequestOptionsMixin.class);
5847
// this.mapper.addMixin(ImmutableAuthenticationExtensionsClientInputs.class, AuthenticationExtensionsClientInputsMixin.class);
5948
// this.mapper.addMixin(AuthenticationExtensionsClientInputs.class, AuthenticationExtensionsClientInputsMixin.class);

0 commit comments

Comments
 (0)