OLD | NEW |
(Empty) | |
| 1 # Copyright 2015 Google Inc. All Rights Reserved. |
| 2 # |
| 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 # you may not use this file except in compliance with the License. |
| 5 # You may obtain a copy of the License at |
| 6 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # |
| 9 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 # See the License for the specific language governing permissions and |
| 13 # limitations under the License. |
| 14 |
| 15 """OAuth 2.0 utitilies for Google Developer Shell environment.""" |
| 16 |
| 17 import json |
| 18 import os |
| 19 |
| 20 from . import client |
| 21 |
| 22 |
| 23 DEVSHELL_ENV = 'DEVSHELL_CLIENT_PORT' |
| 24 |
| 25 |
| 26 class Error(Exception): |
| 27 """Errors for this module.""" |
| 28 pass |
| 29 |
| 30 |
| 31 class CommunicationError(Error): |
| 32 """Errors for communication with the Developer Shell server.""" |
| 33 |
| 34 |
| 35 class NoDevshellServer(Error): |
| 36 """Error when no Developer Shell server can be contacted.""" |
| 37 |
| 38 |
| 39 # The request for credential information to the Developer Shell client socket is |
| 40 # always an empty PBLite-formatted JSON object, so just define it as a constant. |
| 41 CREDENTIAL_INFO_REQUEST_JSON = '[]' |
| 42 |
| 43 |
| 44 class CredentialInfoResponse(object): |
| 45 """Credential information response from Developer Shell server. |
| 46 |
| 47 The credential information response from Developer Shell socket is a |
| 48 PBLite-formatted JSON array with fields encoded by their index in the array: |
| 49 * Index 0 - user email |
| 50 * Index 1 - default project ID. None if the project context is not known. |
| 51 * Index 2 - OAuth2 access token. None if there is no valid auth context. |
| 52 """ |
| 53 |
| 54 def __init__(self, json_string): |
| 55 """Initialize the response data from JSON PBLite array.""" |
| 56 pbl = json.loads(json_string) |
| 57 if not isinstance(pbl, list): |
| 58 raise ValueError('Not a list: ' + str(pbl)) |
| 59 pbl_len = len(pbl) |
| 60 self.user_email = pbl[0] if pbl_len > 0 else None |
| 61 self.project_id = pbl[1] if pbl_len > 1 else None |
| 62 self.access_token = pbl[2] if pbl_len > 2 else None |
| 63 |
| 64 |
| 65 def _SendRecv(): |
| 66 """Communicate with the Developer Shell server socket.""" |
| 67 |
| 68 port = int(os.getenv(DEVSHELL_ENV, 0)) |
| 69 if port == 0: |
| 70 raise NoDevshellServer() |
| 71 |
| 72 import socket |
| 73 |
| 74 sock = socket.socket() |
| 75 sock.connect(('localhost', port)) |
| 76 |
| 77 data = CREDENTIAL_INFO_REQUEST_JSON |
| 78 msg = '%s\n%s' % (len(data), data) |
| 79 sock.sendall(msg.encode()) |
| 80 |
| 81 header = sock.recv(6).decode() |
| 82 if '\n' not in header: |
| 83 raise CommunicationError('saw no newline in the first 6 bytes') |
| 84 len_str, json_str = header.split('\n', 1) |
| 85 to_read = int(len_str) - len(json_str) |
| 86 if to_read > 0: |
| 87 json_str += sock.recv(to_read, socket.MSG_WAITALL).decode() |
| 88 |
| 89 return CredentialInfoResponse(json_str) |
| 90 |
| 91 |
| 92 class DevshellCredentials(client.GoogleCredentials): |
| 93 """Credentials object for Google Developer Shell environment. |
| 94 |
| 95 This object will allow a Google Developer Shell session to identify its user |
| 96 to Google and other OAuth 2.0 servers that can verify assertions. It can be |
| 97 used for the purpose of accessing data stored under the user account. |
| 98 |
| 99 This credential does not require a flow to instantiate because it represents |
| 100 a two legged flow, and therefore has all of the required information to |
| 101 generate and refresh its own access tokens. |
| 102 """ |
| 103 |
| 104 def __init__(self, user_agent=None): |
| 105 super(DevshellCredentials, self).__init__( |
| 106 None, # access_token, initialized below |
| 107 None, # client_id |
| 108 None, # client_secret |
| 109 None, # refresh_token |
| 110 None, # token_expiry |
| 111 None, # token_uri |
| 112 user_agent) |
| 113 self._refresh(None) |
| 114 |
| 115 def _refresh(self, http_request): |
| 116 self.devshell_response = _SendRecv() |
| 117 self.access_token = self.devshell_response.access_token |
| 118 |
| 119 @property |
| 120 def user_email(self): |
| 121 return self.devshell_response.user_email |
| 122 |
| 123 @property |
| 124 def project_id(self): |
| 125 return self.devshell_response.project_id |
| 126 |
| 127 @classmethod |
| 128 def from_json(cls, json_data): |
| 129 raise NotImplementedError( |
| 130 'Cannot load Developer Shell credentials from JSON.') |
| 131 |
| 132 @property |
| 133 def serialization_data(self): |
| 134 raise NotImplementedError( |
| 135 'Cannot serialize Developer Shell credentials.') |
OLD | NEW |