Beispiel #1
0
def sig2(method, endpoint, params, provider, aws_api_version):
    '''
    Sign a query against AWS services using Signature Version 2 Signing
    Process. This is documented at:

    http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
    '''
    timenow = datetime.datetime.utcnow()
    timestamp = timenow.strftime('%Y-%m-%dT%H:%M:%SZ')

    params_with_headers = params.copy()
    params_with_headers['AWSAccessKeyId'] = provider.get('id', '')
    params_with_headers['SignatureVersion'] = '2'
    params_with_headers['SignatureMethod'] = 'HmacSHA256'
    params_with_headers['Timestamp'] = '{0}'.format(timestamp)
    params_with_headers['Version'] = aws_api_version
    keys = sorted(params_with_headers.keys())
    values = list(list(map(params_with_headers.get, keys)))
    querystring = urlencode(list(zip(keys, values)))

    canonical = '{0}\n{1}\n/\n{2}'.format(
        method.encode('utf-8'),
        endpoint.encode('utf-8'),
        querystring.encode('utf-8'),
    )

    hashed = hmac.new(provider['key'], canonical, hashlib.sha256)
    sig = binascii.b2a_base64(hashed.digest())
    params_with_headers['Signature'] = sig.strip()
    return params_with_headers
Beispiel #2
0
 def test_urlencoded_ctype(self):
     data = {'valid': 'stuff'}
     request, response = self.request('/', method='POST',
         body=urlencode(data), headers=(
             ('Content-type', 'application/x-www-form-urlencoded'),
     ))
     self.assertEqual(response.status, '200 OK')
     self.assertDictEqual(request.unserialized_data, data)
Beispiel #3
0
 def test_bad_login(self):
     '''
     Test logging in
     '''
     body = urlencode({'totally': 'invalid_creds'})
     request, response = self.request('/login', method='POST', body=body,
         headers={
             'content-type': 'application/x-www-form-urlencoded'
     })
     self.assertEqual(response.status, '401 Unauthorized')
Beispiel #4
0
 def test_webhook_noauth(self):
     '''
     Auth can be disabled for requests to the webhook URL
     '''
     body = urlencode({'foo': 'Foo!'})
     request, response = self.request('/hook', method='POST', body=body,
         headers={
             'content-type': 'application/x-www-form-urlencoded'
     })
     self.assertEqual(response.status, '200 OK')
Beispiel #5
0
 def test_good_login(self):
     '''
     Test logging in
     '''
     body = urlencode(self.auth_creds)
     request, response = self.request('/login', method='POST', body=body,
         headers={
             'content-type': 'application/x-www-form-urlencoded'
     })
     self.assertEqual(response.status, '200 OK')
     return response
Beispiel #6
0
    def test_logout(self):
        ret = self.test_good_login()
        token = ret.headers['X-Auth-Token']

        body = urlencode({})
        request, response = self.request('/logout', method='POST', body=body,
            headers={
                'content-type': 'application/x-www-form-urlencoded',
                'X-Auth-Token': token,
        })
        self.assertEqual(response.status, '200 OK')
Beispiel #7
0
    def test_run_bad_login(self):
        '''
        Test the run URL with bad auth credentials
        '''
        cmd = dict(self.low, **{'totally': 'invalid_creds'})
        body = urlencode(cmd)

        request, response = self.request('/run', method='POST', body=body,
            headers={
                'content-type': 'application/x-www-form-urlencoded'
        })
        self.assertEqual(response.status, '401 Unauthorized')
Beispiel #8
0
    def test_run_good_login(self):
        '''
        Test the run URL with good auth credentials
        '''
        cmd = dict(self.low, **dict(self.auth_creds))
        body = urlencode(cmd)

        request, response = self.request('/run', method='POST', body=body,
            headers={
                'content-type': 'application/x-www-form-urlencoded'
        })
        self.assertEqual(response.status, '200 OK')
Beispiel #9
0
    def test_bad_login(self):
        '''
        Test logging in
        '''
        # Mock mk_token for a negative return
        self.Resolver.return_value.mk_token.return_value = {}

        body = urlencode({'totally': 'invalid_creds'})
        request, response = self.request('/login', method='POST', body=body,
            headers={
                'content-type': 'application/x-www-form-urlencoded'
        })
        self.assertEqual(response.status, '401 Unauthorized')
Beispiel #10
0
    def test_run_good_login(self):
        '''
        Test the run URL with good auth credentials
        '''
        cmd = dict(self.low, **dict(self.auth_creds))
        body = urlencode(cmd)

        request, response = self.request(
            '/run',
            method='POST',
            body=body,
            headers={'content-type': 'application/x-www-form-urlencoded'})
        self.assertEqual(response.status, '200 OK')
Beispiel #11
0
    def test_webhook_noauth(self):
        '''
        Auth can be disabled for requests to the webhook URL
        '''
        # Mock fire_event() since we're only testing auth here.
        self.get_event.return_value.fire_event.return_value = True

        body = urlencode({'foo': 'Foo!'})
        request, response = self.request('/hook', method='POST', body=body,
            headers={
                'content-type': 'application/x-www-form-urlencoded'
        })
        self.assertEqual(response.status, '200 OK')
Beispiel #12
0
    def test_run_wrong_token(self):
        '''
        Test the run URL with incorrect token
        '''
        cmd = dict(self.low, **{'token': 'bad'})
        body = urlencode(cmd)

        request, response = self.request(
            '/run',
            method='POST',
            body=body,
            headers={'content-type': 'application/x-www-form-urlencoded'})
        assert response.status == '401 Unauthorized'
