Skip to content

Commit

Permalink
fix(VR3): Authentication using apikey is deprecated
Browse files Browse the repository at this point in the history
  • Loading branch information
ehdsouza committed Oct 10, 2018
1 parent 2c06e48 commit 58c9552
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 72 deletions.
Binary file modified .env.enc
Binary file not shown.
18 changes: 0 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ Python client library to quickly get started with the various [Watson APIs][wdc]
* [Getting credentials](#getting-credentials)
* [IAM](#iam)
* [Username and password](#username-and-password)
* [API key](#api-key)
* [Python version](#python-version)
* [Changes for v1.0](#changes-for-v10)
* [Changes for v2.0](#changes-for-v20)
Expand Down Expand Up @@ -83,7 +82,6 @@ Watson services are migrating to token-based Identity and Access Management (IAM

- With some service instances, you authenticate to the API by using **[IAM](#iam)**.
- In other instances, you authenticate by providing the **[username and password](#username-and-password)** for the service instance.
- Visual Recognition uses a form of [API key](#api-key) only with instances created before May 23, 2018. Newer instances of Visual Recognition use IAM.

**Note:** Authenticating with the X-Watson-Authorization-Token header is deprecated. The token continues to work with Cloud Foundry services, but is not supported for services that use Identity and Access Management (IAM) authentication. See [here](#iam) for details.

Expand Down Expand Up @@ -146,22 +144,6 @@ discovery = DiscoveryV1(version='2018-08-01', url='<url_as_per_region>')
discovery.set_username_and_password('<username>', '<password>')
```

### API key

**Important**: This type of authentication works only with Visual Recognition instances created before May 23, 2018. Newer instances of Visual Recognition use [IAM](#iam).

```python
from watson_developer_cloud import VisualRecognitionV3
# In the constructor
visual_recognition = VisualRecognitionV3(version='2018-03-19', url='<url_as_per_region>', api_key='<api_key>')
```

```python
# After instantiation
visual_recognition = VisualRecognitionV3(version='2018-03-19')
visual_recognition.set_api_key('<api_key>')
```

## Python version

Tested on Python 2.7, 3.4, 3.5, and 3.6.
Expand Down
17 changes: 6 additions & 11 deletions examples/visual_recognition_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,12 @@
test_url = 'https://www.ibm.com/ibm/ginni/images' \
'/ginni_bio_780x981_v4_03162016.jpg'

# # If service instance provides IAM API key authentication
# service = VisualRecognitionV3(
# '2018-03-19',
# ## url is optional, and defaults to the URL below. Use the correct URL for your region.
# url='https://gateway.watsonplatform.net/visual-recognition/api',
# iam_apikey='iam_apikey')

service = VisualRecognitionV3('2018-03-19',
## url is optional, and defaults to the URL below. Use the correct URL for your region.
# url='https://gateway.watsonplatform.net/visual-recognition/api',
api_key='YOUR API KEY')
# If service instance provides IAM API key authentication
service = VisualRecognitionV3(
'2018-03-19',
## url is optional, and defaults to the URL below. Use the correct URL for your region.
url='https://gateway.watsonplatform.net/visual-recognition/api',
iam_apikey='iam_apikey')

# with open(abspath('resources/cars.zip'), 'rb') as cars, \
# open(abspath('resources/trucks.zip'), 'rb') as trucks:
Expand Down
6 changes: 3 additions & 3 deletions test/integration/test_visual_recognition.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ class IntegrationTestVisualRecognitionV3(TestCase):
@classmethod
def setup_class(cls):
cls.visual_recognition = watson_developer_cloud.VisualRecognitionV3(
'2018-03-19', api_key='YOUR API KEY')
'2018-03-19', iam_apikey='YOUR IAM API KEY')
cls.visual_recognition.set_default_headers({
'X-Watson-Learning-Opt-Out':
'1',
'X-Watson-Test':
'1'
})
cls.classifier_id = 'doxnotxdeletexintegrationxtest_397877192'
cls.classifier_id = 'sdkxtestxclassifierxdoxnotxdel_1089651138'

def test_classify(self):
dog_path = abspath('resources/dog.jpg')
Expand All @@ -37,7 +37,7 @@ def test_detect_faces(self):
url='https://www.ibm.com/ibm/ginni/images/ginni_bio_780x981_v4_03162016.jpg').get_result()
assert output is not None

# @pytest.mark.skip(reason="Time consuming")
@pytest.mark.skip(reason="Time consuming")
def test_custom_classifier(self):
with open(abspath('resources/cars.zip'), 'rb') as cars, \
open(abspath('resources/trucks.zip'), 'rb') as trucks:
Expand Down
68 changes: 40 additions & 28 deletions test/unit/test_visual_recognition_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,21 @@
base_url = "https://gateway-a.watsonplatform.net/visual-recognition/api/"

class TestVisualRecognitionV3(TestCase):
@classmethod
def setUp(cls):
iam_url = "https://iam.bluemix.net/identity/token"
iam_token_response = """{
"access_token": "oAeisG8yqPY7sFR_x66Z15",
"token_type": "Bearer",
"expires_in": 3600,
"expiration": 1524167011,
"refresh_token": "jy4gl91BQ"
}"""
responses.add(responses.POST, url=iam_url, body=iam_token_response, status=200)

@responses.activate
def test_get_classifier(self):
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', api_key='bogusapikey')
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', iam_apikey='bogusapikey')

gc_url = "{0}{1}".format(base_url, 'v3/classifiers/bogusnumber')

Expand All @@ -31,11 +43,11 @@ def test_get_classifier(self):
content_type='application/json')
vr_service.get_classifier(classifier_id='bogusnumber')

assert len(responses.calls) == 1
assert len(responses.calls) == 2

@responses.activate
def test_delete_classifier(self):
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', api_key='bogusapikey')
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', iam_apikey='bogusapikey')

gc_url = "{0}{1}".format(base_url, 'v3/classifiers/bogusnumber')

Expand All @@ -46,11 +58,11 @@ def test_delete_classifier(self):
content_type='application/json')
vr_service.delete_classifier(classifier_id='bogusnumber')

assert len(responses.calls) == 1
assert len(responses.calls) == 2

@responses.activate
def test_list_classifiers(self):
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', api_key='bogusapikey')
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', iam_apikey='bogusapikey')

gc_url = "{0}{1}".format(base_url, 'v3/classifiers')

Expand All @@ -74,11 +86,11 @@ def test_list_classifiers(self):
content_type='application/json')
vr_service.list_classifiers()

assert len(responses.calls) == 1
assert len(responses.calls) == 2

@responses.activate
def test_create_classifier(self):
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', api_key='bogusapikey')
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', iam_apikey='bogusapikey')

gc_url = "{0}{1}".format(base_url, 'v3/classifiers')

Expand All @@ -101,11 +113,11 @@ def test_create_classifier(self):
open(os.path.join(os.path.dirname(__file__), '../../resources/trucks.zip'), 'rb') as trucks:
vr_service.create_classifier('Cars vs Trucks', cars_positive_examples=cars, negative_examples=trucks)

assert len(responses.calls) == 1
assert len(responses.calls) == 2

@responses.activate
def test_update_classifier(self):
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', api_key='bogusapikey')
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', iam_apikey='bogusapikey')

gc_url = "{0}{1}".format(base_url, 'v3/classifiers/bogusid')

Expand All @@ -129,11 +141,11 @@ def test_update_classifier(self):
content_type='application/json')

vr_service.update_classifier(classifier_id="bogusid")
assert len(responses.calls) == 1
assert len(responses.calls) == 2

@responses.activate
def test_classify(self):
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', api_key='bogusapikey')
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', iam_apikey='bogusapikey')

gc_url = "{0}{1}".format(base_url, 'v3/classify')

Expand Down Expand Up @@ -175,11 +187,11 @@ def test_classify(self):

with open(os.path.join(os.path.dirname(__file__), '../../resources/test.jpg'), 'rb') as image_file:
vr_service.classify(images_file=image_file)
assert len(responses.calls) == 4
assert len(responses.calls) == 8

@responses.activate
def test_detect_faces(self):
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', api_key='bogusapikey')
vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', iam_apikey='bogusapikey')

gc_url = "{0}{1}".format(base_url, 'v3/detect_faces')

Expand Down Expand Up @@ -232,19 +244,19 @@ def test_detect_faces(self):
vr_service.detect_faces(parameters='{"url": "http://google.com"}')
with open(os.path.join(os.path.dirname(__file__), '../../resources/test.jpg'), 'rb') as image_file:
vr_service.detect_faces(images_file=image_file)
assert len(responses.calls) == 2
assert len(responses.calls) == 4

@responses.activate
def test_delete_user_data():
url = "{0}{1}".format(base_url, 'v3/user_data')
responses.add(
responses.DELETE,
url,
body='{"description": "success" }',
status=204,
content_type='application_json')

vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', api_key='bogusapikey')
response = vr_service.delete_user_data('id').get_result()
assert response is None
assert len(responses.calls) == 1
@responses.activate
def test_delete_user_data(self):
url = "{0}{1}".format(base_url, 'v3/user_data')
responses.add(
responses.DELETE,
url,
body='{"description": "success" }',
status=204,
content_type='application_json')

vr_service = watson_developer_cloud.VisualRecognitionV3('2016-10-20', iam_apikey='bogusapikey')
response = vr_service.delete_user_data('id').get_result()
assert response is None
assert len(responses.calls) == 2
21 changes: 9 additions & 12 deletions watson_developer_cloud/watson_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
AUTH_HEADER_DEPRECATION_MESSAGE = 'Authenticating with the X-Watson-Authorization-Token header is deprecated. The token continues to work with Cloud Foundry services, but is not supported for services that use Identity and Access Management (IAM) authentication.'
ICP_PREFIX = 'icp-'
APIKEY = 'apikey'
APIKEY_DEPRECATION_MESSAGE = 'Authenticating with apikey is deprecated. Move to using Identity and Access Management (IAM) authentication.'

# Uncomment this to enable http debugging
# try:
Expand Down Expand Up @@ -258,19 +259,13 @@ def __init__(self, vcap_services_name, url, username=None, password=None,
self.vcap_service_credentials, dict):
self.url = self.vcap_service_credentials['url']
if 'username' in self.vcap_service_credentials:
self.username = self.vcap_service_credentials['username']
self.username = self.vcap_service_credentials.get('username')
if 'password' in self.vcap_service_credentials:
self.password = self.vcap_service_credentials['password']
if 'apikey' in self.vcap_service_credentials:
self.api_key = self.vcap_service_credentials['apikey']
if 'api_key' in self.vcap_service_credentials:
self.api_key = self.vcap_service_credentials['api_key']
if ('iam_apikey' or 'apikey') in self.vcap_service_credentials:
self.iam_apikey = self.vcap_service_credentials.get('iam_apikey') or self.vcap_service_credentials.get('apikey')
self.password = self.vcap_service_credentials.get('password')
if 'iam_apikey' in self.vcap_service_credentials:
self.set_iam_apikey(self.vcap_service_credentials.get('iam_apikey'))
if 'iam_access_token' in self.vcap_service_credentials:
self.iam_access_token = self.vcap_service_credentials['iam_access_token']
if 'iam_url' in self.vcap_service_credentials:
self.iam_url = self.vcap_service_credentials['iam_url']
self.set_iam_access_token(self.vcap_service_credentials.get('iam_access_token'))

if (self.username is None or self.password is None)\
and self.api_key is None and self.token_manager is None:
Expand All @@ -289,6 +284,8 @@ def set_username_and_password(self, username=None, password=None):
self.jar = CookieJar()

def set_api_key(self, api_key):
if api_key is not None:
warnings.warn(APIKEY_DEPRECATION_MESSAGE)
if api_key == 'YOUR API KEY':
api_key = None
if api_key is not None and api_key.startswith(ICP_PREFIX):
Expand All @@ -304,7 +301,7 @@ def set_api_key(self, api_key):

def set_token_manager(self, iam_apikey=None, iam_access_token=None, iam_url=None):
if iam_apikey == 'YOUR IAM API KEY':
iam_apikey = None
return

self.iam_apikey = iam_apikey
self.iam_access_token = iam_access_token
Expand Down

0 comments on commit 58c9552

Please sign in to comment.