cc1  v2.1
CC1 source code docs
 All Classes Namespaces Files Functions Variables Pages
signature.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 # @COPYRIGHT_begin
3 #
4 # Copyright [2010-2014] Institute of Nuclear Physics PAN, Krakow, Poland
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 # @COPYRIGHT_end
19 
20 ##
21 # @package src.common.signature
22 # Signatures handling for EC2 API for CC1
23 #
24 # @author Rafal Grzymkowski
25 # @author Miłosz Zdybał
26 #
27 
28 import base64
29 import hashlib
30 import hmac
31 import logging
32 import urllib
33 
34 
35 logging.basicConfig(level=logging.DEBUG)
36 log = logging.getLogger(__name__)
37 
38 
39 ##
40 #
41 # <a href="http://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html">Signing AWS API Requests</a>
42 #
43 class Signature:
44  def __init__(self):
45 
46  ## signature body
47  self.signature = "%s\n%s\n%s\n" % ('POST', 'ec2.us-east-1.amazonaws.com', '/')
48 
49  @staticmethod
50  ##
51  #
52  # Method generating signature depending on parameters and password (one
53  # that checks whether it works)
54  #
55  # Version 2
56  #
57  def generateSignatureVer2(password, parameters):
58  toSign = parameters.get('Method') + '\n' + parameters.get('Endpoint').lower() + '\n' + '/\n'
59  keys = parameters.keys()
60  keys.sort()
61  pairs = []
62  for key in keys:
63  val = parameters[key].encode('utf-8')
64  if key == 'Signature' or key == 'Method' or key == 'Endpoint':
65  continue
66  pairs.append(urllib.quote(key, safe='') + '=' + urllib.quote(val, safe='-_~'))
67  qs = '&'.join(pairs)
68  toSign += qs
69  h = hmac.new(password, toSign, hashlib.sha256)
70  b64 = base64.b64encode(h.digest())
71 
72  return b64
73 
74  @staticmethod
75  ##
76  #
77  # Method generating signature depending on parameters and password
78  # (once again).
79  #
80  # Version 1
81  #
82  def generateSignatureVer1(password, parameters):
83  params = ''
84  for key in sorted(parameters.iterkeys(), key=str.lower):
85  if key == 'Signature' or key == 'Method' or key == 'Endpoint':
86  pass
87  else:
88  params += str(key)
89  params += str(parameters.get(key))
90  h = hmac.new(password, params, hashlib.sha1)
91  signature = h.digest()
92  signature = base64.b64encode(signature)
93  return signature
94 
95  @staticmethod
96  ##
97  #
98  # Method for generating signature of parameters using password
99  # It is mainly used for Amazon S3, because EC2 doesn't support
100  # this version is signature
101  #
102  # Parameters should have:
103  # - Method
104  # - Content-MD5
105  # - Content-Type
106  # - Date
107  # - Resource - path including buckets, object and subresource e.g. /bucket/object?acl
108  # - X_Amz_Headers - dictionary with x_amz_* headers passed by client
109  #
110  def generateSignatureS3(password, parameters):
111  bucket = parameters.get('Bucket')
112 
113  CanonicalizedResource = parameters.get('path_info') + parameters.get('query_string')
114 
115  CanonicalizedAmdHeaders = u''
116 
117  # TODO tutaj powinniśmy sprawdzać czy już nie dodaliśmy któregoś amz_header chyba, Amazon wspomina
118  # o czymś takim
119  for header in sorted(parameters.iterkeys(), key=unicode.lower):
120  if header.startswith('x_amz_'):
121  header_string = str(header) + ':' + ','.join([parameters[header]]) + '\n'
122  header_string = header_string.replace('_', '-')
123  CanonicalizedAmdHeaders += header_string
124 
125  print CanonicalizedAmdHeaders.__class__
126  print CanonicalizedAmdHeaders, CanonicalizedResource
127  toSign = parameters.get('request_method') + \
128  '\n' + parameters.get('content_md5') + \
129  '\n' + parameters.get('content_type') + \
130  '\n' + parameters.get('date') + \
131  '\n' + CanonicalizedAmdHeaders + CanonicalizedResource
132 
133  print 'StringToSign', toSign
134 
135  h = hmac.new(password, toSign, hashlib.sha1)
136  signature = h.digest()
137  signature = base64.b64encode(signature)
138  print 'Signature:', signature
139  return signature
140 
141  @staticmethod
142  ##
143  #
144  # Check, whether signature is correct (depending on the signature's
145  # version).
146  #
147  def checkSignature(password, signatureToCheck, parameters):
148  # first check for S3 request
149  if parameters.get('authorization'):
150  correctSignature = Signature.generateSignatureS3(str(password), parameters)
151  else:
152  version = int(parameters.get('SignatureVersion'))
153  correctSignature = None
154  if version == 1:
155  correctSignature = Signature.generateSignatureVer1(str(password), parameters)
156  elif version == 2:
157  correctSignature = Signature.generateSignatureVer2(str(password), parameters)
158  return True if correctSignature == signatureToCheck else False
159