From 1afef649e8992a37741cc88ed453e69c57013983 Mon Sep 17 00:00:00 2001 From: shabbywu Date: Fri, 26 Jan 2024 18:28:39 +0800 Subject: [PATCH] =?UTF-8?q?enhance:=20=E6=94=AF=E6=8C=81=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20auth=20timeout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- moby_distribution/__init__.py | 2 +- moby_distribution/registry/auth.py | 27 +++++++++++++++++++-------- moby_distribution/registry/client.py | 10 ++++++++-- pyproject.toml | 2 +- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/moby_distribution/__init__.py b/moby_distribution/__init__.py index ab52a04..ef67f32 100644 --- a/moby_distribution/__init__.py +++ b/moby_distribution/__init__.py @@ -7,7 +7,7 @@ from moby_distribution.spec.image_json import ImageJSON from moby_distribution.spec.manifest import ManifestSchema1, ManifestSchema2, OCIManifestSchema1 -__version__ = "0.5.9" +__version__ = "0.5.10" __ALL__ = [ "DockerRegistryV2Client", "Blob", diff --git a/moby_distribution/registry/auth.py b/moby_distribution/registry/auth.py index 42228a3..343c696 100644 --- a/moby_distribution/registry/auth.py +++ b/moby_distribution/registry/auth.py @@ -7,9 +7,10 @@ from www_authenticate import parse from moby_distribution.registry.exceptions import AuthFailed +from moby_distribution.registry.utils import TypeTimeout from moby_distribution.spec.auth import TokenResponse -AUTH_TIMEOUT = 60 * 3 +AUTH_TIMEOUT = 30 logger = logging.getLogger(__name__) @@ -35,7 +36,9 @@ def www_authenticate(self): self._www_authenticate = parse(self._raw_www_authenticate) return self._www_authenticate - def authenticate(self, username: Optional[str] = None, password: Optional[str] = None) -> AuthorizationProvider: + def authenticate( + self, username: Optional[str] = None, password: Optional[str] = None, *, timeout: TypeTimeout = AUTH_TIMEOUT + ) -> AuthorizationProvider: raise NotImplementedError @property @@ -73,7 +76,9 @@ def provide(self) -> str: class HTTPBasicAuthentication(BaseAuthentication): """`HTTP Basic Authentication` Authenticator""" - def authenticate(self, username: Optional[str] = None, password: Optional[str] = None) -> AuthorizationProvider: + def authenticate( + self, username: Optional[str] = None, password: Optional[str] = None, *, timeout: TypeTimeout = AUTH_TIMEOUT + ) -> AuthorizationProvider: if username is None or password is None: raise AuthFailed( message="请提供用户名和密码", @@ -108,7 +113,9 @@ def __init__(self, www_authenticate: str, offline_token: bool = True): self.service = self.bearer["service"] self.scope = self.bearer.get("scope", None) - def authenticate(self, username: Optional[str] = None, password: Optional[str] = None) -> AuthorizationProvider: + def authenticate( + self, username: Optional[str] = None, password: Optional[str] = None, *, timeout: TypeTimeout = AUTH_TIMEOUT + ) -> AuthorizationProvider: """Authenticate to the registry. If no username and password provided, will authenticate as the anonymous user. @@ -130,7 +137,7 @@ def authenticate(self, username: Optional[str] = None, password: Optional[str] = logger.warning("请同时提供 username 和 password!") logger.info("sending authentication request to authorization service<%s>", self.backend) - resp = requests.get(self.backend, headers=headers, params=params, timeout=AUTH_TIMEOUT) + resp = requests.get(self.backend, headers=headers, params=params, timeout=timeout) if resp.status_code != 200: raise AuthFailed( message="用户凭证校验失败, 请检查用户信息和操作权限", @@ -143,9 +150,13 @@ def authenticate(self, username: Optional[str] = None, password: Optional[str] = class UniversalAuthentication(BaseAuthentication): """An Auto auth backend, which will auto auth by `scheme` provided by www_authenticate""" - def authenticate(self, username: Optional[str] = None, password: Optional[str] = None) -> AuthorizationProvider: + def authenticate( + self, username: Optional[str] = None, password: Optional[str] = None, *, timeout: TypeTimeout = AUTH_TIMEOUT + ) -> AuthorizationProvider: if "basic" in self.www_authenticate: - return HTTPBasicAuthentication(self.raw_www_authenticate).authenticate(username, password) + return HTTPBasicAuthentication(self.raw_www_authenticate).authenticate(username, password, timeout=timeout) elif "bearer" in self.www_authenticate: - return DockerRegistryTokenAuthentication(self.raw_www_authenticate).authenticate(username, password) + return DockerRegistryTokenAuthentication(self.raw_www_authenticate).authenticate( + username, password, timeout=timeout + ) raise NotImplementedError("未支持的认证方式") diff --git a/moby_distribution/registry/client.py b/moby_distribution/registry/client.py index 7da4ae8..562cd65 100644 --- a/moby_distribution/registry/client.py +++ b/moby_distribution/registry/client.py @@ -29,7 +29,7 @@ def from_api_endpoint( password: Optional[str] = None, authenticator_class: Type[BaseAuthentication] = UniversalAuthentication, default_timeout: TypeTimeout = 60 * 10, - https_detect_timeout: float = 10, + https_detect_timeout: float = 30, ): https_scheme = "https://" http_scheme = "http://" @@ -62,15 +62,19 @@ def __init__( verify_certificate: bool = True, authenticator_class: Type[BaseAuthentication] = UniversalAuthentication, default_timeout: TypeTimeout = 60 * 10, + auth_timeout: TypeTimeout = 30, ): if default_timeout is not None and not isinstance(default_timeout, tuple) and isinf(default_timeout): raise ValueError("default_timeout should not be infinity.") + if auth_timeout is not None and not isinstance(auth_timeout, tuple) and isinf(auth_timeout): + raise ValueError("auth_timeout should not be infinity.") if api_base_url.endswith("/"): api_base_url = api_base_url.rstrip("/") self.api_base_url = api_base_url self.session = requests.session() self.session.verify = verify_certificate self.default_timeout = default_timeout + self.auth_timeout = auth_timeout self.username = username self.password = password @@ -141,7 +145,9 @@ def _validate_response(self, resp: requests.Response, auto_auth: bool = True) -> if auto_auth: www_authenticate = resp.headers["www-authenticate"] auth = self.authenticator_class(www_authenticate) - self._authed = auth.authenticate(username=self.username, password=self.password) + self._authed = auth.authenticate( + username=self.username, password=self.password, timeout=self.auth_timeout + ) raise exceptions.RetryAgain logger.debug("Requesting %s, but PermissionDeny, Equivalent curl command: %s", url, curl) diff --git a/pyproject.toml b/pyproject.toml index 20e22d7..0516578 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "moby-distribution" -version = "0.5.9" +version = "0.5.10" description = "Yet another moby(docker) distribution implement by python." authors = ["shabbywu "] license = "Apache-2.0"