Beispiel #13
0
    def test_websocket_handler_upgrade_to_websocket(self):
        response = yield self.http_client.fetch(self.get_url('/login'),
                                                method='POST',
                                                body=urlencode(self.auth_creds),
                                                headers={'Content-Type': self.content_type_map['form']})
        token = json.loads(response.body)['return'][0]['token']

        url = 'ws://127.0.0.1:{0}/all_events/{1}'.format(self.get_http_port(), token)
        request = HTTPRequest(url, headers={'Origin': 'http://example.com',
                                            'Host': 'example.com'})
        ws = yield websocket_connect(request)
        ws.write_message('websocket client ready')
        ws.close()
Beispiel #14
0
    def test_run_pathname_not_exists_token(self):
        '''
        Test the run URL with path that does not exist in token
        '''
        cmd = dict(self.low, **{'token': os.path.join('tmp', 'doesnotexist')})
        body = urlencode(cmd)

        request, response = self.request(
            '/run',
            method='POST',
            body=body,
            headers={'content-type': 'application/x-www-form-urlencoded'})
        assert response.status == '401 Unauthorized'
Beispiel #15
0
 def test_good_login(self):
     """
     Test logging in
     """
     body = urlencode(self.auth_creds)
     request, response = self.request(
         "/login",
         method="POST",
         body=body,
         headers={"content-type": "application/x-www-form-urlencoded"},
     )
     self.assertEqual(response.status, "200 OK")
     return response
Beispiel #16
0
    def test_run_bad_login(self):
        '''
        Test the run URL with bad auth credentials
        '''
        cmd = dict(self.low, **{'totally': 'invalid_creds'})
        body = urlencode(cmd)

        request, response = self.request(
            '/run',
            method='POST',
            body=body,
            headers={'content-type': 'application/x-www-form-urlencoded'})
        self.assertEqual(response.status, '401 Unauthorized')
Beispiel #17
0
    def _add_job(self):
        '''
        Helper function to add a job to the job cache
        '''
        cmd = dict(self.low, **dict(self.auth_creds))
        body = urlencode(cmd)

        request, response = self.request(
            '/run',
            method='POST',
            body=body,
            headers={'content-type': 'application/x-www-form-urlencoded'})
        self.assertEqual(response.status, '200 OK')
Beispiel #18
0
    def test_run_empty_token_upercase(self):
        '''
        Test the run URL with empty token with upercase characters
        '''
        cmd = dict(self.low, **{'ToKen': ''})
        body = urlencode(cmd)

        request, response = self.request(
            '/run',
            method='POST',
            body=body,
            headers={'content-type': 'application/x-www-form-urlencoded'})
        assert response.status == '401 Unauthorized'
Beispiel #19
0
    def test_websocket_handler_upgrade_to_websocket(self):
        response = yield self.http_client.fetch(self.get_url('/login'),
                                                method='POST',
                                                body=urlencode(self.auth_creds),
                                                headers={'Content-Type': self.content_type_map['form']})
        token = json.loads(response.body)['return'][0]['token']

        url = 'ws://127.0.0.1:{0}/hook/{1}'.format(self.get_http_port(), token)
        request = HTTPRequest(url, headers={'Origin': 'http://example.com',
                                            'Host': 'example.com'})
        ws = yield websocket_connect(request)
        ws.write_message('websocket client ready')
        ws.close()
Beispiel #20
0
    def test_login(self):
        '''
        Test valid logins
        '''
        # Test in form encoded
        response = self.fetch('/login',
                               method='POST',
                               body=urlencode(self.auth_creds),
                               headers={'Content-Type': self.content_type_map['form']})

        cookies = response.headers['Set-Cookie']
        self.assertEqual(response.code, 200)
        response_obj = salt.utils.json.loads(response.body)['return'][0]
        token = response_obj['token']
        self.assertIn('session_id={0}'.format(token), cookies)
        self.assertEqual(sorted(response_obj['perms']), sorted(self.opts['external_auth']['auto'][self.auth_creds_dict['username']]))
        self.assertIn('token', response_obj)  # TODO: verify that its valid?
        self.assertEqual(response_obj['user'], self.auth_creds_dict['username'])
        self.assertEqual(response_obj['eauth'], self.auth_creds_dict['eauth'])

        # Test in JSON
        response = self.fetch('/login',
                               method='POST',
                               body=salt.utils.json.dumps(self.auth_creds_dict),
                               headers={'Content-Type': self.content_type_map['json']})

        cookies = response.headers['Set-Cookie']
        self.assertEqual(response.code, 200)
        response_obj = salt.utils.json.loads(response.body)['return'][0]
        token = response_obj['token']
        self.assertIn('session_id={0}'.format(token), cookies)
        self.assertEqual(sorted(response_obj['perms']), sorted(self.opts['external_auth']['auto'][self.auth_creds_dict['username']]))
        self.assertIn('token', response_obj)  # TODO: verify that its valid?
        self.assertEqual(response_obj['user'], self.auth_creds_dict['username'])
        self.assertEqual(response_obj['eauth'], self.auth_creds_dict['eauth'])

        # Test in YAML
        response = self.fetch('/login',
                               method='POST',
                               body=salt.utils.yaml.safe_dump(self.auth_creds_dict),
                               headers={'Content-Type': self.content_type_map['yaml']})

        cookies = response.headers['Set-Cookie']
        self.assertEqual(response.code, 200)
        response_obj = salt.utils.json.loads(response.body)['return'][0]
        token = response_obj['token']
        self.assertIn('session_id={0}'.format(token), cookies)
        self.assertEqual(sorted(response_obj['perms']), sorted(self.opts['external_auth']['auto'][self.auth_creds_dict['username']]))
        self.assertIn('token', response_obj)  # TODO: verify that its valid?
        self.assertEqual(response_obj['user'], self.auth_creds_dict['username'])
        self.assertEqual(response_obj['eauth'], self.auth_creds_dict['eauth'])
