Skip to content

Commit c047089

Browse files
committed
Makes Authentication More Flexible
1 parent ae8cb0a commit c047089

6 files changed

Lines changed: 65 additions & 46 deletions

File tree

SoftLayer/API.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,6 @@ def call(self, service, method, *args, **kwargs):
146146

147147
headers = kwargs.get('headers', {})
148148

149-
if self.auth:
150-
headers.update(self.auth.get_headers())
151-
152149
if kwargs.get('id') is not None:
153150
headers[service + 'InitParameters'] = {'id': kwargs.get('id')}
154151

@@ -178,11 +175,18 @@ def call(self, service, method, *args, **kwargs):
178175
http_headers.update(kwargs.get('raw_headers'))
179176

180177
uri = '/'.join([self.endpoint_url, service])
178+
options = {
179+
'headers': headers,
180+
'http_headers': http_headers,
181+
'timeout': self.timeout,
182+
'proxy': self.proxy,
183+
}
184+
185+
if self.auth:
186+
options = self.auth.get_options(options)
187+
181188
return transports.make_xml_rpc_api_call(uri, method, args,
182-
headers=headers,
183-
http_headers=http_headers,
184-
timeout=self.timeout,
185-
proxy=self.proxy)
189+
**options)
186190

187191
__call__ = call
188192

@@ -326,6 +330,8 @@ def call(self, name, *args, **kwargs):
326330
:param int offset: (optional) offset results by this many
327331
:param boolean iter: (optional) if True, returns a generator with the
328332
results
333+
:param bool verify: verify SSL cert
334+
:param cert: client certificate path
329335
330336
Usage:
331337
>>> import SoftLayer

SoftLayer/auth.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010

1111
class AuthenticationBase(object):
1212
"""A base authentication class intended to be overridden."""
13-
def get_headers(self):
14-
"""Return a dictionary of headers to be inserted for authentication."""
13+
def get_options(self, options):
14+
"""Receives request options and returns request options."""
1515
raise NotImplementedError
1616

1717

@@ -26,15 +26,14 @@ def __init__(self, user_id, auth_token):
2626
self.user_id = user_id
2727
self.auth_token = auth_token
2828

