Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d1773bc

Browse files
committed
Signature not matching mysteriously
1 parent 765fb08 commit d1773bc

File tree

1 file changed

+69
-19
lines changed

1 file changed

+69
-19
lines changed

storage/signed_urls/sign_url.py

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,49 @@
1616

1717
from six.moves import urllib
1818
import argparse
19-
from oauth2client.client import GoogleCredentials
2019
import time
21-
22-
23-
def sign_string(credentials, s):
24-
# TODO add IAM workaround, will raise NotImplementedError in GCE
25-
return credentials.sign_blob(s)
20+
import httplib2
21+
import base64
22+
23+
24+
def sign_gae(b):
25+
from oauth2client.contrib import appengine
26+
creds = appengine.AppAssertionCredentials([])
27+
return creds.service_account_email, creds.sign_blob(b)[1]
28+
29+
30+
def sign_from_file(filename, b):
31+
from oauth2client.service_account import ServiceAccountCredentials
32+
creds = ServiceAccountCredentials.from_json_keyfile_name(filename)
33+
return creds.service_account_email, creds.sign_blob(b)[1]
34+
35+
36+
def sign_gce(b):
37+
from googleapiclient.discovery import build
38+
from oauth2client.contrib import gce
39+
40+
creds = gce.AppAssertionCredentials()
41+
iam = build('iam', 'v1', credentials=creds)
42+
resp = iam.projects().serviceAccounts().signBlob(
43+
name="projects/{project_id}/serviceAccounts/{sa_email}".format(
44+
project_id=_project_id_from_metadata(),
45+
sa_email=creds.service_account_email
46+
),
47+
body={
48+
"bytesToSign": b
49+
}
50+
).execute()
51+
return creds.service_account_email, resp['signature']
52+
53+
54+
def _project_id_from_metadata():
55+
http_request = httplib2.Http().request
56+
response, content = http_request(
57+
('http://metadata.google.internal/computeMetadata/'
58+
'v1/project/project-id'),
59+
headers={'Metadata-Flavor': 'Google'}
60+
)
61+
return None, content.decode('utf-8')
2662

2763

2864
def make_signature_string(method,
@@ -36,7 +72,7 @@ def make_signature_string(method,
3672
method,
3773
content,
3874
content_type,
39-
expiration,
75+
str(expiration),
4076
extension_header_string,
4177
resource
4278
])
@@ -60,7 +96,7 @@ def make_resource_string(parsed):
6096
def make_header_string(**custom_headers):
6197
return '\n'.join([
6298
':'.join([header.lower(), value.lower()])
63-
for header, value in custom_headers.iteritems().sort()
99+
for header, value in sorted(custom_headers.items())
64100
])
65101

66102

@@ -69,53 +105,67 @@ def main(url=None,
69105
content_file=None,
70106
content_type='',
71107
method='GET',
108+
credentials=None,
72109
**kwargs):
73110
parsed = urllib.parse.urlparse(url)
74111

75-
credentials = GoogleCredentials.get_application_default()
76-
77112
if content_file:
78113
with open(content_file, 'r') as content_f:
79114
content = content_f.read()
80115
else:
81116
content = ''
82117

83-
expiration = time.time() + duration
118+
expiration = int(time.time() + duration)
84119

85120
signature_string = make_signature_string(
86121
method,
87122
make_resource_string(parsed),
88123
expiration,
89-
extension_header_stirng=make_header_string(**headers),
124+
extension_header_string=make_header_string(**headers),
90125
content=content,
91126
content_type=content_type
92127
)
93128

94-
signed_string = sign_string(credentials, signature_string)
129+
print(signature_string)
130+
131+
if credentials == 'gae':
132+
email, signed_string = sign_gae(signature_string)
133+
elif credentials == 'gce':
134+
email, signed_string = sign_gce(signature_string)
135+
else:
136+
email, signed_string = sign_from_file(credentials, signature_string)
137+
138+
sig_bytes = base64.b64encode(signed_string)
95139

96140
query_params = urllib.parse.parse_qs(parsed.query)
97141
query_params.update(
98-
GoogleAccessId=credentials.email,
142+
GoogleAccessId=email,
99143
Expires=expiration,
100-
Signature=signed_string
144+
Signature=sig_bytes
101145
)
102-
new_query_string = urllib.parse.urlencode(query_params)
103-
parsed[3] = new_query_string
146+
url_tuple = list(parsed)
147+
url_tuple[4] = urllib.parse.urlencode(query_params, doseq=True)
104148

105-
print(urllib.parse.urlunparse(parsed))
149+
print(urllib.parse.urlunparse(url_tuple))
106150

107151

108152
if __name__ == '__main__':
109153
parser = argparse.ArgumentParser('Arguments for signing a url')
110-
parser.add_argument('url', required=True, help='A fully qualified url')
154+
parser.add_argument('url', help='A fully qualified url')
111155
parser.add_argument(
112156
'--method',
113157
default='GET',
114158
help='HTTP Method for the request'
115159
)
160+
parser.add_argument(
161+
'--credentials',
162+
required=True,
163+
help="Either the string \"gae\" the string \"gce\" or a filename"
164+
)
116165
parser.add_argument('--content-file', help='File name for request content')
117166
parser.add_argument(
118167
'--content-type',
168+
default='',
119169
help='MIME type for the content'
120170
)
121171
parser.add_argument(

0 commit comments

Comments
 (0)