Beispiel #21
0
    def test_run_bad_login(self):
        """
        Test the run URL with bad auth credentials
        """
        cmd = dict(self.low, **{"totally": "invalid_creds"})
        body = urlencode(cmd)

        request, response = self.request(
            "/run",
            method="POST",
            body=body,
            headers={"content-type": "application/x-www-form-urlencoded"},
        )
        self.assertEqual(response.status, "401 Unauthorized")
Beispiel #22
0
    def test_run_good_login(self):
        """
        Test the run URL with good auth credentials
        """
        cmd = dict(self.low, **dict(self.auth_creds))
        body = urlencode(cmd)

        request, response = self.request(
            "/run",
            method="POST",
            body=body,
            headers={"content-type": "application/x-www-form-urlencoded"},
        )
        self.assertEqual(response.status, "200 OK")
Beispiel #23
0
    def test_bad_login(self):
        '''
        Test logging in
        '''
        # Mock mk_token for a negative return
        self.Resolver.return_value.mk_token.return_value = {}

        body = urlencode({'totally': 'invalid_creds'})
        request, response = self.request(
            '/login',
            method='POST',
            body=body,
            headers={'content-type': 'application/x-www-form-urlencoded'})
        self.assertEqual(response.status, '401 Unauthorized')
Beispiel #24
0
    def test_webhook_noauth(self):
        '''
        Auth can be disabled for requests to the webhook URL
        '''
        # Mock fire_event() since we're only testing auth here.
        self.get_event.return_value.fire_event.return_value = True

        body = urlencode({'foo': 'Foo!'})
        request, response = self.request(
            '/hook',
            method='POST',
            body=body,
            headers={'content-type': 'application/x-www-form-urlencoded'})
        self.assertEqual(response.status, '200 OK')
Beispiel #25
0
    def test_login(self):
        '''
        Test valid logins
        '''
        response = self.fetch('/login',
                               method='POST',
                               body=urlencode(self.auth_creds),
                               headers={'Content-Type': self.content_type_map['form']})

        response_obj = json.loads(response.body)['return'][0]
        self.assertEqual(response_obj['perms'], self.opts['external_auth']['auto'][self.auth_creds_dict['username']])
        self.assertIn('token', response_obj)  # TODO: verify that its valid?
        self.assertEqual(response_obj['user'], self.auth_creds_dict['username'])
        self.assertEqual(response_obj['eauth'], self.auth_creds_dict['eauth'])
Beispiel #26
0
 def _token(self):
     '''
     Return the token
     '''
     body = urlencode(self.auth_creds)
     request, response = self.request(
         '/login',
         method='POST',
         body=body,
         headers={
             'content-type': 'application/x-www-form-urlencoded'
         }
     )
     return response.headers['X-Auth-Token']
Beispiel #27
0
    def test_run_pathname_not_exists_token(self):
        """
        Test the run URL with path that does not exist in token
        """
        cmd = dict(self.low, **{"token": os.path.join("tmp", "doesnotexist")})
        body = urlencode(cmd)

        request, response = self.request(
            "/run",
            method="POST",
            body=body,
            headers={"content-type": "application/x-www-form-urlencoded"},
        )
        assert response.status == "401 Unauthorized"
Beispiel #28
0
    def test_run_wrong_token(self):
        """
        Test the run URL with incorrect token
        """
        cmd = dict(self.low, **{"token": "bad"})
        body = urlencode(cmd)

        request, response = self.request(
            "/run",
            method="POST",
            body=body,
            headers={"content-type": "application/x-www-form-urlencoded"},
        )
        assert response.status == "401 Unauthorized"
Beispiel #29
0
 def test_good_pwd_pam_chsh_service(self):
     '''
     Test login while specifying chsh service with good passwd
     This test ensures this PR is working correctly:
     https://github.com/saltstack/salt/pull/31826
     '''
     copyauth_creds = AUTH_CREDS.copy()
     copyauth_creds['service'] = 'chsh'
     body = urlencode(copyauth_creds)
     request, response = self.request('/login', method='POST', body=body,
                                      headers={
                                          'content-type': 'application/x-www-form-urlencoded'
                                          })
     self.assertEqual(response.status, '200 OK')
Beispiel #30
0
    def _add_job(self):
        """
        Helper function to add a job to the job cache
        """
        cmd = dict(self.low, **dict(self.auth_creds))
        body = urlencode(cmd)

        request, response = self.request(
            "/run",
            method="POST",
            body=body,
            headers={"content-type": "application/x-www-form-urlencoded"},
        )
        self.assertEqual(response.status, "200 OK")
Beispiel #31
0
    def test_login(self):
        '''
        Test valid logins
        '''
        response = self.fetch('/login',
                               method='POST',
                               body=urlencode(self.auth_creds),
                               headers={'Content-Type': self.content_type_map['form']})

        response_obj = json.loads(response.body)['return'][0]
        self.assertEqual(response_obj['perms'], self.opts['external_auth']['auto'][self.auth_creds_dict['username']])
        self.assertIn('token', response_obj)  # TODO: verify that its valid?
        self.assertEqual(response_obj['user'], self.auth_creds_dict['username'])
        self.assertEqual(response_obj['eauth'], self.auth_creds_dict['eauth'])
