@@ -31,7 +31,7 @@ use himmelblau::auth::{BrokerClientApplication, UserToken as UnixUserToken};
31
31
use himmelblau:: discovery:: EnrollAttrs ;
32
32
use himmelblau:: error:: { MsalError , DEVICE_AUTH_FAIL } ;
33
33
use himmelblau:: graph:: { DirectoryObject , Graph } ;
34
- use himmelblau:: MFAAuthContinue ;
34
+ use himmelblau:: { AuthOption , MFAAuthContinue } ;
35
35
use idmap:: Idmap ;
36
36
use kanidm_hsm_crypto:: { LoadableIdentityKey , LoadableMsOapxbcRsaKey , PinValue , SealedData , Tpm } ;
37
37
use reqwest;
@@ -362,6 +362,7 @@ impl IdProvider for HimmelblauMultiProvider {
362
362
async fn unix_user_online_auth_step < D : KeyStoreTxn + Send > (
363
363
& self ,
364
364
account_id : & str ,
365
+ service : & str ,
365
366
cred_handler : & mut AuthCredHandler ,
366
367
pam_next_req : PamAuthRequest ,
367
368
keystore : & mut D ,
@@ -377,6 +378,7 @@ impl IdProvider for HimmelblauMultiProvider {
377
378
provider
378
379
. unix_user_online_auth_step (
379
380
account_id,
381
+ service,
380
382
cred_handler,
381
383
pam_next_req,
382
384
keystore,
@@ -835,6 +837,7 @@ impl IdProvider for HimmelblauProvider {
835
837
async fn unix_user_online_auth_step < D : KeyStoreTxn + Send > (
836
838
& self ,
837
839
account_id : & str ,
840
+ service : & str ,
838
841
cred_handler : & mut AuthCredHandler ,
839
842
pam_next_req : PamAuthRequest ,
840
843
keystore : & mut D ,
@@ -1000,14 +1003,17 @@ impl IdProvider for HimmelblauProvider {
1000
1003
// enrolled but creating a new Hello Pin, we follow the same process,
1001
1004
// since only an enrollment token can be exchanged for a PRT (which
1002
1005
// will be needed to enroll the Hello Pin).
1006
+ let mut opts = vec ! [ ] ;
1007
+ // Prohibit Fido over ssh (since it can't work)
1008
+ if service != "ssh" {
1009
+ opts. push ( AuthOption :: Fido ) ;
1010
+ }
1003
1011
let mresp = self
1004
1012
. client
1005
1013
. write ( )
1006
1014
. await
1007
1015
. initiate_acquire_token_by_mfa_flow_for_device_enrollment (
1008
- account_id,
1009
- & cred,
1010
- vec ! [ ] ,
1016
+ account_id, & cred, opts,
1011
1017
)
1012
1018
. await ;
1013
1019
// We need to wait to handle the response until after we've released
@@ -1064,6 +1070,25 @@ impl IdProvider for HimmelblauProvider {
1064
1070
}
1065
1071
} ;
1066
1072
match resp. mfa_method . as_str ( ) {
1073
+ "FidoKey" => {
1074
+ let fido_challenge =
1075
+ resp. fido_challenge . clone ( ) . ok_or ( IdpError :: BadRequest ) ?;
1076
+
1077
+ let fido_allow_list =
1078
+ resp. fido_allow_list . clone ( ) . ok_or ( IdpError :: BadRequest ) ?;
1079
+ * cred_handler = AuthCredHandler :: MFA { flow : resp } ;
1080
+ return Ok ( (
1081
+ AuthResult :: Next ( AuthRequest :: Fido {
1082
+ fido_allow_list,
1083
+ fido_challenge,
1084
+ } ) ,
1085
+ /* An MFA auth cannot cache the password. This would
1086
+ * lead to a potential downgrade to SFA attack (where
1087
+ * the attacker auths with a stolen password, then
1088
+ * disconnects the network to complete the auth). */
1089
+ AuthCacheAction :: None ,
1090
+ ) ) ;
1091
+ }
1067
1092
"PhoneAppOTP" | "OneWaySMS" | "ConsolidatedTelephony" => {
1068
1093
let msg = resp. msg . clone ( ) ;
1069
1094
* cred_handler = AuthCredHandler :: MFA { flow : resp } ;
@@ -1210,6 +1235,47 @@ impl IdProvider for HimmelblauProvider {
1210
1235
Err ( e) => Err ( e) ,
1211
1236
}
1212
1237
}
1238
+ ( AuthCredHandler :: MFA { ref mut flow } , PamAuthRequest :: Fido { assertion } ) => {
1239
+ let token = self
1240
+ . client
1241
+ . write ( )
1242
+ . await
1243
+ . acquire_token_by_mfa_flow ( account_id, Some ( & assertion) , None , flow)
1244
+ . await
1245
+ . map_err ( |e| {
1246
+ error ! ( "{:?}" , e) ;
1247
+ IdpError :: NotFound
1248
+ } ) ?;
1249
+ let token2 = enroll_and_obtain_enrolled_token ! ( token) ;
1250
+ match self . token_validate ( account_id, & token2) . await {
1251
+ Ok ( AuthResult :: Success { token : token3 } ) => {
1252
+ // Skip Hello enrollment if it is disabled by config
1253
+ let hello_enabled = self . config . read ( ) . await . get_enable_hello ( ) ;
1254
+ if !hello_enabled {
1255
+ info ! ( "Skipping Hello enrollment because it is disabled" ) ;
1256
+ return Ok ( (
1257
+ AuthResult :: Success { token : token3 } ,
1258
+ AuthCacheAction :: None ,
1259
+ ) ) ;
1260
+ }
1261
+
1262
+ // Setup Windows Hello
1263
+ * cred_handler = AuthCredHandler :: SetupPin { token } ;
1264
+ return Ok ( (
1265
+ AuthResult :: Next ( AuthRequest :: SetupPin {
1266
+ msg : format ! (
1267
+ "Set up a PIN\n {}{}" ,
1268
+ "A Hello PIN is a fast, secure way to sign" ,
1269
+ "in to your device, apps, and services."
1270
+ ) ,
1271
+ } ) ,
1272
+ AuthCacheAction :: None ,
1273
+ ) ) ;
1274
+ }
1275
+ Ok ( auth_result) => Ok ( ( auth_result, AuthCacheAction :: None ) ) ,
1276
+ Err ( e) => Err ( e) ,
1277
+ }
1278
+ }
1213
1279
_ => {
1214
1280
error ! ( "Unexpected AuthCredHandler and PamAuthRequest pairing" ) ;
1215
1281
Err ( IdpError :: NotFound )
0 commit comments