Skip to content

Commit

Permalink
Merge branch 'master' into 470-type-hints
Browse files Browse the repository at this point in the history
  • Loading branch information
Viicos committed Apr 5, 2023
2 parents 6daa0df + 1e2b7be commit b8bc3b5
Show file tree
Hide file tree
Showing 11 changed files with 386 additions and 91 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Change Log

## [4.1.0](https://github.com/auth0/auth0-python/tree/4.1.0) (2023-03-14)
[Full Changelog](https://github.com/auth0/auth0-python/compare/4.0.0...4.1.0)

**Added**
- Add branding theme endpoints [\#477](https://github.com/auth0/auth0-python/pull/477) ([adamjmcgrath](https://github.com/adamjmcgrath))
- [SDK-4011] Add API2 Factor Management Endpoints [\#476](https://github.com/auth0/auth0-python/pull/476) ([adamjmcgrath](https://github.com/adamjmcgrath))
- Use declarative setup with `pyproject.toml` [\#474](https://github.com/auth0/auth0-python/pull/474) ([Viicos](https://github.com/Viicos))

## [4.0.0](https://github.com/auth0/auth0-python/tree/4.0.0) (2023-01-19)
[Full Changelog](https://github.com/auth0/auth0-python/compare/3.24.1...4.0.0)

Expand Down
12 changes: 6 additions & 6 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
- [Authenticating with a application configured to use `private_key_jwt` token endpoint auth method](#authenticating-with-a-application-configured-to-use-private-key-jwt-token-endpoint-auth-method)
- [Management SDK](#management-sdk)
- [Connections](#connections)
- [Error handling](#error-handling)
- [Asynchronous environments](#asynchronous-environments)
- [Error handling](#error-handling)
- [Asynchronous environments](#asynchronous-environments)

## Authentication SDK

Expand All @@ -32,7 +32,7 @@ For symmetric algorithms like HS256, use the `SymmetricSignatureVerifier` class,
The following example demonstrates the verification of an ID token signed with the RS256 signing algorithm:

```python
from auth0.authentication import TokenVerifier, AsymmetricSignatureVerifier
from auth0.authentication.token_verifier import TokenVerifier, AsymmetricSignatureVerifier

domain = 'myaccount.auth0.com'
client_id = 'exampleid'
Expand Down Expand Up @@ -135,15 +135,15 @@ Success!
All endpoints follow a similar structure to `connections`, and try to follow as
closely as possible the [API documentation](https://auth0.com/docs/api/v2).

### Error handling
## Error handling

When consuming methods from the API clients, the requests could fail for a number of reasons:
- Invalid data sent as part of the request: An `Auth0Error` is raised with the error code and description.
- Global or Client Rate Limit reached: A `RateLimitError` is raised and the time at which the limit
resets is exposed in the `reset_at` property. When the header is unset, this value will be `-1`.
- Network timeouts: Adjustable by passing a `timeout` argument to the client. See the [rate limit docs](https://auth0.com/docs/policies/rate-limits) for details.

### Asynchronous environments
## Asynchronous environments

This SDK provides async methods built on top of [asyncio](https://docs.python.org/3/library/asyncio.html). To make them available you must have the [aiohttp](https://docs.aiohttp.org/en/stable/) module installed.

Expand Down Expand Up @@ -194,4 +194,4 @@ async def main():


asyncio.run(main())
```
```
2 changes: 1 addition & 1 deletion auth0/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "4.0.0"
__version__ = "4.1.0"

from auth0.exceptions import Auth0Error, RateLimitError, TokenValidationError

Expand Down
6 changes: 3 additions & 3 deletions auth0/management/async_auth0.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import aiohttp

from ..asyncify import asyncify
from .auth0 import modules
from .auth0 import Auth0


class AsyncAuth0:
Expand All @@ -20,8 +20,8 @@ class AsyncAuth0:

def __init__(self, domain, token, rest_options=None):
self._services = []
for name, cls in modules.items():
cls = asyncify(cls)
for name, attr in vars(Auth0(domain, token, rest_options=rest_options)).items():
cls = asyncify(attr.__class__)
service = cls(domain=domain, token=token, rest_options=rest_options)
self._services.append(service)
setattr(
Expand Down
78 changes: 38 additions & 40 deletions auth0/management/auth0.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from ..utils import is_async_available
from .actions import Actions
from .attack_protection import AttackProtection
from .blacklists import Blacklists
Expand Down Expand Up @@ -30,39 +29,6 @@
from .users import Users
from .users_by_email import UsersByEmail

modules = {
"actions": Actions,
"attack_protection": AttackProtection,
"blacklists": Blacklists,
"branding": Branding,
"client_credentials": ClientCredentials,
"client_grants": ClientGrants,
"clients": Clients,
"connections": Connections,
"custom_domains": CustomDomains,
"device_credentials": DeviceCredentials,
"email_templates": EmailTemplates,
"emails": Emails,
"grants": Grants,
"guardian": Guardian,
"hooks": Hooks,
"jobs": Jobs,
"log_streams": LogStreams,
"logs": Logs,
"organizations": Organizations,
"prompts": Prompts,
"resource_servers": ResourceServers,
"roles": Roles,
"rules_configs": RulesConfigs,
"rules": Rules,
"stats": Stats,
"tenants": Tenants,
"tickets": Tickets,
"user_blocks": UserBlocks,
"users_by_email": UsersByEmail,
"users": Users,
}


class Auth0:
"""Provides easy access to all endpoint classes
Expand All @@ -79,9 +45,41 @@ class Auth0:
"""

def __init__(self, domain, token, rest_options=None):
for name, cls in modules.items():
setattr(
self,
name,
cls(domain=domain, token=token, rest_options=rest_options),
)
self.actions = Actions(domain, token, rest_options=rest_options)
self.attack_protection = AttackProtection(
domain, token, rest_options=rest_options
)
self.blacklists = Blacklists(domain, token, rest_options=rest_options)
self.branding = Branding(domain, token, rest_options=rest_options)
self.client_credentials = ClientCredentials(
domain, token, rest_options=rest_options
)
self.client_grants = ClientGrants(domain, token, rest_options=rest_options)
self.clients = Clients(domain, token, rest_options=rest_options)
self.connections = Connections(domain, token, rest_options=rest_options)
self.custom_domains = CustomDomains(domain, token, rest_options=rest_options)
self.device_credentials = DeviceCredentials(
domain, token, rest_options=rest_options
)
self.email_templates = EmailTemplates(domain, token, rest_options=rest_options)
self.emails = Emails(domain, token, rest_options=rest_options)
self.grants = Grants(domain, token, rest_options=rest_options)
self.guardian = Guardian(domain, token, rest_options=rest_options)
self.hooks = Hooks(domain, token, rest_options=rest_options)
self.jobs = Jobs(domain, token, rest_options=rest_options)
self.log_streams = LogStreams(domain, token, rest_options=rest_options)
self.logs = Logs(domain, token, rest_options=rest_options)
self.organizations = Organizations(domain, token, rest_options=rest_options)
self.prompts = Prompts(domain, token, rest_options=rest_options)
self.resource_servers = ResourceServers(
domain, token, rest_options=rest_options
)
self.roles = Roles(domain, token, rest_options=rest_options)
self.rules_configs = RulesConfigs(domain, token, rest_options=rest_options)
self.rules = Rules(domain, token, rest_options=rest_options)
self.stats = Stats(domain, token, rest_options=rest_options)
self.tenants = Tenants(domain, token, rest_options=rest_options)
self.tickets = Tickets(domain, token, rest_options=rest_options)
self.user_blocks = UserBlocks(domain, token, rest_options=rest_options)
self.users_by_email = UsersByEmail(domain, token, rest_options=rest_options)
self.users = Users(domain, token, rest_options=rest_options)
53 changes: 53 additions & 0 deletions auth0/management/branding.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,56 @@ def update_template_universal_login(self, body):
self._url("templates", "universal-login"),
body={"template": body},
)

def get_default_branding_theme(self):
"""Retrieve default branding theme.
See: https://auth0.com/docs/api/management/v2#!/Branding/get_default_branding_theme
"""

return self.client.get(self._url("themes", "default"))

def get_branding_theme(self, theme_id):
"""Retrieve branding theme.
Args:
theme_id (str): The theme_id to retrieve branding theme for.
See: https://auth0.com/docs/api/management/v2#!/Branding/get_branding_theme
"""

return self.client.get(self._url("themes", theme_id))

def delete_branding_theme(self, theme_id):
"""Delete branding theme.
Args:
theme_id (str): The theme_id to delete branding theme for.
See: https://auth0.com/docs/api/management/v2#!/Branding/delete_branding_theme
"""

return self.client.delete(self._url("themes", theme_id))

def update_branding_theme(self, theme_id, body):
"""Update branding theme.
Args:
theme_id (str): The theme_id to update branding theme for.
body (dict): The attributes to set on the theme.
See: https://auth0.com/docs/api/management/v2#!/Branding/patch_branding_theme
"""

return self.client.patch(self._url("themes", theme_id), data=body)

def create_branding_theme(self, body):
"""Create branding theme.
Args:
body (dict): The attributes to set on the theme.
See: https://auth0.com/docs/api/management/v2#!/Branding/post_branding_theme
"""

return self.client.post(self._url("themes"), data=body)
92 changes: 92 additions & 0 deletions auth0/management/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,95 @@ def invalidate_remembered_browsers(self, user_id):

url = self._url(f"{user_id}/multifactor/actions/invalidate-remember-browser")
return self.client.post(url)

def get_authentication_methods(self, user_id):
"""Gets a list of authentication methods
Args:
user_id (str): The user_id to get a list of authentication methods for.
See: https://auth0.com/docs/api/management/v2#!/Users/get_authentication_methods
"""

url = self._url(f"{user_id}/authentication-methods")
return self.client.get(url)

def get_authentication_method_by_id(self, user_id, authentication_method_id):
"""Gets an authentication method by ID.
Args:
user_id (str): The user_id to get an authentication method by ID for.
authentication_method_id (str): The authentication_method_id to get an authentication method by ID for.
See: https://auth0.com/docs/api/management/v2#!/Users/get_authentication_methods_by_authentication_method_id
"""

url = self._url(f"{user_id}/authentication-methods/{authentication_method_id}")
return self.client.get(url)

def create_authentication_method(self, user_id, body):
"""Creates an authentication method for a given user.
Args:
user_id (str): The user_id to create an authentication method for a given user.
body (dict): the request body to create an authentication method for a given user.
See: https://auth0.com/docs/api/management/v2#!/Users/post_authentication_methods
"""

url = self._url(f"{user_id}/authentication-methods")
return self.client.post(url, data=body)

def update_authentication_methods(self, user_id, body):
"""Updates all authentication methods for a user by replacing them with the given ones.
Args:
user_id (str): The user_id to update all authentication methods for.
body (dict): the request body to update all authentication methods with.
See: https://auth0.com/docs/api/management/v2#!/Users/put_authentication_methods
"""

url = self._url(f"{user_id}/authentication-methods")
return self.client.put(url, data=body)

def update_authentication_method_by_id(
self, user_id, authentication_method_id, body
):
"""Updates an authentication method.
Args:
user_id (str): The user_id to update an authentication method.
authentication_method_id (str): The authentication_method_id to update an authentication method for.
body (dict): the request body to update an authentication method.
See: https://auth0.com/docs/api/management/v2#!/Users/patch_authentication_methods_by_authentication_method_id
"""

url = self._url(f"{user_id}/authentication-methods/{authentication_method_id}")
return self.client.patch(url, data=body)

def delete_authentication_methods(self, user_id):
"""Deletes all authentication methods for the given user.
Args:
user_id (str): The user_id to delete all authentication methods for the given user for.
See: https://auth0.com/docs/api/management/v2#!/Users/delete_authentication_methods
"""

url = self._url(f"{user_id}/authentication-methods")
return self.client.delete(url)

def delete_authentication_method_by_id(self, user_id, authentication_method_id):
"""Deletes an authentication method by ID.
Args:
user_id (str): The user_id to delete an authentication method by ID for.
authentication_method_id (str): The authentication_method_id to delete an authentication method by ID for.
See: https://auth0.com/docs/api/management/v2#!/Users/delete_authentication_methods_by_authentication_method_id
"""

url = self._url(f"{user_id}/authentication-methods/{authentication_method_id}")
return self.client.delete(url)
62 changes: 62 additions & 0 deletions auth0/test/management/test_branding.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,65 @@ def test_update_template_universal_login(self, mock_rc):
"https://domain/api/v2/branding/templates/universal-login",
body={"template": {"a": "b", "c": "d"}},
)

@mock.patch("auth0.management.branding.RestClient")
def test_get_default_branding_theme(self, mock_rc):
api = mock_rc.return_value
api.get.return_value = {}

branding = Branding(domain="domain", token="jwttoken")
branding.get_default_branding_theme()

api.get.assert_called_with(
"https://domain/api/v2/branding/themes/default",
)

@mock.patch("auth0.management.branding.RestClient")
def test_get_branding_theme(self, mock_rc):
api = mock_rc.return_value
api.get.return_value = {}

branding = Branding(domain="domain", token="jwttoken")
branding.get_branding_theme("theme_id")

api.get.assert_called_with(
"https://domain/api/v2/branding/themes/theme_id",
)

@mock.patch("auth0.management.branding.RestClient")
def test_delete_branding_theme(self, mock_rc):
api = mock_rc.return_value
api.delete.return_value = {}

branding = Branding(domain="domain", token="jwttoken")
branding.delete_branding_theme("theme_id")

api.delete.assert_called_with(
"https://domain/api/v2/branding/themes/theme_id",
)

@mock.patch("auth0.management.branding.RestClient")
def test_update_branding_theme(self, mock_rc):
api = mock_rc.return_value
api.patch.return_value = {}

branding = Branding(domain="domain", token="jwttoken")
branding.update_branding_theme("theme_id", {})

api.patch.assert_called_with(
"https://domain/api/v2/branding/themes/theme_id",
data={},
)

@mock.patch("auth0.management.branding.RestClient")
def test_create_branding_theme(self, mock_rc):
api = mock_rc.return_value
api.post.return_value = {}

branding = Branding(domain="domain", token="jwttoken")
branding.create_branding_theme({})

api.post.assert_called_with(
"https://domain/api/v2/branding/themes",
data={},
)
Loading

0 comments on commit b8bc3b5

Please sign in to comment.