Beispiel #32
0
    def test_run_empty_token_upercase(self):
        """
        Test the run URL with empty token with upercase characters
        """
        cmd = dict(self.low, **{"ToKen": ""})
        body = urlencode(cmd)

        request, response = self.request(
            "/run",
            method="POST",
            body=body,
            headers={"content-type": "application/x-www-form-urlencoded"},
        )
        assert response.status == "401 Unauthorized"
Beispiel #33
0
 def _token(self):
     '''
     Return the token
     '''
     body = urlencode(self.auth_creds)
     request, response = self.request(
         '/login',
         method='POST',
         body=body,
         headers={
             'content-type': 'application/x-www-form-urlencoded'
         }
     )
     return response.headers['X-Auth-Token']
Beispiel #34
0
    def test_logout(self):
        ret = self.test_good_login()
        token = ret.headers['X-Auth-Token']

        body = urlencode({})
        request, response = self.request(
            '/logout',
            method='POST',
            body=body,
            headers={
                'content-type': 'application/x-www-form-urlencoded',
                'X-Auth-Token': token,
            })
        self.assertEqual(response.status, '200 OK')
Beispiel #35
0
    def test_websocket_handler_cors_origin_wildcard(self):
        self._app.mod_opts['cors_origin'] = '*'

        response = yield self.http_client.fetch(self.get_url('/login'),
                                                method='POST',
                                                body=urlencode(self.auth_creds),
                                                headers={'Content-Type': self.content_type_map['form']})
        token = salt.utils.json.loads(self.decode_body(response).body)['return'][0]['token']

        url = 'ws://127.0.0.1:{0}/all_events/{1}'.format(self.get_http_port(), token)
        request = HTTPRequest(url, headers={'Origin': 'http://foo.bar',
                                            'Host': 'example.com'})
        ws = yield websocket_connect(request)
        ws.write_message('websocket client ready')
        ws.close()
Beispiel #36
0
    def test_logout(self):
        ret = self.test_good_login()
        token = ret.headers["X-Auth-Token"]

        body = urlencode({})
        request, response = self.request(
            "/logout",
            method="POST",
            body=body,
            headers={
                "content-type": "application/x-www-form-urlencoded",
                "X-Auth-Token": token,
            },
        )
        self.assertEqual(response.status, "200 OK")
Beispiel #37
0
    def test_login_bad_creds(self):
        '''
        Test logins with bad/missing passwords
        '''
        bad_creds = []
        for key, val in self.auth_creds_dict.iteritems():
            if key == 'username':
                val = val + 'foo'
            bad_creds.append((key, val))
        response = self.fetch('/login',
                               method='POST',
                               body=urlencode(bad_creds),
                               headers={'Content-Type': self.content_type_map['form']})

        self.assertEqual(response.code, 401)
Beispiel #38
0
    def test_login_missing_password(self):
        '''
        Test logins with bad/missing passwords
        '''
        bad_creds = []
        for key, val in six.iteritems(self.auth_creds_dict):
            if key == 'password':
                continue
            bad_creds.append((key, val))
        response = self.fetch('/login',
                               method='POST',
                               body=urlencode(bad_creds),
                               headers={'Content-Type': self.content_type_map['form']})

        self.assertEqual(response.code, 400)
Beispiel #39
0
 def test_good_pwd_pam_chsh_service(self):
     """
     Test login while specifying chsh service with good passwd
     This test ensures this PR is working correctly:
     https://github.com/saltstack/salt/pull/31826
     """
     copyauth_creds = AUTH_CREDS.copy()
     copyauth_creds["service"] = "chsh"
     body = urlencode(copyauth_creds)
     request, response = self.request(
         "/login",
         method="POST",
         body=body,
         headers={"content-type": "application/x-www-form-urlencoded"},
     )
     self.assertEqual(response.status, "200 OK")
Beispiel #40
0
    def test_run_bad_login(self):
        '''
        Test the run URL with bad auth credentials
        '''
        cmd = dict(self.low, **{'totally': 'invalid_creds'})
        body = urlencode(cmd)

        # Mock the interaction with Salt so we can focus on the API.
        with mock.patch.object(self.app.salt.netapi.NetapiClient, 'run',
                side_effect=EauthAuthenticationError('Oh noes!')):
            request, response = self.request('/run', method='POST', body=body,
                headers={
                    'content-type': 'application/x-www-form-urlencoded'
            })

        self.assertEqual(response.status, '401 Unauthorized')
Beispiel #41
0
    def test_run_good_login(self):
        '''
        Test the run URL with good auth credentials
        '''
        cmd = dict(self.low, **dict(self.auth_creds))
        body = urlencode(cmd)

        # Mock the interaction with Salt so we can focus on the API.
        with mock.patch.object(self.app.salt.netapi.NetapiClient, 'run',
                return_value=True):
            request, response = self.request('/run', method='POST', body=body,
                headers={
                    'content-type': 'application/x-www-form-urlencoded'
            })

        self.assertEqual(response.status, '200 OK')
Beispiel #42
0
    def _get_response(self, action, params, method='POST'):

        headers = {
            'Accept': 'application/json',
            'Content-Type': 'application/json; charset=UTF-8'
        }

        if not params:
            params = {}

        query_params = {}

        if ('server_basic_username' in globals()
                and len(self.server_basic_username) > 0):
            userAndPass = b64encode(
                str.encode(self.server_basic_username + ':' +
                           self.server_basic_password)).decode('ascii')
            headers['Authorization'] = 'Basic %s' % userAndPass

        if (len(self._session) > 0):
            params['ses'] = self._session

        query_params['a'] = action

        if not method:
            method = 'POST'

        if method == 'POST':
            data = urlencode(params)
        else:
            data = None
            query_params.update(params)

        http_timeout = 10 * 60

        result = salt.utils.http.query(
            self._url,
            method=method,
            params=query_params,
            data=data,
            headers_dict=headers,
            decode=True,
            status=True,
            opts=__opts__,
        )
        return result
