mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-07-16 19:30:13 -04:00
Handle errors when registration fails
Previously we would raise a 500 error in a variety of cases: - If a second key was being registered simultaneously (e.g. in a separate tab), which means the registration state could be missing after the first registration completes. That smells like an attack. - If the server-side verification failed e.g. origin verification, challenge verification, etc. The library seems to use 'ValueError' for all such errors [1] (after auditing its 'raise' statements, and excluding AttestationError [2], since we're not doing that). - If a key is used that attempts to sign with an unsupported algorithm. This would normally raise a NotImplemented error as part of verifying attestation [3], but we don't do that, so we need to verify the algorithm is supported by the library manually. This adds error handling to return a 400 response and error message in these cases, since the error is not unexpected (i.e. not a 500). A 400 seems more appropriate than a 403, since in many cases it's not clear if the request data is valid. I've used CBOR for the transport encoding, to match the successful request / response encoding. Note that the ordering of then/catch matters in JS - we don't want to catch our own throws! [1]:142587b3e6/fido2/server.py (L255)[2]:c42d9628a4/fido2/attestation/base.py (L39)[3]:c42d9628a4/fido2/cose.py (L92)
This commit is contained in:
@@ -98,9 +98,10 @@ describe('Register security key', () => {
|
||||
})
|
||||
|
||||
test.each([
|
||||
['network'],
|
||||
['server'],
|
||||
])('alerts if sending WebAuthn credentials fails (%s error)', (errorType, done) => {
|
||||
['network error'],
|
||||
['internal server error'],
|
||||
['bad request'],
|
||||
])('alerts if sending WebAuthn credentials fails (%s)', (errorType, done) => {
|
||||
jest.spyOn(window.navigator.credentials, 'create').mockImplementation(() => {
|
||||
// fake PublicKeyCredential response from WebAuthn API
|
||||
return Promise.resolve({ response: {} })
|
||||
@@ -117,10 +118,15 @@ describe('Register security key', () => {
|
||||
|
||||
// subsequent POST of credential data to server
|
||||
} else {
|
||||
if (errorType == 'network') {
|
||||
return Promise.reject('error')
|
||||
} else {
|
||||
return Promise.resolve({ ok: false, statusText: 'error' })
|
||||
switch (errorType) {
|
||||
case 'network error':
|
||||
return Promise.reject('error')
|
||||
case 'bad request':
|
||||
message = Promise.resolve(window.CBOR.encode('error'))
|
||||
return Promise.resolve({ ok: false, arrayBuffer: () => message })
|
||||
case 'internal server error':
|
||||
message = Promise.reject('encoding error')
|
||||
return Promise.resolve({ ok: false, arrayBuffer: () => message, statusText: 'error' })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user