27
27
from bson .binary import Binary
28
28
from bson .son import SON
29
29
from pymongo .auth_aws import _authenticate_aws
30
+ from pymongo .auth_oidc import _authenticate_oidc , _get_authenticator , _OIDCProperties
30
31
from pymongo .errors import ConfigurationError , OperationFailure
31
32
from pymongo .saslprep import saslprep
32
33
48
49
[
49
50
"GSSAPI" ,
50
51
"MONGODB-CR" ,
52
+ "MONGODB-OIDC" ,
51
53
"MONGODB-X509" ,
52
54
"MONGODB-AWS" ,
53
55
"PLAIN" ,
@@ -101,7 +103,7 @@ def __hash__(self):
101
103
102
104
def _build_credentials_tuple (mech , source , user , passwd , extra , database ):
103
105
"""Build and return a mechanism specific credentials tuple."""
104
- if mech not in ("MONGODB-X509" , "MONGODB-AWS" ) and user is None :
106
+ if mech not in ("MONGODB-X509" , "MONGODB-AWS" , "MONGODB-OIDC" ) and user is None :
105
107
raise ConfigurationError ("%s requires a username." % (mech ,))
106
108
if mech == "GSSAPI" :
107
109
if source is not None and source != "$external" :
@@ -137,6 +139,32 @@ def _build_credentials_tuple(mech, source, user, passwd, extra, database):
137
139
aws_props = _AWSProperties (aws_session_token = aws_session_token )
138
140
# user can be None for temporary link-local EC2 credentials.
139
141
return MongoCredential (mech , "$external" , user , passwd , aws_props , None )
142
+ elif mech == "MONGODB-OIDC" :
143
+ properties = extra .get ("authmechanismproperties" , {})
144
+ request_token_callback = properties .get ("request_token_callback" )
145
+ refresh_token_callback = properties .get ("refresh_token_callback" , None )
146
+ provider_name = properties .get ("PROVIDER_NAME" , "" )
147
+ default_allowed = [
148
+ "*.mongodb.net" ,
149
+ "*.mongodb-dev.net" ,
150
+ "*.mongodbgov.net" ,
151
+ "localhost" ,
152
+ "127.0.0.1" ,
153
+ "::1" ,
154
+ ]
155
+ allowed_hosts = properties .get ("allowed_hosts" , default_allowed )
156
+ if not request_token_callback and provider_name != "aws" :
157
+ raise ConfigurationError (
158
+ "authentication with MONGODB-OIDC requires providing an request_token_callback or a provider_name of 'aws'"
159
+ )
160
+ oidc_props = _OIDCProperties (
161
+ request_token_callback = request_token_callback ,
162
+ refresh_token_callback = refresh_token_callback ,
163
+ provider_name = provider_name ,
164
+ allowed_hosts = allowed_hosts ,
165
+ )
166
+ return MongoCredential (mech , "$external" , user , passwd , oidc_props , None )
167
+
140
168
elif mech == "PLAIN" :
141
169
source_database = source or database or "$external"
142
170
return MongoCredential (mech , source_database , user , passwd , None , None )
@@ -439,7 +467,7 @@ def _authenticate_x509(credentials, sock_info):
439
467
# MONGODB-X509 is done after the speculative auth step.
440
468
return
441
469
442
- cmd = _X509Context (credentials ).speculate_command ()
470
+ cmd = _X509Context (credentials , sock_info . address ).speculate_command ()
443
471
sock_info .command ("$external" , cmd )
444
472
445
473
@@ -482,6 +510,7 @@ def _authenticate_default(credentials, sock_info):
482
510
"MONGODB-CR" : _authenticate_mongo_cr ,
483
511
"MONGODB-X509" : _authenticate_x509 ,
484
512
"MONGODB-AWS" : _authenticate_aws ,
513
+ "MONGODB-OIDC" : _authenticate_oidc ,
485
514
"PLAIN" : _authenticate_plain ,
486
515
"SCRAM-SHA-1" : functools .partial (_authenticate_scram , mechanism = "SCRAM-SHA-1" ),
487
516
"SCRAM-SHA-256" : functools .partial (_authenticate_scram , mechanism = "SCRAM-SHA-256" ),
@@ -490,15 +519,16 @@ def _authenticate_default(credentials, sock_info):
490
519
491
520
492
521
class _AuthContext (object ):
493
- def __init__ (self , credentials ):
522
+ def __init__ (self , credentials , address ):
494
523
self .credentials = credentials
495
524
self .speculative_authenticate = None
525
+ self .address = address
496
526
497
527
@staticmethod
498
- def from_credentials (creds ):
528
+ def from_credentials (creds , address ):
499
529
spec_cls = _SPECULATIVE_AUTH_MAP .get (creds .mechanism )
500
530
if spec_cls :
501
- return spec_cls (creds )
531
+ return spec_cls (creds , address )
502
532
return None
503
533
504
534
def speculate_command (self ):
@@ -512,8 +542,8 @@ def speculate_succeeded(self):
512
542
513
543
514
544
class _ScramContext (_AuthContext ):
515
- def __init__ (self , credentials , mechanism ):
516
- super (_ScramContext , self ).__init__ (credentials )
545
+ def __init__ (self , credentials , address , mechanism ):
546
+ super (_ScramContext , self ).__init__ (credentials , address )
517
547
self .scram_data = None
518
548
self .mechanism = mechanism
519
549
@@ -534,16 +564,30 @@ def speculate_command(self):
534
564
return cmd
535
565
536
566
567
+ class _OIDCContext (_AuthContext ):
568
+ def speculate_command (self ):
569
+ authenticator = _get_authenticator (self .credentials , self .address )
570
+ cmd = authenticator .auth_start_cmd (False )
571
+ if cmd is None :
572
+ return
573
+ cmd ["db" ] = self .credentials .source
574
+ return cmd
575
+
576
+
537
577
_SPECULATIVE_AUTH_MAP : Mapping [str , Callable ] = {
538
578
"MONGODB-X509" : _X509Context ,
539
579
"SCRAM-SHA-1" : functools .partial (_ScramContext , mechanism = "SCRAM-SHA-1" ),
540
580
"SCRAM-SHA-256" : functools .partial (_ScramContext , mechanism = "SCRAM-SHA-256" ),
581
+ "MONGODB-OIDC" : _OIDCContext ,
541
582
"DEFAULT" : functools .partial (_ScramContext , mechanism = "SCRAM-SHA-256" ),
542
583
}
543
584
544
585
545
- def authenticate (credentials , sock_info ):
586
+ def authenticate (credentials , sock_info , reauthenticate = False ):
546
587
"""Authenticate sock_info."""
547
588
mechanism = credentials .mechanism
548
589
auth_func = _AUTH_MAP [mechanism ]
549
- auth_func (credentials , sock_info )
590
+ if mechanism == "MONGODB-OIDC" :
591
+ _authenticate_oidc (credentials , sock_info , reauthenticate )
592
+ else :
593
+ auth_func (credentials , sock_info )
0 commit comments