Beispiel #43
0
    def test_login_missing_password(self):
        """
        Test logins with bad/missing passwords
        """
        bad_creds = []
        for key, val in six.iteritems(self.auth_creds_dict):
            if key == "password":
                continue
            bad_creds.append((key, val))
        response = self.fetch(
            "/login",
            method="POST",
            body=urlencode(bad_creds),
            headers={"Content-Type": self.content_type_map["form"]},
        )

        self.assertEqual(response.code, 400)
Beispiel #44
0
    def test_run_good_login(self):
        '''
        Test the run URL with good auth credentials
        '''
        cmd = dict(self.low, **dict(self.auth_creds))
        body = urlencode(cmd)

        # Mock the interaction with Salt so we can focus on the API.
        with mock.patch.object(self.app.salt.netapi.NetapiClient,
                               'run',
                               return_value=True):
            request, response = self.request(
                '/run',
                method='POST',
                body=body,
                headers={'content-type': 'application/x-www-form-urlencoded'})

        self.assertEqual(response.status, '200 OK')
Beispiel #45
0
    def test_websocket_handler_upgrade_to_websocket(self):
        response = yield self.http_client.fetch(
            self.get_url("/login"),
            method="POST",
            body=urlencode(self.auth_creds),
            headers={"Content-Type": self.content_type_map["form"]},
        )
        token = salt.utils.json.loads(self.decode_body(response).body)["return"][0][
            "token"
        ]

        url = "ws://127.0.0.1:{0}/all_events/{1}".format(self.get_http_port(), token)
        request = HTTPRequest(
            url, headers={"Origin": "http://example.com", "Host": "example.com"}
        )
        ws = yield websocket_connect(request)
        ws.write_message("websocket client ready")
        ws.close()
Beispiel #46
0
    def test_login_bad_creds(self):
        '''
        Test logins with bad/missing passwords
        '''
        bad_creds = []
        for key, val in six.iteritems(self.auth_creds_dict):
            if key == 'username':
                val = val + 'foo'
            if key == 'eauth':
                val = 'sharedsecret'
            bad_creds.append((key, val))

        response = self.fetch('/login',
                               method='POST',
                               body=urlencode(bad_creds),
                               headers={'Content-Type': self.content_type_map['form']})

        self.assertEqual(response.code, 401)
Beispiel #47
0
    def test_good_login(self):
        '''
        Test logging in
        '''
        # Mock mk_token for a positive return
        self.Resolver.return_value.mk_token.return_value = {
            'token': '6d1b722e',
            'start': 1363805943.776223,
            'expire': 1363849143.776224,
            'name': 'saltdev',
            'eauth': 'auto',
        }

        body = urlencode(self.auth_creds)
        request, response = self.request('/login', method='POST', body=body,
            headers={
                'content-type': 'application/x-www-form-urlencoded'
        })
        self.assertEqual(response.status, '200 OK')
        return response
Beispiel #48
0
def sig2(method, endpoint, params, provider, aws_api_version):
    '''
    Sign a query against AWS services using Signature Version 2 Signing
    Process. This is documented at:

    http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
    '''
    timenow = datetime.datetime.utcnow()
    timestamp = timenow.strftime('%Y-%m-%dT%H:%M:%SZ')

    # Retrieve access credentials from meta-data, or use provided
    access_key_id, secret_access_key, token = creds(provider)

    params_with_headers = params.copy()
    params_with_headers['AWSAccessKeyId'] = access_key_id
    params_with_headers['SignatureVersion'] = '2'
    params_with_headers['SignatureMethod'] = 'HmacSHA256'
    params_with_headers['Timestamp'] = '{0}'.format(timestamp)
    params_with_headers['Version'] = aws_api_version
    keys = sorted(params_with_headers.keys())
    values = list(list(map(params_with_headers.get, keys)))
    querystring = urlencode(list(zip(keys, values)))

    canonical = '{0}\n{1}\n/\n{2}'.format(
        method.encode('utf-8'),
        endpoint.encode('utf-8'),
        querystring.encode('utf-8'),
    )

    hashed = hmac.new(secret_access_key, canonical, hashlib.sha256)
    sig = binascii.b2a_base64(hashed.digest())
    params_with_headers['Signature'] = sig.strip()

    # Add in security token if we have one
    if token != '':
        params_with_headers['SecurityToken'] = token

    return params_with_headers
Beispiel #49
0
    def test_cors_origin_multiple(self):
        self._app.mod_opts['cors_origin'] = ['http://example.com', 'http://foo.bar']

        response = yield self.http_client.fetch(self.get_url('/login'),
                                                method='POST',
                                                body=urlencode(self.auth_creds),
                                                headers={'Content-Type': self.content_type_map['form']})
        token = json.loads(response.body)['return'][0]['token']
        url = 'ws://127.0.0.1:{0}/hook/{1}'.format(self.get_http_port(), token)

        # Example.com should works
        request = HTTPRequest(url, headers={'Origin': 'http://example.com',
                                            'Host': 'example.com'})
        ws = yield websocket_connect(request)
        ws.write_message('websocket client ready')
        ws.close()

        # Foo.bar too
        request = HTTPRequest(url, headers={'Origin': 'http://foo.bar',
                                            'Host': 'example.com'})
        ws = yield websocket_connect(request)
        ws.write_message('websocket client ready')
        ws.close()
