Skip to content

Commit 5f46cfd

Browse files
udanejch
authored andcommitted
feat: Use requests AuthBase classes
1 parent 3b83d5d commit 5f46cfd

File tree

4 files changed

+86
-32
lines changed

4 files changed

+86
-32
lines changed

gitlab/_backends/__init__.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,21 @@
22
Defines http backends for processing http requests
33
"""
44

5-
from .requests_backend import RequestsBackend, RequestsResponse
5+
from .requests_backend import (
6+
JobTokenAuth,
7+
OAuthTokenAuth,
8+
PrivateTokenAuth,
9+
RequestsBackend,
10+
RequestsResponse,
11+
)
612

713
DefaultBackend = RequestsBackend
814
DefaultResponse = RequestsResponse
15+
16+
__all__ = [
17+
"DefaultBackend",
18+
"DefaultResponse",
19+
"JobTokenAuth",
20+
"OAuthTokenAuth",
21+
"PrivateTokenAuth",
22+
]

gitlab/_backends/requests_backend.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,43 @@
44
from typing import Any, Dict, Optional, TYPE_CHECKING, Union
55

66
import requests
7+
from requests import PreparedRequest
8+
from requests.auth import AuthBase
79
from requests.structures import CaseInsensitiveDict
810
from requests_toolbelt.multipart.encoder import MultipartEncoder # type: ignore
911

1012
from . import protocol
1113

1214

15+
class TokenAuth:
16+
def __init__(self, token: str):
17+
self.token = token
18+
19+
20+
class OAuthTokenAuth(TokenAuth, AuthBase):
21+
def __call__(self, r: PreparedRequest) -> PreparedRequest:
22+
r.headers["Authorization"] = f"Bearer {self.token}"
23+
r.headers.pop("PRIVATE-TOKEN", None)
24+
r.headers.pop("JOB-TOKEN", None)
25+
return r
26+
27+
28+
class PrivateTokenAuth(TokenAuth, AuthBase):
29+
def __call__(self, r: PreparedRequest) -> PreparedRequest:
30+
r.headers["PRIVATE-TOKEN"] = self.token
31+
r.headers.pop("JOB-TOKEN", None)
32+
r.headers.pop("Authorization", None)
33+
return r
34+
35+
36+
class JobTokenAuth(TokenAuth, AuthBase):
37+
def __call__(self, r: PreparedRequest) -> PreparedRequest:
38+
r.headers["JOB-TOKEN"] = self.token
39+
r.headers.pop("PRIVATE-TOKEN", None)
40+
r.headers.pop("Authorization", None)
41+
return r
42+
43+
1344
@dataclasses.dataclass
1445
class SendData:
1546
content_type: str

gitlab/client.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -485,30 +485,24 @@ def _set_auth_info(self) -> None:
485485
not self.http_username and self.http_password
486486
):
487487
raise ValueError("Both http_username and http_password should be defined")
488-
if self.oauth_token and self.http_username:
488+
if tokens and self.http_username:
489489
raise ValueError(
490-
"Only one of oauth authentication or http "
490+
"Only one of token authentications or http "
491491
"authentication should be defined"
492492
)
493493

494-
self._http_auth = None
494+
self._auth: Optional[requests.auth.AuthBase] = None
495495
if self.private_token:
496-
self.headers.pop("Authorization", None)
497-
self.headers["PRIVATE-TOKEN"] = self.private_token
498-
self.headers.pop("JOB-TOKEN", None)
496+
self._auth = _backends.PrivateTokenAuth(self.private_token)
499497

500498
if self.oauth_token:
501-
self.headers["Authorization"] = f"Bearer {self.oauth_token}"
502-
self.headers.pop("PRIVATE-TOKEN", None)
503-
self.headers.pop("JOB-TOKEN", None)
499+
self._auth = _backends.OAuthTokenAuth(self.oauth_token)
504500

505501
if self.job_token:
506-
self.headers.pop("Authorization", None)
507-
self.headers.pop("PRIVATE-TOKEN", None)
508-
self.headers["JOB-TOKEN"] = self.job_token
502+
self._auth = _backends.JobTokenAuth(self.job_token)
509503

510504
if self.http_username and self.http_password:
511-
self._http_auth = requests.auth.HTTPBasicAuth(
505+
self._auth = requests.auth.HTTPBasicAuth(
512506
self.http_username, self.http_password
513507
)
514508

@@ -527,7 +521,7 @@ def enable_debug() -> None:
527521
def _get_session_opts(self) -> Dict[str, Any]:
528522
return {
529523
"headers": self.headers.copy(),
530-
"auth": self._http_auth,
524+
"auth": self._auth,
531525
"timeout": self.timeout,
532526
"verify": self.ssl_verify,
533527
}

tests/unit/test_gitlab_auth.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import pytest
22
import requests
3+
from requests import PreparedRequest
34

45
from gitlab import Gitlab
6+
from gitlab._backends import JobTokenAuth, OAuthTokenAuth, PrivateTokenAuth
57
from gitlab.config import GitlabConfigParser
68

79

@@ -39,51 +41,64 @@ def test_invalid_auth_args():
3941

4042
def test_private_token_auth():
4143
gl = Gitlab("http://localhost", private_token="private_token", api_version="4")
44+
p = PreparedRequest()
45+
p.prepare(url=gl.url, auth=gl._auth)
4246
assert gl.private_token == "private_token"
4347
assert gl.oauth_token is None
4448
assert gl.job_token is None
45-
assert gl._http_auth is None
46-
assert "Authorization" not in gl.headers
47-
assert gl.headers["PRIVATE-TOKEN"] == "private_token"
48-
assert "JOB-TOKEN" not in gl.headers
49+
assert isinstance(gl._auth, PrivateTokenAuth)
50+
assert gl._auth.token == "private_token"
51+
assert p.headers["PRIVATE-TOKEN"] == "private_token"
52+
assert "JOB-TOKEN" not in p.headers
53+
assert "Authorization" not in p.headers
4954

5055

5156
def test_oauth_token_auth():
5257
gl = Gitlab("http://localhost", oauth_token="oauth_token", api_version="4")
58+
p = PreparedRequest()
59+
p.prepare(url=gl.url, auth=gl._auth)
5360
assert gl.private_token is None
5461
assert gl.oauth_token == "oauth_token"
5562
assert gl.job_token is None
56-
assert gl._http_auth is None
57-
assert gl.headers["Authorization"] == "Bearer oauth_token"
58-
assert "PRIVATE-TOKEN" not in gl.headers
59-
assert "JOB-TOKEN" not in gl.headers
63+
assert isinstance(gl._auth, OAuthTokenAuth)
64+
assert gl._auth.token == "oauth_token"
65+
assert p.headers["Authorization"] == "Bearer oauth_token"
66+
assert "PRIVATE-TOKEN" not in p.headers
67+
assert "JOB-TOKEN" not in p.headers
6068

6169

6270
def test_job_token_auth():
6371
gl = Gitlab("http://localhost", job_token="CI_JOB_TOKEN", api_version="4")
72+
p = PreparedRequest()
73+
p.prepare(url=gl.url, auth=gl._auth)
6474
assert gl.private_token is None
6575
assert gl.oauth_token is None
6676
assert gl.job_token == "CI_JOB_TOKEN"
67-
assert gl._http_auth is None
68-
assert "Authorization" not in gl.headers
69-
assert "PRIVATE-TOKEN" not in gl.headers
70-
assert gl.headers["JOB-TOKEN"] == "CI_JOB_TOKEN"
77+
assert isinstance(gl._auth, JobTokenAuth)
78+
assert gl._auth.token == "CI_JOB_TOKEN"
79+
assert p.headers["JOB-TOKEN"] == "CI_JOB_TOKEN"
80+
assert "PRIVATE-TOKEN" not in p.headers
81+
assert "Authorization" not in p.headers
7182

7283

7384
def test_http_auth():
7485
gl = Gitlab(
7586
"http://localhost",
76-
private_token="private_token",
7787
http_username="foo",
7888
http_password="bar",
7989
api_version="4",
8090
)
81-
assert gl.private_token == "private_token"
91+
p = PreparedRequest()
92+
p.prepare(url=gl.url, auth=gl._auth)
93+
assert gl.private_token is None
8294
assert gl.oauth_token is None
8395
assert gl.job_token is None
84-
assert isinstance(gl._http_auth, requests.auth.HTTPBasicAuth)
85-
assert gl.headers["PRIVATE-TOKEN"] == "private_token"
86-
assert "Authorization" not in gl.headers
96+
assert isinstance(gl._auth, requests.auth.HTTPBasicAuth)
97+
assert gl._auth.username == "foo"
98+
assert gl._auth.password == "bar"
99+
assert p.headers["Authorization"] == "Basic Zm9vOmJhcg=="
100+
assert "PRIVATE-TOKEN" not in p.headers
101+
assert "JOB-TOKEN" not in p.headers
87102

88103

89104
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)