◐ Shell
reader mode source ↗
Skip to content
Draft
Show file tree
Changes from all commits
File filter
Conversations
Jump to
Diff view
Apply and reload
Show whitespace
Diff view
Apply and reload
28 changes: 23 additions & 5 deletions docs/api-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,32 @@ Note on password authentication

GitLab has long removed password-based basic authentication. You can currently still use the
`resource owner password credentials <https://docs.gitlab.com/ee/api/oauth2.html#resource-owner-password-credentials-flow>`_
flow to obtain an OAuth token.

However, we do not recommend this as it will not work with 2FA enabled, and GitLab is removing
ROPC-based flows without client IDs in a future release. We recommend you obtain tokens for
automated workflows as linked above or obtain a session cookie from your browser.

For a python example of password authentication using the ROPC-based OAuth2
flow, see `this Ansible snippet <https://github.com/ansible-collections/community.general/blob/1c06e237c8100ac30d3941d5a3869a4428ba2974/plugins/module_utils/gitlab.py#L86-L92>`_.

Managers
========
3 changes: 1 addition & 2 deletions docs/cli-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,7 @@ We recommend that you use `Credential helpers`_ to securely store your tokens.
<https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html>`__
to learn how to obtain a token.
* - ``oauth_token``
- An Oauth token for authentication. The Gitlab server must be configured
to support this authentication method.
* - ``job_token``
- Your job token. See `the official documentation
<https://docs.gitlab.com/ce/api/jobs.html#get-job-artifacts>`__
Expand Down
68 changes: 37 additions & 31 deletions gitlab/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import gitlab.config
import gitlab.const
import gitlab.exceptions
from gitlab import _backends, utils

REDIRECT_MSG = (
"python-gitlab detected a {status_code} ({reason!r}) redirection. You must update "
Expand Down Expand Up @@ -41,8 +41,6 @@ class Gitlab:
the value is a string, it is the path to a CA file used for
certificate validation.
timeout: Timeout to use for requests to the GitLab server.
http_username: Username for HTTP authentication
http_password: Password for HTTP authentication
api_version: Gitlab API version to use (support for 4 only)
pagination: Can be set to 'keyset' to use keyset pagination
order_by: Set order_by globally
Expand All @@ -51,6 +49,7 @@ class Gitlab:
or 52x responses. Defaults to False.
keep_base_url: keep user-provided base URL for pagination if it
differs from response headers

Keyword Args:
requests.Session session: HTTP Requests Session
Expand All @@ -64,8 +63,6 @@ def __init__(
oauth_token: Optional[str] = None,
job_token: Optional[str] = None,
ssl_verify: Union[bool, str] = True,
http_username: Optional[str] = None,
http_password: Optional[str] = None,
timeout: Optional[float] = None,
api_version: str = "4",
per_page: Optional[int] = None,
Expand All @@ -74,6 +71,8 @@ def __init__(
user_agent: str = gitlab.const.USER_AGENT,
retry_transient_errors: bool = False,
keep_base_url: bool = False,
**kwargs: Any,
) -> None:
self._api_version = str(api_version)
Expand All @@ -92,11 +91,9 @@ def __init__(
self.ssl_verify = ssl_verify

self.private_token = private_token
self.http_username = http_username
self.http_password = http_password
self.oauth_token = oauth_token
self.job_token = job_token
self._set_auth_info()

#: Create a session object for requests
_backend: Type[_backends.DefaultBackend] = kwargs.pop(
Expand All @@ -105,6 +102,7 @@ def __init__(
self._backend = _backend(**kwargs)
self.session = self._backend.client

self.per_page = per_page
self.pagination = pagination
self.order_by = order_by
Expand Down Expand Up @@ -271,8 +269,6 @@ def from_config(
job_token=config.job_token,
ssl_verify=config.ssl_verify,
timeout=config.timeout,
http_username=config.http_username,
http_password=config.http_password,
api_version=config.api_version,
per_page=config.per_page,
pagination=config.pagination,
Expand Down Expand Up @@ -471,41 +467,51 @@ def set_license(self, license: str, **kwargs: Any) -> Dict[str, Any]:
return result

def _set_auth_info(self) -> None:
tokens = [
token
for token in [self.private_token, self.oauth_token, self.job_token]
if token
]
if len(tokens) > 1:
raise ValueError(
"Only one of private_token, oauth_token or job_token should "
"be defined"
)
if (self.http_username and not self.http_password) or (
not self.http_username and self.http_password
):
raise ValueError("Both http_username and http_password should be defined")
if tokens and self.http_username:
raise ValueError(
"Only one of token authentications or http "
"authentication should be defined"
)

self._auth: Optional[requests.auth.AuthBase] = None
if self.private_token:
self._auth = _backends.PrivateTokenAuth(self.private_token)

if self.oauth_token:
self._auth = _backends.OAuthTokenAuth(self.oauth_token)

if self.job_token:
self._auth = _backends.JobTokenAuth(self.job_token)

if self.http_username and self.http_password:
self._auth = requests.auth.HTTPBasicAuth(
self.http_username, self.http_password
)

@staticmethod
def enable_debug() -> None:
import logging
Expand Down
33 changes: 33 additions & 0 deletions gitlab/oauth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
8 changes: 8 additions & 0 deletions tests/functional/api/test_gitlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import requests

import gitlab


@pytest.fixture(
Expand All @@ -22,6 +23,13 @@ def test_auth_from_config(gl, gitlab_config, temp_dir):
assert isinstance(test_gitlab.user, gitlab.v4.objects.CurrentUser)


def test_no_custom_session(gl, temp_dir):
"""Test no custom session"""
custom_session = requests.Session()
Expand Down
40 changes: 30 additions & 10 deletions tests/unit/test_gitlab_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,33 @@
from gitlab import Gitlab
from gitlab._backends import JobTokenAuth, OAuthTokenAuth, PrivateTokenAuth
from gitlab.config import GitlabConfigParser


@pytest.fixture
Expand Down @@ -91,24 +118,17 @@ def test_job_token_auth():
assert "Authorization" not in p.headers


def test_http_auth():
gl = Gitlab(
"http://localhost",
http_username="foo",
http_password="bar",
api_version="4",
)
p = PreparedRequest()
p.prepare(url=gl.url, auth=gl._auth)
assert gl.private_token is None
assert gl.oauth_token is None
assert gl.job_token is None
assert isinstance(gl._auth, requests.auth.HTTPBasicAuth)
assert gl._auth.username == "foo"
assert gl._auth.password == "bar"
assert p.headers["Authorization"] == "Basic Zm9vOmJhcg=="
assert "PRIVATE-TOKEN" not in p.headers
assert "JOB-TOKEN" not in p.headers


@responses.activate
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/test_oauth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Toggle all file notes Toggle all file annotations