12
12
import gitlab .config
13
13
import gitlab .const
14
14
import gitlab .exceptions
15
- from gitlab import _backends ,utils
15
+ from gitlab import _backends ,oauth , utils
16
16
17
17
REDIRECT_MSG = (
18
18
"python-gitlab detected a {status_code} ({reason!r}) redirection. You must update "
@@ -41,8 +41,6 @@ class Gitlab:
41
41
the value is a string, it is the path to a CA file used for
42
42
certificate validation.
43
43
timeout: Timeout to use for requests to the GitLab server.
44
- http_username: Username for HTTP authentication
45
- http_password: Password for HTTP authentication
46
44
api_version: Gitlab API version to use (support for 4 only)
47
45
pagination: Can be set to 'keyset' to use keyset pagination
48
46
order_by: Set order_by globally
@@ -51,6 +49,7 @@ class Gitlab:
51
49
or 52x responses. Defaults to False.
52
50
keep_base_url: keep user-provided base URL for pagination if it
53
51
differs from response headers
52
+ oauth_credentials: Password credentials for authenticating via OAuth ROPC flow
54
53
55
54
Keyword Args:
56
55
requests.Session session: HTTP Requests Session
@@ -64,8 +63,6 @@ def __init__(
64
63
oauth_token :Optional [str ]= None ,
65
64
job_token :Optional [str ]= None ,
66
65
ssl_verify :Union [bool ,str ]= True ,
67
- http_username :Optional [str ]= None ,
68
- http_password :Optional [str ]= None ,
69
66
timeout :Optional [float ]= None ,
70
67
api_version :str = "4" ,
71
68
per_page :Optional [int ]= None ,
@@ -74,6 +71,8 @@ def __init__(
74
71
user_agent :str = gitlab .const .USER_AGENT ,
75
72
retry_transient_errors :bool = False ,
76
73
keep_base_url :bool = False ,
74
+ * ,
75
+ oauth_credentials :Optional [oauth .PasswordCredentials ]= None ,
77
76
** kwargs :Any ,
78
77
)-> None :
79
78
self ._api_version = str (api_version )
@@ -92,11 +91,9 @@ def __init__(
92
91
self .ssl_verify = ssl_verify
93
92
94
93
self .private_token = private_token
95
- self .http_username = http_username
96
- self .http_password = http_password
97
94
self .oauth_token = oauth_token
98
95
self .job_token = job_token
99
- self ._set_auth_info ()
96
+ self .oauth_credentials = oauth_credentials
100
97
101
98
#: Create a session object for requests
102
99
_backend :Type [_backends .DefaultBackend ]= kwargs .pop (
@@ -105,6 +102,7 @@ def __init__(
105
102
self ._backend = _backend (** kwargs )
106
103
self .session = self ._backend .client
107
104
105
+ self ._set_auth_info ()
108
106
self .per_page = per_page
109
107
self .pagination = pagination
110
108
self .order_by = order_by
@@ -271,8 +269,6 @@ def from_config(
271
269
job_token = config .job_token ,
272
270
ssl_verify = config .ssl_verify ,
273
271
timeout = config .timeout ,
274
- http_username = config .http_username ,
275
- http_password = config .http_password ,
276
272
api_version = config .api_version ,
277
273
per_page = config .per_page ,
278
274
pagination = config .pagination ,
@@ -471,41 +467,51 @@ def set_license(self, license: str, **kwargs: Any) -> Dict[str, Any]:
471
467
return result
472
468
473
469
def _set_auth_info (self )-> None :
474
- tokens = [
475
- token
476
- for token in [self .private_token ,self .oauth_token ,self .job_token ]
477
- if token
470
+ auth_types = [
471
+ auth
472
+ for auth in [
473
+ self .private_token ,
474
+ self .oauth_token ,
475
+ self .oauth_credentials ,
476
+ self .job_token ,
477
+ ]
478
+ if auth
478
479
]
479
- if len (tokens )> 1 :
480
+ if len (auth_types )> 1 :
480
481
raise ValueError (
481
- "Only one of private_token, oauth_token or job_token should "
482
- "be defined"
483
- )
484
- if (self .http_username and not self .http_password )or (
485
- not self .http_username and self .http_password
486
- ):
487
- raise ValueError ("Both http_username and http_password should be defined" )
488
- if tokens and self .http_username :
489
- raise ValueError (
490
- "Only one of token authentications or http "
491
- "authentication should be defined"
482
+ "Only one of private_token, oauth_token, oauth_credentials"
483
+ "or job_token should be defined"
492
484
)
493
485
494
486
self ._auth :Optional [requests .auth .AuthBase ]= None
495
487
if self .private_token :
496
488
self ._auth = _backends .PrivateTokenAuth (self .private_token )
489
+ return
497
490
498
491
if self .oauth_token :
499
492
self ._auth = _backends .OAuthTokenAuth (self .oauth_token )
493
+ return
494
+
495
+ if self .oauth_credentials :
496
+ post_data = {
497
+ "grant_type" :self .oauth_credentials .grant_type ,
498
+ "scope" :self .oauth_credentials .scope ,
499
+ "username" :self .oauth_credentials .username ,
500
+ "password" :self .oauth_credentials .password ,
501
+ }
502
+ response = self .http_post (
503
+ f"{ self ._base_url } /oauth/token" ,post_data = post_data
504
+ )
505
+ if isinstance (response ,dict ):
506
+ self .oauth_token = response ["access_token" ]
507
+ else :
508
+ self .oauth_token = response .json ()["access_token" ]
509
+ self ._auth = self .oauth_credentials .basic_auth
510
+ return
500
511
501
512
if self .job_token :
502
513
self ._auth = _backends .JobTokenAuth (self .job_token )
503
514
504
- if self .http_username and self .http_password :
505
- self ._auth = requests .auth .HTTPBasicAuth (
506
- self .http_username ,self .http_password
507
- )
508
-
509
515
@staticmethod
510
516
def enable_debug ()-> None :
511
517
import logging