예제 #1
0
 def check_signature(self, creds_ref, credentials):
     signer = ec2_utils.Ec2Signer(creds_ref['secret'])
     signature = signer.generate(credentials)
     # NOTE(davechen): credentials.get('signature') is not guaranteed to
     # exist, we need check it explicitly.
     if credentials.get('signature'):
         if utils.auth_str_equal(credentials['signature'], signature):
             return True
         # NOTE(vish): Some client libraries don't use the port when signing
         #             requests, so try again without port.
         elif ':' in credentials['host']:
             hostname, _port = credentials['host'].split(':')
             credentials['host'] = hostname
             # NOTE(davechen): we need reinitialize 'signer' to avoid
             # contaminated status of signature, this is similar with
             # other programming language libraries, JAVA for example.
             signer = ec2_utils.Ec2Signer(creds_ref['secret'])
             signature = signer.generate(credentials)
             if utils.auth_str_equal(credentials['signature'], signature):
                 return True
             raise exception.Unauthorized(
                 message=_('Invalid EC2 signature.'))
         else:
             raise exception.Unauthorized(
                 message=_('EC2 signature not supplied.'))
     # Raise the exception when credentials.get('signature') is None
     else:
         raise exception.Unauthorized(
             message=_('EC2 signature not supplied.'))
예제 #2
0
    def test_authenticate_without_proper_secret_returns_unauthorized(self):
        cred_blob, credential = unit.new_ec2_credential(
            self.user_foo['id'], self.tenant_bar['id'])

        PROVIDERS.credential_api.create_credential(credential['id'],
                                                   credential)

        signer = ec2_utils.Ec2Signer('totally not the secret')
        credentials = {
            'access': cred_blob['access'],
            'secret': 'totally not the secret',
            'host': 'localhost',
            'verb': 'GET',
            'path': '/',
            'params': {
                'SignatureVersion': '2',
                'Action': 'Test',
                'Timestamp': '2007-01-31T23:59:59Z'
            },
        }
        credentials['signature'] = signer.generate(credentials)
        self.public_request(method='POST',
                            path='/v2.0/ec2tokens',
                            body={'credentials': credentials},
                            expected_status=http_client.UNAUTHORIZED)
    def test_generate_v4_port(self):
        """Test v4 generator with host:port format."""
        # Create a new signer object with the AWS example key
        secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
        signer = utils.Ec2Signer(secret)

        body_hash = ('b6359072c78d70ebee1e81adcbab4f0'
                     '1bf2c23245fa365ef83fe8f1f955085e2')
        auth_str = ('AWS4-HMAC-SHA256 '
                    'Credential=AKIAIOSFODNN7EXAMPLE/20110909/'
                    'us-east-1/iam/aws4_request,'
                    'SignedHeaders=content-type;host;x-amz-date,')
        headers = {'Content-type':
                   'application/x-www-form-urlencoded; charset=utf-8',
                   'X-Amz-Date': '20110909T233600Z',
                   'Host': 'foo:8000',
                   'Authorization': auth_str}
        # Note the example in the AWS docs is inconsistent, previous
        # examples specify no query string, but the final POST example
        # does, apparently incorrectly since an empty parameter list
        # aligns all steps and the final signature with the examples
        params = {}
        credentials = {'host': 'foo:8000',
                       'verb': 'POST',
                       'path': '/',
                       'params': params,
                       'headers': headers,
                       'body_hash': body_hash}
        signature = signer.generate(credentials)

        expected = ('26dd92ea79aaa49f533d13b1055acdc'
                    'd7d7321460d64621f96cc79c4f4d4ab2b')
        self.assertEqual(signature, expected)
