here.platform.credentials
Source code for here.platform.credentials
Copyright (C) 2020-2022 HERE Global B.V. and its affiliate(s).
All rights reserved.
This software and other materials contain proprietary information
controlled by HERE and are protected by applicable copyright legislation.
Any use and utilization of this software and other materials and
disclosure to any third parties is conditional upon having a separate
agreement with HERE for the access, use, utilization or disclosure of this
software. In the absence of such agreement, the use of the software is not
allowed.
"""
This module provides a PlatformCredentials class to be used for authentication.
A credentials object can be created from a credentials.properties file obtained
from the HERE platform portal or from environment variables or from a access-token
file generated in a pipeline.
"""
import enum
import os
from os import getenv
from os.path import expanduser, expandvars
from typing import List
from here.platform.exceptions import ConfigException
from here.platform.utils.properties_helper import PropertiesDict
PLATFORM_DEFAULT_CREDENTIALS_PATH = os.path.join(
expanduser("~"), ".here", "credentials.properties"
)
[docs]
class CredentialsType(enum.Enum):
"""
CredentialsType enum defines the different types of credentials supported.
Types: Credentials, Token.
"""
Credentials = 1
Token = 2
[docs]
class PlatformCredentials:
"""
PlatformCredentials provides functions for dealing with the HERE platform
Credentials.
Credentials can be read from the following locations:
- The default location: "~/.here/credentials.properties"
- A custom path to a credentials properties file
- Environment variables
"""
def init(
self,
cred_type: CredentialsType,
cred_properties: dict,
):
"""
Instantiate the credentials object.
:param cred_type: the type of Credentials.
:param cred_properties: the properties of Credentials.
"""
self.cred_type = cred_type
self.cred_properties = cred_properties
[docs]
@classmethod
def from_default(cls) -> "PlatformCredentials":
"""Return the credentials object from the default credential path
at '~/.here/credentials.properties'.
If environmental variables are set, these values will override the ones
found in the default file.
If no default file is found, this method will try to read the
credentials from the environmental variables.
:return: credentials
"""
try:
credentials = cls.from_credentials_file(PLATFORM_DEFAULT_CREDENTIALS_PATH)
except (ConfigException, FileNotFoundError):
credentials = cls.from_env()
if credentials.cred_type == CredentialsType.Credentials:
credentials.patch_using_env()
return credentials
[docs]
@classmethod
def from_credentials_file(cls, path: str) -> "PlatformCredentials":
"""
Return the credentials object from a specified credentials path.
:param path: path to a HERE platform credentials.properties file.
:return: credentials
:raises ConfigException: Erroneous credentials.properties file in path
"""
credentials_path = expanduser(expandvars(path))
try:
credentials_properties = PropertiesDict.parse(credentials_path)
user = credentials_properties["here.user.id"]
client = credentials_properties["here.client.id"]
key = credentials_properties["here.access.key.id"]
secret = credentials_properties["here.access.key.secret"]
endpoint = credentials_properties["here.token.endpoint.url"]
scope = credentials_properties.get("here.token.scope", None)
if user and client and key and secret and endpoint:
credentials_config = dict()
credentials_config["user"] = user
credentials_config["client"] = client
credentials_config["key"] = key
credentials_config["secret"] = secret
credentials_config["endpoint"] = endpoint
if scope:
credentials_config["scope"] = scope
return PlatformCredentials(CredentialsType.Credentials, credentials_config)
else:
raise ConfigException("Erroneous ", credentials_path, " file")
except Exception as e:
raise ConfigException(f"Erroneous {credentials_path} file: {e}")
[docs]
@classmethod
def from_token_file(cls, path: str) -> "PlatformCredentials":
"""
Return the credentials from a specified token file path.
:param path: path to a HERE platform token file.
:return: credentials
:raises ConfigException: Erroneous token file in path
"""
token_file_path = expanduser(expandvars(path))
try:
token_properties = PropertiesDict.parse(token_file_path)
access_token = token_properties["access_token"]
expires_in = token_properties["expires_in"]
exp = token_properties["exp"]
if access_token and expires_in and exp:
token_config = dict()
token_config["access_token"] = access_token
token_config["expires_in"] = expires_in
token_config["exp"] = exp
return PlatformCredentials(CredentialsType.Token, token_config)
else:
raise ConfigException("Erroneous", token_file_path, "file")
except Exception as e:
raise ConfigException(f"Erroneous {token_file_path} file: {e}")
[docs]
@classmethod
def from_env(cls) -> "PlatformCredentials":
"""
Return the credentials object from the following environment variables:
HERE_USER_IDHERE_CLIENT_IDHERE_ACCESS_KEY_IDHERE_ACCESS_KEY_SECRETHERE_TOKEN_ENDPOINT_URL(optional)HERE_TOKEN_SCOPE(optional)
:return: credentials parsed from the environment variables
:raises ConfigException: missing environmental variables that are mandatory
"""
user = getenv("HERE_USER_ID")
client = getenv("HERE_CLIENT_ID")
access_key_id = getenv("HERE_ACCESS_KEY_ID") or getenv("HERE_ACCESS_KEY")
access_key_secret = getenv("HERE_ACCESS_KEY_SECRET") or getenv("HERE_ACCESS_SECRET")
endpoint = (
getenv("HERE_TOKEN_ENDPOINT_URL")
or getenv("HERE_TOKEN_ENDPOINT")
or "https://account.api.here.com/oauth2/token"
)
scope = getenv("HERE_TOKEN_SCOPE")
missing_env_vars: List[str] = []
if not user:
missing_env_vars.append("HERE_USER_ID")
if not client:
missing_env_vars.append("HERE_CLIENT_ID")
if not access_key_id:
missing_env_vars.append("HERE_ACCESS_KEY_ID")
if not access_key_secret:
missing_env_vars.append("HERE_ACCESS_KEY_SECRET")
if missing_env_vars:
raise ConfigException(
"Missing environmental variables: ".format(", ".join(missing_env_vars))
)
at this points, we should have all the variables with a non-empty value
assert user and client and access_key_id and access_key_secret and endpoint
credentials_config = dict()
credentials_config["user"] = user
credentials_config["client"] = client
credentials_config["key"] = access_key_id
credentials_config["secret"] = access_key_secret
credentials_config["endpoint"] = endpoint
if scope:
credentials_config["scope"] = scope
return PlatformCredentials(CredentialsType.Credentials, credentials_config)
[docs]
def patch_using_env(self):
"""
Patch the credentials by reading the following environment variables and
applying them accordingly.
HERE_USER_IDHERE_CLIENT_IDHERE_ACCESS_KEY_IDHERE_ACCESS_KEY_SECRETHERE_TOKEN_ENDPOINT_URLHERE_TOKEN_SCOPE(optional)
Whenever such an environment variable is set,
it overrides the one loaded from file.
"""
if self.cred_type == CredentialsType.Credentials and self.cred_properties:
credentials_config = self.cred_properties
user = getenv("HERE_USER_ID") or credentials_config["user"]
client = getenv("HERE_CLIENT_ID") or credentials_config["client"]
key = (
getenv("HERE_ACCESS_KEY_ID")
or getenv("HERE_ACCESS_KEY")
or credentials_config["key"]
)
secret = (
getenv("HERE_ACCESS_KEY_SECRET")
or getenv("HERE_ACCESS_SECRET")
or credentials_config["secret"]
)
endpoint = (
getenv("HERE_TOKEN_ENDPOINT_URL")
or getenv("HERE_TOKEN_ENDPOINT")
or credentials_config["endpoint"]
)
scope = getenv("HERE_TOKEN_SCOPE")
credentials_config["user"] = user
credentials_config["client"] = client
credentials_config["key"] = key
credentials_config["secret"] = secret
credentials_config["endpoint"] = endpoint
if scope:
credentials_config["scope"] = scope