-
-
Notifications
You must be signed in to change notification settings - Fork 65
Expand file tree
/
Copy pathauthenticator_response.rb
More file actions
137 lines (105 loc) · 3.82 KB
/
authenticator_response.rb
File metadata and controls
137 lines (105 loc) · 3.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# frozen_string_literal: true
require "webauthn/authenticator_data"
require "webauthn/client_data"
require "webauthn/error"
module WebAuthn
TYPES = { create: "webauthn.create", get: "webauthn.get" }.freeze
class VerificationError < Error; end
class AuthenticatorDataVerificationError < VerificationError; end
class ChallengeVerificationError < VerificationError; end
class OriginVerificationError < VerificationError; end
class RpIdVerificationError < VerificationError; end
class TokenBindingVerificationError < VerificationError; end
class TopOriginVerificationError < VerificationError; end
class TypeVerificationError < VerificationError; end
class UserPresenceVerificationError < VerificationError; end
class UserVerifiedVerificationError < VerificationError; end
class AuthenticatorResponse
def initialize(client_data_json:, relying_party: WebAuthn.configuration.relying_party)
@client_data_json = client_data_json
@relying_party = relying_party
end
def verify(expected_challenge, expected_origin = nil, user_presence: nil, user_verification: nil, rp_id: nil)
expected_origin ||= relying_party.allowed_origins || raise("Unspecified expected origin")
rp_id ||= relying_party.id
verify_item(:type)
verify_item(:token_binding)
verify_item(:challenge, expected_challenge)
verify_item(:origin, expected_origin)
verify_item(:top_origin) if needs_top_origin_verification?
verify_item(:authenticator_data)
verify_item(
:rp_id,
rp_id || rp_id_from_origin(expected_origin)
)
# Fallback to RP configuration unless user_presence is passed in explicitely
if user_presence.nil? && !relying_party.silent_authentication || user_presence
verify_item(:user_presence)
end
if user_verification
verify_item(:user_verified)
end
true
end
def valid?(*args, **keyword_arguments)
verify(*args, **keyword_arguments)
rescue WebAuthn::VerificationError
false
end
def client_data
@client_data ||= WebAuthn::ClientData.new(client_data_json)
end
private
attr_reader :client_data_json, :relying_party
def verify_item(item, *args)
if send("valid_#{item}?", *args)
true
else
camelized_item = item.to_s.split('_').map { |w| w.capitalize }.join
error_const_name = "WebAuthn::#{camelized_item}VerificationError"
raise Object.const_get(error_const_name)
end
end
def valid_type?
client_data.type == type
end
def valid_token_binding?
client_data.valid_token_binding_format?
end
def valid_top_origin?
return false unless client_data.cross_origin
relying_party.allowed_top_origins&.include?(client_data.top_origin)
end
def valid_challenge?(expected_challenge)
OpenSSL.secure_compare(client_data.challenge, expected_challenge)
end
def valid_origin?(expected_origin)
return false unless expected_origin
expected_origin.include?(client_data.origin)
end
def valid_rp_id?(rp_id)
return false unless rp_id
OpenSSL::Digest::SHA256.digest(rp_id) == authenticator_data.rp_id_hash
end
def valid_authenticator_data?
authenticator_data.valid?
rescue WebAuthn::AuthenticatorDataFormatError
false
end
def valid_user_presence?
authenticator_data.user_flagged?
end
def valid_user_verified?
authenticator_data.user_verified?
end
def rp_id_from_origin(expected_origin)
URI.parse(expected_origin.first).host if expected_origin.size == 1
end
def type
raise NotImplementedError, "Please define #type method in subclass"
end
def needs_top_origin_verification?
relying_party.verify_top_origin && (client_data.cross_origin || client_data.top_origin)
end
end
end