28
28
29
29
asab .Config .add_defaults ({
30
30
"seacatauth:webauthn" : {
31
- "attestation" : "direct"
31
+ "attestation" : "direct" ,
32
+
33
+ # Authenticator metadata source file, for details see https://fidoalliance.org/metadata
34
+ # Possible values:
35
+ # - HTTPS or HTTP address of a JWT MDS file (defaults to "https://mds3.fidoalliance.org")
36
+ # - Relative or absolute path of a JWT MDS file
37
+ # - Empty value or "DISABLED" (disables the metadata service)
38
+ "metadata_service_url" : "https://mds3.fidoalliance.org" ,
32
39
}
33
40
})
34
41
@@ -37,7 +44,6 @@ class WebAuthnService(asab.Service):
37
44
WebAuthnCredentialCollection = "wa"
38
45
WebAuthnRegistrationChallengeCollection = "warc"
39
46
FidoMetadataServiceCollection = "fms"
40
- FidoMetadataServiceUrl = "https://mds3.fidoalliance.org"
41
47
42
48
def __init__ (self , app , service_name = "seacatauth.WebAuthnService" ):
43
49
super ().__init__ (app , service_name )
@@ -69,41 +75,54 @@ def __init__(self, app, service_name="seacatauth.WebAuthnService"):
69
75
webauthn .helpers .structs .COSEAlgorithmIdentifier (- 7 ) # Es256
70
76
]
71
77
78
+ self .FidoMetadataServiceUrl = asab .Config .get ("seacatauth:webauthn" , "metadata_service_url" )
79
+ if self .FidoMetadataServiceUrl in ("" , "DISABLED" ):
80
+ self .FidoMetadataServiceUrl = None
72
81
self ._FidoMetadataByAAGUID : typing .Dict [int , dict ] | None = None
73
82
74
83
app .PubSub .subscribe ("Application.housekeeping!" , self ._on_housekeeping )
75
84
76
85
77
86
async def initialize (self , app ):
78
- await self ._load_fido_metadata ()
87
+ try :
88
+ await self ._load_fido_metadata ()
89
+ except Exception as e :
90
+ L .exception ("Failed to fetch FIDO Alliance Metadata ({}: {})" .format (e .__class__ .__name__ , e ))
79
91
80
92
81
93
async def _on_housekeeping (self , event_name ):
82
94
await self ._delete_expired_challenges ()
83
- await self ._load_fido_metadata (only_if_empty = False )
95
+ try :
96
+ await self ._load_fido_metadata (force_reload = True )
97
+ except Exception as e :
98
+ L .info ("Failed to fetch FIDO Alliance Metadata: {}" .format (e ))
84
99
85
100
86
- async def _load_fido_metadata (self , only_if_empty = True ):
101
+ async def _load_fido_metadata (self , * , force_reload : bool = False ):
87
102
"""
88
103
Download and decode FIDO metadata from FIDO Alliance Metadata Service (MDS) and prepare a lookup dictionary.
89
104
"""
90
- if only_if_empty :
105
+ if not self .FidoMetadataServiceUrl :
106
+ return
107
+
108
+ if not force_reload :
91
109
coll = await self .StorageService .collection (self .FidoMetadataServiceCollection )
92
110
count = await coll .estimated_document_count ()
93
111
if count > 0 :
94
112
return
95
113
96
- try :
114
+ if self . FidoMetadataServiceUrl . startswith ( "https://" ) or self . FidoMetadataServiceUrl . startswith ( "http://" ) :
97
115
async with aiohttp .ClientSession () as session :
98
116
async with session .get (self .FidoMetadataServiceUrl ) as resp :
99
117
if resp .status != 200 :
100
118
text = await resp .text ()
101
119
L .error ("Failed to fetch FIDO metadata:\n {}" .format (text [:1000 ]))
102
120
return
103
121
jwt = await resp .text ()
104
- except ConnectionError :
105
- L .error ("Cannot connect to FIDO Alliance Metadata Service." )
106
- return
122
+ else :
123
+ # Load from local file
124
+ with open (self .FidoMetadataServiceUrl ) as f :
125
+ jwt = f .read ()
107
126
108
127
jwt = jwcrypto .jwt .JWT (jwt = jwt )
109
128
cert_chain = jwt .token .jose_header .get ("x5c" , [])
@@ -179,7 +198,11 @@ async def create_webauthn_credential(
179
198
L .log (asab .LOG_NOTICE , "WebAuthn credential created" , struct_data = {"wacid" : wacid .hex ()})
180
199
181
200
async def _get_authenticator_metadata (self , verified_registration ):
182
- await self ._load_fido_metadata ()
201
+ try :
202
+ await self ._load_fido_metadata ()
203
+ except Exception as e :
204
+ L .info ("Failed to fetch FIDO Alliance Metadata: {}" .format (e ))
205
+
183
206
aaguid = bytes .fromhex (verified_registration .aaguid .replace ("-" , "" ))
184
207
if aaguid == 0 :
185
208
# Authenticators with other identifiers than AAGUID are not supported
0 commit comments