def list(pat: str, resource_registration_endpoint: str, secure: bool = False) -> List[str]: """ Lists all previously registered resources by ID for this resource owner. - CAN THROW EXCEPTIONS - MAKES A CONNECTION TO AN EXTERNAL ENDPOINT Args: - pat = String containing the pat (token) - resource_registration_endpoint = URL of the resource registration endpoint in the AS - secure = toggle checking of SSL certificates. Activating this is recommended on production environments Returns: List of IDs (str) registered """ headers = {"Authorization": "Bearer " + pat} disable_warnings_if_debug(secure) response = request("GET", resource_registration_endpoint, headers=headers, verify=secure) if not is_ok(response): raise Exception("An error occurred while listing resources: " + str(response.status_code) + ":" + str(response.reason) + ":" + str(response.text)) return response.json()
def delete(pat: str, resource_registration_endpoint: str, resource_id: str, secure: bool = False): """ Deletes a resource from the AS. - CAN THROW EXCEPTIONS - MAKES A CONNECTION TO AN EXTERNAL ENDPOINT Args: - pat = String containing the pat (token) - resource_registration_endpoint = URL of the resource registration endpoint in the AS - resource_id = ID of the resource - secure = toggle checking of SSL certificates. Activating this is recommended on production environments Returns: Nothing. If no exceptions are raised, the operation completed succesfully. """ headers = {"Authorization": "Bearer " + pat} disable_warnings_if_debug(secure) response = request("DELETE", resource_registration_endpoint + resource_id, headers=headers, verify=secure) if not is_ok(response): raise Exception("An error occurred while deleting the resource: " + str(response.status_code) + ":" + str(response.reason) + ":" + str(response.text))
def introspect(rpt: str, pat: str, introspection_endpoint: str, secure: bool = False) -> dict: """ Gets information about an RPT, using the AS' introspection endpoint. - CAN THROW EXCEPTIONS - MAKES A CONNECTION TO AN EXTERNAL ENDPOINT Args: - rpt = String containing the rpt (token) - pat = String containing the pat (token) - introspection_endpoint = String containing the url to the AS' introspection endpoint - secure = toggle checking of SSL certificates. Activating this is recommended on production environments Returns: JSON-formatted data about the RPT, or an error from the AS """ headers = { 'content-type': "application/x-www-form-urlencoded", 'authorization': "Bearer "+pat, } payload = "token="+rpt disable_warnings_if_debug(secure) r = request("POST", introspection_endpoint, headers=headers, data=payload, verify=secure) if not is_ok(r): raise Exception("An error occurred while registering the resource: "+str(r.status_code)+":"+str(r.reason)) try: return r.json() except Exception as e: raise Exception("Call to introspection point returned unexpected value: "+str(e))
def request_access_ticket(pat: str, permission_endpoint: str, resources: List[dict], secure: bool = False) -> str: """ As a Resource Server, request permission to the AS to access a resource, generating a ticket as a result. - CAN THROW EXCEPTIONS - MAKES A CONNECTION TO AN EXTERNAL ENDPOINT Args: - pat = String containing the pat (token) - permission_endpoint = URL of the token permission endpoint in the AS - resources = List of resources to request permission to. Format: [ { "resource_id": <str resource id>, "resource_scopes": [ <scope 1>, <scope 2>, ...] }, ... ] - secure = toggle checking of SSL certificates. Activating this is recommended on production environments Returns: A string containing the ticket for accessing those resources. """ headers = { 'content-type': "application/json", 'authorization': "Bearer " + pat, } if len(resources) == 1: resources = resources[ 0] # Use a single dict instead of a list for 1 resource disable_warnings_if_debug(secure) response = request("POST", permission_endpoint, json=resources, headers=headers, verify=secure) if not is_ok(response): raise Exception( "An error occurred while requesting permission for a resource: " + str(response.status_code) + ":" + str(response.reason) + ":" + str(response.text)) try: return response.json()["ticket"] except Exception as e: raise Exception( "Call to permission endpoint returned unexpected value or error: '" + response.text + "'" + ". Error: " + str(e))
def create(pat: str, resource_registration_endpoint: str, name: str, scopes: List[str], description: str = None, icon_uri: str = None, typ: str = None, secure: bool = False) -> str: """ Registers a new resource in the AS. - CAN THROW EXCEPTIONS - MAKES A CONNECTION TO AN EXTERNAL ENDPOINT Args: - pat = String containing the pat (token) - resource_registration_endpoint = URL of the resource registration endpoint in the AS - name = Name given to the new resource - scopes = List of scopes (strings) assigned to this resource - description (Optional) = Description for the resource - icon_uri (Optional) = URI to an icon representing this resource - typ (Optional) = Type (string/URI) of this resource - secure = toggle checking of SSL certificates. Activating this is recommended on production environments Returns: Resource ID given by the AS associated with the newly created resource, or an error """ payload = {"name": name, "resource_scopes": scopes} dict_insert_if_exists(payload, "description", description) dict_insert_if_exists(payload, "icon_uri", icon_uri) dict_insert_if_exists(payload, "type", typ) headers = { 'Content-Type': "application/json", 'Authorization': "Bearer " + pat, } disable_warnings_if_debug(secure) response = request("POST", resource_registration_endpoint, json=payload, headers=headers, verify=secure) if not is_ok(response): raise Exception("An error occurred while registering the resource: " + str(response.status_code) + ":" + str(response.reason) + ":" + str(response.text)) try: return response.json()["_id"] except Exception as e: raise Exception( "Call to registration endpoint returned unexpected value: '" + response.text + "'" + ". Error: " + str(e))
def request_for_rpt(client_creds_token: str, token_endpoint: str, ticket: str, claim_token: str = None, claim_token_format: str = None, scopes: List[str] = None, rpt: str = None, pct: str = None, secure: bool = True) -> dict: """ Requests the AS for an RPT given the arguments used. Reference: https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-grant-2.0.html#uma-grant-type - CAN THROW EXCEPTIONS - MAKES A CONNECTION TO AN EXTERNAL ENDPOINT Args: - client_creds_token = token obtained from AS with client credentials - token_endpoint = String containing the url to the AS' token endpoint - ticket = Ticket obtained from Resource Server for this request - claim_token (Optional) = A string containing directly pushed claim information in the indicated format. It MUST be base64url encoded unless specified otherwise by the claim token format - claim_token_format (Optional) = If this parameter is used, it MUST appear together with the claim_token parameter. A string specifying the format of the claim token in which the client is directly pushing claims to the authorization server. The string MAY be a URI - scopes (Optional) = List of requested scopes - rpt (Optional) = A string containing an existing RPT. Allows the Auth Server to upgrade instead of issuing a new RPT. - pct (Optional) = A string with an old PCT to optimize looking for a new RPT. - secure = toggle checking of SSL certificates. Activating this is recommended on production environments Returns: A dictionary with at least an access_token and a 'token_type', or an exception """ grant_type = "urn:ietf:params:oauth:grant-type:uma-ticket" # Fixed value according to https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-grant-2.0.html#uma-grant-type headers = {"Authorization": "Basic "+ client_creds_token} payload = "grant_type="+grant_type+"&ticket="+ticket if claim_token: payload+="&claim_token="+claim_token # Format only allowed when claim token is given. if claim_token_format: payload+="&claim_token_format="+claim_token_format if scopes and len(scopes) > 0: payload+="&scope="+" ".join(scopes) if rpt and len(rpt) > 0: payload+="&rpt="+rpt if pct and len(pct) > 0: payload+="&pct="+pct disable_warnings_if_debug(secure) response = request("POST", token_endpoint , data=payload, headers=headers, verify=secure) if not is_ok(response): raise Exception("An error occurred while requesting RPT: "+str(response.status_code)+":"+str(response.reason)) return response.json()
def request_resource(self, uri: str, rpt: str = None, secure: bool = True) -> bytes: """ Requests a resource from the resource server. If you have an RPT token for this resource, you can try to re-use it calling this function with your RPT, but please notice this function wont try to re-generate an RPT via ticket if one is given. If you have no RPT but you have initialized this client with the proper credentials, this function call will auto-authenticate, handling ticket and RPT calls until the resource is obtained. - CAN THROW EXCEPTIONS - MAKES A CONNECTION TO AN EXTERNAL ENDPOINT Args: - uri = URI to the resource you want to access inside the resource server. - rpt (Optional) = String containing the rpt (token) - secure (Optional) = toggle checking of SSL certificates. Activating this is recommended on production environments Returns: The resource requested in bytes, or an exception if something went wrong. """ headers = {} if rpt: headers = {"Authorization": "Bearer " + rpt} # Request resource ret = request("GET", self.resource_server + uri, headers=headers, secure=secure) # Handle ticket if ret.status_code == 401: rpt = self._handle_ticket_request(ret) # Re-try with an rpt obtained from ticket return self.request_resource(uri, rpt, secure) # Any error other than a 401 is an error that this client cannot automatically solve elif not is_ok(ret): raise Exception( "Resource server denied access with an unexpected error: " + str(ret.status_code) + ": " + str(ret.reason)) # Return resource when access is achieved return ret.content
def read(pat: str, resource_registration_endpoint: str, resource_id: str, secure: bool = False) -> dict: """ Reads the information for a single resource, indicated by resource ID. Note that if an empty resource ID is given, this function is identical to 'list()', but please use each function for their respective intended use as this behaviour is not intended by design and may change at any time - CAN THROW EXCEPTIONS - MAKES A CONNECTION TO AN EXTERNAL ENDPOINT Args: - pat = String containing the pat (token) - resource_registration_endpoint = URL of the resource registration endpoint in the AS - resource_id = ID of the resource on the AS - secure = toggle checking of SSL certificates. Activating this is recommended on production environments Returns: JSON-formatted information about the resource """ headers = {"Authorization": "Bearer " + pat} disable_warnings_if_debug(secure) if resource_registration_endpoint[-1] is not "/": resource_registration_endpoint += "/" response = request("GET", resource_registration_endpoint + resource_id, headers=headers, verify=secure) if not is_ok(response): raise Exception( "An error occurred while getting a resource's information: " + str(response.status_code) + ":" + str(response.reason) + ":" + str(response.text)) return response.json()
def update(pat: str, resource_registration_endpoint: str, resource_id: str, name: str, scopes: List[str], description: str = None, icon_uri: str = None, typ: str = None, secure: bool = False) -> str: """ Updates one or more aspects of the resource indicated by id. The entirety of the resource will be overwritten with these values as per UMA 2.0's standard. https://docs.kantarainitiative.org/uma/wg/rec-oauth-uma-federated-authz-2.0.html#update-resource-set - CAN THROW EXCEPTIONS - MAKES A CONNECTION TO AN EXTERNAL ENDPOINT Args: - pat = String containing the pat (token) - resource_registration_endpoint = URL of the resource registration endpoint in the AS - resource_id = ID of the resource - name (Optional) = Name given to the new resource - scopes (Optional) = List of scopes (strings) assigned to this resource - description (Optional) = Description for the resource - icon_uri (Optional) = URI to an icon representing this resource - typ (Optional) = Type (string/URI) of this resource - secure = toggle checking of SSL certificates. Activating this is recommended on production environments Returns: Resource ID given by the AS associated with the edited resource """ payload = {} dict_insert_if_exists(payload, "name", name) dict_insert_if_exists(payload, "resource_scopes", scopes) dict_insert_if_exists(payload, "description", description) dict_insert_if_exists(payload, "icon_uri", icon_uri) dict_insert_if_exists(payload, "type", typ) if len(payload) == 0: raise Exception( "No attribute to update the resource with, payload empty") headers = { 'content-type': "application/json", 'authorization': "Bearer " + pat, } disable_warnings_if_debug(secure) response = request("PUT", resource_registration_endpoint + resource_id, json=payload, headers=headers, verify=secure) if not is_ok(response): raise Exception("An error occurred while registering the resource: " + str(response.status_code) + ":" + str(response.reason) + ":" + str(response.text)) try: return response.json()["_id"] except Exception as e: raise Exception( "Call to registration endpoint returned unexpected value: '" + response.text + "'" + ". Error: " + str(e))