1212import gitlab .config
1313import gitlab .const
1414import gitlab .exceptions
15- from gitlab import _backends , utils
15+ from gitlab import _backends , oauth , utils
1616
1717REDIRECT_MSG = (
1818 "python-gitlab detected a {status_code} ({reason!r}) redirection. You must update "
@@ -41,8 +41,6 @@ class Gitlab:
4141 the value is a string, it is the path to a CA file used for
4242 certificate validation.
4343 timeout: Timeout to use for requests to the GitLab server.
44- http_username: Username for HTTP authentication
45- http_password: Password for HTTP authentication
4644 api_version: Gitlab API version to use (support for 4 only)
4745 pagination: Can be set to 'keyset' to use keyset pagination
4846 order_by: Set order_by globally
@@ -51,6 +49,7 @@ class Gitlab:
5149 or 52x responses. Defaults to False.
5250 keep_base_url: keep user-provided base URL for pagination if it
5351 differs from response headers
52+ oauth_credentials: Password credentials for authenticating via OAuth ROPC flow
5453
5554 Keyword Args:
5655 requests.Session session: HTTP Requests Session
@@ -64,8 +63,6 @@ def __init__(
6463 oauth_token : Optional [str ] = None ,
6564 job_token : Optional [str ] = None ,
6665 ssl_verify : Union [bool , str ] = True ,
67- http_username : Optional [str ] = None ,
68- http_password : Optional [str ] = None ,
6966 timeout : Optional [float ] = None ,
7067 api_version : str = "4" ,
7168 per_page : Optional [int ] = None ,
@@ -74,6 +71,8 @@ def __init__(
7471 user_agent : str = gitlab .const .USER_AGENT ,
7572 retry_transient_errors : bool = False ,
7673 keep_base_url : bool = False ,
74+ * ,
75+ oauth_credentials : Optional [oauth .PasswordCredentials ] = None ,
7776 ** kwargs : Any ,
7877 ) -> None :
7978 self ._api_version = str (api_version )
@@ -92,11 +91,9 @@ def __init__(
9291 self .ssl_verify = ssl_verify
9392
9493 self .private_token = private_token
95- self .http_username = http_username
96- self .http_password = http_password
9794 self .oauth_token = oauth_token
9895 self .job_token = job_token
99- self ._set_auth_info ()
96+ self .oauth_credentials = oauth_credentials
10097
10198 #: Create a session object for requests
10299 _backend : Type [_backends .DefaultBackend ] = kwargs .pop (
@@ -105,6 +102,7 @@ def __init__(
105102 self ._backend = _backend (** kwargs )
106103 self .session = self ._backend .client
107104
105+ self ._set_auth_info ()
108106 self .per_page = per_page
109107 self .pagination = pagination
110108 self .order_by = order_by
@@ -271,8 +269,6 @@ def from_config(
271269 job_token = config .job_token ,
272270 ssl_verify = config .ssl_verify ,
273271 timeout = config .timeout ,
274- http_username = config .http_username ,
275- http_password = config .http_password ,
276272 api_version = config .api_version ,
277273 per_page = config .per_page ,
278274 pagination = config .pagination ,
@@ -471,41 +467,51 @@ def set_license(self, license: str, **kwargs: Any) -> Dict[str, Any]:
471467 return result
472468
473469 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
478479 ]
479- if len (tokens ) > 1 :
480+ if len (auth_types ) > 1 :
480481 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"
492484 )
493485
494486 self ._auth : Optional [requests .auth .AuthBase ] = None
495487 if self .private_token :
496488 self ._auth = _backends .PrivateTokenAuth (self .private_token )
489+ return
497490
498491 if self .oauth_token :
499492 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
500511
501512 if self .job_token :
502513 self ._auth = _backends .JobTokenAuth (self .job_token )
503514
504- if self .http_username and self .http_password :
505- self ._auth = requests .auth .HTTPBasicAuth (
506- self .http_username , self .http_password
507- )
508-
509515 @staticmethod
510516 def enable_debug () -> None :
511517 import logging
0 commit comments