mirror of
https://github.com/vmware/vsphere-automation-sdk-python.git
synced 2024-11-24 18:30:00 -05:00
commit
a7813fdca8
@ -21,7 +21,7 @@ samples require the vSphere Management SDK packages (pyVmomi) to be installed on
|
||||
The samples have been developed to work with python 2.7.x and 3.3+
|
||||
|
||||
## Supported OnPrem vCenter Releases
|
||||
vCenter 6.0, 6.5, 6.7 and 7.0.
|
||||
vCenter 6.0, 6.5, 6.7, 7.0 and 7.0U1.
|
||||
Certain APIs and samples that are introduced in 6.5 release, such as vCenter, Virtual Machine and Appliance Management. Please refer to the notes in each sample for detailed compatibility information.
|
||||
|
||||
## Supported NSX-T Releases
|
||||
@ -214,8 +214,8 @@ $ python samples/vsphere/vcenter/vm/list_vms.py -v
|
||||
### vSphere API Documentation
|
||||
|
||||
* [VMware Cloud on AWS vSphere (latest version)](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/cloud/index.html)
|
||||
* [vSphere 7.0 (latest)](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/7.0.0.1/)
|
||||
* Previous releases: [6.7.1](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.7.1/) [6.7.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.7.0) [6.6.1](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.6.1) [6.5](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.5) [6.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.0)
|
||||
* [vSphere 7.0 Update 1 (latest)](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/7.0.1.0/)
|
||||
* Previous releases: [7.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/7.0.0.1/) [6.7.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.7.0) [6.6.1](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.6.1) [6.5](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.5) [6.0](https://vmware.github.io/vsphere-automation-sdk-python/vsphere/6.0)
|
||||
|
||||
### VMware Cloud on AWS API Documentation
|
||||
|
||||
@ -250,5 +250,5 @@ Members:
|
||||
* [VMware Sample Exchange](https://code.vmware.com/samples) It is highly recommended to add any and all submitted samples to the VMware Sample Exchange
|
||||
* [VMware Code](https://code.vmware.com/home)
|
||||
* [VMware Developer Community](https://communities.vmware.com/community/vmtn/developer)
|
||||
* VMware vSphere [REST API Reference documentation](https://code.vmware.com/apis/366/vsphere-automation).
|
||||
* VMware vSphere [REST API Reference documentation](https://developer.vmware.com/docs/vsphere-automation/latest/).
|
||||
* [VMware Python forum](https://code.vmware.com/forums/7508/vsphere-automation-sdk-for-python)
|
||||
|
@ -1 +1 @@
|
||||
<a href='vapi_client_bindings-3.3.0-py2.py3-none-any.whl'>vapi_client_bindings-3.3.0-py2.py3-none-any.whl</a><br />
|
||||
<a href='vapi_client_bindings-3.5.0-py2.py3-none-any.whl'>vapi_client_bindings-3.5.0-py2.py3-none-any.whl</a><br />
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
||||
<a href='vapi_common_client-2.15.0-py2.py3-none-any.whl'>vapi_common_client-2.15.0-py2.py3-none-any.whl</a><br />
|
||||
<a href='vapi_common_client-2.19.0-py2.py3-none-any.whl'>vapi_common_client-2.19.0-py2.py3-none-any.whl</a><br />
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
||||
<a href='vapi_runtime-2.15.0-py2.py3-none-any.whl'>vapi_runtime-2.15.0-py2.py3-none-any.whl</a><br />
|
||||
<a href='vapi_runtime-2.19.0-py2.py3-none-any.whl'>vapi_runtime-2.19.0-py2.py3-none-any.whl</a><br />
|
Binary file not shown.
Binary file not shown.
@ -2,7 +2,7 @@ lxml >= 4.3.0
|
||||
pyVmomi >= 6.7
|
||||
suds ; python_version < '3'
|
||||
suds-jurko ; python_version >= '3.0'
|
||||
vapi-client-bindings == 3.3.0
|
||||
vapi-client-bindings == 3.5.0
|
||||
vmc-client-bindings
|
||||
nsx-python-sdk
|
||||
nsx-policy-python-sdk
|
||||
|
54
samples/vsphere/oauth/grant_types/README.md
Normal file
54
samples/vsphere/oauth/grant_types/README.md
Normal file
@ -0,0 +1,54 @@
|
||||
## Grant types available
|
||||
|
||||
| sample | grant_type |
|
||||
| ------ | ------ |
|
||||
| list_vms_authotization_code.py | authorization_code |
|
||||
| list_vms_client_credentials.py | client_credentials |
|
||||
| list_vms_refresh_token.py | refresh_token |
|
||||
| list_vms_password.py | password |
|
||||
|
||||
## Login Steps
|
||||
1. From a given VC IP/hostname, find the Identity Provider (sample available at [list_external_identity_providers.py](https://github.com/vmware/vsphere-automation-sdk-python/blob/master/samples/vsphere/oauth/list_external_identity_providers.py))
|
||||
2. Make a note of the auth/discovery/token endpoints from the identity provider object
|
||||
3. Get access token by making the call to endpoints based on parameters relevant to different grant types
|
||||
4. Convert access token to saml token (sample avaialble at [exchange_access_id_token_for_saml.py](https://github.com/vmware/vsphere-automation-sdk-python/blob/master/samples/vsphere/oauth/exchange_access_id_token_for_saml.py))
|
||||
5. Use this saml assertion to login to vCenter as a bearer token
|
||||
|
||||
|
||||
## Executing the samples
|
||||
vCenter needs to be registered with an Identity Provider. Applicable for VC 7.0+
|
||||
### list_vms_authorization_code.py
|
||||
Create an OAuth app and make a note of the *app_id*, *app_secret* and *redirect_uri*
|
||||
|
||||
First start the webserver code at [webserver.py](https://github.com/vmware/vsphere-automation-sdk-python/blob/master/samples/vsphere/oauth/grant_types/webserver.py). Note, this server is not recommended in a production setting, this is only to demonstarte the sample workflow
|
||||
|
||||
`$ python3 webserver.py`
|
||||
|
||||
Run the sample,
|
||||
|
||||
`$ python list_vms_authorization_code.py --server <VC_IP> --client_id <client_id> --client_secret <client_secret> --org_id <org_id> --skipverification`
|
||||
|
||||
### list_vms_client_credentials.py
|
||||
Create an OAuth app and make a note of the *client_id* and *client_secret*
|
||||
|
||||
Run the sample,
|
||||
|
||||
`$ python list_vms_client_credentials.py --server <VC_IP> -- client_id <client_id> --client_secret <client_secret> --skipverification`
|
||||
|
||||
### list_vms_refresh_token.py
|
||||
Use the *refresh_token* that was returned along with the access token in authorization_code workflow
|
||||
|
||||
Run the sample,
|
||||
|
||||
`$ python list_vms_refresh_token.py --server <VC_IP> --client_id <client_id> --client_secret <client_secret> --refresh_token <refresh_token> --skipverification`
|
||||
|
||||
### list_vms_password.py
|
||||
Obtain access token using *username* and *password*
|
||||
|
||||
Run the sample,
|
||||
|
||||
`$ python list_vms_password --server <VC_IP> --username <username> --password <password> --skipverification`
|
||||
|
||||
|
||||
## References
|
||||
[Understanding vCenter Server Identity Provider Federation](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.authentication.doc/GUID-0A3A19E6-150A-493B-8B57-37E19AB420F2.html)
|
25
samples/vsphere/oauth/grant_types/__init__.py
Normal file
25
samples/vsphere/oauth/grant_types/__init__.py
Normal file
@ -0,0 +1,25 @@
|
||||
"""
|
||||
* *******************************************************
|
||||
* Copyright VMware, Inc. 2020. All Rights Reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
* *******************************************************
|
||||
*
|
||||
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
|
||||
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
|
||||
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
"""
|
||||
|
||||
__author__ = 'VMware, Inc.'
|
||||
|
||||
# Required to distribute different parts of this
|
||||
# package as multiple distribution
|
||||
try:
|
||||
import pkg_resources
|
||||
|
||||
pkg_resources.declare_namespace(__name__)
|
||||
except ImportError:
|
||||
from pkgutil import extend_path
|
||||
|
||||
__path__ = extend_path(__path__, __name__) # @ReservedAssignment
|
103
samples/vsphere/oauth/grant_types/list_vms_authorization_code.py
Normal file
103
samples/vsphere/oauth/grant_types/list_vms_authorization_code.py
Normal file
@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
* *******************************************************
|
||||
* Copyright (c) VMware, Inc. 2020. All Rights Reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
* *******************************************************
|
||||
*
|
||||
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
|
||||
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
|
||||
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
"""
|
||||
from vmware.vapi.vsphere.client import create_vsphere_client
|
||||
|
||||
from samples.vsphere.common.ssl_helper import get_unverified_session
|
||||
from samples.vsphere.oauth.grant_types.oauth_utility \
|
||||
import login_using_authorization_code
|
||||
|
||||
from urllib.parse import parse_qs
|
||||
import webbrowser
|
||||
import urllib.parse as urlparse
|
||||
import requests
|
||||
import uuid
|
||||
import argparse
|
||||
|
||||
__author__ = 'VMware, Inc.'
|
||||
__copyright__ = 'Copyright 2020 VMware, Inc. All rights reserved.'
|
||||
__vcenter_version__ = '7.0+'
|
||||
|
||||
"""
|
||||
To run this sample,
|
||||
|
||||
In a different tab, keep the webserver running,
|
||||
$ python webserver.py
|
||||
|
||||
Then execute the following
|
||||
$ python list_vms_authorization_code.py --server <VC_IP> \
|
||||
--client_id <client_id> --client_secret <client_secret> \
|
||||
--org_id <org_id> --skipverification
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--server",
|
||||
help="VC IP or hostname")
|
||||
parser.add_argument("--client_id",
|
||||
help="Client/Application ID of the webapp")
|
||||
parser.add_argument("--client_secret",
|
||||
help="Client/Application secret \
|
||||
of the webapp")
|
||||
parser.add_argument("--redirect_uri",
|
||||
help="Redirect uri \
|
||||
given at the time of client registration")
|
||||
parser.add_argument('--skipverification',
|
||||
action='store_true',
|
||||
help='Verify server certificate when connecting to vc.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
def get_auth_code_and_state(url):
|
||||
openbrowser(url)
|
||||
parsed = urlparse.urlparse(url)
|
||||
redirect_uri = parse_qs(parsed.query)['redirect_uri']
|
||||
|
||||
get_code_uri = redirect_uri[0].rsplit('/', 1)[0]
|
||||
get_code_uri = get_code_uri + "/getcode"
|
||||
|
||||
response = get_response(get_code_uri)
|
||||
while "code" not in response or response == '':
|
||||
response = get_response(get_code_uri)
|
||||
|
||||
res = response.split(':')
|
||||
code = res[1]
|
||||
state = res[3]
|
||||
return [code, state]
|
||||
|
||||
|
||||
def openbrowser(url):
|
||||
webbrowser.open(url)
|
||||
pass
|
||||
|
||||
|
||||
def get_response(url):
|
||||
response = requests.get(url)
|
||||
return response.text
|
||||
|
||||
|
||||
session = get_unverified_session() if args.skipverification else None
|
||||
saml_assertion = login_using_authorization_code(
|
||||
args.server,
|
||||
session,
|
||||
args.client_id,
|
||||
args.client_secret,
|
||||
args.redirect_uri,
|
||||
get_auth_code_and_state)
|
||||
client = create_vsphere_client(
|
||||
server=args.server,
|
||||
bearer_token=saml_assertion,
|
||||
session=session)
|
||||
vms = client.vcenter.VM.list()
|
||||
print(vms)
|
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
* *******************************************************
|
||||
* Copyright (c) VMware, Inc. 2020. All Rights Reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
* *******************************************************
|
||||
*
|
||||
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
|
||||
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
|
||||
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
"""
|
||||
from vmware.vapi.vsphere.client import create_vsphere_client
|
||||
|
||||
from samples.vsphere.common import sample_cli
|
||||
from samples.vsphere.common import sample_util
|
||||
from samples.vsphere.common.ssl_helper import get_unverified_session
|
||||
from samples.vsphere.oauth.grant_types.oauth_utility \
|
||||
import login_using_client_credentials
|
||||
import argparse
|
||||
|
||||
__author__ = 'VMware, Inc.'
|
||||
__copyright__ = 'Copyright 2020 VMware, Inc. All rights reserved.'
|
||||
__vcenter_version__ = '7.0+'
|
||||
|
||||
"""
|
||||
To run this sample,
|
||||
$ python list_vms_client_credentials.py --server <VC_IP> \
|
||||
-- client_id <client_id> --client_secret <client_secret> --skipverification
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--server",
|
||||
help="VC IP or hostname")
|
||||
parser.add_argument("--client_id",
|
||||
help="Client/Application ID of the server to server app")
|
||||
parser.add_argument("--client_secret",
|
||||
help="Client/Application secret \
|
||||
of the server to server app")
|
||||
parser.add_argument('--skipverification',
|
||||
action='store_true',
|
||||
help='Verify server certificate when connecting to vc.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
session = get_unverified_session() if args.skipverification else None
|
||||
saml_assertion = login_using_client_credentials(
|
||||
args.server,
|
||||
session,
|
||||
args.client_id,
|
||||
args.client_secret)
|
||||
|
||||
client = create_vsphere_client(
|
||||
server=args.server,
|
||||
bearer_token=saml_assertion,
|
||||
session=session)
|
||||
vms = client.vcenter.VM.list()
|
||||
print(vms)
|
61
samples/vsphere/oauth/grant_types/list_vms_password.py
Normal file
61
samples/vsphere/oauth/grant_types/list_vms_password.py
Normal file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
* *******************************************************
|
||||
* Copyright (c) VMware, Inc. 2020. All Rights Reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
* *******************************************************
|
||||
*
|
||||
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
|
||||
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
|
||||
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
"""
|
||||
from vmware.vapi.vsphere.client import create_vsphere_client
|
||||
|
||||
from samples.vsphere.common import sample_cli
|
||||
from samples.vsphere.common import sample_util
|
||||
from samples.vsphere.common.ssl_helper import get_unverified_session
|
||||
from samples.vsphere.oauth.grant_types.oauth_utility \
|
||||
import login_using_password
|
||||
import argparse
|
||||
|
||||
__author__ = 'VMware, Inc.'
|
||||
__copyright__ = 'Copyright 2020 VMware, Inc. All rights reserved.'
|
||||
__vcenter_version__ = '7.0+'
|
||||
|
||||
"""
|
||||
To run this sample,
|
||||
$ python list_vms_password --server <VC_IP> \
|
||||
--username <username> --password <password> --skipverification
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--server",
|
||||
help="VC IP or hostname")
|
||||
parser.add_argument("--username",
|
||||
help="username to login \
|
||||
to vCenter")
|
||||
parser.add_argument("--password",
|
||||
help="password to login \
|
||||
to vCenter")
|
||||
parser.add_argument('--skipverification',
|
||||
action='store_true',
|
||||
help='Verify server certificate when connecting to vc.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
session = get_unverified_session() if args.skipverification else None
|
||||
saml_assertion = login_using_password(
|
||||
args.server,
|
||||
session,
|
||||
args.username,
|
||||
args.password)
|
||||
|
||||
client = create_vsphere_client(
|
||||
server=args.server,
|
||||
bearer_token=saml_assertion,
|
||||
session=session)
|
||||
vms = client.vcenter.VM.list()
|
||||
print(vms)
|
64
samples/vsphere/oauth/grant_types/list_vms_refresh_token.py
Normal file
64
samples/vsphere/oauth/grant_types/list_vms_refresh_token.py
Normal file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
* *******************************************************
|
||||
* Copyright (c) VMware, Inc. 2020. All Rights Reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
* *******************************************************
|
||||
*
|
||||
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
|
||||
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
|
||||
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
"""
|
||||
from vmware.vapi.vsphere.client import create_vsphere_client
|
||||
|
||||
from samples.vsphere.common import sample_cli
|
||||
from samples.vsphere.common import sample_util
|
||||
from samples.vsphere.common.ssl_helper import get_unverified_session
|
||||
from samples.vsphere.oauth.grant_types.oauth_utility \
|
||||
import login_using_refresh_token
|
||||
import argparse
|
||||
|
||||
__author__ = 'VMware, Inc.'
|
||||
__copyright__ = 'Copyright 2020 VMware, Inc. All rights reserved.'
|
||||
__vcenter_version__ = '7.0+'
|
||||
|
||||
"""
|
||||
To run this sample,
|
||||
$ python list_vms_refresh_token.py \
|
||||
--server <VC_IP> --client_id <client_id> --client_secret <client_secret>\
|
||||
--refresh_token <refresh_token> --skipverification
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--server",
|
||||
help="VC IP or hostname")
|
||||
parser.add_argument("--client_id",
|
||||
help="Client/Application ID of the server to server app")
|
||||
parser.add_argument("--client_secret",
|
||||
help="Client/Application secret \
|
||||
of the server to server app")
|
||||
parser.add_argument("--refresh_token",
|
||||
help="Refresh token used to refresh the access token")
|
||||
parser.add_argument('--skipverification',
|
||||
action='store_true',
|
||||
help='Verify server certificate when connecting to vc.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
session = get_unverified_session() if args.skipverification else None
|
||||
saml_assertion = login_using_refresh_token(
|
||||
args.server,
|
||||
session,
|
||||
args.client_id,
|
||||
args.client_secret,
|
||||
args.refresh_token)
|
||||
|
||||
client = create_vsphere_client(
|
||||
server=args.server,
|
||||
bearer_token=saml_assertion,
|
||||
session=session)
|
||||
vms = client.vcenter.VM.list()
|
||||
print(vms)
|
233
samples/vsphere/oauth/grant_types/oauth_utility.py
Normal file
233
samples/vsphere/oauth/grant_types/oauth_utility.py
Normal file
@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
* *******************************************************
|
||||
* Copyright (c) VMware, Inc. 2020. All Rights Reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
* *******************************************************
|
||||
*
|
||||
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
|
||||
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
|
||||
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
"""
|
||||
|
||||
from vmware.vapi.stdlib.client.factories import StubConfigurationFactory
|
||||
from vmware.vapi.lib.connect import get_requests_connector
|
||||
from com.vmware.vcenter.identity_client import Providers
|
||||
from com.vmware.vcenter.tokenservice_client import TokenExchange
|
||||
from vmware.vapi.security.oauth import create_oauth_security_context
|
||||
import base64
|
||||
from lxml import etree
|
||||
import uuid
|
||||
|
||||
# Constants
|
||||
HTTP_ENDPOINT = "https://{}/api"
|
||||
AUTHORIZATION_CODE = "authorization_code"
|
||||
CLIENT_CREDENTIALS = "client_credentials"
|
||||
REFRESH_TOKEN = "refresh_token"
|
||||
PASSWORD = "password"
|
||||
OAUTH2_CONFIG_TYPE = "oauth2"
|
||||
OIDC_CONFIG_TYPE = "oidc"
|
||||
|
||||
|
||||
def get_identity_provider(server, session):
|
||||
'''
|
||||
Get the identity provider for the given vc/server
|
||||
Sample can be found at
|
||||
https://github.com/vmware/vsphere-automation-sdk-python/blob/master/samples/vsphere/oauth/list_external_identity_providers.py
|
||||
'''
|
||||
stub_config = StubConfigurationFactory.new_std_configuration(
|
||||
get_requests_connector(
|
||||
session=session,
|
||||
url=HTTP_ENDPOINT.format(
|
||||
server)))
|
||||
id_client = Providers(stub_config)
|
||||
providers = id_client.list()
|
||||
identity_provider = ""
|
||||
for provider in providers:
|
||||
if provider.is_default:
|
||||
identity_provider = provider
|
||||
break
|
||||
return identity_provider
|
||||
|
||||
|
||||
def get_saml_assertion(server, session, access_token, id_token=None):
|
||||
"""
|
||||
Exchange access token to saml token to connect to VC
|
||||
Sample can be found at
|
||||
https://github.com/vmware/vsphere-automation-sdk-python/blob/master/samples/vsphere/oauth/exchange_access_id_token_for_saml.py
|
||||
"""
|
||||
stub_config = StubConfigurationFactory.new_std_configuration(
|
||||
get_requests_connector(
|
||||
session=session,
|
||||
url=HTTP_ENDPOINT.format(server)
|
||||
)
|
||||
)
|
||||
|
||||
oauth_security_context = create_oauth_security_context(access_token)
|
||||
stub_config.connector.set_security_context(oauth_security_context)
|
||||
token_exchange = TokenExchange(stub_config)
|
||||
exchange_spec = token_exchange.ExchangeSpec(
|
||||
grant_type=token_exchange.TOKEN_EXCHANGE_GRANT,
|
||||
subject_token_type=token_exchange.ACCESS_TOKEN_TYPE,
|
||||
actor_token_type=token_exchange.ID_TOKEN_TYPE,
|
||||
requested_token_type=token_exchange.SAML2_TOKEN_TYPE,
|
||||
actor_token=id_token, subject_token=access_token)
|
||||
response = token_exchange.exchange(exchange_spec)
|
||||
saml_token = response.access_token
|
||||
|
||||
# convert saml token to saml assertion
|
||||
samlAssertion = etree.tostring(
|
||||
etree.XML(base64.decodebytes(
|
||||
bytes(saml_token, 'utf-8')
|
||||
))
|
||||
).decode('utf-8')
|
||||
return samlAssertion
|
||||
|
||||
|
||||
def get_endpoints(identity_provider):
|
||||
"""
|
||||
Extract different ednpoints from the identity provider object
|
||||
Note that the endpoint naming convention might vary for different providers
|
||||
Currently, support is provided for
|
||||
oauth2 -> Cloud Service Provider (CSP)
|
||||
oidc -> Microssoft ADFS
|
||||
"""
|
||||
if identity_provider.auth_query_params is not None:
|
||||
auth_query_params = identity_provider.auth_query_params
|
||||
else:
|
||||
auth_query_params = {}
|
||||
|
||||
if identity_provider.config_tag.lower() == OAUTH2_CONFIG_TYPE:
|
||||
auth_endpoint = identity_provider.oauth2.auth_endpoint
|
||||
token_endpoint = identity_provider.oauth2.token_endpoint
|
||||
auth_query_params.update(identity_provider.oauth2.auth_query_params)
|
||||
if identity_provider.config_tag.lower() == OIDC_CONFIG_TYPE:
|
||||
auth_endpoint = identity_provider.oidc.discovery_endpoint
|
||||
token_endpoint = identity_provider.oidc.auth_endpoint
|
||||
auth_query_params.update(identity_provider.oidc.auth_query_params)
|
||||
return [auth_endpoint, token_endpoint, auth_query_params]
|
||||
|
||||
|
||||
def get_basic_auth_string(id, secret):
|
||||
"""
|
||||
Return authorization string
|
||||
"""
|
||||
auth_string = id + ":" + secret
|
||||
auth_string = "Basic " + base64.b64encode(auth_string.encode()).decode()
|
||||
return auth_string
|
||||
|
||||
|
||||
def login_using_client_credentials(server, session, client_id, client_secret):
|
||||
"""
|
||||
Get access token when grant_type is client_credentials
|
||||
"""
|
||||
identity_provider = get_identity_provider(server, session)
|
||||
[discovery_endpoint, token_endpoint, auth_query_params] = \
|
||||
get_endpoints(identity_provider)
|
||||
headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Authorization': get_basic_auth_string(client_id, client_secret),
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
data = {
|
||||
'grant_type': CLIENT_CREDENTIALS
|
||||
}
|
||||
response = session.post(token_endpoint, headers=headers, data=data).json()
|
||||
access_token = response['access_token']
|
||||
return get_saml_assertion(server, session, access_token)
|
||||
|
||||
|
||||
def login_using_authorization_code(
|
||||
server,
|
||||
session,
|
||||
client_id,
|
||||
client_secret,
|
||||
redirect_uri,
|
||||
callback):
|
||||
"""
|
||||
Get access token when grant_type is authorization_code
|
||||
"""
|
||||
identity_provider = get_identity_provider(server, session)
|
||||
[auth_endpoint, token_endpoint, auth_query_params] = \
|
||||
get_endpoints(identity_provider)
|
||||
state = uuid.uuid1()
|
||||
|
||||
auth_endpoint += "?client_id=" + client_id + "&redirect_uri=" + \
|
||||
redirect_uri + "&state=" + str(state)
|
||||
for key, value in auth_query_params.items():
|
||||
auth_endpoint += "&" + key + "="
|
||||
if isinstance(value, list):
|
||||
auth_endpoint += value[0]
|
||||
|
||||
[code, state] = callback(auth_endpoint)
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Authorization": get_basic_auth_string(client_id, client_secret),
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
data = {
|
||||
"grant_type": AUTHORIZATION_CODE,
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
"redirect_uri": redirect_uri,
|
||||
"code": code,
|
||||
"state": state
|
||||
}
|
||||
|
||||
response = session.post(token_endpoint, headers=headers, data=data).json()
|
||||
access_token = response['access_token']
|
||||
return get_saml_assertion(server, session, access_token)
|
||||
|
||||
|
||||
def login_using_refresh_token(
|
||||
server,
|
||||
session,
|
||||
client_id,
|
||||
client_secret,
|
||||
refresh_token):
|
||||
"""
|
||||
Get access token when grant_type is refresh_token
|
||||
"""
|
||||
identity_provider = get_identity_provider(server, session)
|
||||
[auth_endpoint, token_endpoint, auth_query_params] = \
|
||||
get_endpoints(identity_provider)
|
||||
headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Authorization": get_basic_auth_string(client_id, client_secret),
|
||||
"Accept": "application/json"
|
||||
}
|
||||
data = {
|
||||
"grant_type": REFRESH_TOKEN,
|
||||
"refresh_token": refresh_token
|
||||
}
|
||||
response = session.post(token_endpoint, headers=headers, data=data).json()
|
||||
access_token = response['access_token']
|
||||
return get_saml_assertion(server, session, access_token)
|
||||
|
||||
|
||||
def login_using_password(server, session, username, password):
|
||||
"""
|
||||
Get access token when grant_type is password
|
||||
"""
|
||||
identity_provider = get_identity_provider(server, session)
|
||||
[auth_endpoint, token_endpoint, auth_query_params] = \
|
||||
get_endpoints(identity_provider)
|
||||
headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Authorization": get_basic_auth_string(username, password),
|
||||
"Accept": "application/json"
|
||||
}
|
||||
data = {
|
||||
"grant_type": PASSWORD,
|
||||
"username": username,
|
||||
"password": password
|
||||
}
|
||||
response = session.post(token_endpoint, headers=headers, data=data).json()
|
||||
print(response)
|
||||
access_token = response['access_token']
|
||||
return get_saml_assertion(server, session, access_token)
|
146
samples/vsphere/oauth/grant_types/webserver.py
Normal file
146
samples/vsphere/oauth/grant_types/webserver.py
Normal file
@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
* *******************************************************
|
||||
* Copyright (c) VMware, Inc. 2020. All Rights Reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
* *******************************************************
|
||||
*
|
||||
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
|
||||
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
|
||||
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
This is a lightweight webserver
|
||||
****Not recommended in a production setting****
|
||||
|
||||
Before you run the oauth samples, this server needs to be up.
|
||||
Make sure to start it before trying out the samples
|
||||
Or start it as a daemon process
|
||||
|
||||
We define listeners for two endpoints,
|
||||
|
||||
1. /getcode -> Endpoint to fetch the 'code' and 'state' variable
|
||||
It is a GET request
|
||||
Once the response is returned,
|
||||
the variables need to be reassigned with ''
|
||||
or None, to avoid inconsistent values
|
||||
|
||||
2. /authcode -> Redirect endpoint which will be called by the CSP server
|
||||
It is a GET request
|
||||
code and state are the request params
|
||||
e.g., /authcode?code=xxxx&state=xxxxx
|
||||
|
||||
In case, you want to change the names of these endpoints in your client,
|
||||
make sure to change in the below server code as well
|
||||
"""
|
||||
|
||||
try:
|
||||
# these imports are specific to Python 2.x
|
||||
from BaseHTTPServer import BaseHTTPRequestHandler
|
||||
import SocketServer
|
||||
from urlparse import urlparse
|
||||
except ImportError:
|
||||
# these imports are specific to Python 3.x
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import argparse
|
||||
import socket
|
||||
import json
|
||||
|
||||
PORT = ''
|
||||
AUTHCODE = '/authcode'
|
||||
|
||||
code = state = ''
|
||||
|
||||
hostname = socket.gethostname()
|
||||
IPAddr = "127.0.0.1"
|
||||
|
||||
|
||||
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
'''
|
||||
This class defines the handlers for the incoming GET requests
|
||||
'''
|
||||
|
||||
def _set_headers(self):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'text/html')
|
||||
self.end_headers()
|
||||
|
||||
def do_GET(self):
|
||||
global code, state, AUTHCODE
|
||||
print(self.path)
|
||||
|
||||
'''
|
||||
defining multiple GET endpoints is not very elegant,
|
||||
the very reason why you shouldn't use this in a production setting!
|
||||
below are the listeners for /getcode and /authcode
|
||||
'''
|
||||
if self.path == '/getcode':
|
||||
self._set_headers()
|
||||
print('call to getcode')
|
||||
print(code)
|
||||
print(state)
|
||||
if code != '' and state != '':
|
||||
'''
|
||||
the response is defined to be in this format
|
||||
code:xxxx:state:xxxx
|
||||
the client sample assumes the response to be in this format,
|
||||
any change to the response format,
|
||||
will need changes in the client code response parser
|
||||
'''
|
||||
res = "code:" + code + ":state:" + state
|
||||
|
||||
self.wfile.write(res.encode('utf-8'))
|
||||
|
||||
# code and state variables need to be reset
|
||||
code = state = ''
|
||||
|
||||
elif self.path.startswith(AUTHCODE, 0):
|
||||
print("call to authcode")
|
||||
global IPAddr, PORT
|
||||
redirect_url = "http://" + IPAddr + ":" + str(PORT) + "/authcode"
|
||||
print("Redirect URL: " + redirect_url)
|
||||
self._set_headers()
|
||||
query = urlparse(self.path).query
|
||||
# CSP always sends request in this format
|
||||
# /authcode?code=xxxx&state=xxxxx
|
||||
query = query.split('&')
|
||||
param_code = query[0].split('=')
|
||||
code = param_code[1]
|
||||
|
||||
param_state = query[1].split('=')
|
||||
state = param_state[1]
|
||||
print("code: ", code)
|
||||
print("state: ", state)
|
||||
self.wfile.write(b'Code and state variables are set,\
|
||||
you may now close the browser tab')
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Input port and pathname')
|
||||
# port number by default will be 8080
|
||||
parser.add_argument(
|
||||
'--port',
|
||||
dest='port',
|
||||
default=8086,
|
||||
help='webserver port')
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = parse_args()
|
||||
PORT = int(args.port)
|
||||
try:
|
||||
httpd = SocketServer.TCPServer(("", PORT), SimpleHTTPRequestHandler)
|
||||
except Exception as e:
|
||||
httpd = HTTPServer(("", PORT), SimpleHTTPRequestHandler)
|
||||
httpd.serve_forever()
|
8
setup.py
8
setup.py
@ -5,7 +5,7 @@ import os
|
||||
from setuptools import setup
|
||||
|
||||
setup(name='vSphere Automation SDK',
|
||||
version='1.38.0',
|
||||
version='1.39.0',
|
||||
description='VMware vSphere Automation SDK for Python',
|
||||
url='https://github.com/vmware/vsphere-automation-sdk-python',
|
||||
author='VMware, Inc.',
|
||||
@ -15,9 +15,9 @@ setup(name='vSphere Automation SDK',
|
||||
'suds ; python_version < "3"',
|
||||
'suds-jurko ; python_version >= "3.0"',
|
||||
'pyVmomi >= 6.7',
|
||||
'vapi-runtime @ file://localhost/{}/lib/vapi-runtime/vapi_runtime-2.15.0-py2.py3-none-any.whl'.format(os.getcwd()),
|
||||
'vapi-client-bindings @ file://localhost/{}/lib/vapi-client-bindings/vapi_client_bindings-3.3.0-py2.py3-none-any.whl'.format(os.getcwd()),
|
||||
'vapi-common-client @ file://localhost/{}/lib/vapi-common-client/vapi_common_client-2.15.0-py2.py3-none-any.whl'.format(os.getcwd()),
|
||||
'vapi-runtime @ file://localhost/{}/lib/vapi-runtime/vapi_runtime-2.19.0-py2.py3-none-any.whl'.format(os.getcwd()),
|
||||
'vapi-client-bindings @ file://localhost/{}/lib/vapi-client-bindings/vapi_client_bindings-3.5.0-py2.py3-none-any.whl'.format(os.getcwd()),
|
||||
'vapi-common-client @ file://localhost/{}/lib/vapi-common-client/vapi_common_client-2.19.0-py2.py3-none-any.whl'.format(os.getcwd()),
|
||||
'vmc-client-bindings @ file://localhost/{}/lib/vmc-client-bindings/vmc_client_bindings-1.29.0-py2.py3-none-any.whl'.format(os.getcwd()),
|
||||
'nsx-python-sdk @ file://localhost/{}/lib/nsx-python-sdk/nsx_python_sdk-3.0.2.0.0.16837625-py2.py3-none-any.whl'.format(os.getcwd()),
|
||||
'nsx-policy-python-sdk @ file://localhost/{}/lib/nsx-policy-python-sdk/nsx_policy_python_sdk-3.0.2.0.0.16837625-py2.py3-none-any.whl'.format(os.getcwd()),
|
||||
|
Loading…
Reference in New Issue
Block a user