This repository has been archived by the owner on Oct 15, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(auth): update auth classes from gcloud-aio (#34)
- Loading branch information
1 parent
bf6af90
commit 6feecd0
Showing
13 changed files
with
412 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
from pkg_resources import get_distribution | ||
__version__ = get_distribution('gcloud-rest').version | ||
|
||
from gcloud.rest.auth.iam import IamClient | ||
from gcloud.rest.auth.token import Token | ||
from gcloud.rest.auth.utils import decode | ||
from gcloud.rest.auth.utils import encode | ||
|
||
|
||
__all__ = ['__version__', 'Token'] | ||
__all__ = ['__version__', 'IamClient', 'Token', 'decode', 'encode'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import json | ||
import threading | ||
from typing import Dict # pylint: disable=unused-import | ||
from typing import List # pylint: disable=unused-import | ||
from typing import Optional # pylint: disable=unused-import | ||
from typing import Union # pylint: disable=unused-import | ||
|
||
import requests | ||
|
||
from .token import Token | ||
from .token import Type | ||
from .utils import encode | ||
|
||
|
||
API_ROOT_IAM = 'https://iam.googleapis.com/v1' | ||
API_ROOT_IAM_CREDENTIALS = 'https://iamcredentials.googleapis.com/v1' | ||
SCOPES = ['https://www.googleapis.com/auth/iam'] | ||
|
||
|
||
class IamClient(object): | ||
def __init__(self, | ||
service_file=None, # type: Optional[str] | ||
session=None, # type: Optional[requests.Session] | ||
google_api_lock=None, # type: Optional[threading.RLock] | ||
token=None # type: Optional[Token] | ||
): | ||
# type: (...) -> None | ||
self.session = session | ||
self.google_api_lock = google_api_lock or threading.RLock() | ||
self.token = token or Token(service_file=service_file, | ||
session=session, scopes=SCOPES) | ||
|
||
if self.token.token_type != Type.SERVICE_ACCOUNT: | ||
raise TypeError('IAM Credentials Client is only valid for use' | ||
' with Service Accounts') | ||
|
||
def headers(self): | ||
# type: () -> Dict[str, str] | ||
token = self.token.get() | ||
return { | ||
'Authorization': 'Bearer {}'.format(token), | ||
} | ||
|
||
@property | ||
def service_account_email(self): | ||
# type: () -> Optional[str] | ||
return self.token.service_data.get('client_email') | ||
|
||
# https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts.keys/get | ||
def get_public_key(self, | ||
key_id=None, # type: Optional[str] | ||
key=None, # type: Optional[str] | ||
service_account_email=None, # type: Optional[str] | ||
project=None, # type: Optional[str] | ||
session=None, # type: requests.Session | ||
timeout=10 # type: int | ||
): | ||
# type: (...) -> Dict[str, str] | ||
service_account_email = (service_account_email | ||
or self.service_account_email) | ||
project = project or self.token.get_project() | ||
|
||
if not key_id and not key: | ||
raise ValueError('get_public_key must have either key_id or key') | ||
|
||
if not key: | ||
key = 'projects/{}/serviceAccounts/{}/keys/{}' \ | ||
.format(project, service_account_email, key_id) | ||
|
||
url = '{}/{}?publicKeyType=TYPE_X509_PEM_FILE'.format( | ||
API_ROOT_IAM, key) | ||
headers = self.headers() | ||
|
||
if not self.session: | ||
self.session = requests.Session() | ||
|
||
session = session or self.session | ||
with self.google_api_lock: | ||
resp = session.get(url, headers=headers, timeout=timeout) | ||
resp.raise_for_status() | ||
return resp.json() | ||
|
||
# https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts.keys/list | ||
def list_public_keys(self, | ||
service_account_email=None, # type: Optional[str] | ||
project=None, # type: Optional[str] | ||
session=None, # type: requests.Session | ||
timeout=10 # type: int | ||
): | ||
# type: (...) -> List[Dict[str, str]] | ||
service_account_email = (service_account_email | ||
or self.service_account_email) | ||
project = project or self.token.get_project() | ||
|
||
url = ('{}/projects/{}/serviceAccounts/' | ||
'{}/keys').format(API_ROOT_IAM, project, service_account_email) | ||
|
||
headers = self.headers() | ||
|
||
if not self.session: | ||
self.session = requests.Session() | ||
|
||
session = session or self.session | ||
with self.google_api_lock: | ||
resp = session.get(url, headers=headers, timeout=timeout) | ||
resp.raise_for_status() | ||
return resp.json().get('keys', []) | ||
|
||
# https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/signBlob | ||
def sign_blob(self, | ||
payload, # type: Optional[Union[str, bytes]] | ||
service_account_email=None, # type: Optional[str] | ||
delegates=None, # type: Optional[list] | ||
session=None, # type: requests.Session | ||
timeout=10 # type: int | ||
): | ||
# type: (...) -> Dict[str, str] | ||
service_account_email = ( | ||
service_account_email or self.service_account_email) | ||
if not service_account_email: | ||
raise TypeError('sign_blob must have a valid ' | ||
'service_account_email') | ||
|
||
resource_name = 'projects/-/serviceAccounts/{}'.format( | ||
service_account_email) | ||
url = '{}/{}:signBlob'.format(API_ROOT_IAM_CREDENTIALS, resource_name) | ||
|
||
json_str = json.dumps({ | ||
'delegates': delegates or [resource_name], | ||
'payload': encode(payload).decode('utf-8'), | ||
}) | ||
|
||
headers = self.headers() | ||
headers.update({ | ||
'Content-Length': str(len(json_str)), | ||
'Content-Type': 'application/json', | ||
}) | ||
|
||
if not self.session: | ||
self.session = requests.Session() | ||
|
||
session = session or self.session | ||
with self.google_api_lock: | ||
resp = session.post(url, data=json_str, | ||
headers=headers, timeout=timeout) | ||
resp.raise_for_status() | ||
return resp.json() |
Oops, something went wrong.