예제 #4
0
    def test_signature_validate_no_host_port(self):
        """Test signature validation with the access/secret provided."""
        access = self.blob['access']
        secret = self.blob['secret']
        signer = ec2_utils.Ec2Signer(secret)
        params = {
            'SignatureMethod': 'HmacSHA256',
            'SignatureVersion': '2',
            'AWSAccessKeyId': access
        }
        request = {
            'host': 'foo',
            'verb': 'GET',
            'path': '/bar',
            'params': params
        }
        signature = signer.generate(request)

        sig_ref = {
            'access': access,
            'signature': signature,
            'host': 'foo',
            'verb': 'GET',
            'path': '/bar',
            'params': params
        }

        # Now validate the signature based on the dummy request
        self.assertTrue(
            self.controller.check_signature(self.creds_ref, sig_ref))
예제 #5
0
    def test_ec2_auth(self):
        client = self.get_client()
        cred = client.ec2.create(user_id=self.user_foo['id'],
                                 tenant_id=self.tenant_bar['id'])

        from keystoneclient.contrib.ec2 import utils as ec2_utils
        signer = ec2_utils.Ec2Signer(cred.secret)
        credentials = {
            'params': {
                'SignatureVersion': '2'
            },
            'access': cred.access,
            'verb': 'GET',
            'host': 'localhost',
            'path': '/thisisgoingtowork'
        }
        signature = signer.generate(credentials)
        credentials['signature'] = signature
        url = '%s/ec2tokens' % (client.auth_url)
        (resp, token) = client.request(url=url,
                                       method='POST',
                                       body={'credentials': credentials})
        # make sure we have a v2 token
        self.assertEqual(resp.status_code, 200)
        self.assertIn('access', token)
예제 #6
0
    def test_signature_validate_with_host_port(self):
        """Test signature validation when host is bound with port.

        Host is bound with a port, generally, the port here is not the
        standard port for the protocol, like '80' for HTTP and port 443
        for HTTPS, the port is not omitted by the client library.
        """
        access = self.blob['access']
        secret = self.blob['secret']
        signer = ec2_utils.Ec2Signer(secret)
        params = {
            'SignatureMethod': 'HmacSHA256',
            'SignatureVersion': '2',
            'AWSAccessKeyId': access
        }
        request = {
            'host': 'foo:8181',
            'verb': 'GET',
            'path': '/bar',
            'params': params
        }
        signature = signer.generate(request)

        sig_ref = {
            'access': access,
            'signature': signature,
            'host': 'foo:8181',
            'verb': 'GET',
            'path': '/bar',
            'params': params
        }

        # Now validate the signature based on the dummy request
        self.assertTrue(
            self.controller.check_signature(self.creds_ref, sig_ref))
예제 #7
0
    def test_signature_validate_invalid_signature(self):
        """Signature is not signed on the correct data."""
        access = self.blob['access']
        secret = self.blob['secret']
        signer = ec2_utils.Ec2Signer(secret)
        params = {
            'SignatureMethod': 'HmacSHA256',
            'SignatureVersion': '2',
            'AWSAccessKeyId': access
        }
        request = {
            'host': 'bar',
            'verb': 'GET',
            'path': '/bar',
            'params': params
        }
        signature = signer.generate(request)

        sig_ref = {
            'access': access,
            'signature': signature,
            'host': 'foo:8080',
            'verb': 'GET',
            'path': '/bar',
            'params': params
        }

        # Now validate the signature based on the dummy request
        self.assertRaises(exception.Unauthorized,
                          self.controller.check_signature, self.creds_ref,
                          sig_ref)
예제 #8
0
    def _validate_signature(self, access, secret):
        """Test signature validation with the access/secret provided."""
        signer = ec2_utils.Ec2Signer(secret)
        params = {
            'SignatureMethod': 'HmacSHA256',
            'SignatureVersion': '2',
            'AWSAccessKeyId': access
        }
        request = {
            'host': 'foo',
            'verb': 'GET',
            'path': '/bar',
            'params': params
        }
        signature = signer.generate(request)

        # Now make a request to validate the signed dummy request via the
        # ec2tokens API.  This proves the v3 ec2 credentials actually work.
        sig_ref = {
            'access': access,
            'signature': signature,
            'host': 'foo',
            'verb': 'GET',
            'path': '/bar',
            'params': params
        }
        r = self.post('/ec2tokens',
                      body={'ec2Credentials': sig_ref},
                      expected_status=http_client.OK)
        self.assertValidTokenResponse(r)
