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 |