cliV1 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cliv1-0.1.1.dist-info/METADATA +156 -0
- cliv1-0.1.1.dist-info/RECORD +83 -0
- cliv1-0.1.1.dist-info/WHEEL +4 -0
- cliv1-0.1.1.dist-info/licenses/LICENSE +21 -0
- swagger_petstore_open_api_3_0/__init__.py +15 -0
- swagger_petstore_open_api_3_0/apis/__init__.py +5 -0
- swagger_petstore_open_api_3_0/apis/pet_api.py +881 -0
- swagger_petstore_open_api_3_0/apis/store.py +411 -0
- swagger_petstore_open_api_3_0/apis/user_api.py +792 -0
- swagger_petstore_open_api_3_0/async_client.py +79 -0
- swagger_petstore_open_api_3_0/auth.py +17 -0
- swagger_petstore_open_api_3_0/base_client.py +18 -0
- swagger_petstore_open_api_3_0/client.py +77 -0
- swagger_petstore_open_api_3_0/core/__init__.py +342 -0
- swagger_petstore_open_api_3_0/core/_internal/__init__.py +7 -0
- swagger_petstore_open_api_3_0/core/_internal/content_disposition.py +154 -0
- swagger_petstore_open_api_3_0/core/_internal/flattening.py +139 -0
- swagger_petstore_open_api_3_0/core/_internal/headers.py +144 -0
- swagger_petstore_open_api_3_0/core/_internal/urls.py +166 -0
- swagger_petstore_open_api_3_0/core/_internal/wire.py +173 -0
- swagger_petstore_open_api_3_0/core/adapters.py +177 -0
- swagger_petstore_open_api_3_0/core/auth/__init__.py +70 -0
- swagger_petstore_open_api_3_0/core/auth/composition.py +175 -0
- swagger_petstore_open_api_3_0/core/auth/models.py +217 -0
- swagger_petstore_open_api_3_0/core/auth/protocols.py +103 -0
- swagger_petstore_open_api_3_0/core/auth/schemes/__init__.py +94 -0
- swagger_petstore_open_api_3_0/core/auth/schemes/api_key_auth.py +53 -0
- swagger_petstore_open_api_3_0/core/auth/schemes/basic_auth.py +73 -0
- swagger_petstore_open_api_3_0/core/auth/schemes/bearer_auth.py +21 -0
- swagger_petstore_open_api_3_0/core/auth/schemes/oauth2_authorization_code.py +393 -0
- swagger_petstore_open_api_3_0/core/auth/schemes/oauth2_client_credentials.py +127 -0
- swagger_petstore_open_api_3_0/core/auth/schemes/oauth2_password.py +142 -0
- swagger_petstore_open_api_3_0/core/auth/schemes/oauth2_schemes.py +300 -0
- swagger_petstore_open_api_3_0/core/base_raw_response.py +49 -0
- swagger_petstore_open_api_3_0/core/bodies.py +563 -0
- swagger_petstore_open_api_3_0/core/converters/__init__.py +68 -0
- swagger_petstore_open_api_3_0/core/converters/date_time.py +237 -0
- swagger_petstore_open_api_3_0/core/converters/encoded_bytes.py +271 -0
- swagger_petstore_open_api_3_0/core/converters/open_enum.py +35 -0
- swagger_petstore_open_api_3_0/core/decoding.py +263 -0
- swagger_petstore_open_api_3_0/core/exceptions.py +41 -0
- swagger_petstore_open_api_3_0/core/file_responses.py +324 -0
- swagger_petstore_open_api_3_0/core/files.py +173 -0
- swagger_petstore_open_api_3_0/core/httpx_transport.py +766 -0
- swagger_petstore_open_api_3_0/core/models.py +143 -0
- swagger_petstore_open_api_3_0/core/optionality.py +130 -0
- swagger_petstore_open_api_3_0/core/params.py +161 -0
- swagger_petstore_open_api_3_0/core/raw_client.py +388 -0
- swagger_petstore_open_api_3_0/core/request_options.py +94 -0
- swagger_petstore_open_api_3_0/core/results.py +110 -0
- swagger_petstore_open_api_3_0/core/runtime_env.py +43 -0
- swagger_petstore_open_api_3_0/core/servers.py +33 -0
- swagger_petstore_open_api_3_0/core/transport.py +248 -0
- swagger_petstore_open_api_3_0/errors/__init__.py +48 -0
- swagger_petstore_open_api_3_0/errors/add_pet_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/delete_order_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/delete_pet_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/delete_user_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/find_pets_by_status_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/find_pets_by_tags_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/get_order_by_id_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/get_pet_by_id_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/get_user_by_name_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/login_user_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/place_order_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/update_pet_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/update_pet_with_form_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/update_user_error.py +21 -0
- swagger_petstore_open_api_3_0/errors/upload_file_error.py +21 -0
- swagger_petstore_open_api_3_0/models/__init__.py +23 -0
- swagger_petstore_open_api_3_0/models/api_response.py +18 -0
- swagger_petstore_open_api_3_0/models/category.py +15 -0
- swagger_petstore_open_api_3_0/models/enums/__init__.py +4 -0
- swagger_petstore_open_api_3_0/models/enums/order_status.py +17 -0
- swagger_petstore_open_api_3_0/models/enums/pet_status.py +17 -0
- swagger_petstore_open_api_3_0/models/order.py +27 -0
- swagger_petstore_open_api_3_0/models/pet.py +28 -0
- swagger_petstore_open_api_3_0/models/tag.py +15 -0
- swagger_petstore_open_api_3_0/models/user.py +29 -0
- swagger_petstore_open_api_3_0/py.typed +0 -0
- swagger_petstore_open_api_3_0/server/__init__.py +21 -0
- swagger_petstore_open_api_3_0/server/server.py +17 -0
- swagger_petstore_open_api_3_0/server/server_config.py +52 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Every protocol the authentication layer defines: what a scheme is, and where a token comes from.
|
|
2
|
+
|
|
3
|
+
Two families, one file. :class:`AuthScheme` and its async twin are the whole contract for applying a
|
|
4
|
+
credential to a request, so a scheme this runtime does not ship is a class a *caller* writes; ``apply``
|
|
5
|
+
runs once per request, which is what makes rotation and just-in-time signing work.
|
|
6
|
+
:class:`TokenSource` and its three relatives are the seam managed OAuth 2.0 fetches through, so a
|
|
7
|
+
consumer replaces the built-in source without touching the caching scheme that calls it.
|
|
8
|
+
|
|
9
|
+
Nothing here has a body, so nothing here reaches a scheme, a composite or a transport -- only the
|
|
10
|
+
models its members name."""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from collections.abc import Awaitable
|
|
15
|
+
from typing import Protocol, TypeVar, runtime_checkable
|
|
16
|
+
|
|
17
|
+
from .models import AuthParams, OAuthToken, OAuthTokenRefreshable
|
|
18
|
+
|
|
19
|
+
CredentialsT_contra = TypeVar("CredentialsT_contra", contravariant=True)
|
|
20
|
+
"""A grant's credentials, as a source accepts them.
|
|
21
|
+
|
|
22
|
+
Contravariant because the protocols below take it in an *argument* position and nowhere else."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AuthScheme(Protocol):
|
|
26
|
+
"""A security scheme, as the synchronous client sees it.
|
|
27
|
+
|
|
28
|
+
Implementations:
|
|
29
|
+
|
|
30
|
+
- MUST be safe to call repeatedly -- ``apply`` runs once per request.
|
|
31
|
+
- SHOULD be frozen: one scheme instance serves every request a client makes.
|
|
32
|
+
- MAY block, but only if the synchronous client is the only one that will hold it."""
|
|
33
|
+
|
|
34
|
+
def apply(self) -> AuthParams: ...
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class AsyncAuthScheme(Protocol):
|
|
38
|
+
"""A security scheme, as the asynchronous client sees it.
|
|
39
|
+
|
|
40
|
+
``apply`` may return the parameters directly *or* an awaitable of them, so one synchronous method
|
|
41
|
+
satisfies this protocol **and** :class:`AuthScheme` and no async twin of a static scheme is
|
|
42
|
+
needed. A scheme that must reach the network declares ``async def apply`` and satisfies only this
|
|
43
|
+
one, which is what keeps it off the synchronous transport it could not use."""
|
|
44
|
+
|
|
45
|
+
def apply(self) -> AuthParams | Awaitable[AuthParams]: ...
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@runtime_checkable
|
|
49
|
+
class RevocableAuthScheme(Protocol):
|
|
50
|
+
"""A scheme whose credential can go stale before it expires.
|
|
51
|
+
|
|
52
|
+
``invalidate`` is a **hint, not a barrier**: it runs after a 401 and must not block, so a fetch
|
|
53
|
+
already in flight may repopulate the cache immediately afterwards. ``runtime_checkable`` because
|
|
54
|
+
``composition.invalidate`` has to ask a scheme whose type it does not know."""
|
|
55
|
+
|
|
56
|
+
def invalidate(self) -> None: ...
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class TokenSource(Protocol[CredentialsT_contra]):
|
|
60
|
+
"""Where an OAuth 2.0 scheme gets its token, given that grant's credentials.
|
|
61
|
+
|
|
62
|
+
Generic because the credentials differ between grants, so a mismatch is reported at the client
|
|
63
|
+
constructor rather than at the first request. ``fetch`` always receives the validated credentials
|
|
64
|
+
model, never the mapping form.
|
|
65
|
+
|
|
66
|
+
Implementations:
|
|
67
|
+
|
|
68
|
+
- MUST be safe to call repeatedly, and MAY be called concurrently.
|
|
69
|
+
- MUST NOT issue a request that itself uses the scheme holding them -- ``fetch`` runs inside that
|
|
70
|
+
scheme's lock, so doing so deadlocks.
|
|
71
|
+
- SHOULD bound their own I/O. The built-in source inherits the client's timeout."""
|
|
72
|
+
|
|
73
|
+
def fetch(self, credentials: CredentialsT_contra) -> OAuthToken: ...
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class AsyncTokenSource(Protocol[CredentialsT_contra]):
|
|
77
|
+
""":class:`TokenSource` as the asynchronous client sees it.
|
|
78
|
+
|
|
79
|
+
``fetch`` is a coroutine, deliberately unlike :meth:`AsyncAuthScheme.apply`'s union: nothing about
|
|
80
|
+
obtaining a token is static, so declaring it makes a synchronous source a **type** error rather
|
|
81
|
+
than a ``TypeError`` at the first request."""
|
|
82
|
+
|
|
83
|
+
async def fetch(self, credentials: CredentialsT_contra) -> OAuthToken: ...
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class RefreshableTokenSource(TokenSource[CredentialsT_contra], Protocol[CredentialsT_contra]):
|
|
87
|
+
"""A :class:`TokenSource` that can also exchange a refresh token for a new access token.
|
|
88
|
+
|
|
89
|
+
Extends rather than replaces: ``fetch`` still runs when there is nothing to refresh, and again
|
|
90
|
+
when a refresh is refused. ``refresh`` returns ``None`` for a *provider* refusal rather than
|
|
91
|
+
raising; a transport failure still propagates, as does a success whose body will not decode."""
|
|
92
|
+
|
|
93
|
+
def fetch(self, credentials: CredentialsT_contra) -> OAuthTokenRefreshable: ...
|
|
94
|
+
|
|
95
|
+
def refresh(self, credentials: CredentialsT_contra, refresh_token: str) -> OAuthTokenRefreshable | None: ...
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class AsyncRefreshableTokenSource(AsyncTokenSource[CredentialsT_contra], Protocol[CredentialsT_contra]):
|
|
99
|
+
""":class:`RefreshableTokenSource` as the asynchronous client sees it: both members are awaited."""
|
|
100
|
+
|
|
101
|
+
async def fetch(self, credentials: CredentialsT_contra) -> OAuthTokenRefreshable: ...
|
|
102
|
+
|
|
103
|
+
async def refresh(self, credentials: CredentialsT_contra, refresh_token: str) -> OAuthTokenRefreshable | None: ...
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Every scheme this runtime ships, plus the two caching tiers a managed OAuth 2.0 grant applies through.
|
|
2
|
+
|
|
3
|
+
One module per scheme *type* -- together the whole of OpenAPI's ``securitySchemes`` surface:
|
|
4
|
+
``http``/``basic`` and ``http``/``bearer``, ``apiKey`` in a header, a query parameter or a cookie, and
|
|
5
|
+
three ``oauth2`` flows. ``openIdConnect`` and ``implicit`` need no module of their own -- both reach this
|
|
6
|
+
runtime as a plain bearer token. Adding a fourth grant is one more module here and nothing anywhere else.
|
|
7
|
+
|
|
8
|
+
``oauth2_schemes`` is the exception that earns its place: it names no grant, holding the two
|
|
9
|
+
grant-agnostic tiers every flow's credentials and source are handed to."""
|
|
10
|
+
|
|
11
|
+
from .api_key_auth import ApiKeyCookieScheme, ApiKeyHeaderScheme, ApiKeyQueryScheme
|
|
12
|
+
from .basic_auth import (
|
|
13
|
+
BasicAuthCredentials,
|
|
14
|
+
BasicAuthCredentialsDict,
|
|
15
|
+
BasicAuthCredentialsOrDict,
|
|
16
|
+
BasicAuthScheme,
|
|
17
|
+
)
|
|
18
|
+
from .bearer_auth import BearerAuthScheme
|
|
19
|
+
from .oauth2_authorization_code import (
|
|
20
|
+
AsyncAuthorizationCodeCredentials,
|
|
21
|
+
AsyncAuthorizationCodeCredentialsDict,
|
|
22
|
+
AsyncAuthorizationCodeCredentialsOrDict,
|
|
23
|
+
AsyncAuthorizationCodePrompt,
|
|
24
|
+
AsyncAuthorizationCodeTokenSource,
|
|
25
|
+
AuthorizationCodeCredentials,
|
|
26
|
+
AuthorizationCodeCredentialsDict,
|
|
27
|
+
AuthorizationCodeCredentialsOrDict,
|
|
28
|
+
AuthorizationCodePrompt,
|
|
29
|
+
AuthorizationCodeTokenSource,
|
|
30
|
+
PkceMethod,
|
|
31
|
+
)
|
|
32
|
+
from .oauth2_client_credentials import (
|
|
33
|
+
AsyncClientCredentialsTokenSource,
|
|
34
|
+
ClientCredentials,
|
|
35
|
+
ClientCredentialsDict,
|
|
36
|
+
ClientCredentialsOrDict,
|
|
37
|
+
ClientCredentialsTokenSource,
|
|
38
|
+
)
|
|
39
|
+
from .oauth2_password import (
|
|
40
|
+
AsyncPasswordTokenSource,
|
|
41
|
+
PasswordCredentials,
|
|
42
|
+
PasswordCredentialsDict,
|
|
43
|
+
PasswordCredentialsOrDict,
|
|
44
|
+
PasswordTokenSource,
|
|
45
|
+
)
|
|
46
|
+
from .oauth2_schemes import (
|
|
47
|
+
AsyncOAuth2RefreshableScheme,
|
|
48
|
+
AsyncOAuth2Scheme,
|
|
49
|
+
OAuth2RefreshableScheme,
|
|
50
|
+
OAuth2Scheme,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
# http / basic
|
|
55
|
+
"BasicAuthCredentials",
|
|
56
|
+
"BasicAuthCredentialsDict",
|
|
57
|
+
"BasicAuthCredentialsOrDict",
|
|
58
|
+
"BasicAuthScheme",
|
|
59
|
+
# http / bearer
|
|
60
|
+
"BearerAuthScheme",
|
|
61
|
+
# apiKey
|
|
62
|
+
"ApiKeyHeaderScheme",
|
|
63
|
+
"ApiKeyQueryScheme",
|
|
64
|
+
"ApiKeyCookieScheme",
|
|
65
|
+
# oauth2 -- the two caching tiers, grant-agnostic
|
|
66
|
+
"OAuth2Scheme",
|
|
67
|
+
"AsyncOAuth2Scheme",
|
|
68
|
+
"OAuth2RefreshableScheme",
|
|
69
|
+
"AsyncOAuth2RefreshableScheme",
|
|
70
|
+
# oauth2 / clientCredentials
|
|
71
|
+
"ClientCredentials",
|
|
72
|
+
"ClientCredentialsDict",
|
|
73
|
+
"ClientCredentialsOrDict",
|
|
74
|
+
"ClientCredentialsTokenSource",
|
|
75
|
+
"AsyncClientCredentialsTokenSource",
|
|
76
|
+
# oauth2 / password
|
|
77
|
+
"PasswordCredentials",
|
|
78
|
+
"PasswordCredentialsDict",
|
|
79
|
+
"PasswordCredentialsOrDict",
|
|
80
|
+
"PasswordTokenSource",
|
|
81
|
+
"AsyncPasswordTokenSource",
|
|
82
|
+
# oauth2 / authorizationCode
|
|
83
|
+
"AuthorizationCodeCredentials",
|
|
84
|
+
"AuthorizationCodeCredentialsDict",
|
|
85
|
+
"AuthorizationCodeCredentialsOrDict",
|
|
86
|
+
"AsyncAuthorizationCodeCredentials",
|
|
87
|
+
"AsyncAuthorizationCodeCredentialsDict",
|
|
88
|
+
"AsyncAuthorizationCodeCredentialsOrDict",
|
|
89
|
+
"AuthorizationCodePrompt",
|
|
90
|
+
"AsyncAuthorizationCodePrompt",
|
|
91
|
+
"PkceMethod",
|
|
92
|
+
"AuthorizationCodeTokenSource",
|
|
93
|
+
"AsyncAuthorizationCodeTokenSource",
|
|
94
|
+
]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""``apiKey`` -- one credential, three destinations.
|
|
2
|
+
|
|
3
|
+
OpenAPI's ``apiKey`` is a single type parameterised by ``in:``, so the three classes below differ
|
|
4
|
+
only in which bucket of :class:`AuthParams` they fill."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
|
|
10
|
+
from ...params import param
|
|
11
|
+
from ..models import AuthParams
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True, slots=True)
|
|
15
|
+
class ApiKeyHeaderScheme:
|
|
16
|
+
"""``apiKey`` with ``in: header``.
|
|
17
|
+
|
|
18
|
+
Also every custom ``Authorization`` keyword an API invents, which needs no scheme of its own:
|
|
19
|
+
pass ``name="Authorization"`` and a value that already carries the keyword."""
|
|
20
|
+
|
|
21
|
+
name: str
|
|
22
|
+
value: str = field(repr=False)
|
|
23
|
+
|
|
24
|
+
def apply(self) -> AuthParams:
|
|
25
|
+
return AuthParams(headers=(param[str](self.name, self.value),))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True, slots=True)
|
|
29
|
+
class ApiKeyQueryScheme:
|
|
30
|
+
"""``apiKey`` with ``in: query``.
|
|
31
|
+
|
|
32
|
+
The value is percent-encoded, because :class:`Param` renders it exactly as an endpoint's own
|
|
33
|
+
query parameter -- the opposite obligation from the cookie below."""
|
|
34
|
+
|
|
35
|
+
name: str
|
|
36
|
+
value: str = field(repr=False)
|
|
37
|
+
|
|
38
|
+
def apply(self) -> AuthParams:
|
|
39
|
+
return AuthParams(query_params=(param[str](self.name, self.value),))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(frozen=True, slots=True)
|
|
43
|
+
class ApiKeyCookieScheme:
|
|
44
|
+
"""``apiKey`` with ``in: cookie``.
|
|
45
|
+
|
|
46
|
+
The value is sent verbatim. RFC 6265's ``cookie-value`` alphabet already admits every character
|
|
47
|
+
a base64 key uses, so percent-encoding it would corrupt the credential rather than protect it."""
|
|
48
|
+
|
|
49
|
+
name: str
|
|
50
|
+
value: str = field(repr=False)
|
|
51
|
+
|
|
52
|
+
def apply(self) -> AuthParams:
|
|
53
|
+
return AuthParams(cookies=(param[str](self.name, self.value),))
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""``http`` / ``basic`` -- RFC 7617."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from base64 import b64encode
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import TypeAlias
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
10
|
+
from typing_extensions import TypedDict
|
|
11
|
+
|
|
12
|
+
from ...params import param
|
|
13
|
+
from ..models import AuthParams
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BasicAuthCredentials(BaseModel):
|
|
17
|
+
"""The user-id and password of an ``http``/``basic`` scheme (RFC 7617)."""
|
|
18
|
+
|
|
19
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
20
|
+
|
|
21
|
+
username: str
|
|
22
|
+
password: str = Field(repr=False)
|
|
23
|
+
|
|
24
|
+
@field_validator("username")
|
|
25
|
+
@classmethod
|
|
26
|
+
def _reject_colon(cls, value: str) -> str:
|
|
27
|
+
if ":" in value:
|
|
28
|
+
raise ValueError(
|
|
29
|
+
"username must not contain ':' -- RFC 7617 encodes 'user-id:password', so a colon "
|
|
30
|
+
f"in the user-id cannot be decoded unambiguously; got {value!r}"
|
|
31
|
+
)
|
|
32
|
+
return value
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def coerce(cls, value: BasicAuthCredentialsOrDict) -> BasicAuthCredentials:
|
|
36
|
+
"""Accept either spelling, validating the mapping form.
|
|
37
|
+
|
|
38
|
+
Unlike the other coercion seams in this runtime, no credential model's ``coerce`` takes
|
|
39
|
+
``None``: an absent credential means *no scheme*, which the client decides before this.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
value: The credential, as the typed model or as a mapping.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
The validated model, passed straight through when it already is one.
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
ValidationError: If the mapping is missing a key, carries an unknown one, or holds a
|
|
49
|
+
user-id with a colon. It subclasses ``ValueError``."""
|
|
50
|
+
if isinstance(value, cls):
|
|
51
|
+
return value
|
|
52
|
+
return cls.model_validate(value)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class BasicAuthCredentialsDict(TypedDict):
|
|
56
|
+
username: str
|
|
57
|
+
password: str
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
BasicAuthCredentialsOrDict: TypeAlias = BasicAuthCredentials | BasicAuthCredentialsDict
|
|
61
|
+
"""What a Basic credential accepts: the typed model, or a mapping carrying the same two keys."""
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass(frozen=True, slots=True)
|
|
65
|
+
class BasicAuthScheme:
|
|
66
|
+
"""``http``/``basic``: ``Authorization: Basic base64(user-id:password)``."""
|
|
67
|
+
|
|
68
|
+
credentials: BasicAuthCredentials
|
|
69
|
+
|
|
70
|
+
def apply(self) -> AuthParams:
|
|
71
|
+
raw = f"{self.credentials.username}:{self.credentials.password}"
|
|
72
|
+
encoded = b64encode(raw.encode()).decode()
|
|
73
|
+
return AuthParams(headers=(param[str]("Authorization", f"Basic {encoded}"),))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""``http`` / ``bearer`` -- and, on the wire, ``openIdConnect`` too."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
|
|
7
|
+
from ...params import param
|
|
8
|
+
from ..models import AuthParams
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True, slots=True)
|
|
12
|
+
class BearerAuthScheme:
|
|
13
|
+
"""``http``/``bearer``: ``Authorization: Bearer <token>``.
|
|
14
|
+
|
|
15
|
+
Also the wire form of an ``openIdConnect`` scheme, whose discovery document says how a token is
|
|
16
|
+
obtained but not how it is sent."""
|
|
17
|
+
|
|
18
|
+
token: str = field(repr=False)
|
|
19
|
+
|
|
20
|
+
def apply(self) -> AuthParams:
|
|
21
|
+
return AuthParams(headers=(param[str]("Authorization", f"Bearer {self.token}"),))
|