예제 #9
0
    def test_valid_authentication_response_with_proper_secret(self):
        cred_blob, credential = unit.new_ec2_credential(
            self.user_foo['id'], self.tenant_bar['id'])

        self.credential_api.create_credential(credential['id'], credential)

        signer = ec2_utils.Ec2Signer(cred_blob['secret'])
        credentials = {
            'access': cred_blob['access'],
            'secret': cred_blob['secret'],
            'host': 'localhost',
            'verb': 'GET',
            'path': '/',
            'params': {
                'SignatureVersion': '2',
                'Action': 'Test',
                'Timestamp': '2007-01-31T23:59:59Z'
            },
        }
        credentials['signature'] = signer.generate(credentials)
        resp = self.public_request(method='POST',
                                   path='/v2.0/ec2tokens',
                                   body={'credentials': credentials},
                                   expected_status=http_client.OK)
        self.assertValidAuthenticationResponse(resp)
예제 #10
0
    def _validate_signature(self, access, secret):
        """Test signature validation with the access/secret provided."""
        signer = ec2_utils.Ec2Signer(secret)
        params = {'SignatureMethod': 'HmacSHA256',
                  'SignatureVersion': '2',
                  'AWSAccessKeyId': access}
        request = {'host': 'foo',
                   'verb': 'GET',
                   'path': '/bar',
                   'params': params}
        signature = signer.generate(request)

        # Now make a request to validate the signed dummy request via the
        # ec2tokens API.  This proves the v3 ec2 credentials actually work.
        sig_ref = {'access': access,
                   'signature': signature,
                   'host': 'foo',
                   'verb': 'GET',
                   'path': '/bar',
                   'params': params}
        r = self.post(
            '/ec2tokens',
            body={'ec2Credentials': sig_ref},
            expected_status=200)
        # FIXME(shardy): ec2tokens is available via both v3 and v2
        # paths, but it returns a v2 token in both cases, so we can
        # only do a sanity assertion here for now.
        self.assertIsNotNone(r.result['access']['token']['id'])
예제 #11
0
 def _generate_user_ec2_credentials(self, access, secret):
     signer = ec2_utils.Ec2Signer(secret)
     credentials = {'params': {'SignatureVersion': '2'},
                    'access': access,
                    'verb': 'GET',
                    'host': 'localhost',
                    'path': '/service/cloud'}
     signature = signer.generate(credentials)
     return credentials, signature
예제 #12
0
    def _get_signed_url(self, signal_type=SIGNAL):
        """Create properly formatted and pre-signed URL.

        This uses the created user for the credentials.

        See boto/auth.py::QuerySignatureV2AuthHandler

        :param signal_type: either WAITCONDITION or SIGNAL.
        """
        try:
            stored = db_api.resource_data_get(self, 'ec2_signed_url')
        except exception.NotFound:
            stored = None
        if stored is not None:
            return stored

        try:
            access_key = db_api.resource_data_get(self, 'access_key')
            secret_key = db_api.resource_data_get(self, 'secret_key')
        except exception.NotFound:
            logger.warning(
                _('Cannot generate signed url, '
                  'no stored access/secret key'))
            return

        waitcond_url = cfg.CONF.heat_waitcondition_server_url
        signal_url = waitcond_url.replace('/waitcondition', signal_type)
        host_url = urlutils.urlparse(signal_url)

        path = self.identifier().arn_url_path()

        # Note the WSGI spec apparently means that the webob request we end up
        # prcessing in the CFN API (ec2token.py) has an unquoted path, so we
        # need to calculate the signature with the path component unquoted, but
        # ensure the actual URL contains the quoted version...
        unquoted_path = urlutils.unquote(host_url.path + path)
        request = {
            'host': host_url.netloc.lower(),
            'verb': SIGNAL_VERB[signal_type],
            'path': unquoted_path,
            'params': {
                'SignatureMethod': 'HmacSHA256',
                'SignatureVersion': '2',
                'AWSAccessKeyId': access_key,
                'Timestamp': self.created_time.strftime("%Y-%m-%dT%H:%M:%SZ")
            }
        }
        # Sign the request
        signer = ec2_utils.Ec2Signer(secret_key)
        request['params']['Signature'] = signer.generate(request)

        qs = urlutils.urlencode(request['params'])
        url = "%s%s?%s" % (signal_url.lower(), path, qs)

        db_api.resource_data_set(self, 'ec2_signed_url', url)
        return url