Beispiel #50
0
def sig4(method, endpoint, params, prov_dict, aws_api_version, location,
         product='ec2', uri='/', requesturl=None):
    '''
    Sign a query against AWS services using Signature Version 4 Signing
    Process. This is documented at:

    http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
    http://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
    http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
    '''
    timenow = datetime.datetime.utcnow()
    timestamp = timenow.strftime('%Y-%m-%dT%H:%M:%SZ')

    params_with_headers = params.copy()
    params_with_headers['Version'] = aws_api_version
    keys = sorted(params_with_headers.keys())
    values = list(map(params_with_headers.get, keys))
    querystring = urlencode(list(zip(keys, values)))

    amzdate = timenow.strftime('%Y%m%dT%H%M%SZ')
    datestamp = timenow.strftime('%Y%m%d')
    payload_hash = hashlib.sha256('').hexdigest()

    canonical_headers = 'host:{0}\nx-amz-date:{1}\n'.format(
        endpoint,
        amzdate,
    )
    signed_headers = 'host;x-amz-date'

    request = '\n'.join((
        method, endpoint, querystring, canonical_headers,
        signed_headers, payload_hash
    ))

    algorithm = 'AWS4-HMAC-SHA256'

    # Create payload hash (hash of the request body content). For GET
    # requests, the payload is an empty string ('').
    payload_hash = hashlib.sha256('').hexdigest()

    # Combine elements to create create canonical request
    canonical_request = '\n'.join((
        method,
        uri,
        querystring,
        canonical_headers,
        signed_headers,
        payload_hash
    ))

    # Create the string to sign
    credential_scope = '/'.join((
        datestamp, location, product, 'aws4_request'
    ))
    string_to_sign = '\n'.join((
        algorithm,
        amzdate,
        credential_scope,
        hashlib.sha256(canonical_request).hexdigest()
    ))

    # Create the signing key using the function defined above.
    signing_key = _sig_key(
        prov_dict.get('key', ''),
        datestamp,
        location,
        product
    )

    # Sign the string_to_sign using the signing_key
    signature = hmac.new(
        signing_key,
        string_to_sign.encode('utf-8'),
        hashlib.sha256).hexdigest()

    # Add signing information to the request
    authorization_header = (
            '{0} Credential={1}/{2}, SignedHeaders={3}, Signature={4}'
        ).format(
            algorithm,
            prov_dict.get('id', ''),
            credential_scope,
            signed_headers,
            signature,
        )

    headers = {
        'x-amz-date': amzdate,
        'Authorization': authorization_header
    }

    requesturl = '{0}?{1}'.format(requesturl, querystring)
    return headers, requesturl
Beispiel #51
0
def sig4(method, endpoint, params, prov_dict,
         aws_api_version=DEFAULT_AWS_API_VERSION, location=DEFAULT_LOCATION,
         product='ec2', uri='/', requesturl=None, data='', headers=None):
    '''
    Sign a query against AWS services using Signature Version 4 Signing
    Process. This is documented at:

    http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
    http://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
    http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
    '''
    timenow = datetime.datetime.utcnow()

    # Retrieve access credentials from meta-data, or use provided
    access_key_id, secret_access_key, token = creds(prov_dict)

    params_with_headers = params.copy()
    if product != 's3':
        params_with_headers['Version'] = aws_api_version
    keys = sorted(params_with_headers.keys())
    values = list(map(params_with_headers.get, keys))
    querystring = urlencode(list(zip(keys, values))).replace('+', '%20')

    amzdate = timenow.strftime('%Y%m%dT%H%M%SZ')
    datestamp = timenow.strftime('%Y%m%d')

    canonical_headers = 'host:{0}\nx-amz-date:{1}'.format(
        endpoint,
        amzdate,
    )
    signed_headers = 'host;x-amz-date'

    if isinstance(headers, dict):
        for header in sorted(headers.keys()):
            canonical_headers += '\n{0}:{1}'.format(header, headers[header])
            signed_headers += ';{0}'.format(header)
    canonical_headers += '\n'

    algorithm = 'AWS4-HMAC-SHA256'

    # Create payload hash (hash of the request body content). For GET
    # requests, the payload is an empty string ('').
    payload_hash = hashlib.sha256(data).hexdigest()

    # Combine elements to create create canonical request
    canonical_request = '\n'.join((
        method,
        uri,
        querystring,
        canonical_headers,
        signed_headers,
        payload_hash
    ))

    # Create the string to sign
    credential_scope = '/'.join((
        datestamp, location, product, 'aws4_request'
    ))
    string_to_sign = '\n'.join((
        algorithm,
        amzdate,
        credential_scope,
        hashlib.sha256(canonical_request).hexdigest()
    ))

    # Create the signing key using the function defined above.
    signing_key = _sig_key(
        secret_access_key,
        datestamp,
        location,
        product
    )

    # Sign the string_to_sign using the signing_key
    signature = hmac.new(
        signing_key,
        string_to_sign.encode('utf-8'),
        hashlib.sha256).hexdigest()

    # Add signing information to the request
    authorization_header = (
            '{0} Credential={1}/{2}, SignedHeaders={3}, Signature={4}'
        ).format(
            algorithm,
            access_key_id,
            credential_scope,
            signed_headers,
            signature,
        )

    new_headers = {
        'x-amz-date': amzdate,
        'x-amz-content-sha256': payload_hash,
        'Authorization': authorization_header,
    }
    if isinstance(headers, dict):
        for header in sorted(headers.keys()):
            new_headers[header] = headers[header]

    # Add in security token if we have one
    if token != '':
        new_headers['X-Amz-Security-Token'] = token

    requesturl = '{0}?{1}'.format(requesturl, querystring)
    return new_headers, requesturl
