Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit 2b3b14a

Browse files
committed
Add option for client to authenticate with IAM token server.
1 parent 827f646 commit 2b3b14a

File tree

4 files changed

+55
-7
lines changed

4 files changed

+55
-7
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# UNRELEASED
2+
3+
- [NEW] Added option for client to authenticate with IAM token server.
4+
15
# 2.10.2 (2018-12-19)
26

37
- [FIXED] A performance regression deserializing JSON in version 2.10.1.

src/cloudant/_client_session.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python
2-
# Copyright (C) 2015, 2018 IBM Corp. All rights reserved.
2+
# Copyright (c) 2015, 2019 IBM Corp. All rights reserved.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -189,14 +189,18 @@ class IAMSession(ClientSession):
189189
This class extends ClientSession and provides IAM authentication.
190190
"""
191191

192-
def __init__(self, api_key, server_url, **kwargs):
192+
def __init__(self, api_key, server_url, client_id=None, client_secret=None,
193+
**kwargs):
193194
super(IAMSession, self).__init__(
194195
session_url=url_join(server_url, '_iam_session'),
195196
**kwargs)
196197

197198
self._api_key = api_key
198199
self._token_url = os.environ.get(
199200
'IAM_TOKEN_URL', 'https://iam.bluemix.net/identity/token')
201+
self._token_auth = None
202+
if client_id and client_secret:
203+
self._token_auth = (client_id, client_secret)
200204

201205
@property
202206
def get_api_key(self):
@@ -277,7 +281,7 @@ def _get_access_token(self):
277281
resp = super(IAMSession, self).request(
278282
'POST',
279283
self._token_url,
280-
auth=('bx', 'bx'), # required for user API keys
284+
auth=self._token_auth,
281285
headers={'Accepts': 'application/json'},
282286
data={
283287
'grant_type': 'urn:ibm:params:oauth:grant-type:apikey',

src/cloudant/client.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python
2-
# Copyright (C) 2015, 2018 IBM Corp. All rights reserved.
2+
# Copyright (c) 2015, 2019 IBM Corp. All rights reserved.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -78,6 +78,10 @@ class CouchDB(dict):
7878
IAM authentication with server. Default is False.
7979
Use :func:`~cloudant.client.CouchDB.iam` to construct an IAM
8080
authenticated client.
81+
:param string iam_client_id: Keyword argument, client ID to use when
82+
authenticating with the IAM token server. Default is ``None``.
83+
:param string iam_client_secret: Keyword argument, client secret to use when
84+
authenticating with the IAM token server. Default is ``None``.
8185
"""
8286
_DATABASE_CLASS = CouchDatabase
8387

@@ -95,6 +99,8 @@ def __init__(self, user, auth_token, admin_party=False, **kwargs):
9599
self._auto_renew = kwargs.get('auto_renew', False)
96100
self._use_basic_auth = kwargs.get('use_basic_auth', False)
97101
self._use_iam = kwargs.get('use_iam', False)
102+
self._iam_client_id = kwargs.get('iam_client_id', None)
103+
self._iam_client_secret = kwargs.get('iam_client_secret', None)
98104
# If user/pass exist in URL, remove and set variables
99105
if not self._use_basic_auth and self.server_url:
100106
parsed_url = url_parse(kwargs.get('url'))
@@ -162,6 +168,8 @@ def connect(self):
162168
self._auth_token,
163169
self.server_url,
164170
auto_renew=self._auto_renew,
171+
client_id=self._iam_client_id,
172+
client_secret=self._iam_client_secret,
165173
timeout=self._timeout
166174
)
167175
else:
@@ -844,7 +852,8 @@ def bluemix(cls, vcap_services, instance_name=None, service_name=None, **kwargs)
844852
if hasattr(service, 'iam_api_key'):
845853
return Cloudant.iam(service.username,
846854
service.iam_api_key,
847-
url=service.url)
855+
url=service.url,
856+
**kwargs)
848857
return Cloudant(service.username,
849858
service.password,
850859
url=service.url,

tests/unit/iam_auth_tests.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python
2-
# Copyright (c) 2017 IBM. All rights reserved.
2+
# Copyright (c) 2017, 2019 IBM. All rights reserved.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -108,7 +108,38 @@ def test_iam_get_access_token(self, m_req):
108108
m_req.assert_called_once_with(
109109
'POST',
110110
iam._token_url,
111-
auth=('bx', 'bx'),
111+
auth=None,
112+
headers={'Accepts': 'application/json'},
113+
data={
114+
'grant_type': 'urn:ibm:params:oauth:grant-type:apikey',
115+
'response_type': 'cloud_iam',
116+
'apikey': MOCK_API_KEY
117+
}
118+
)
119+
120+
self.assertEqual(access_token, MOCK_ACCESS_TOKEN)
121+
self.assertTrue(m_response.raise_for_status.called)
122+
mock_token_response_text.assert_called_with()
123+
124+
@mock.patch('cloudant._client_session.ClientSession.request')
125+
def test_iam_get_access_token_with_iam_client_id_and_secret(self, m_req):
126+
m_response = mock.MagicMock()
127+
mock_token_response_text = mock.PropertyMock(return_value=MOCK_IAM_TOKEN_RESPONSE)
128+
type(m_response).text = mock_token_response_text
129+
m_req.return_value = m_response
130+
131+
iam_client_id = 'foo'
132+
iam_client_secret = 'bar'
133+
134+
iam = IAMSession(MOCK_API_KEY, 'http://127.0.0.1:5984',
135+
client_id=iam_client_id,
136+
client_secret=iam_client_secret)
137+
access_token = iam._get_access_token()
138+
139+
m_req.assert_called_once_with(
140+
'POST',
141+
iam._token_url,
142+
auth=(iam_client_id, iam_client_secret),
112143
headers={'Accepts': 'application/json'},
113144
data={
114145
'grant_type': 'urn:ibm:params:oauth:grant-type:apikey',

0 commit comments

Comments
 (0)