예제 #13
0
    def test_generate_v4(self):
        """Test v4 generator with data from AWS docs example.

        see:
        http://docs.aws.amazon.com/general/latest/gr/
        sigv4-create-canonical-request.html
        and
        http://docs.aws.amazon.com/general/latest/gr/
        sigv4-signed-request-examples.html
        """
        # Create a new signer object with the AWS example key
        secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
        signer = utils.Ec2Signer(secret)

        body_hash = ('b6359072c78d70ebee1e81adcbab4f0'
                     '1bf2c23245fa365ef83fe8f1f955085e2')
        auth_str = ('AWS4-HMAC-SHA256 '
                    'Credential=AKIAIOSFODNN7EXAMPLE/20110909/'
                    'us-east-1/iam/aws4_request,'
                    'SignedHeaders=content-type;host;x-amz-date,')
        headers = {'Content-type':
                   'application/x-www-form-urlencoded; charset=utf-8',
                   'X-Amz-Date': '20110909T233600Z',
                   'Host': 'iam.amazonaws.com',
                   'Authorization': auth_str}
        # Note the example in the AWS docs is inconsistent, previous
        # examples specify no query string, but the final POST example
        # does, apparently incorrectly since an empty parameter list
        # aligns all steps and the final signature with the examples
        params = {'Action': 'CreateUser',
                  'UserName': '******',
                  'Version': '2010-05-08',
                  'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
                  'X-Amz-Credential': 'AKIAEXAMPLE/20140611/'
                                      'us-east-1/iam/aws4_request',
                  'X-Amz-Date': '20140611T231318Z',
                  'X-Amz-Expires': '30',
                  'X-Amz-SignedHeaders': 'host',
                  'X-Amz-Signature': 'ced6826de92d2bdeed8f846f0bf508e8'
                                     '559e98e4b0199114b84c54174deb456c'}
        credentials = {'host': 'iam.amazonaws.com',
                       'verb': 'POST',
                       'path': '/',
                       'params': params,
                       'headers': headers,
                       'body_hash': body_hash}
        signature = signer.generate(credentials)
        expected = ('ced6826de92d2bdeed8f846f0bf508e8'
                    '559e98e4b0199114b84c54174deb456c')
        self.assertEqual(signature, expected)
예제 #14
0
 def check_signature(self, creds_ref, credentials):
     signer = ec2_utils.Ec2Signer(creds_ref['secret'])
     signature = signer.generate(credentials)
     if utils.auth_str_equal(credentials['signature'], signature):
         return
     # NOTE(vish): Some libraries don't use the port when signing
     #             requests, so try again without port.
     elif ':' in credentials['signature']:
         hostname, _port = credentials['host'].split(':')
         credentials['host'] = hostname
         signature = signer.generate(credentials)
         if not utils.auth_str_equal(credentials.signature, signature):
             raise exception.Unauthorized(message='Invalid EC2 signature.')
     else:
         raise exception.Unauthorized(message='EC2 signature not supplied.')
예제 #15
0
 def _generate_default_user_ec2_credentials(self):
     cred = self.default_client.ec2.create(user_id=self.user_foo['id'],
                                           tenant_id=self.tenant_bar['id'])
     signer = ec2_utils.Ec2Signer(cred.secret)
     credentials = {
         'params': {
             'SignatureVersion': '2'
         },
         'access': cred.access,
         'verb': 'GET',
         'host': 'localhost',
         'path': '/service/cloud'
     }
     signature = signer.generate(credentials)
     return credentials, signature
