Skip to content

Commit 1be97e5

Browse files
authored
feat(MCSPAuthenticator): add new authenticator for Multi-Cloud Saas Platform (#181)
This commit introduces the new MCSPAuthenticator that can be used to exchange an apikey for an MCSP access token using the Multi-Cloud Saas Platform authentication token server's 'POST /siusermgr/api/1.0/apikeys/token' operation. Signed-off-by: Phil Adams <[email protected]>
1 parent e105a8b commit 1be97e5

19 files changed

+681
-21
lines changed

.secrets.baseline

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"files": "package-lock.json|^.secrets.baseline$",
44
"lines": null
55
},
6-
"generated_at": "2023-03-23T17:37:09Z",
6+
"generated_at": "2023-11-10T17:28:14Z",
77
"plugins_used": [
88
{
99
"name": "AWSKeyDetector"
@@ -70,23 +70,23 @@
7070
"hashed_secret": "91dfd9ddb4198affc5c194cd8ce6d338fde470e2",
7171
"is_secret": false,
7272
"is_verified": false,
73-
"line_number": 64,
73+
"line_number": 65,
7474
"type": "Secret Keyword",
7575
"verified_result": null
7676
},
7777
{
7878
"hashed_secret": "98635b2eaa2379f28cd6d72a38299f286b81b459",
7979
"is_secret": false,
8080
"is_verified": false,
81-
"line_number": 385,
81+
"line_number": 387,
8282
"type": "Secret Keyword",
8383
"verified_result": null
8484
},
8585
{
8686
"hashed_secret": "47fcf185ee7e15fe05cae31fbe9e4ebe4a06a40d",
8787
"is_secret": false,
8888
"is_verified": false,
89-
"line_number": 416,
89+
"line_number": 482,
9090
"type": "Secret Keyword",
9191
"verified_result": null
9292
}
@@ -161,6 +161,16 @@
161161
"verified_result": null
162162
}
163163
],
164+
"resources/ibm-credentials-mcsp.env": [
165+
{
166+
"hashed_secret": "f2e7745f43b0ef0e2c2faf61d6c6a28be2965750",
167+
"is_secret": false,
168+
"is_verified": false,
169+
"line_number": 2,
170+
"type": "Secret Keyword",
171+
"verified_result": null
172+
}
173+
],
164174
"resources/ibm-credentials-retry.env": [
165175
{
166176
"hashed_secret": "ce49dd46e23153d6593eccd68534b9f1465d5bbd",
@@ -341,28 +351,80 @@
341351
"verified_result": null
342352
}
343353
],
354+
"test/test_mcsp_authenticator.py": [
355+
{
356+
"hashed_secret": "da2f27d2c57a0e1ed2dc3a34b4ef02faf2f7a4c2",
357+
"is_secret": false,
358+
"is_verified": false,
359+
"line_number": 91,
360+
"type": "Hex High Entropy String",
361+
"verified_result": null
362+
},
363+
{
364+
"hashed_secret": "f2e7745f43b0ef0e2c2faf61d6c6a28be2965750",
365+
"is_secret": false,
366+
"is_verified": false,
367+
"line_number": 147,
368+
"type": "Secret Keyword",
369+
"verified_result": null
370+
}
371+
],
372+
"test/test_mcsp_token_manager.py": [
373+
{
374+
"hashed_secret": "da2f27d2c57a0e1ed2dc3a34b4ef02faf2f7a4c2",
375+
"is_secret": false,
376+
"is_verified": false,
377+
"line_number": 30,
378+
"type": "Hex High Entropy String",
379+
"verified_result": null
380+
},
381+
{
382+
"hashed_secret": "f2e7745f43b0ef0e2c2faf61d6c6a28be2965750",
383+
"is_secret": false,
384+
"is_verified": false,
385+
"line_number": 43,
386+
"type": "Secret Keyword",
387+
"verified_result": null
388+
},
389+
{
390+
"hashed_secret": "ace1a5bf229c3af3f699369c6f2fa1a628692ab8",
391+
"is_secret": false,
392+
"is_verified": false,
393+
"line_number": 60,
394+
"type": "Secret Keyword",
395+
"verified_result": null
396+
}
397+
],
344398
"test/test_utils.py": [
345399
{
346400
"hashed_secret": "34a0a47a51d5bf739df0214450385e29ee7e9847",
347401
"is_secret": false,
348402
"is_verified": false,
349-
"line_number": 423,
403+
"line_number": 435,
404+
"type": "Secret Keyword",
405+
"verified_result": null
406+
},
407+
{
408+
"hashed_secret": "f2e7745f43b0ef0e2c2faf61d6c6a28be2965750",
409+
"is_secret": false,
410+
"is_verified": false,
411+
"line_number": 446,
350412
"type": "Secret Keyword",
351413
"verified_result": null
352414
},
353415
{
354416
"hashed_secret": "2863fa4b5510c46afc2bd2998dfbc0cf3d6df032",
355417
"is_secret": false,
356418
"is_verified": false,
357-
"line_number": 503,
419+
"line_number": 528,
358420
"type": "Secret Keyword",
359421
"verified_result": null
360422
},
361423
{
362424
"hashed_secret": "b9cad336062c0dc3bb30145b1a6697fccfe755a6",
363425
"is_secret": false,
364426
"is_verified": false,
365-
"line_number": 564,
427+
"line_number": 589,
366428
"type": "Secret Keyword",
367429
"verified_result": null
368430
}
@@ -378,7 +440,7 @@
378440
}
379441
]
380442
},
381-
"version": "0.13.1+ibm.57.dss",
443+
"version": "0.13.1+ibm.61.dss",
382444
"word_list": {
383445
"file": null,
384446
"hash": null

Authentication.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The python-sdk-core project supports the following types of authentication:
66
- Container Authentication
77
- VPC Instance Authentication
88
- Cloud Pak for Data Authentication
9+
- Multi-Cloud Saas Platform (MCSP) Authentication
910
- No Authentication (for testing)
1011

1112
The SDK user configures the appropriate type of authentication for use with service instances.
@@ -427,6 +428,71 @@ service = ExampleServiceV1.new_instance(service_name='example_service')
427428
# 'service' can now be used to invoke operations.
428429
```
429430

431+
432+
## Multi-Cloud Saas Platform (MCSP) Authentication
433+
The `MCSPAuthenticator` can be used in scenarios where an application needs to
434+
interact with an IBM Cloud service that has been deployed to a non-IBM Cloud environment (e.g. AWS).
435+
It accepts a user-supplied apikey and performs the necessary interactions with the
436+
Multi-Cloud Saas Platform token service to obtain a suitable MCSP access token (a bearer token)
437+
for the specified apikey.
438+
The authenticator will also obtain a new bearer token when the current token expires.
439+
The bearer token is then added to each outbound request in the `Authorization` header in the
440+
form:
441+
```
442+
Authorization: Bearer <bearer-token>
443+
```
444+
445+
### Properties
446+
447+
- apikey: (required) the apikey to be used to obtain an MCSP access token.
448+
449+
- url: (required) The URL representing the MCSP token service endpoint's base URL string. Do not include the
450+
operation path (e.g. `/siusermgr/api/1.0/apikeys/token`) as part of this property's value.
451+
452+
- disable_ssl_verification: (optional) A flag that indicates whether verificaton of the server's SSL
453+
certificate should be disabled or not. The default value is `false`.
454+
455+
- headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
456+
made to the MCSP token service.
457+
458+
### Usage Notes
459+
- When constructing an MCSPAuthenticator instance, you must specify the apikey and url properties.
460+
461+
- The authenticator will use the token server's `POST /siusermgr/api/1.0/apikeys/token` operation to
462+
exchange the user-supplied apikey for an MCSP access token (the bearer token).
463+
464+
### Programming example
465+
```python
466+
from ibm_cloud_sdk_core.authenticators import MCSPAuthenticator
467+
from <sdk-package-name>.example_service_v1 import *
468+
469+
# Create the authenticator.
470+
authenticator = MCSPAuthenticator(apikey='myapikey', url='https://example.mcsp.token-exchange.com')
471+
472+
# Construct the service instance.
473+
service = ExampleServiceV1(authenticator=authenticator)
474+
475+
# 'service' can now be used to invoke operations.
476+
```
477+
478+
### Configuration example
479+
External configuration:
480+
```
481+
export EXAMPLE_SERVICE_AUTH_TYPE=mcsp
482+
export EXAMPLE_SERVICE_APIKEY=myapikey
483+
export EXAMPLE_SERVICE_AUTH_URL=https://example.mcsp.token-exchange.com
484+
```
485+
Application code:
486+
```python
487+
from <sdk-package-name>.example_service_v1 import *
488+
489+
# Construct the service instance.
490+
service = ExampleServiceV1.new_instance(service_name='example_service')
491+
492+
# 'service' can now be used to invoke operations.
493+
```
494+
495+
430496
## No Auth Authentication
431497
The `NoAuthAuthenticator` is a placeholder authenticator which performs no actual authentication function.
432498
It can be used in situations where authentication needs to be bypassed, perhaps while developing

Makefile

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,33 @@
22
# to be ready for development work in the local sandbox.
33
# example: "make setup"
44

5+
PYTHON=python3
6+
LINT_DIRS=ibm_cloud_sdk_core test test_integration
7+
58
setup: deps dev_deps install_project
69

710
all: upgrade_pip setup test-unit lint
811

912
ci: setup test-unit lint
1013

1114
upgrade_pip:
12-
python -m pip install --upgrade pip
15+
${PYTHON} -m pip install --upgrade pip
1316

1417
deps:
15-
python -m pip install -r requirements.txt
18+
${PYTHON} -m pip install -r requirements.txt
1619

1720
dev_deps:
18-
python -m pip install -r requirements-dev.txt
21+
${PYTHON} -m pip install -r requirements-dev.txt
1922

2023
install_project:
21-
python -m pip install -e .
24+
${PYTHON} -m pip install -e .
2225

2326
test-unit:
24-
python -m pytest --cov=ibm_cloud_sdk_core test
27+
${PYTHON} -m pytest --cov=ibm_cloud_sdk_core test
2528

2629
lint:
27-
./pylint.sh && black --check .
30+
${PYTHON} -m pylint ${LINT_DIRS}
31+
black --check ${LINT_DIRS}
2832

2933
lint-fix:
30-
black .
34+
black ${LINT_DIRS}

ibm_cloud_sdk_core/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
from .token_managers.cp4d_token_manager import CP4DTokenManager
4444
from .token_managers.container_token_manager import ContainerTokenManager
4545
from .token_managers.vpc_instance_token_manager import VPCInstanceTokenManager
46+
from .token_managers.mcsp_token_manager import MCSPTokenManager
4647
from .api_exception import ApiException
4748
from .utils import datetime_to_string, string_to_datetime, read_external_sources
4849
from .utils import datetime_to_string_list, string_to_datetime_list

ibm_cloud_sdk_core/authenticators/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,4 @@
4141
from .iam_authenticator import IAMAuthenticator
4242
from .vpc_instance_authenticator import VPCInstanceAuthenticator
4343
from .no_auth_authenticator import NoAuthAuthenticator
44+
from .mcsp_authenticator import MCSPAuthenticator

ibm_cloud_sdk_core/authenticators/authenticator.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# coding: utf-8
22

3-
# Copyright 2019 IBM All Rights Reserved.
3+
# Copyright 2019, 2023 IBM All Rights Reserved.
44
#
55
# Licensed under the Apache License, Version 2.0 (the "License");
66
# you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ class Authenticator(ABC):
2828
AUTHTYPE_CP4D = 'cp4d'
2929
AUTHTYPE_VPC = 'vpc'
3030
AUTHTYPE_NOAUTH = 'noAuth'
31+
AUTHTYPE_MCSP = 'mcsp'
3132
AUTHTYPE_UNKNOWN = 'unknown'
3233

3334
@abstractmethod

ibm_cloud_sdk_core/authenticators/basic_authenticator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def authenticate(self, req: Request) -> None:
7676
Authorization: Basic <encoded username and password>
7777
7878
Args:
79-
req: The request to add basic auth information too. Must contain a key to a dictionary
79+
req: The request to add basic auth information to. Must contain a key to a dictionary
8080
called headers.
8181
"""
8282
headers = req.get('headers')

ibm_cloud_sdk_core/authenticators/bearer_token_authenticator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def authenticate(self, req: Request) -> None:
6161
Authorization: Bearer <bearer-token>
6262
6363
Args:
64-
req: The request to add bearer authentication information too. Must contain a key to a dictionary
64+
req: The request to add bearer authentication information to. Must contain a key to a dictionary
6565
called headers.
6666
"""
6767
headers = req.get('headers')

ibm_cloud_sdk_core/authenticators/cp4d_authenticator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def authenticate(self, req: Request) -> None:
127127
Authorization: Bearer <bearer-token>
128128
129129
Args:
130-
req: The request to add CP4D authentication information too. Must contain a key to a dictionary
130+
req: The request to add CP4D authentication information to. Must contain a key to a dictionary
131131
called headers.
132132
"""
133133
headers = req.get('headers')

ibm_cloud_sdk_core/authenticators/iam_request_based_authenticator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def authenticate(self, req: Request) -> None:
5454
Authorization: Bearer <bearer-token>
5555
5656
Args:
57-
req: The request to add IAM authentication information too. Must contain a key to a dictionary
57+
req: The request to add IAM authentication information to. Must contain a key to a dictionary
5858
called headers.
5959
"""
6060
headers = req.get('headers')

0 commit comments

Comments
 (0)