Skip to content

Commit

Permalink
Merge pull request boto#2720 from kyleknap/sts-anonymous
Browse files Browse the repository at this point in the history
Url encode query string for pure query
  • Loading branch information
kyleknap committed Oct 31, 2014
2 parents 3265cad + 1a51599 commit bbbf9d2
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 10 deletions.
7 changes: 5 additions & 2 deletions boto/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -773,8 +773,11 @@ class QueryAuthHandler(AuthHandler):
capability = ['pure-query']

def _escape_value(self, value):
# Would normally be ``return urllib.parse.quote(value)``.
return value
# This is changed from a previous version because this string is
# being passed to the query string and query strings must
# be url encoded. In particular STS requires the saml_response to
# be urlencoded when calling assume_role_with_saml.
return urllib.parse.quote(value)

def _build_query_string(self, params):
keys = list(params.keys())
Expand Down
5 changes: 3 additions & 2 deletions boto/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,7 @@ def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
is_secure=True, port=None, proxy=None, proxy_port=None,
proxy_user=None, proxy_pass=None, host=None, debug=0,
https_connection_factory=None, path='/', security_token=None,
validate_certs=True, profile_name=None):
validate_certs=True, profile_name=None, provider='aws'):
super(AWSQueryConnection, self).__init__(
host, aws_access_key_id,
aws_secret_access_key,
Expand All @@ -1093,7 +1093,8 @@ def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
debug, https_connection_factory, path,
security_token=security_token,
validate_certs=validate_certs,
profile_name=profile_name)
profile_name=profile_name,
provider=provider)

def _required_auth_capability(self):
return []
Expand Down
1 change: 1 addition & 0 deletions boto/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
STORAGE_DATA_ERROR = 'StorageDataError'
STORAGE_PERMISSIONS_ERROR = 'StoragePermissionsError'
STORAGE_RESPONSE_ERROR = 'StorageResponseError'
NO_CREDENTIALS_PROVIDED = object()


class ProfileNotFoundError(ValueError):
Expand Down
20 changes: 19 additions & 1 deletion boto/sts/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
# IN THE SOFTWARE.

from boto.connection import AWSQueryConnection
from boto.provider import Provider, NO_CREDENTIALS_PROVIDED
from boto.regioninfo import RegionInfo
from boto.sts.credentials import Credentials, FederationToken, AssumedRole
from boto.sts.credentials import DecodeAuthorizationMessage
Expand Down Expand Up @@ -71,13 +72,29 @@ def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
https_connection_factory=None, region=None, path='/',
converter=None, validate_certs=True, anon=False,
security_token=None, profile_name=None):
"""
:type anon: boolean
:param anon: If this parameter is True, the ``STSConnection`` object
will make anonymous requests, and it will not use AWS
Credentials or even search for AWS Credentials to make these
requests.
"""
if not region:
region = RegionInfo(self, self.DefaultRegionName,
self.DefaultRegionEndpoint,
connection_cls=STSConnection)
self.region = region
self.anon = anon
self._mutex = threading.Semaphore()
provider = 'aws'
# If an anonymous request is sent, do not try to look for credentials.
# So we pass in dummy values for the access key id, secret access
# key, and session token. It does not matter that they are
# not actual values because the request is anonymous.
if self.anon:
provider = Provider('aws', NO_CREDENTIALS_PROVIDED,
NO_CREDENTIALS_PROVIDED,
NO_CREDENTIALS_PROVIDED)
super(STSConnection, self).__init__(aws_access_key_id,
aws_secret_access_key,
is_secure, port, proxy, proxy_port,
Expand All @@ -86,7 +103,8 @@ def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
https_connection_factory, path,
validate_certs=validate_certs,
security_token=security_token,
profile_name=profile_name)
profile_name=profile_name,
provider=provider)

def _required_auth_capability(self):
if self.anon:
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/sts/test_session_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,4 @@ def test_decode_authorization_message(self):
creds = c.decode_authorization_message('b94d27b9934')
except BotoServerError as err:
self.assertEqual(err.status, 400)
self.assertTrue('Invalid token' in err.body)
self.assertIn('InvalidAuthorizationMessageException', err.body)
10 changes: 6 additions & 4 deletions tests/unit/auth/test_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,19 @@ def setUp(self):
def test_escape_value(self):
auth = QueryAuthHandler('sts.amazonaws.com',
Mock(), self.provider)
# This should **NOT** get escaped.
# This is changed from a previous version because this string is
# being passed to the query string and query strings must
# be url encoded.
value = auth._escape_value('Atza|IQEBLjAsAhRkcxQ')
self.assertEqual(value, 'Atza|IQEBLjAsAhRkcxQ')
self.assertEqual(value, 'Atza%7CIQEBLjAsAhRkcxQ')

def test_build_query_string(self):
auth = QueryAuthHandler('sts.amazonaws.com',
Mock(), self.provider)
query_string = auth._build_query_string(self.request.params)
self.assertEqual(query_string, 'Action=AssumeRoleWithWebIdentity' + \
'&ProviderId=2012-06-01&RoleSessionName=web-identity-federation' + \
'&Version=2011-06-15&WebIdentityToken=Atza|IQEBLjAsAhRkcxQ')
'&Version=2011-06-15&WebIdentityToken=Atza%7CIQEBLjAsAhRkcxQ')

def test_add_auth(self):
auth = QueryAuthHandler('sts.amazonaws.com',
Expand All @@ -73,4 +75,4 @@ def test_add_auth(self):
self.assertEqual(req.path,
'/?Action=AssumeRoleWithWebIdentity' + \
'&ProviderId=2012-06-01&RoleSessionName=web-identity-federation' + \
'&Version=2011-06-15&WebIdentityToken=Atza|IQEBLjAsAhRkcxQ')
'&Version=2011-06-15&WebIdentityToken=Atza%7CIQEBLjAsAhRkcxQ')
11 changes: 11 additions & 0 deletions tests/unit/provider/test_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ def test_environment_variable_aws_security_token(self):
self.assertEqual(p.secret_key, 'env_secret_key')
self.assertEqual(p.security_token, 'env_security_token')

def test_no_credentials_provided(self):
p = provider.Provider(
'aws',
provider.NO_CREDENTIALS_PROVIDED,
provider.NO_CREDENTIALS_PROVIDED,
provider.NO_CREDENTIALS_PROVIDED
)
self.assertEqual(p.access_key, provider.NO_CREDENTIALS_PROVIDED)
self.assertEqual(p.secret_key, provider.NO_CREDENTIALS_PROVIDED)
self.assertEqual(p.security_token, provider.NO_CREDENTIALS_PROVIDED)

def test_config_profile_values_are_used(self):
self.config = {
'profile dev': {
Expand Down

0 comments on commit bbbf9d2

Please sign in to comment.