예제 #16
0
 def test_authenticate_without_proper_secret_returns_unauthorized(self):
     signer = ec2_utils.Ec2Signer('totally not the secret')
     credentials = {
         'access': self.cred_blob['access'],
         'secret': 'totally not the secret',
         'host': 'localhost',
         'verb': 'GET',
         'path': '/',
         'params': {
             'SignatureVersion': '2',
             'Action': 'Test',
             'Timestamp': '2007-01-31T23:59:59Z'
         },
     }
     credentials['signature'] = signer.generate(credentials)
     self.post('/ec2tokens',
               body={'credentials': credentials},
               expected_status=http_client.UNAUTHORIZED)
예제 #17
0
 def test_valid_authentication_response_with_proper_secret(self):
     signer = ec2_utils.Ec2Signer(self.cred_blob['secret'])
     credentials = {
         'access': self.cred_blob['access'],
         'secret': self.cred_blob['secret'],
         'host': 'localhost',
         'verb': 'GET',
         'path': '/',
         'params': {
             'SignatureVersion': '2',
             'Action': 'Test',
             'Timestamp': '2007-01-31T23:59:59Z'
         },
     }
     credentials['signature'] = signer.generate(credentials)
     resp = self.post('/ec2tokens',
                      body={'credentials': credentials},
                      expected_status=http_client.OK)
     self.assertValidProjectScopedTokenResponse(resp, self.user)
예제 #18
0
    def test_signature_validate_with_missed_host_port(self):
        """Test signature validation when host is bound with well-known port.

        Host is bound with a port, but the port is well-know port like '80'
        for HTTP and port 443 for HTTPS, sometimes, client library omit
        the port but then make the request with the port.
        see (How to create the string to sign): 'http://docs.aws.amazon.com/
        general/latest/gr/signature-version-2.html'.

        Since "credentials['host']" is not set by client library but is
        taken from "req.host", so caused the differences.
        """
        access = self.blob['access']
        secret = self.blob['secret']
        signer = ec2_utils.Ec2Signer(secret)
        params = {
            'SignatureMethod': 'HmacSHA256',
            'SignatureVersion': '2',
            'AWSAccessKeyId': access
        }
        # Omit the port to generate the signature.
        cnt_req = {
            'host': 'foo',
            'verb': 'GET',
            'path': '/bar',
            'params': params
        }
        signature = signer.generate(cnt_req)

        sig_ref = {
            'access': access,
            'signature': signature,
            'host': 'foo:8080',
            'verb': 'GET',
            'path': '/bar',
            'params': params
        }

        # Now validate the signature based on the dummy request
        # Check the signature again after omitting the port.
        self.assertTrue(
            self.controller.check_signature(self.creds_ref, sig_ref))
예제 #19
0
    def _get_signed_url(self, signal_type=SIGNAL):
        """Create properly formatted and pre-signed URL.

        This uses the created user for the credentials.

        See http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/
        restarter-signature.html
        Also see boto/auth.py::QuerySignatureV2AuthHandler

        :param signal_type: either WAITCONDITION or SIGNAL.
        """
        waitcond_url = cfg.CONF.heat_waitcondition_server_url
        signal_url = waitcond_url.replace('/waitcondition', signal_type)
        host_url = urlparse.urlparse(signal_url)

        path = self.identifier().arn_url_path()
        credentials = self.keystone().get_ec2_keypair(self.resource_id)

        # Note the WSGI spec apparently means that the webob request we end up
        # prcessing in the CFN API (ec2token.py) has an unquoted path, so we
        # need to calculate the signature with the path component unquoted, but
        # ensure the actual URL contains the quoted version...
        unquoted_path = urllib.unquote(host_url.path + path)
        request = {
            'host': host_url.netloc.lower(),
            'verb': SIGNAL_VERB[signal_type],
            'path': unquoted_path,
            'params': {
                'SignatureMethod': 'HmacSHA256',
                'SignatureVersion': '2',
                'AWSAccessKeyId': credentials.access,
                'Timestamp': self.created_time.strftime("%Y-%m-%dT%H:%M:%SZ")
            }
        }
        # Sign the requested
        signer = ec2_utils.Ec2Signer(credentials.secret)
        request['params']['Signature'] = signer.generate(request)

        qs = urllib.urlencode(request['params'])
        url = "%s%s?%s" % (signal_url.lower(), path, qs)
        return url
