Skip to content

Commit

Permalink
Hide internals (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
Colin-b authored Jun 17, 2024
1 parent cbe65d7 commit 6a53852
Show file tree
Hide file tree
Showing 34 changed files with 1,707 additions and 1,475 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Adding explicit support for Python `3.12`.

### Changed
- Except for `requests_auth.testing`, only direct access via `requests_auth.` was considered publicly exposed. This is now explicit, as inner packages are now using private prefix (`_`).
If you were relying on some classes or functions that are now internal, feel free to open an issue.

### Fixed
- Type information is now provided following [PEP 561](https://www.python.org/dev/peps/pep-0561/)

### Removed
- Removing support for Python `3.7`.

Expand Down
57 changes: 49 additions & 8 deletions requests_auth/__init__.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
from requests_auth.authentication import (
from requests_auth._authentication import (
Basic,
HeaderApiKey,
QueryApiKey,
NTLM,
Auths,
OAuth2,
)
from requests_auth._oauth2.common import OAuth2
from requests_auth._oauth2.authorization_code import (
OAuth2AuthorizationCode,
OktaAuthorizationCode,
)
from requests_auth._oauth2.authorization_code_pkce import (
OAuth2AuthorizationCodePKCE,
OktaAuthorizationCodePKCE,
)
from requests_auth._oauth2.client_credentials import (
OAuth2ClientCredentials,
OktaClientCredentials,
)
from requests_auth._oauth2.implicit import (
OAuth2Implicit,
OktaImplicit,
OktaImplicitIdToken,
AzureActiveDirectoryImplicit,
AzureActiveDirectoryImplicitIdToken,
OAuth2AuthorizationCode,
OktaAuthorizationCode,
OAuth2ClientCredentials,
OktaClientCredentials,
)
from requests_auth._oauth2.resource_owner_password import (
OAuth2ResourceOwnerPasswordCredentials,
OktaResourceOwnerPasswordCredentials,
)
from requests_auth.oauth2_tokens import JsonTokenFileCache
from requests_auth.errors import (
from requests_auth._oauth2.tokens import JsonTokenFileCache
from requests_auth._errors import (
GrantNotProvided,
TimeoutOccurred,
AuthenticationFailed,
Expand All @@ -30,3 +40,34 @@
InvalidGrantRequest,
)
from requests_auth.version import __version__

__all__ = [
"Basic",
"HeaderApiKey",
"QueryApiKey",
"OAuth2",
"OAuth2AuthorizationCodePKCE",
"OktaAuthorizationCodePKCE",
"OAuth2Implicit",
"OktaImplicit",
"OktaImplicitIdToken",
"AzureActiveDirectoryImplicit",
"AzureActiveDirectoryImplicitIdToken",
"OAuth2AuthorizationCode",
"OktaAuthorizationCode",
"OAuth2ClientCredentials",
"OktaClientCredentials",
"OAuth2ResourceOwnerPasswordCredentials",
"OktaResourceOwnerPasswordCredentials",
"NTLM",
"Auths",
"JsonTokenFileCache",
"GrantNotProvided",
"TimeoutOccurred",
"AuthenticationFailed",
"StateNotProvided",
"InvalidToken",
"TokenExpiryNotProvided",
"InvalidGrantRequest",
"__version__",
]
155 changes: 155 additions & 0 deletions requests_auth/_authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
from urllib.parse import parse_qs, urlsplit, urlunsplit, urlencode

import requests
import requests.auth
import warnings


class SupportMultiAuth:
"""Inherit from this class to be able to use your class with requests_auth provided authentication classes."""

def __add__(self, other):
if isinstance(other, _MultiAuth):
return _MultiAuth(self, *other.authentication_modes)
return _MultiAuth(self, other)

def __and__(self, other):
if isinstance(other, _MultiAuth):
return _MultiAuth(self, *other.authentication_modes)
return _MultiAuth(self, other)


class HeaderApiKey(requests.auth.AuthBase, SupportMultiAuth):
"""Describes an API Key requests authentication."""

def __init__(self, api_key: str, header_name: str = None):
"""
:param api_key: The API key that will be sent.
:param header_name: Name of the header field. "X-API-Key" by default.
"""
self.api_key = api_key
if not api_key:
raise Exception("API Key is mandatory.")
self.header_name = header_name or "X-API-Key"

def __call__(self, r):
r.headers[self.header_name] = self.api_key
return r


class QueryApiKey(requests.auth.AuthBase, SupportMultiAuth):
"""Describes an API Key requests authentication."""

def __init__(self, api_key: str, query_parameter_name: str = None):
"""
:param api_key: The API key that will be sent.
:param query_parameter_name: Name of the query parameter. "api_key" by default.
"""
self.api_key = api_key
if not api_key:
raise Exception("API Key is mandatory.")
self.query_parameter_name = query_parameter_name or "api_key"

def __call__(self, r):
r.url = _add_parameters(r.url, {self.query_parameter_name: self.api_key})
return r


class Basic(requests.auth.HTTPBasicAuth, SupportMultiAuth):
"""Describes a basic requests authentication."""

def __init__(self, username: str, password: str):
requests.auth.HTTPBasicAuth.__init__(self, username, password)


class NTLM(requests.auth.AuthBase, SupportMultiAuth):
"""Describes a NTLM requests authentication."""

def __init__(self, username: str = None, password: str = None):
"""
:param username: Mandatory if requests_negotiate_sspi module is not installed.
:param password: Mandatory if requests_negotiate_sspi module is not installed.
"""
self.username = username
self.password = password
if not username and not password:
try:
import requests_negotiate_sspi

self.auth = requests_negotiate_sspi.HttpNegotiateAuth()
except ImportError:
raise Exception(
"NTLM authentication requires requests_negotiate_sspi module."
)
else:
if not username:
raise Exception(
'NTLM authentication requires "username" to be provided in security_details.'
)
if not password:
raise Exception(
'NTLM authentication requires "password" to be provided in security_details.'
)
try:
import requests_ntlm

self.auth = requests_ntlm.HttpNtlmAuth(username, password)
except ImportError:
raise Exception("NTLM authentication requires requests_ntlm module.")

def __call__(self, r):
self.auth.__call__(r)
return r


class _MultiAuth(requests.auth.AuthBase):
"""Authentication using multiple authentication methods."""

def __init__(self, *authentication_modes):
self.authentication_modes = authentication_modes

def __call__(self, r):
for authentication_mode in self.authentication_modes:
authentication_mode.__call__(r)
return r

def __add__(self, other):
if isinstance(other, _MultiAuth):
return _MultiAuth(*self.authentication_modes, *other.authentication_modes)
return _MultiAuth(*self.authentication_modes, other)

def __and__(self, other):
if isinstance(other, _MultiAuth):
return _MultiAuth(*self.authentication_modes, *other.authentication_modes)
return _MultiAuth(*self.authentication_modes, other)


class Auths(_MultiAuth):
def __init__(self, *authentication_modes):
warnings.warn(
"Auths class will be removed in the future. Use + instead.",
DeprecationWarning,
)
super().__init__(*authentication_modes)


def _add_parameters(initial_url: str, extra_parameters: dict) -> str:
"""
Add parameters to an URL and return the new URL.
:param initial_url:
:param extra_parameters: dictionary of parameters name and value.
:return: the new URL containing parameters.
"""
scheme, netloc, path, query_string, fragment = urlsplit(initial_url)
query_params = parse_qs(query_string)
query_params.update(
{
parameter_name: [parameter_value]
for parameter_name, parameter_value in extra_parameters.items()
}
)

new_query_string = urlencode(query_params, doseq=True)

return urlunsplit((scheme, netloc, path, new_query_string, fragment))
File renamed without changes.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from urllib.parse import parse_qs, urlparse
from socket import socket

from requests_auth.errors import *
from requests_auth._errors import *

logger = logging.getLogger(__name__)

Expand Down
Loading

0 comments on commit 6a53852

Please sign in to comment.