Beispiel #52
0
def query(key, keyid, method='GET', params=None, headers=None,
          requesturl=None, return_url=False, bucket=None, service_url=None,
          path=None, return_bin=False, action=None, local_file=None,
          verify_ssl=True, full_headers=False):
    '''
    Perform a query against an S3-like API. This function requires that a
    secret key and the id for that key are passed in. For instance:

        s3.keyid: GKTADJGHEIQSXMKKRBJ08H
        s3.key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs

    A service_url may also be specified in the configuration::

        s3.service_url: s3.amazonaws.com

    If a service_url is not specified, the default is s3.amazonaws.com. This
    may appear in various documentation as an "endpoint". A comprehensive list
    for Amazon S3 may be found at::

        http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region

    The service_url will form the basis for the final endpoint that is used to
    query the service.

    SSL verification may also be turned off in the configuration:

    s3.verify_ssl: False

    This is required if using S3 bucket names that contain a period, as
    these will not match Amazon's S3 wildcard certificates. Certificate
    verification is enabled by default.
    '''
    if not HAS_REQUESTS:
        log.error('There was an error: requests is required for s3 access')

    if not headers:
        headers = {}

    if not params:
        params = {}

    if path is None:
        path = ''

    if not service_url:
        service_url = 's3.amazonaws.com'

    if bucket:
        endpoint = '{0}.{1}'.format(bucket, service_url)
    else:
        endpoint = service_url

    # Try grabbing the credentials from the EC2 instance IAM metadata if available
    token = None
    if not key or not keyid:
        iam_creds = iam.get_iam_metadata()
        key = iam_creds['secret_key']
        keyid = iam_creds['access_key']
        token = iam_creds['security_token']

    if not requesturl:
        x_amz_date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
        content_type = 'text/plain'
        if method == 'GET':
            if bucket:
                can_resource = '/{0}/{1}'.format(bucket, path)
            else:
                can_resource = '/'
        elif method == 'PUT' or method == 'HEAD' or method == 'DELETE':
            if path:
                can_resource = '/{0}/{1}'.format(bucket, path)
            else:
                can_resource = '/{0}/'.format(bucket)

        if action:
            can_resource += '?{0}'.format(action)

        log.debug('CanonicalizedResource: {0}'.format(can_resource))

        headers['Host'] = endpoint
        headers['Content-type'] = content_type
        headers['Date'] = x_amz_date
        if token:
            headers['x-amz-security-token'] = token

        string_to_sign = '{0}\n'.format(method)

        new_headers = []
        for header in sorted(headers):
            if header.lower().startswith('x-amz'):
                log.debug(header.lower())
                new_headers.append('{0}:{1}'.format(header.lower(),
                                                    headers[header]))
        can_headers = '\n'.join(new_headers)
        log.debug('CanonicalizedAmzHeaders: {0}'.format(can_headers))

        string_to_sign += '\n{0}'.format(content_type)
        string_to_sign += '\n{0}'.format(x_amz_date)
        if can_headers:
            string_to_sign += '\n{0}'.format(can_headers)
        string_to_sign += '\n{0}'.format(can_resource)
        log.debug('String To Sign:: \n{0}'.format(string_to_sign))

        hashed = hmac.new(key, string_to_sign, hashlib.sha1)
        sig = binascii.b2a_base64(hashed.digest())
        headers['Authorization'] = 'AWS {0}:{1}'.format(keyid, sig.strip())

        querystring = urlencode(params)
        if action:
            if querystring:
                querystring = '{0}&{1}'.format(action, querystring)
            else:
                querystring = action
        requesturl = 'https://{0}/'.format(endpoint)
        if path:
            requesturl += path
        if querystring:
            requesturl += '?{0}'.format(querystring)

    data = None
    if method == 'PUT':
        if local_file:
            with salt.utils.fopen(local_file, 'r') as ifile:
                data = ifile.read()

    log.debug('S3 Request: {0}'.format(requesturl))
    log.debug('S3 Headers::')
    log.debug('    Authorization: {0}'.format(headers['Authorization']))

    try:
        result = requests.request(method, requesturl, headers=headers,
                                  data=data,
                                  verify=verify_ssl)
        response = result.content
    except requests.exceptions.HTTPError as exc:
        log.error('There was an error::')
        if hasattr(exc, 'code') and hasattr(exc, 'msg'):
            log.error('    Code: {0}: {1}'.format(exc.code, exc.msg))
        log.error('    Content: \n{0}'.format(exc.read()))
        return False

    log.debug('S3 Response Status Code: {0}'.format(result.status_code))

    if method == 'PUT':
        if result.status_code == 200:
            if local_file:
                log.debug('Uploaded from {0} to {1}'.format(local_file, path))
            else:
                log.debug('Created bucket {0}'.format(bucket))
        else:
            if local_file:
                log.debug('Failed to upload from {0} to {1}: {2}'.format(
                                                    local_file,
                                                    path,
                                                    result.status_code,
                                                    ))
            else:
                log.debug('Failed to create bucket {0}'.format(bucket))
        return

    if method == 'DELETE':
        if str(result.status_code).startswith('2'):
            if path:
                log.debug('Deleted {0} from bucket {1}'.format(path, bucket))
            else:
                log.debug('Deleted bucket {0}'.format(bucket))
        else:
            if path:
                log.debug('Failed to delete {0} from bucket {1}: {2}'.format(
                                                    path,
                                                    bucket,
                                                    result.status_code,
                                                    ))
            else:
                log.debug('Failed to delete bucket {0}'.format(bucket))
        return

    # This can be used to save a binary object to disk
    if local_file and method == 'GET':
        log.debug('Saving to local file: {0}'.format(local_file))
        with salt.utils.fopen(local_file, 'w') as out:
            out.write(response)
        return 'Saved to local file: {0}'.format(local_file)

    # This can be used to return a binary object wholesale
    if return_bin:
        return response

    if response:
        items = ET.fromstring(response)

        ret = []
        for item in items:
            ret.append(xml.to_dict(item))

        if return_url is True:
            return ret, requesturl
    else:
        if result.status_code != requests.codes.ok:
            return
        ret = {'headers': []}
        if full_headers:
            ret['headers'] = dict(result.headers)
        else:
            for header in result.headers:
                ret['headers'].append(header.strip())

    return ret