예제 #20
0
    def test_generate_v4_port_strip(self):
        """Test v4 generator with host:port format for old boto version.

        Validate for old (<2.9.3) version of boto, where the port should
        be stripped to match boto behavior.
        """
        # Create a new signer object with the AWS example key
        secret = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
        signer = utils.Ec2Signer(secret)

        body_hash = ('b6359072c78d70ebee1e81adcbab4f0'
                     '1bf2c23245fa365ef83fe8f1f955085e2')
        auth_str = ('AWS4-HMAC-SHA256 '
                    'Credential=AKIAIOSFODNN7EXAMPLE/20110909/'
                    'us-east-1/iam/aws4_request,'
                    'SignedHeaders=content-type;host;x-amz-date,')
        headers = {
            'Content-type': 'application/x-www-form-urlencoded; charset=utf-8',
            'X-Amz-Date': '20110909T233600Z',
            'Host': 'foo:8000',
            'Authorization': auth_str,
            'User-Agent': 'Boto/2.9.2 (linux2)'
        }
        # Note the example in the AWS docs is inconsistent, previous
        # examples specify no query string, but the final POST example
        # does, apparently incorrectly since an empty parameter list
        # aligns all steps and the final signature with the examples
        params = {}
        credentials = {
            'host': 'foo:8000',
            'verb': 'POST',
            'path': '/',
            'params': params,
            'headers': headers,
            'body_hash': body_hash
        }
        signature = signer.generate(credentials)

        expected = ('9a4b2276a5039ada3b90f72ea8ec1745'
                    '14b92b909fb106b22ad910c5d75a54f4')
        self.assertEqual(expected, signature)
예제 #21
0
 def test_authenticate_expired_request(self):
     self.config_fixture.config(group='credential', auth_ttl=5)
     signer = ec2_utils.Ec2Signer(self.cred_blob['secret'])
     past = timeutils.utcnow() - datetime.timedelta(minutes=10)
     timestamp = utils.isotime(past)
     credentials = {
         'access': self.cred_blob['access'],
         'secret': self.cred_blob['secret'],
         'host': 'localhost',
         'verb': 'GET',
         'path': '/',
         'params': {
             'SignatureVersion': '2',
             'Action': 'Test',
             'Timestamp': timestamp
         },
     }
     credentials['signature'] = signer.generate(credentials)
     self.post('/ec2tokens',
               body={'credentials': credentials},
               expected_status=http.client.UNAUTHORIZED)
