Skip to content

Commit 090c909

Browse files
Added client registration and authentication integration tests
1 parent 2999ea1 commit 090c909

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

Tests/WebAuthnTests/WebAuthnManagerIntegrationTests.swift

+138
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,142 @@ final class WebAuthnManagerIntegrationTests: XCTestCase {
160160

161161
// We did it!
162162
}
163+
164+
func testClientRegistrationAndAuthentication() async throws {
165+
let challenge: [UInt8] = [1, 0, 1]
166+
let relyingPartyDisplayName = "Testy test"
167+
let relyingPartyID = "example.com"
168+
let relyingPartyOrigin = "https://example.com"
169+
170+
let server = WebAuthnManager(
171+
configuration: .init(
172+
relyingPartyID: relyingPartyID,
173+
relyingPartyName: relyingPartyDisplayName,
174+
relyingPartyOrigin: relyingPartyOrigin
175+
),
176+
challengeGenerator: .mock(generate: challenge)
177+
)
178+
179+
let client = WebAuthnClient()
180+
let aaguid = AAGUID(uuid: UUID())
181+
let authenticator = KeyPairAuthenticator(attestationGloballyUniqueID: aaguid)
182+
183+
let credentialCreationOptions = server.beginRegistration(user: .init(id: [1, 2, 3], name: "123", displayName: "One Two Three"))
184+
185+
let (registrationCredential, credentialSource) = try await client.createRegistrationCredential(
186+
options: credentialCreationOptions,
187+
origin: relyingPartyOrigin,
188+
authenticator: authenticator
189+
)
190+
191+
XCTAssertEqual(registrationCredential.type, .publicKey)
192+
XCTAssertEqual(registrationCredential.rawID.count, 16)
193+
XCTAssertEqual(registrationCredential.id, registrationCredential.rawID.base64URLEncodedString())
194+
195+
let parsedAttestationResponse = try ParsedAuthenticatorAttestationResponse(from: registrationCredential.attestationResponse)
196+
XCTAssertEqual(parsedAttestationResponse.clientData.type, .create)
197+
XCTAssertEqual(parsedAttestationResponse.clientData.challenge.decodedBytes, [1, 0, 1])
198+
XCTAssertEqual(parsedAttestationResponse.clientData.origin, "https://example.com")
199+
200+
XCTAssertEqual(parsedAttestationResponse.attestationObject.authenticatorData.relyingPartyIDHash, [163, 121, 166, 246, 238, 175, 185, 165, 94, 55, 140, 17, 128, 52, 226, 117, 30, 104, 47, 171, 159, 45, 48, 171, 19, 210, 18, 85, 134, 206, 25, 71])
201+
XCTAssertEqual(parsedAttestationResponse.attestationObject.authenticatorData.flags.bytes, [0b01011101])
202+
XCTAssertEqual(parsedAttestationResponse.attestationObject.authenticatorData.counter, 0)
203+
XCTAssertNotNil(parsedAttestationResponse.attestationObject.authenticatorData.attestedData)
204+
XCTAssertEqual(parsedAttestationResponse.attestationObject.authenticatorData.attestedData?.authenticatorAttestationGUID, AAGUID.anonymous)
205+
XCTAssertEqual(parsedAttestationResponse.attestationObject.authenticatorData.attestedData?.credentialID, credentialSource.id.bytes)
206+
XCTAssertEqual(parsedAttestationResponse.attestationObject.authenticatorData.extData, nil)
207+
208+
let publicKey = try CredentialPublicKey(publicKeyBytes: parsedAttestationResponse.attestationObject.authenticatorData.attestedData?.publicKey ?? [])
209+
if case .ec2(let key) = publicKey {
210+
XCTAssertEqual(key.algorithm, .algES256)
211+
XCTAssertEqual(key.curve, .p256)
212+
XCTAssertEqual(key.xCoordinate.count, 32)
213+
XCTAssertEqual(key.yCoordinate.count, 32)
214+
XCTAssertEqual(key.rawRepresentation, (credentialSource.publicKey as? EC2PublicKey)?.rawRepresentation)
215+
} else {
216+
XCTFail("Unexpected publicKey format")
217+
}
218+
219+
XCTAssertEqual(parsedAttestationResponse.attestationObject.format, .none)
220+
XCTAssertEqual(parsedAttestationResponse.attestationObject.attestationStatement, [:])
221+
222+
XCTAssertEqual(credentialSource.relyingPartyID, "example.com")
223+
XCTAssertEqual(credentialSource.userHandle, [1, 2, 3])
224+
XCTAssertEqual(credentialSource.counter, 0)
225+
if case .es256(let privateKey) = credentialSource.key {
226+
XCTAssertEqual(Array(privateKey.publicKey.rawRepresentation), (credentialSource.publicKey as? EC2PublicKey)?.rawRepresentation)
227+
} else {
228+
XCTFail("Unexpected credentialSource.key format")
229+
}
230+
231+
let registeredCredential = try await server.finishRegistration(
232+
challenge: challenge,
233+
credentialCreationData: registrationCredential
234+
) { credentialID in
235+
XCTAssertEqual(credentialID, credentialSource.id.bytes.base64URLEncodedString().asString())
236+
return true
237+
}
238+
239+
XCTAssertEqual(registeredCredential.type, .publicKey)
240+
XCTAssertEqual(registeredCredential.id, credentialSource.id.bytes.base64EncodedString().asString())
241+
XCTAssertEqual(registeredCredential.publicKey, (credentialSource.publicKey as? EC2PublicKey)?.bytes)
242+
XCTAssertEqual(registeredCredential.signCount, 0)
243+
XCTAssertEqual(registeredCredential.backupEligible, true)
244+
XCTAssertEqual(registeredCredential.isBackedUp, true)
245+
246+
let credentialRequestOptions = try server.beginAuthentication()
247+
248+
XCTAssertEqual(credentialRequestOptions.challenge, [1, 0, 1])
249+
XCTAssertEqual(credentialRequestOptions.timeout, .milliseconds(60000))
250+
XCTAssertEqual(credentialRequestOptions.relyingPartyID, "example.com")
251+
XCTAssertNil(credentialRequestOptions.allowCredentials)
252+
XCTAssertEqual(credentialRequestOptions.userVerification, .preferred)
253+
254+
let (authenticationCredential, updatedCredentialSource) = try await client.assertAuthenticationCredential(
255+
options: credentialRequestOptions,
256+
origin: relyingPartyOrigin,
257+
authenticator: authenticator,
258+
credentialStore: [credentialSource.id : credentialSource]
259+
)
260+
261+
XCTAssertEqual(authenticationCredential.type, .publicKey)
262+
XCTAssertEqual(authenticationCredential.rawID.count, 16)
263+
XCTAssertEqual(authenticationCredential.id, authenticationCredential.rawID.base64URLEncodedString())
264+
XCTAssertEqual(authenticationCredential.authenticatorAttachment, .platform)
265+
266+
let parsedAssertionResponse = try ParsedAuthenticatorAssertionResponse(from: authenticationCredential.response)
267+
XCTAssertEqual(parsedAssertionResponse.clientData.type, .assert)
268+
XCTAssertEqual(parsedAssertionResponse.clientData.challenge.decodedBytes, [1, 0, 1])
269+
XCTAssertEqual(parsedAssertionResponse.clientData.origin, "https://example.com")
270+
271+
XCTAssertEqual(parsedAssertionResponse.authenticatorData.relyingPartyIDHash, [163, 121, 166, 246, 238, 175, 185, 165, 94, 55, 140, 17, 128, 52, 226, 117, 30, 104, 47, 171, 159, 45, 48, 171, 19, 210, 18, 85, 134, 206, 25, 71])
272+
XCTAssertEqual(parsedAssertionResponse.authenticatorData.flags.bytes, [0b00011101])
273+
XCTAssertEqual(parsedAssertionResponse.authenticatorData.counter, 0)
274+
XCTAssertNil(parsedAssertionResponse.authenticatorData.attestedData)
275+
XCTAssertNil(parsedAssertionResponse.authenticatorData.extData)
276+
277+
XCTAssertNotNil(parsedAssertionResponse.signature.decodedBytes)
278+
XCTAssertEqual(parsedAssertionResponse.userHandle, [1, 2, 3])
279+
280+
XCTAssertEqual(credentialSource.id, updatedCredentialSource.id)
281+
XCTAssertEqual(updatedCredentialSource.relyingPartyID, "example.com")
282+
XCTAssertEqual(updatedCredentialSource.userHandle, [1, 2, 3])
283+
XCTAssertEqual(updatedCredentialSource.counter, 0)
284+
if case .es256(let privateKey) = updatedCredentialSource.key {
285+
XCTAssertEqual(Array(privateKey.publicKey.rawRepresentation), (updatedCredentialSource.publicKey as? EC2PublicKey)?.rawRepresentation)
286+
} else {
287+
XCTFail("Unexpected credentialSource.key format")
288+
}
289+
290+
let verifiedAuthentication = try server.finishAuthentication(
291+
credential: authenticationCredential,
292+
expectedChallenge: challenge,
293+
credentialPublicKey: registeredCredential.publicKey, credentialCurrentSignCount: registeredCredential.signCount
294+
)
295+
296+
XCTAssertEqual(verifiedAuthentication.credentialID.urlDecoded.asString(), registeredCredential.id)
297+
XCTAssertEqual(verifiedAuthentication.newSignCount, 0)
298+
XCTAssertEqual(verifiedAuthentication.credentialDeviceType, .multiDevice)
299+
XCTAssertEqual(verifiedAuthentication.credentialBackedUp, true)
300+
}
163301
}

0 commit comments

Comments
 (0)