29-
def get_headers(self):
30-
"""Returns token-based auth headers."""
31-
return {
32-
'authenticate': {
33-
'complexType': 'PortalLoginToken',
34-
'userId': self.user_id,
35-
'authToken': self.auth_token,
36-
}
29+
def get_options(self, options):
30+
"""Sets token-based auth headers."""
31+
options['headers']['authenticate'] = {
32+
'complexType': 'PortalLoginToken',
33+
'userId': self.user_id,
34+
'authToken': self.auth_token,
3735
}
36+
return options
3837

3938
def __repr__(self):
4039
return "<TokenAuthentication: %s %s>" % (self.user_id, self.auth_token)
@@ -50,14 +49,13 @@ def __init__(self, username, api_key):
5049
self.username = username
5150
self.api_key = api_key
5251

53-
def get_headers(self):
54-
"""Returns token-based auth headers."""
55-
return {
56-
'authenticate': {
57-
'username': self.username,
58-
'apiKey': self.api_key,
59-
}
52+
def get_options(self, options):
53+
"""Sets token-based auth headers."""
54+
options['headers']['authenticate'] = {
55+
'username': self.username,
56+
'apiKey': self.api_key,
6057
}
58+
return options
6159

6260
def __repr__(self):
6361
return "<BasicAuthentication: %s>" % (self.username)

SoftLayer/tests/api_tests.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ def test_init(self):
1717
client = SoftLayer.Client(username='doesnotexist',
1818
api_key='issurelywrong', timeout=10)
1919

20-
auth_headers = {'authenticate': {'username': 'doesnotexist',
21-
'apiKey': 'issurelywrong'}}
22-
self.assertEqual(client.auth.get_headers(), auth_headers)
20+
self.assertIsInstance(client.auth, SoftLayer.BasicAuthentication)
21+
self.assertEqual(client.auth.username, 'doesnotexist')
22+
self.assertEqual(client.auth.api_key, 'issurelywrong')
2323
self.assertEqual(client.endpoint_url,
2424
SoftLayer.API_PUBLIC_ENDPOINT.rstrip('/'))
2525
self.assertEqual(client.timeout, 10)

SoftLayer/tests/auth_tests.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99

1010

1111
class TestAuthenticationBase(testing.TestCase):
12-
def test_get_headers(self):
12+
def test_get_options(self):
1313
auth_base = auth.AuthenticationBase()
14-
self.assertRaises(NotImplementedError, auth_base.get_headers)
14+
self.assertRaises(NotImplementedError, auth_base.get_options, {})
1515

1616

1717
class TestBasicAuthentication(testing.TestCase):
@@ -22,11 +22,14 @@ def test_attribs(self):
2222
self.assertEqual(self.auth.username, 'USERNAME')
2323
self.assertEqual(self.auth.api_key, 'APIKEY')
2424

25-
def test_get_headers(self):
26-
self.assertEqual(self.auth.get_headers(), {
27-
'authenticate': {
28-
'username': 'USERNAME',
29-
'apiKey': 'APIKEY',
25+
def test_get_options(self):
26+
headers = {'headers': {}}
27+
self.assertEqual(self.auth.get_options(headers), {
28+
'headers': {
29+
'authenticate': {
30+
'username': 'USERNAME',
31+
'apiKey': 'APIKEY',
32+
}
3033
}
3134
})
3235

@@ -44,12 +47,15 @@ def test_attribs(self):
4447
self.assertEqual(self.auth.user_id, 12345)
4548
self.assertEqual(self.auth.auth_token, 'TOKEN')
4649

47-
def test_get_headers(self):
48-
self.assertEqual(self.auth.get_headers(), {
49-
'authenticate': {
50-
'complexType': 'PortalLoginToken',
51-
'userId': 12345,
52-
'authToken': 'TOKEN',
50+
def test_get_options(self):
51+
headers = {'headers': {}}
52+
self.assertEqual(self.auth.get_options(headers), {
53+
'headers': {
54+
'authenticate': {
55+
'complexType': 'PortalLoginToken',
56+
'userId': 12345,
57+
'authToken': 'TOKEN',
58+
}
5359
}
5460
})
5561

SoftLayer/tests/transport_tests.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ def test_call(self, request):
5656
headers=None,
5757
proxies=None,
5858
data=data,
59-
timeout=None)
59+
timeout=None,
60+
cert=None,
61+
verify=True)
6062
self.assertEqual(resp, [])
6163

6264
def test_proxy_without_protocol(self):
@@ -81,7 +83,9 @@ def test_valid_proxy(self, request):
8183
proxies={'https': 'http://localhost:3128',
8284
'http': 'http://localhost:3128'},
8385
data=mock.ANY,
84-
timeout=None)
86+
timeout=None,
87+
cert=None,
88+
verify=True)
8589

8690

8791
class TestRestAPICall(testing.TestCase):

SoftLayer/transports.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,18 @@ def _proxies_dict(proxy):
2323
return {'http': proxy, 'https': proxy}
2424

2525

26-
def make_xml_rpc_api_call(uri, method, args=None, headers=None,
27-
http_headers=None, timeout=None, proxy=None):
26+
def make_xml_rpc_api_call(url, method, args=None, headers=None,
27+
http_headers=None, timeout=None, proxy=None,
28+
verify=True, cert=None):
2829
"""Makes a SoftLayer API call against the XML-RPC endpoint.
2930
3031
:param string uri: endpoint URL
3132
:param string method: method to call E.G.: 'getObject'
3233
:param dict headers: XML-RPC headers to use for the request
3334
:param dict http_headers: HTTP headers to use for the request
3435
:param int timeout: number of seconds to use as a timeout
36+
:param bool verify: verify SSL cert
37+
:param cert: client certificate path
3538
"""
3639
if args is None:
3740
args = tuple()
@@ -43,14 +46,16 @@ def make_xml_rpc_api_call(uri, method, args=None, headers=None,
4346
methodname=method,
4447
allow_none=True)
4548
LOGGER.debug("=== REQUEST ===")
46-
LOGGER.info('POST %s', uri)
49+
LOGGER.info('POST %s', url)
4750
LOGGER.debug(http_headers)
4851
LOGGER.debug(payload)
4952

50-
response = requests.request('POST', uri,
53+
response = requests.request('POST', url,
5154
data=payload,
5255
headers=http_headers,
5356
timeout=timeout,
57+
verify=verify,
58+
cert=cert,
5459
proxies=_proxies_dict(proxy))
5560
LOGGER.debug("=== RESPONSE ===")
5661
LOGGER.debug(response.headers)

0 commit comments

Comments
 (0)