Reference Guide
This package provides functionality to authenticate/authorize requests sent to Envase services. It also provides classes
that can be extended to support other services. The main goal is to provide classes that can be used as targets to the
auth
parameter in the Requests Library that handle the
authentication/authorization process, as well as the refresh of access tokens, so that clients don’t need to worry
about those operations.
The problem that this library tries to solve is the fact that most authentication libraries only care about the authentication negotiation, and enforce that client applications and services follow a predetermine sequence of calls to retrieve and refresh tokens. This causes that most applications and services completely separate the process of authenticating from the process of sending authenticated requests, and forces the implementation to pass authentication information all over the place just to make sure the interface needed is available.
The following pseudocode shows the problem:
Warning
The following snippet is pseudocode and will not execute. The code doesn’t show how to use this library.
import request
import third_party_auth as tpa
class AuthenticationService:
def __init__(self, client_id, client_secret):
self._client_id = client_id
self._client_secret = client_secret
self._token = None
def get_access_token(self):
# Use the client information to get the access token
self._token = tpa.get_access_token(self._client_id, self._client_secret)
return self._token.access_token
def refresh_token(self):
self._token = tpa.refresh_token(self._token)
return self._token.access_token
# The client usually does something like this.
client_id = 'the-client-id'
client_secret = 'the-client-secret'
service = AuthenticationService(client_id, client_secret)
token = get_access_token(service)
response = send_request(service, token)
def get_access_token(service):
return service.get_access_token()
def send_request(service, token):
headers = {
'Authorization': token
}
response = request.get('https://server.com/api, headers=headers)
if response.status_code == http.HTTPStatusCodes.Forbidden:
# Refresh and retry
token = service.refresh_token()
return send_request(service, token)
return response.json()
The problem is that in most cases the function that retrieves the access token is far away from the function that sends the request, and the application needs to insure that the service and token are passed around, so that if the token has expired, it can be refreshed.
The solution is to encapsulate the process of retrieving and managing access tokens in a single class that insures the token is maintained valid. This library provides classes that solve this problem.
This library provides the concept of an IAuthorizer
interface, which handles the full negotiation of tokens and
their refresh when and if needed. The interface also takes care of updating request with the necessary information when
needed. The following is pseudocode showing how the example above is solved with this library:
import en_core.data as data
client_info = data.ClientInfo('the-client-id', 'the-client-secret')
authorizer = SomeConcreteAuthorizer(client_info)
send_request(authorizer)
def send_request(authorizer):
response = request.get('https://server.com/api, auth=authorizer)
return response.json()
The implementation of IAuthorizer
ensures the request is properly authorized before is sent to the server. It also
takes care of refreshing the access token when needed. Client applications and services only need to worry about managing
the life-time of the authorizer when needed.
Data Structures
This module provides data structures and constants used during authentication.
- AUTHORIZATION_HEADER
The standard Authorization header name.
- API_KEY_HEADER
The common X-Api-Header name.
- EXPIRATION_GAP
An expiration buffer used to insure that the access token doesn’t expire right after the expiration has been checked.
- class ClientInfo(client_id: str, client_secret: str, api_key: str = '')
Data structure that contains the authentication/authorization parameters for a client. The structure also supports an optional
api_key
for clients that may require it.- Parameters
client_id (str) – Client id for authorization.
client_secret (str) – Client secret for authorization
api_key (str) – Optional API key parameter for clients that might require it.
- to_basic_auth()
Returns a tuple of the
client_id
andclient_secret
that can be used as basic authentiation/authorization.- Returns
Basic authentication/authorization from the information specified.
Base Classes
This module provides base classes and general functionality to authorize HTTP requests. Base classes have been designed to be inherited and allow derived classes to implement a specific abstract interface to insure the correct functioning of the base classes.
- class Authorizer(client_info)
Base class for Authorization object that implements the
callable()
interface to support instances to be target of theauth
parameter of the exposed functions and Session objects in the Request python library.This is an ABC (Abstract Base Class) that cannot be directly instantiated. Instead, users should use one of the provided authorizers, or implement their own by deriving from this class.
The class manages the life-time of authorization tokens by providing an abstract interface that derived classes must implement. Derived classes that implement the exposed abstract interface will inherit the functionality to insure that access tokens are retrieve and refreshed as needed.
The class requires the client information to be specified during contruction. Derived classes can extend their contruction to allow additional parameters, but they should initialize the client information parameter.
- Parameters
client_info (ClientInfo) – Client information object that contains the id and secret of the client. It can also contain an optional API key.
- __call__(request)
This method allows instances of this class to be used as the target to the
auth
parameter in the Request python library. The function takes therequest
from the library and adds theAuthorization
header, as well as theX-Api-Key
header if it was provided in the client information.- Parameters
request (Request) –
Request object that will be processed by the Request library.
- Returns
Returns the modified request.
- property access_token
Provides the current access token. Client applications are not required to access this parameters to send calls. Instead, they will set the object as the value to the
auth
parameter on their call to Request
- abstract authorize()
Derived classes must implement this method to return an object representing authorization token. This authorization token must expose an
access_token
property/attribute that contains the string value for the access token that will be included in the header.The value returned by this function will be passed as parameters of the other abstract interface methods.
- Returns
An authorization token object that contains the
access_token
- property client_id
Returns the client id specified in the client information during initialization.
Warning
Do not expose the client secret in this class unless you have a very good reason and you got approval to do it.
- abstract expired(token)
This method must be implemented by derived classes to check if the specified token has expired. The function must return
True
if the token is expired orFalse
otherwise.
- abstract refresh(token)
This method must be implemented by derived classes to refresh the current token when the token has expired. The function takes the existing
token
as parameter, and should return a new refreshedtoken
. The returned token must contain anaccess_token
property.
OAuth2 Support
This module provides authorization classes for applications and services that use OAuth2 with the Envase authorization/authentication service.
Important
If your application or service is using this module, the requests
library must be installed as a dependency. This
library doesn’t install it to allow clients to select the authorizer type without installing unsued dependencies.
- class ServiceAccountAuthorizer(client_info, environment, _test_client=None)
This authorizer handles the authorization negotiation for Envase clients using service accounts (client credentials). It implements the
Authorizer
interface that authorizes the client, and allows to refresh tokens when they expire.The class is initialized with the client information and the environment indentifier for which to negotiate the token.
- Parameters
client_info (ClientInfo) – Client information used to generate access tokens.
environment (str) – Environment identifier to know which pool to use for authentication.
The following example shows how this class can be used:
import en_auth.oauth2 as auth import en_auth.data as data import requests config = get_config() client_id = config.get('CLIENT_ID') client_secret = config.get('CLIENT_SECRET') environment = config.get('ENVIRONMENT') client_info = data.ClientInfo(client_id, client_secret) authorizer = auth.ServiceAccountAuthorizer(client_info, environment) response = requests.get('https://envase.protected.url.com/api/resource', auth=authorizer)
Provided that client id and secret are valid for client credentials, the request will be authorized regardless of the status of authentication. The authorizer will handle the necessary negotiation to retrieve or refresh access tokens, so that the application doesn’t need to worry about that process.
- authorize()
Generates a token containing the
access_token
required for authorized requests.- Returns
Token object that contains the
access_token
used for authorization.
- expired(token)
Returns whether the token is expired or not.
- Parameters
token (Token) – The token retrieved from
authorize()
during authorization.- Returns
True
if the token has expired orFalse
otherwise.
- refresh(_not_used_token)
Generates a new token that can be used for authentication.
- Parameters
token (Token) – The token retrieved from
authorize()
during authorization. This implementation does not use the token parameter.- Returns
A new token object that contains the
access_token
used for authorization.
SRP Support
This module implements the Authorizer interface to use SRP the (Secure Remote Password) negotiation protocol with a Cognito AWS instance. Trusted clients enabled for SRP can use this authorizer to log in a user and gain an access token required for subsequent calls to Envase services.
Important
If your application or service is using this module, it needs to add the pycognito
library as a dependency. This
library doesn’t install the dependency to allow client applications and services to select the appropriate
authorization protocol without installing unused dependencies.
- class SrpAuthorizer(client_info, credentials, environment, _test_client=None)
This authorizer handles the authorization negotiation using the SRP (Secure Remote Password) protocol. The SRP protocol allows an application to log in a user with the authorization/authentication system and provide its identity information in the access token.
Envase applications and services that require access to user owned resources can use this protocol to retrieve the access token. This class will take care of renewing tokens when necessary.
The class is initialized using the
ClientInfo
for the client and theCredentials
of the user. The class also requires to specified the environment for which the application will require authentication.- Parameters
client_info (ClientInfo) – Client information (client id and secret) for the application or service initiating authentication.
credentials (Credentials) – User information for the user to log in.
environment (str) – Environment identifier for the environment to which the application will authenticate.
The following example shows how this class can be used:
import en_auth.srp as auth import en_auth.data as data import requests config = get_config() client_id = config.get('CLIENT_ID') client_secret = config.get('CLIENT_SECRET') user_name = config.get('USER_NAME') pwd = config.get('USER_PWD') environment = config.get('ENVIRONMENT') client_info = data.ClientInfo(client_id, client_secret) credentials = data.Credentials(user_name, pwd) authorizer = auth.SrpAuthorizer(client_info, credentials, environment) response = requests.get('https://envase.protected.url.com/api/resource', auth=authorizer)
- authorize()
Generates a token containing the
access_token
required for authorized requests.- Returns
A token object that exposes the access token.
- expired(token)
Returns whether the token is expired or not.
- Parameters
token (Token) – The token retrieved from
authorize()
during authorization.- Returns
True
if the token has expired orFalse
otherwise.
- refresh(_not_used_token)
Refreshes the token and returns it, so authorized requests can continue.
- Parameters
token (Token) – The token retrieved from
authorize()
during authorization.- Returns
A new refreshed token that can be use during authorization.
- report_invalid_client()
Raises an
InvalidClientError
. This method is for internal puposes only and client applications should not call the method.
- report_invalid_credentials()
Raises an
InvalidCredentialsError
. This method is for internal puposes only and client applications should not call the method.
- report_unknown_aws_error(status_code, message)
Raises an
AuthorizationError
. This method is for internal puposes only and client applications should not call the method.
Exceptions
This module provides the exceptions that will be raised during the authentication/authorization process. Classes that extend the functionality of this library should use the exceptions provided on this module.
- exception AuthorizationError(status_code, message)
This exception is raised when the authorization/authentication process cannot be completed for unknown reasons. The class exposes information about what happened as the message, as well as the status code returned by the authorization service.
- Parameters
status_code (int) – The status code returned by the authorization service.
message (str) – Information provided by the authorization service.
- exception InvalidClientError(client_info)
This exception is raised when the client information provided is not valid for authentication/authorization.
- Parameters
client_info (ClientInfo) – The client information that caused the problem.
- exception InvalidCredentialsError(credentials)