1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2010 United States Government as represented by the
4
# Administrator of the National Aeronautics and Space Administration.
7
# Licensed under the Apache License, Version 2.0 (the "License"); you may
8
# not use this file except in compliance with the License. You may obtain
9
# a copy of the License at
11
# http://www.apache.org/licenses/LICENSE-2.0
13
# Unless required by applicable law or agreed to in writing, software
14
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
# License for the specific language governing permissions and limitations
19
# PORTIONS OF THIS FILE ARE FROM:
20
# http://code.google.com/p/boto
21
# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
23
# Permission is hereby granted, free of charge, to any person obtaining a
24
# copy of this software and associated documentation files (the
25
# "Software"), to deal in the Software without restriction, including
26
# without limitation the rights to use, copy, modify, merge, publish, dis-
27
# tribute, sublicense, and/or sell copies of the Software, and to permit
28
# persons to whom the Software is furnished to do so, subject to the fol-
31
# The above copyright notice and this permission notice shall be included
32
# in all copies or substantial portions of the Software.
34
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
35
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
36
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
37
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
38
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
43
Utility class for parsing signed AMI manifests.
52
# NOTE(vish): for new boto
56
# NOTE(vish): for old boto
61
from nova import exception
62
from nova.openstack.common import log as logging
65
LOG = logging.getLogger(__name__)
69
"""Hacked up code from boto/connection.py"""
71
def __init__(self, secret_key):
72
self.hmac = hmac.new(secret_key, digestmod=hashlib.sha1)
74
self.hmac_256 = hmac.new(secret_key, digestmod=hashlib.sha256)
78
def s3_authorization(self, headers, verb, path):
79
"""Generate S3 authorization string."""
81
raise exception.NovaException('boto is not installed')
82
c_string = boto.utils.canonical_string(verb, path, headers)
83
hmac_copy = self.hmac.copy()
84
hmac_copy.update(c_string)
85
b64_hmac = base64.encodestring(hmac_copy.digest()).strip()
88
def generate(self, params, verb, server_string, path):
89
"""Generate auth string according to what SignatureVersion is given.
91
The signature method must be SHA1 or SHA256.
94
if params['SignatureVersion'] == '0':
95
return self._calc_signature_0(params)
96
if params['SignatureVersion'] == '1':
97
return self._calc_signature_1(params)
98
if params['SignatureVersion'] == '2':
99
return self._calc_signature_2(params, verb, server_string, path)
100
raise exception.NovaException('Unknown Signature Version: %s' %
101
params['SignatureVersion'])
104
def _get_utf8_value(value):
105
"""Get the UTF8-encoded version of a value."""
106
if not isinstance(value, str) and not isinstance(value, unicode):
108
if isinstance(value, unicode):
109
return value.encode('utf-8')
113
def _calc_signature_0(self, params):
114
"""Generate AWS signature version 0 string."""
115
s = params['Action'] + params['Timestamp']
118
keys.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
121
val = self._get_utf8_value(params[key])
122
pairs.append(key + '=' + urllib.quote(val))
123
return base64.b64encode(self.hmac.digest())
125
def _calc_signature_1(self, params):
126
"""Generate AWS signature version 1 string."""
128
keys.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
131
self.hmac.update(key)
132
val = self._get_utf8_value(params[key])
133
self.hmac.update(val)
134
pairs.append(key + '=' + urllib.quote(val))
135
return base64.b64encode(self.hmac.digest())
137
def _calc_signature_2(self, params, verb, server_string, path):
138
"""Generate AWS signature version 2 string."""
139
LOG.debug('using _calc_signature_2')
140
string_to_sign = '%s\n%s\n%s\n' % (verb, server_string, path)
142
if 'SignatureMethod' not in params:
143
raise exception.NovaException('No SignatureMethod specified')
145
if params['SignatureMethod'] == 'HmacSHA256':
146
if not self.hmac_256:
147
msg = _('SHA256 not supported on this server')
148
raise exception.NovaException(msg)
149
current_hmac = self.hmac_256
150
elif params['SignatureMethod'] == 'HmacSHA1':
151
current_hmac = self.hmac
153
raise exception.NovaException('SignatureMethod %s not supported'
154
% params['SignatureMethod'])
160
val = self._get_utf8_value(params[key])
161
val = urllib.quote(val, safe='-_~')
162
pairs.append(urllib.quote(key, safe='') + '=' + val)
164
LOG.debug('query string: %s', qs)
166
LOG.debug('string_to_sign: %s', string_to_sign)
167
current_hmac.update(string_to_sign)
168
b64 = base64.b64encode(current_hmac.digest())
169
LOG.debug('len(b64)=%d', len(b64))
170
LOG.debug('base64 encoded digest: %s', b64)
174
if __name__ == '__main__':
175
print Signer('foo').generate({'SignatureVersion': '2',
176
'SignatureMethod': 'HmacSHA256'},
177
'get', 'server', '/foo')