Beispiel #53
0
    def test_get_lowstate(self):
        '''
        Test transformations low data of the function _get_lowstate
        '''
        valid_lowstate = [{
                "client": "local",
                "tgt": "*",
                "fun": "test.fib",
                "arg": ["10"]
            }]

        # Case 1. dictionary type of lowstate
        request_lowstate = {
                "client": "local",
                "tgt": "*",
                "fun": "test.fib",
                "arg": ["10"]
            }

        response = self.fetch('/',
                              method='POST',
                              body=json.dumps(request_lowstate),
                              headers={'Content-Type': self.content_type_map['json']})

        self.assertEqual(valid_lowstate, json.loads(response.body)['lowstate'])

        # Case 2. string type of arg
        request_lowstate = [{
                "client": "local",
                "tgt": "*",
                "fun": "test.fib",
                "arg": "10"
            }]

        response = self.fetch('/',
                              method='POST',
                              body=json.dumps(request_lowstate),
                              headers={'Content-Type': self.content_type_map['json']})

        self.assertEqual(valid_lowstate, json.loads(response.body)['lowstate'])

        # Case 3. Combine Case 1 and Case 2.
        request_lowstate = {
                "client": "local",
                "tgt": "*",
                "fun": "test.fib",
                "arg": "10"
            }

        # send as json
        response = self.fetch('/',
                              method='POST',
                              body=json.dumps(request_lowstate),
                              headers={'Content-Type': self.content_type_map['json']})

        self.assertEqual(valid_lowstate, json.loads(response.body)['lowstate'])

        # send as yaml
        response = self.fetch('/',
                              method='POST',
                              body=yaml.dump(request_lowstate),
                              headers={'Content-Type': self.content_type_map['yaml']})
        self.assertEqual(valid_lowstate, json.loads(response.body)['lowstate'])

        # send as plain text
        response = self.fetch('/',
                              method='POST',
                              body=json.dumps(request_lowstate),
                              headers={'Content-Type': self.content_type_map['text']})
        self.assertEqual(valid_lowstate, json.loads(response.body)['lowstate'])

        # send as form-urlencoded
        request_form_lowstate = (
            ('client', 'local'),
            ('tgt', '*'),
            ('fun', 'test.fib'),
            ('arg', '10'),
        )

        response = self.fetch('/',
                              method='POST',
                              body=urlencode(request_form_lowstate),
                              headers={'Content-Type': self.content_type_map['form']})
        self.assertEqual(valid_lowstate, json.loads(response.body)['lowstate'])
Beispiel #54
0
    def test_deserialize(self):
        '''
        Send various encoded forms of lowstates (and bad ones) to make sure we
        handle deserialization correctly
        '''
        valid_lowstate = [{
                "client": "local",
                "tgt": "*",
                "fun": "test.fib",
                "arg": ["10"]
            },
            {
                "client": "runner",
                "fun": "jobs.lookup_jid",
                "jid": "20130603122505459265"
            }]

        # send as JSON
        response = self.fetch('/',
                              method='POST',
                              body=json.dumps(valid_lowstate),
                              headers={'Content-Type': self.content_type_map['json']})

        self.assertEqual(valid_lowstate, json.loads(response.body)['lowstate'])

        # send yaml as json (should break)
        response = self.fetch('/',
                              method='POST',
                              body=yaml.dump(valid_lowstate),
                              headers={'Content-Type': self.content_type_map['json']})
        self.assertEqual(response.code, 400)

        # send as yaml
        response = self.fetch('/',
                              method='POST',
                              body=yaml.dump(valid_lowstate),
                              headers={'Content-Type': self.content_type_map['yaml']})
        self.assertEqual(valid_lowstate, json.loads(response.body)['lowstate'])

        # send json as yaml (works since yaml is a superset of json)
        response = self.fetch('/',
                              method='POST',
                              body=json.dumps(valid_lowstate),
                              headers={'Content-Type': self.content_type_map['yaml']})
        self.assertEqual(valid_lowstate, json.loads(response.body)['lowstate'])

        # send json as text/plain
        response = self.fetch('/',
                              method='POST',
                              body=json.dumps(valid_lowstate),
                              headers={'Content-Type': self.content_type_map['text']})
        self.assertEqual(valid_lowstate, json.loads(response.body)['lowstate'])

        # send form-urlencoded
        form_lowstate = (
            ('client', 'local'),
            ('tgt', '*'),
            ('fun', 'test.fib'),
            ('arg', '10'),
            ('arg', 'foo'),
        )
        response = self.fetch('/',
                              method='POST',
                              body=urlencode(form_lowstate),
                              headers={'Content-Type': self.content_type_map['form']})
        returned_lowstate = json.loads(response.body)['lowstate']
        self.assertEqual(len(returned_lowstate), 1)
        returned_lowstate = returned_lowstate[0]

        self.assertEqual(returned_lowstate['client'], 'local')
        self.assertEqual(returned_lowstate['tgt'], '*')
        self.assertEqual(returned_lowstate['fun'], 'test.fib')
        self.assertEqual(returned_lowstate['arg'], ['10', 'foo'])