googlecloud 0.0.2 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +4 -0
- data/LICENSE +674 -0
- data/Manifest +111 -0
- data/README.md +4 -3
- data/bin/gcutil +53 -0
- data/googlecloud.gemspec +4 -3
- data/packages/gcutil-1.7.1/CHANGELOG +197 -0
- data/packages/gcutil-1.7.1/LICENSE +202 -0
- data/packages/gcutil-1.7.1/VERSION +1 -0
- data/packages/gcutil-1.7.1/gcutil +53 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/LICENSE +23 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/discovery.py +743 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/errors.py +123 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/ext/__init__.py +0 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/http.py +1443 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/mimeparse.py +172 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/model.py +385 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/schema.py +303 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/anyjson.py +32 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/appengine.py +528 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/client.py +1139 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/clientsecrets.py +105 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/crypt.py +244 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/django_orm.py +124 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/file.py +107 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/locked_file.py +343 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/multistore_file.py +379 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/tools.py +174 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/uritemplate/__init__.py +147 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/LICENSE +202 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/__init__.py +3 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/__init__.py +3 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/app.py +356 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/appcommands.py +783 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/basetest.py +1260 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/datelib.py +421 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/debug.py +60 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/file_util.py +181 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/resources.py +67 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/run_script_module.py +217 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/setup_command.py +159 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/shellutil.py +49 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/stopwatch.py +204 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/__init__.py +0 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper.py +140 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper_test.py +149 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth.py +130 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth_test.py +75 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds.py +128 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds_test.py +111 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base.py +1808 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base_test.py +1651 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta13.json +2851 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta14.json +3361 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds.py +342 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds_test.py +474 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds.py +344 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds_test.py +231 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/flags_cache.py +274 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil +89 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil_logging.py +69 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds.py +262 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds_test.py +172 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds.py +1506 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds_test.py +1904 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds.py +91 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds_test.py +56 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds.py +106 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds_test.py +59 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata.py +96 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_lib.py +357 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_test.py +84 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_api.py +420 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_metadata.py +58 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.py +824 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds_test.py +307 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds.py +178 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds_test.py +133 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds.py +181 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds_test.py +196 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/path_initializer.py +38 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds.py +173 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds_test.py +111 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes.py +61 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes_test.py +50 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds.py +276 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds_test.py +260 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys.py +266 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys_test.py +128 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/table_formatter.py +563 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool.py +188 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool_test.py +88 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils.py +208 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils_test.py +193 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version.py +17 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker.py +246 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker_test.py +271 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds.py +151 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds_test.py +60 -0
- data/packages/gcutil-1.7.1/lib/httplib2/LICENSE +21 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/__init__.py +1630 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/cacerts.txt +714 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/iri2uri.py +110 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/socks.py +438 -0
- data/packages/gcutil-1.7.1/lib/iso8601/LICENSE +20 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/iso8601.py +102 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/test_iso8601.py +111 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/AUTHORS +2 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/LICENSE +28 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags.py +2862 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags2man.py +544 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags_validators.py +187 -0
- metadata +118 -5
- metadata.gz.sig +0 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
# Copyright (C) 2011 Google Inc.
|
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
|
+
"""Utilities for reading OAuth 2.0 client secret files.
|
16
|
+
|
17
|
+
A client_secrets.json file contains all the information needed to interact with
|
18
|
+
an OAuth 2.0 protected service.
|
19
|
+
"""
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
from anyjson import simplejson
|
25
|
+
|
26
|
+
# Properties that make a client_secrets.json file valid.
|
27
|
+
TYPE_WEB = 'web'
|
28
|
+
TYPE_INSTALLED = 'installed'
|
29
|
+
|
30
|
+
VALID_CLIENT = {
|
31
|
+
TYPE_WEB: {
|
32
|
+
'required': [
|
33
|
+
'client_id',
|
34
|
+
'client_secret',
|
35
|
+
'redirect_uris',
|
36
|
+
'auth_uri',
|
37
|
+
'token_uri'],
|
38
|
+
'string': [
|
39
|
+
'client_id',
|
40
|
+
'client_secret'
|
41
|
+
]
|
42
|
+
},
|
43
|
+
TYPE_INSTALLED: {
|
44
|
+
'required': [
|
45
|
+
'client_id',
|
46
|
+
'client_secret',
|
47
|
+
'redirect_uris',
|
48
|
+
'auth_uri',
|
49
|
+
'token_uri'],
|
50
|
+
'string': [
|
51
|
+
'client_id',
|
52
|
+
'client_secret'
|
53
|
+
]
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
class Error(Exception):
|
58
|
+
"""Base error for this module."""
|
59
|
+
pass
|
60
|
+
|
61
|
+
|
62
|
+
class InvalidClientSecretsError(Error):
|
63
|
+
"""Format of ClientSecrets file is invalid."""
|
64
|
+
pass
|
65
|
+
|
66
|
+
|
67
|
+
def _validate_clientsecrets(obj):
|
68
|
+
if obj is None or len(obj) != 1:
|
69
|
+
raise InvalidClientSecretsError('Invalid file format.')
|
70
|
+
client_type = obj.keys()[0]
|
71
|
+
if client_type not in VALID_CLIENT.keys():
|
72
|
+
raise InvalidClientSecretsError('Unknown client type: %s.' % client_type)
|
73
|
+
client_info = obj[client_type]
|
74
|
+
for prop_name in VALID_CLIENT[client_type]['required']:
|
75
|
+
if prop_name not in client_info:
|
76
|
+
raise InvalidClientSecretsError(
|
77
|
+
'Missing property "%s" in a client type of "%s".' % (prop_name,
|
78
|
+
client_type))
|
79
|
+
for prop_name in VALID_CLIENT[client_type]['string']:
|
80
|
+
if client_info[prop_name].startswith('[['):
|
81
|
+
raise InvalidClientSecretsError(
|
82
|
+
'Property "%s" is not configured.' % prop_name)
|
83
|
+
return client_type, client_info
|
84
|
+
|
85
|
+
|
86
|
+
def load(fp):
|
87
|
+
obj = simplejson.load(fp)
|
88
|
+
return _validate_clientsecrets(obj)
|
89
|
+
|
90
|
+
|
91
|
+
def loads(s):
|
92
|
+
obj = simplejson.loads(s)
|
93
|
+
return _validate_clientsecrets(obj)
|
94
|
+
|
95
|
+
|
96
|
+
def loadfile(filename):
|
97
|
+
try:
|
98
|
+
fp = file(filename, 'r')
|
99
|
+
try:
|
100
|
+
obj = simplejson.load(fp)
|
101
|
+
finally:
|
102
|
+
fp.close()
|
103
|
+
except IOError:
|
104
|
+
raise InvalidClientSecretsError('File not found: "%s"' % filename)
|
105
|
+
return _validate_clientsecrets(obj)
|
@@ -0,0 +1,244 @@
|
|
1
|
+
#!/usr/bin/python2.4
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
#
|
4
|
+
# Copyright (C) 2011 Google Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
import base64
|
19
|
+
import hashlib
|
20
|
+
import logging
|
21
|
+
import time
|
22
|
+
|
23
|
+
from OpenSSL import crypto
|
24
|
+
from anyjson import simplejson
|
25
|
+
|
26
|
+
|
27
|
+
CLOCK_SKEW_SECS = 300 # 5 minutes in seconds
|
28
|
+
AUTH_TOKEN_LIFETIME_SECS = 300 # 5 minutes in seconds
|
29
|
+
MAX_TOKEN_LIFETIME_SECS = 86400 # 1 day in seconds
|
30
|
+
|
31
|
+
|
32
|
+
class AppIdentityError(Exception):
|
33
|
+
pass
|
34
|
+
|
35
|
+
|
36
|
+
class Verifier(object):
|
37
|
+
"""Verifies the signature on a message."""
|
38
|
+
|
39
|
+
def __init__(self, pubkey):
|
40
|
+
"""Constructor.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
pubkey, OpenSSL.crypto.PKey, The public key to verify with.
|
44
|
+
"""
|
45
|
+
self._pubkey = pubkey
|
46
|
+
|
47
|
+
def verify(self, message, signature):
|
48
|
+
"""Verifies a message against a signature.
|
49
|
+
|
50
|
+
Args:
|
51
|
+
message: string, The message to verify.
|
52
|
+
signature: string, The signature on the message.
|
53
|
+
|
54
|
+
Returns:
|
55
|
+
True if message was singed by the private key associated with the public
|
56
|
+
key that this object was constructed with.
|
57
|
+
"""
|
58
|
+
try:
|
59
|
+
crypto.verify(self._pubkey, signature, message, 'sha256')
|
60
|
+
return True
|
61
|
+
except:
|
62
|
+
return False
|
63
|
+
|
64
|
+
@staticmethod
|
65
|
+
def from_string(key_pem, is_x509_cert):
|
66
|
+
"""Construct a Verified instance from a string.
|
67
|
+
|
68
|
+
Args:
|
69
|
+
key_pem: string, public key in PEM format.
|
70
|
+
is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it is
|
71
|
+
expected to be an RSA key in PEM format.
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
Verifier instance.
|
75
|
+
|
76
|
+
Raises:
|
77
|
+
OpenSSL.crypto.Error if the key_pem can't be parsed.
|
78
|
+
"""
|
79
|
+
if is_x509_cert:
|
80
|
+
pubkey = crypto.load_certificate(crypto.FILETYPE_PEM, key_pem)
|
81
|
+
else:
|
82
|
+
pubkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key_pem)
|
83
|
+
return Verifier(pubkey)
|
84
|
+
|
85
|
+
|
86
|
+
class Signer(object):
|
87
|
+
"""Signs messages with a private key."""
|
88
|
+
|
89
|
+
def __init__(self, pkey):
|
90
|
+
"""Constructor.
|
91
|
+
|
92
|
+
Args:
|
93
|
+
pkey, OpenSSL.crypto.PKey, The private key to sign with.
|
94
|
+
"""
|
95
|
+
self._key = pkey
|
96
|
+
|
97
|
+
def sign(self, message):
|
98
|
+
"""Signs a message.
|
99
|
+
|
100
|
+
Args:
|
101
|
+
message: string, Message to be signed.
|
102
|
+
|
103
|
+
Returns:
|
104
|
+
string, The signature of the message for the given key.
|
105
|
+
"""
|
106
|
+
return crypto.sign(self._key, message, 'sha256')
|
107
|
+
|
108
|
+
@staticmethod
|
109
|
+
def from_string(key, password='notasecret'):
|
110
|
+
"""Construct a Signer instance from a string.
|
111
|
+
|
112
|
+
Args:
|
113
|
+
key: string, private key in P12 format.
|
114
|
+
password: string, password for the private key file.
|
115
|
+
|
116
|
+
Returns:
|
117
|
+
Signer instance.
|
118
|
+
|
119
|
+
Raises:
|
120
|
+
OpenSSL.crypto.Error if the key can't be parsed.
|
121
|
+
"""
|
122
|
+
pkey = crypto.load_pkcs12(key, password).get_privatekey()
|
123
|
+
return Signer(pkey)
|
124
|
+
|
125
|
+
|
126
|
+
def _urlsafe_b64encode(raw_bytes):
|
127
|
+
return base64.urlsafe_b64encode(raw_bytes).rstrip('=')
|
128
|
+
|
129
|
+
|
130
|
+
def _urlsafe_b64decode(b64string):
|
131
|
+
# Guard against unicode strings, which base64 can't handle.
|
132
|
+
b64string = b64string.encode('ascii')
|
133
|
+
padded = b64string + '=' * (4 - len(b64string) % 4)
|
134
|
+
return base64.urlsafe_b64decode(padded)
|
135
|
+
|
136
|
+
|
137
|
+
def _json_encode(data):
|
138
|
+
return simplejson.dumps(data, separators = (',', ':'))
|
139
|
+
|
140
|
+
|
141
|
+
def make_signed_jwt(signer, payload):
|
142
|
+
"""Make a signed JWT.
|
143
|
+
|
144
|
+
See http://self-issued.info/docs/draft-jones-json-web-token.html.
|
145
|
+
|
146
|
+
Args:
|
147
|
+
signer: crypt.Signer, Cryptographic signer.
|
148
|
+
payload: dict, Dictionary of data to convert to JSON and then sign.
|
149
|
+
|
150
|
+
Returns:
|
151
|
+
string, The JWT for the payload.
|
152
|
+
"""
|
153
|
+
header = {'typ': 'JWT', 'alg': 'RS256'}
|
154
|
+
|
155
|
+
segments = [
|
156
|
+
_urlsafe_b64encode(_json_encode(header)),
|
157
|
+
_urlsafe_b64encode(_json_encode(payload)),
|
158
|
+
]
|
159
|
+
signing_input = '.'.join(segments)
|
160
|
+
|
161
|
+
signature = signer.sign(signing_input)
|
162
|
+
segments.append(_urlsafe_b64encode(signature))
|
163
|
+
|
164
|
+
logging.debug(str(segments))
|
165
|
+
|
166
|
+
return '.'.join(segments)
|
167
|
+
|
168
|
+
|
169
|
+
def verify_signed_jwt_with_certs(jwt, certs, audience):
|
170
|
+
"""Verify a JWT against public certs.
|
171
|
+
|
172
|
+
See http://self-issued.info/docs/draft-jones-json-web-token.html.
|
173
|
+
|
174
|
+
Args:
|
175
|
+
jwt: string, A JWT.
|
176
|
+
certs: dict, Dictionary where values of public keys in PEM format.
|
177
|
+
audience: string, The audience, 'aud', that this JWT should contain. If
|
178
|
+
None then the JWT's 'aud' parameter is not verified.
|
179
|
+
|
180
|
+
Returns:
|
181
|
+
dict, The deserialized JSON payload in the JWT.
|
182
|
+
|
183
|
+
Raises:
|
184
|
+
AppIdentityError if any checks are failed.
|
185
|
+
"""
|
186
|
+
segments = jwt.split('.')
|
187
|
+
|
188
|
+
if (len(segments) != 3):
|
189
|
+
raise AppIdentityError(
|
190
|
+
'Wrong number of segments in token: %s' % jwt)
|
191
|
+
signed = '%s.%s' % (segments[0], segments[1])
|
192
|
+
|
193
|
+
signature = _urlsafe_b64decode(segments[2])
|
194
|
+
|
195
|
+
# Parse token.
|
196
|
+
json_body = _urlsafe_b64decode(segments[1])
|
197
|
+
try:
|
198
|
+
parsed = simplejson.loads(json_body)
|
199
|
+
except:
|
200
|
+
raise AppIdentityError('Can\'t parse token: %s' % json_body)
|
201
|
+
|
202
|
+
# Check signature.
|
203
|
+
verified = False
|
204
|
+
for (keyname, pem) in certs.items():
|
205
|
+
verifier = Verifier.from_string(pem, True)
|
206
|
+
if (verifier.verify(signed, signature)):
|
207
|
+
verified = True
|
208
|
+
break
|
209
|
+
if not verified:
|
210
|
+
raise AppIdentityError('Invalid token signature: %s' % jwt)
|
211
|
+
|
212
|
+
# Check creation timestamp.
|
213
|
+
iat = parsed.get('iat')
|
214
|
+
if iat is None:
|
215
|
+
raise AppIdentityError('No iat field in token: %s' % json_body)
|
216
|
+
earliest = iat - CLOCK_SKEW_SECS
|
217
|
+
|
218
|
+
# Check expiration timestamp.
|
219
|
+
now = long(time.time())
|
220
|
+
exp = parsed.get('exp')
|
221
|
+
if exp is None:
|
222
|
+
raise AppIdentityError('No exp field in token: %s' % json_body)
|
223
|
+
if exp >= now + MAX_TOKEN_LIFETIME_SECS:
|
224
|
+
raise AppIdentityError(
|
225
|
+
'exp field too far in future: %s' % json_body)
|
226
|
+
latest = exp + CLOCK_SKEW_SECS
|
227
|
+
|
228
|
+
if now < earliest:
|
229
|
+
raise AppIdentityError('Token used too early, %d < %d: %s' %
|
230
|
+
(now, earliest, json_body))
|
231
|
+
if now > latest:
|
232
|
+
raise AppIdentityError('Token used too late, %d > %d: %s' %
|
233
|
+
(now, latest, json_body))
|
234
|
+
|
235
|
+
# Check audience.
|
236
|
+
if audience is not None:
|
237
|
+
aud = parsed.get('aud')
|
238
|
+
if aud is None:
|
239
|
+
raise AppIdentityError('No aud field in token: %s' % json_body)
|
240
|
+
if aud != audience:
|
241
|
+
raise AppIdentityError('Wrong recipient, %s != %s: %s' %
|
242
|
+
(aud, audience, json_body))
|
243
|
+
|
244
|
+
return parsed
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# Copyright (C) 2010 Google Inc.
|
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 utilities for Django.
|
16
|
+
|
17
|
+
Utilities for using OAuth 2.0 in conjunction with
|
18
|
+
the Django datastore.
|
19
|
+
"""
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
import oauth2client
|
24
|
+
import base64
|
25
|
+
import pickle
|
26
|
+
|
27
|
+
from django.db import models
|
28
|
+
from oauth2client.client import Storage as BaseStorage
|
29
|
+
|
30
|
+
class CredentialsField(models.Field):
|
31
|
+
|
32
|
+
__metaclass__ = models.SubfieldBase
|
33
|
+
|
34
|
+
def get_internal_type(self):
|
35
|
+
return "TextField"
|
36
|
+
|
37
|
+
def to_python(self, value):
|
38
|
+
if value is None:
|
39
|
+
return None
|
40
|
+
if isinstance(value, oauth2client.client.Credentials):
|
41
|
+
return value
|
42
|
+
return pickle.loads(base64.b64decode(value))
|
43
|
+
|
44
|
+
def get_db_prep_value(self, value, connection, prepared=False):
|
45
|
+
if value is None:
|
46
|
+
return None
|
47
|
+
return base64.b64encode(pickle.dumps(value))
|
48
|
+
|
49
|
+
|
50
|
+
class FlowField(models.Field):
|
51
|
+
|
52
|
+
__metaclass__ = models.SubfieldBase
|
53
|
+
|
54
|
+
def get_internal_type(self):
|
55
|
+
return "TextField"
|
56
|
+
|
57
|
+
def to_python(self, value):
|
58
|
+
if value is None:
|
59
|
+
return None
|
60
|
+
if isinstance(value, oauth2client.client.Flow):
|
61
|
+
return value
|
62
|
+
return pickle.loads(base64.b64decode(value))
|
63
|
+
|
64
|
+
def get_db_prep_value(self, value, connection, prepared=False):
|
65
|
+
if value is None:
|
66
|
+
return None
|
67
|
+
return base64.b64encode(pickle.dumps(value))
|
68
|
+
|
69
|
+
|
70
|
+
class Storage(BaseStorage):
|
71
|
+
"""Store and retrieve a single credential to and from
|
72
|
+
the datastore.
|
73
|
+
|
74
|
+
This Storage helper presumes the Credentials
|
75
|
+
have been stored as a CredenialsField
|
76
|
+
on a db model class.
|
77
|
+
"""
|
78
|
+
|
79
|
+
def __init__(self, model_class, key_name, key_value, property_name):
|
80
|
+
"""Constructor for Storage.
|
81
|
+
|
82
|
+
Args:
|
83
|
+
model: db.Model, model class
|
84
|
+
key_name: string, key name for the entity that has the credentials
|
85
|
+
key_value: string, key value for the entity that has the credentials
|
86
|
+
property_name: string, name of the property that is an CredentialsProperty
|
87
|
+
"""
|
88
|
+
self.model_class = model_class
|
89
|
+
self.key_name = key_name
|
90
|
+
self.key_value = key_value
|
91
|
+
self.property_name = property_name
|
92
|
+
|
93
|
+
def locked_get(self):
|
94
|
+
"""Retrieve Credential from datastore.
|
95
|
+
|
96
|
+
Returns:
|
97
|
+
oauth2client.Credentials
|
98
|
+
"""
|
99
|
+
credential = None
|
100
|
+
|
101
|
+
query = {self.key_name: self.key_value}
|
102
|
+
entities = self.model_class.objects.filter(**query)
|
103
|
+
if len(entities) > 0:
|
104
|
+
credential = getattr(entities[0], self.property_name)
|
105
|
+
if credential and hasattr(credential, 'set_store'):
|
106
|
+
credential.set_store(self)
|
107
|
+
return credential
|
108
|
+
|
109
|
+
def locked_put(self, credentials):
|
110
|
+
"""Write a Credentials to the datastore.
|
111
|
+
|
112
|
+
Args:
|
113
|
+
credentials: Credentials, the credentials to store.
|
114
|
+
"""
|
115
|
+
args = {self.key_name: self.key_value}
|
116
|
+
entity = self.model_class(**args)
|
117
|
+
setattr(entity, self.property_name, credentials)
|
118
|
+
entity.save()
|
119
|
+
|
120
|
+
def locked_delete(self):
|
121
|
+
"""Delete Credentials from the datastore."""
|
122
|
+
|
123
|
+
query = {self.key_name: self.key_value}
|
124
|
+
entities = self.model_class.objects.filter(**query).delete()
|