예제 #22
0
    def test_authenticate_expired_request_v4(self):
        self.config_fixture.config(group='credential', auth_ttl=5)
        signer = ec2_utils.Ec2Signer(self.cred_blob['secret'])
        past = timeutils.utcnow() - datetime.timedelta(minutes=10)
        timestamp = utils.isotime(past)
        hashed_payload = (
            'GET\n'
            '/\n'
            'Action=Test\n'
            'host:localhost\n'
            'x-amz-date:' + timestamp + '\n'
            '\n'
            'host;x-amz-date\n'
            'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
        body_hash = hashlib.sha256(hashed_payload.encode()).hexdigest()
        amz_credential = (
            'AKIAIOSFODNN7EXAMPLE/%s/us-east-1/iam/aws4_request,' %
            timestamp[:8])

        credentials = {
            'access': self.cred_blob['access'],
            'secret': self.cred_blob['secret'],
            'host': 'localhost',
            'verb': 'GET',
            'path': '/',
            'params': {
                'Action': 'Test',
                'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
                'X-Amz-SignedHeaders': 'host,x-amz-date,',
                'X-Amz-Credential': amz_credential
            },
            'headers': {
                'X-Amz-Date': timestamp
            },
            'body_hash': body_hash
        }
        credentials['signature'] = signer.generate(credentials)
        self.post('/ec2tokens',
                  body={'credentials': credentials},
                  expected_status=http.client.UNAUTHORIZED)
예제 #23
0
    def test_valid_authentication_response_with_signature_v4(self):
        signer = ec2_utils.Ec2Signer(self.cred_blob['secret'])
        timestamp = utils.isotime(timeutils.utcnow())
        hashed_payload = (
            'GET\n'
            '/\n'
            'Action=Test\n'
            'host:localhost\n'
            'x-amz-date:' + timestamp + '\n'
            '\n'
            'host;x-amz-date\n'
            'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
        body_hash = hashlib.sha256(hashed_payload.encode()).hexdigest()
        amz_credential = (
            'AKIAIOSFODNN7EXAMPLE/%s/us-east-1/iam/aws4_request,' %
            timestamp[:8])

        credentials = {
            'access': self.cred_blob['access'],
            'secret': self.cred_blob['secret'],
            'host': 'localhost',
            'verb': 'GET',
            'path': '/',
            'params': {
                'Action': 'Test',
                'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
                'X-Amz-SignedHeaders': 'host,x-amz-date,',
                'X-Amz-Credential': amz_credential
            },
            'headers': {
                'X-Amz-Date': timestamp
            },
            'body_hash': body_hash
        }
        credentials['signature'] = signer.generate(credentials)
        resp = self.post('/ec2tokens',
                         body={'credentials': credentials},
                         expected_status=http.client.OK)
        self.assertValidProjectScopedTokenResponse(resp, self.user)
예제 #24
0
    def _get_ec2_signed_url(self, signal_type=SIGNAL):
        """Create properly formatted and pre-signed URL.

        This uses the created user for the credentials.

        See boto/auth.py::QuerySignatureV2AuthHandler

        :param signal_type: either WAITCONDITION or SIGNAL.
        """
        stored = self.data().get('ec2_signed_url')
        if stored is not None:
            return stored

        access_key = self.data().get('access_key')
        secret_key = self.data().get('secret_key')

        if not access_key or not secret_key:
            if self.id is None:
                # it is too early
                return
            if self._get_user_id() is None:
                self._create_user()
            self._create_keypair()
            access_key = self.data().get('access_key')
            secret_key = self.data().get('secret_key')

            if not access_key or not secret_key:
                LOG.warn(_LW('Cannot generate signed url, '
                             'unable to create keypair'))
                return

        config_url = cfg.CONF.heat_waitcondition_server_url
        if config_url:
            signal_url = config_url.replace('/waitcondition', signal_type)
        else:
            heat_client_plugin = self.stack.clients.client_plugin('heat')
            endpoint = heat_client_plugin.get_heat_cfn_url()
            signal_url = ''.join([endpoint, signal_type])

        host_url = urlparse.urlparse(signal_url)

        path = self.identifier().arn_url_path()

        # Note the WSGI spec apparently means that the webob request we end up
        # processing in the CFN API (ec2token.py) has an unquoted path, so we
        # need to calculate the signature with the path component unquoted, but
        # ensure the actual URL contains the quoted version...
        unquoted_path = urlparse.unquote(host_url.path + path)
        request = {'host': host_url.netloc.lower(),
                   'verb': SIGNAL_VERB[signal_type],
                   'path': unquoted_path,
                   'params': {'SignatureMethod': 'HmacSHA256',
                              'SignatureVersion': '2',
                              'AWSAccessKeyId': access_key,
                              'Timestamp':
                              self.created_time.strftime("%Y-%m-%dT%H:%M:%SZ")
                              }}
        # Sign the request
        signer = ec2_utils.Ec2Signer(secret_key)
        request['params']['Signature'] = signer.generate(request)

        qs = urlparse.urlencode(request['params'])
        url = "%s%s?%s" % (signal_url.lower(),
                           path, qs)

        self.data_set('ec2_signed_url', url)
        return url
예제 #25
0
 def setUp(self):
     super(Ec2SignerTest, self).setUp()
     self.access = '966afbde20b84200ae4e62e09acf46b2'
     self.secret = '89cdf9e94e2643cab35b8b8ac5a51f83'
     self.signer = utils.Ec2Signer(self.secret)
예제 #26
0
    def collect(self):
        if CONF.cfn.metadata_url is None:
            if (CONF.cfn.heat_metadata_hint
                    and os.path.exists(CONF.cfn.heat_metadata_hint)):
                with open(CONF.cfn.heat_metadata_hint) as hint:
                    CONF.cfn.metadata_url = '%s/v1/' % hint.read().strip()
            else:
                logger.info('No metadata_url configured.')
                raise exc.CfnMetadataNotConfigured
        if CONF.cfn.access_key_id is None:
            logger.info('No Access Key ID configured.')
            raise exc.CfnMetadataNotConfigured
        if CONF.cfn.secret_access_key is None:
            logger.info('No Secret Access Key configured.')
            raise exc.CfnMetadataNotConfigured
        url = CONF.cfn.metadata_url
        stack_name = CONF.cfn.stack_name
        headers = {'Content-Type': 'application/json'}
        final_content = {}
        if CONF.cfn.path is None:
            logger.info('No path configured')
            raise exc.CfnMetadataNotConfigured

        signer = ec2_utils.Ec2Signer(secret_key=CONF.cfn.secret_access_key)
        for path in CONF.cfn.path:
            if '.' not in path:
                logger.error('Path not in format resource.field[.x.y] (%s)' %
                             path)
                raise exc.CfnMetadataNotConfigured
            resource, field = path.split('.', 1)
            if '.' in field:
                field, sub_path = field.split('.', 1)
            else:
                sub_path = ''
            params = {'Action': 'DescribeStackResource',
                      'StackName': stack_name,
                      'LogicalResourceId': resource,
                      'AWSAccessKeyId': CONF.cfn.access_key_id,
                      'SignatureVersion': '2'}
            parsed_url = urlparse.urlparse(url)
            credentials = {'params': params,
                           'verb': 'GET',
                           'host': parsed_url.netloc,
                           'path': parsed_url.path}
            params['Signature'] = signer.generate(credentials)
            try:
                content = self._session.get(
                    url, params=params, headers=headers,
                    verify=CONF.cfn.ca_certificate,
                    timeout=CONF.cfn.timeout)
                content.raise_for_status()
            except self._requests_impl.exceptions.RequestException as e:
                logger.warn(e)
                raise exc.CfnMetadataNotAvailable
            map_content = etree.fromstring(content.text)
            resource_detail = map_content.find(
                'DescribeStackResourceResult').find('StackResourceDetail')
            sub_element = resource_detail.find(field)
            if sub_element is None:
                logger.warn('Path %s does not exist.' % (path))
                raise exc.CfnMetadataNotAvailable
            try:
                value = json.loads(sub_element.text)
            except ValueError as e:
                logger.warn(
                    'Path %s failed to parse as json. (%s)' % (path, e))
                raise exc.CfnMetadataNotAvailable
            if sub_path:
                for subkey in sub_path.split('.'):
                    try:
                        value = value[subkey]
                    except KeyError:
                        logger.warn(
                            'Sub-key %s does not exist. (%s)' % (subkey, path))
                        raise exc.CfnMetadataNotAvailable
            final_content.update(value)
        final_list = merger.merged_list_from_content(
            final_content, cfg.CONF.cfn.deployment_key, name)
        return final_list
예제 #27
0
 def setUp(self):
     super(Ec2SignerTest, self).setUp()
     self.useFixture(client_fixtures.Deprecations())
     self.access = '966afbde20b84200ae4e62e09acf46b2'
     self.secret = '89cdf9e94e2643cab35b8b8ac5a51f83'
     self.signer = utils.Ec2Signer(self.secret)