mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
* update username/password auth to use adal lib * remove default client_id after discussion * fix lint error: trailing whitespace
This commit is contained in:
parent
e93fbedcc7
commit
21ea92feca
4 changed files with 117 additions and 6 deletions
|
@ -50,6 +50,7 @@ Command line arguments:
|
||||||
- ad_user
|
- ad_user
|
||||||
- password
|
- password
|
||||||
- cloud_environment
|
- cloud_environment
|
||||||
|
- adfs_authority_url
|
||||||
|
|
||||||
Environment variables:
|
Environment variables:
|
||||||
- AZURE_PROFILE
|
- AZURE_PROFILE
|
||||||
|
@ -60,6 +61,7 @@ Environment variables:
|
||||||
- AZURE_AD_USER
|
- AZURE_AD_USER
|
||||||
- AZURE_PASSWORD
|
- AZURE_PASSWORD
|
||||||
- AZURE_CLOUD_ENVIRONMENT
|
- AZURE_CLOUD_ENVIRONMENT
|
||||||
|
- AZURE_ADFS_AUTHORITY_URL
|
||||||
|
|
||||||
Run for Specific Host
|
Run for Specific Host
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@ -209,6 +211,7 @@ HAS_AZURE_CLI_CORE = True
|
||||||
CLIError = None
|
CLIError = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
from msrestazure.azure_active_directory import AADTokenCredentials
|
||||||
from msrestazure.azure_exceptions import CloudError
|
from msrestazure.azure_exceptions import CloudError
|
||||||
from msrestazure.azure_active_directory import MSIAuthentication
|
from msrestazure.azure_active_directory import MSIAuthentication
|
||||||
from msrestazure import azure_cloud
|
from msrestazure import azure_cloud
|
||||||
|
@ -219,6 +222,7 @@ try:
|
||||||
from azure.mgmt.resource.resources import ResourceManagementClient
|
from azure.mgmt.resource.resources import ResourceManagementClient
|
||||||
from azure.mgmt.resource.subscriptions import SubscriptionClient
|
from azure.mgmt.resource.subscriptions import SubscriptionClient
|
||||||
from azure.mgmt.compute import ComputeManagementClient
|
from azure.mgmt.compute import ComputeManagementClient
|
||||||
|
from adal.authentication_context import AuthenticationContext
|
||||||
except ImportError as exc:
|
except ImportError as exc:
|
||||||
HAS_AZURE_EXC = exc
|
HAS_AZURE_EXC = exc
|
||||||
HAS_AZURE = False
|
HAS_AZURE = False
|
||||||
|
@ -245,6 +249,7 @@ AZURE_CREDENTIAL_ENV_MAPPING = dict(
|
||||||
ad_user='AZURE_AD_USER',
|
ad_user='AZURE_AD_USER',
|
||||||
password='AZURE_PASSWORD',
|
password='AZURE_PASSWORD',
|
||||||
cloud_environment='AZURE_CLOUD_ENVIRONMENT',
|
cloud_environment='AZURE_CLOUD_ENVIRONMENT',
|
||||||
|
adfs_authority_url='AZURE_ADFS_AUTHORITY_URL'
|
||||||
)
|
)
|
||||||
|
|
||||||
AZURE_CONFIG_SETTINGS = dict(
|
AZURE_CONFIG_SETTINGS = dict(
|
||||||
|
@ -281,6 +286,8 @@ class AzureRM(object):
|
||||||
self._compute_client = None
|
self._compute_client = None
|
||||||
self._resource_client = None
|
self._resource_client = None
|
||||||
self._network_client = None
|
self._network_client = None
|
||||||
|
self._adfs_authority_url = None
|
||||||
|
self._resource = None
|
||||||
|
|
||||||
self.debug = False
|
self.debug = False
|
||||||
if args.debug:
|
if args.debug:
|
||||||
|
@ -316,6 +323,17 @@ class AzureRM(object):
|
||||||
self.log("setting subscription_id")
|
self.log("setting subscription_id")
|
||||||
self.subscription_id = self.credentials['subscription_id']
|
self.subscription_id = self.credentials['subscription_id']
|
||||||
|
|
||||||
|
# get authentication authority
|
||||||
|
# for adfs, user could pass in authority or not.
|
||||||
|
# for others, use default authority from cloud environment
|
||||||
|
if self.credentials.get('adfs_authority_url') is None:
|
||||||
|
self._adfs_authority_url = self._cloud_environment.endpoints.active_directory
|
||||||
|
else:
|
||||||
|
self._adfs_authority_url = self.credentials.get('adfs_authority_url')
|
||||||
|
|
||||||
|
# get resource from cloud environment
|
||||||
|
self._resource = self._cloud_environment.endpoints.active_directory_resource_id
|
||||||
|
|
||||||
if self.credentials.get('credentials'):
|
if self.credentials.get('credentials'):
|
||||||
self.azure_credentials = self.credentials.get('credentials')
|
self.azure_credentials = self.credentials.get('credentials')
|
||||||
elif self.credentials.get('client_id') and self.credentials.get('secret') and self.credentials.get('tenant'):
|
elif self.credentials.get('client_id') and self.credentials.get('secret') and self.credentials.get('tenant'):
|
||||||
|
@ -323,6 +341,20 @@ class AzureRM(object):
|
||||||
secret=self.credentials['secret'],
|
secret=self.credentials['secret'],
|
||||||
tenant=self.credentials['tenant'],
|
tenant=self.credentials['tenant'],
|
||||||
cloud_environment=self._cloud_environment)
|
cloud_environment=self._cloud_environment)
|
||||||
|
|
||||||
|
elif self.credentials.get('ad_user') is not None and \
|
||||||
|
self.credentials.get('password') is not None and \
|
||||||
|
self.credentials.get('client_id') is not None and \
|
||||||
|
self.credentials.get('tenant') is not None:
|
||||||
|
|
||||||
|
self.azure_credentials = self.acquire_token_with_username_password(
|
||||||
|
self._adfs_authority_url,
|
||||||
|
self._resource,
|
||||||
|
self.credentials['ad_user'],
|
||||||
|
self.credentials['password'],
|
||||||
|
self.credentials['client_id'],
|
||||||
|
self.credentials['tenant'])
|
||||||
|
|
||||||
elif self.credentials.get('ad_user') is not None and self.credentials.get('password') is not None:
|
elif self.credentials.get('ad_user') is not None and self.credentials.get('password') is not None:
|
||||||
tenant = self.credentials.get('tenant')
|
tenant = self.credentials.get('tenant')
|
||||||
if not tenant:
|
if not tenant:
|
||||||
|
@ -331,9 +363,12 @@ class AzureRM(object):
|
||||||
self.credentials['password'],
|
self.credentials['password'],
|
||||||
tenant=tenant,
|
tenant=tenant,
|
||||||
cloud_environment=self._cloud_environment)
|
cloud_environment=self._cloud_environment)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.fail("Failed to authenticate with provided credentials. Some attributes were missing. "
|
self.fail("Failed to authenticate with provided credentials. Some attributes were missing. "
|
||||||
"Credentials must include client_id, secret and tenant or ad_user and password.")
|
"Credentials must include client_id, secret and tenant or ad_user and password, or "
|
||||||
|
"ad_user, password, client_id, tenant and adfs_authority_url(optional) for ADFS authentication, or "
|
||||||
|
"be logged in using AzureCLI.")
|
||||||
|
|
||||||
def log(self, msg):
|
def log(self, msg):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
|
@ -453,6 +488,16 @@ class AzureRM(object):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def acquire_token_with_username_password(self, authority, resource, username, password, client_id, tenant):
|
||||||
|
authority_uri = authority
|
||||||
|
|
||||||
|
if tenant is not None:
|
||||||
|
authority_uri = authority + '/' + tenant
|
||||||
|
|
||||||
|
context = AuthenticationContext(authority_uri)
|
||||||
|
token_response = context.acquire_token_with_username_password(resource, username, password, client_id)
|
||||||
|
return AADTokenCredentials(token_response)
|
||||||
|
|
||||||
def _register(self, key):
|
def _register(self, key):
|
||||||
try:
|
try:
|
||||||
# We have to perform the one-time registration here. Otherwise, we receive an error the first
|
# We have to perform the one-time registration here. Otherwise, we receive an error the first
|
||||||
|
|
|
@ -84,7 +84,16 @@ To pass Active Directory username/password via the environment, define the follo
|
||||||
|
|
||||||
* AZURE_AD_USER
|
* AZURE_AD_USER
|
||||||
* AZURE_PASSWORD
|
* AZURE_PASSWORD
|
||||||
* AZURE_SUBSCRIPTION_ID
|
|
||||||
|
To pass Active Directory username/password in ADFS via the environment, define the following variables:
|
||||||
|
|
||||||
|
* AZURE_AD_USER
|
||||||
|
* AZURE_PASSWORD
|
||||||
|
* AZURE_CLIENT_ID
|
||||||
|
* AZURE_TENANT
|
||||||
|
* AZURE_ADFS_AUTHORITY_URL
|
||||||
|
|
||||||
|
"AZURE_ADFS_AUTHORITY_URL" is optional. It's necessary only when you have own ADFS authority like https://xxx.com/adfs.
|
||||||
|
|
||||||
Storing in a File
|
Storing in a File
|
||||||
`````````````````
|
`````````````````
|
||||||
|
@ -118,7 +127,16 @@ Or, pass the following parameters for Active Directory username/password:
|
||||||
|
|
||||||
* ad_user
|
* ad_user
|
||||||
* password
|
* password
|
||||||
* subscription_id
|
|
||||||
|
Or, pass the following parameters for ADFS username/pasword:
|
||||||
|
|
||||||
|
* ad_user
|
||||||
|
* password
|
||||||
|
* client_id
|
||||||
|
* tenant
|
||||||
|
* adfs_authority_url
|
||||||
|
|
||||||
|
"adfs_authority_url" is optional. It's necessary only when you have own ADFS authority like https://xxx.com/adfs.
|
||||||
|
|
||||||
|
|
||||||
Other Cloud Environments
|
Other Cloud Environments
|
||||||
|
|
|
@ -35,7 +35,8 @@ AZURE_COMMON_ARGS = dict(
|
||||||
password=dict(type='str', no_log=True),
|
password=dict(type='str', no_log=True),
|
||||||
cloud_environment=dict(type='str', default='AzureCloud'),
|
cloud_environment=dict(type='str', default='AzureCloud'),
|
||||||
cert_validation_mode=dict(type='str', choices=['validate', 'ignore']),
|
cert_validation_mode=dict(type='str', choices=['validate', 'ignore']),
|
||||||
api_profile=dict(type='str', default='latest')
|
api_profile=dict(type='str', default='latest'),
|
||||||
|
adfs_authority_url=dict(type='str', default=None)
|
||||||
# debug=dict(type='bool', default=False),
|
# debug=dict(type='bool', default=False),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@ AZURE_CREDENTIAL_ENV_MAPPING = dict(
|
||||||
password='AZURE_PASSWORD',
|
password='AZURE_PASSWORD',
|
||||||
cloud_environment='AZURE_CLOUD_ENVIRONMENT',
|
cloud_environment='AZURE_CLOUD_ENVIRONMENT',
|
||||||
cert_validation_mode='AZURE_CERT_VALIDATION_MODE',
|
cert_validation_mode='AZURE_CERT_VALIDATION_MODE',
|
||||||
|
adfs_authority_url='AZURE_ADFS_AUTHORITY_URL'
|
||||||
)
|
)
|
||||||
|
|
||||||
# FUTURE: this should come from the SDK or an external location.
|
# FUTURE: this should come from the SDK or an external location.
|
||||||
|
@ -127,6 +129,7 @@ except ImportError as exc:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from msrestazure.azure_active_directory import AADTokenCredentials
|
||||||
from msrestazure.azure_exceptions import CloudError
|
from msrestazure.azure_exceptions import CloudError
|
||||||
from msrestazure.azure_active_directory import MSIAuthentication
|
from msrestazure.azure_active_directory import MSIAuthentication
|
||||||
from msrestazure.tools import resource_id, is_valid_resource_id
|
from msrestazure.tools import resource_id, is_valid_resource_id
|
||||||
|
@ -147,6 +150,7 @@ try:
|
||||||
from azure.mgmt.web import WebSiteManagementClient
|
from azure.mgmt.web import WebSiteManagementClient
|
||||||
from azure.mgmt.containerservice import ContainerServiceClient
|
from azure.mgmt.containerservice import ContainerServiceClient
|
||||||
from azure.storage.cloudstorageaccount import CloudStorageAccount
|
from azure.storage.cloudstorageaccount import CloudStorageAccount
|
||||||
|
from adal.authentication_context import AuthenticationContext
|
||||||
except ImportError as exc:
|
except ImportError as exc:
|
||||||
HAS_AZURE_EXC = exc
|
HAS_AZURE_EXC = exc
|
||||||
HAS_AZURE = False
|
HAS_AZURE = False
|
||||||
|
@ -268,6 +272,8 @@ class AzureRMModuleBase(object):
|
||||||
self._dns_client = None
|
self._dns_client = None
|
||||||
self._web_client = None
|
self._web_client = None
|
||||||
self._containerservice_client = None
|
self._containerservice_client = None
|
||||||
|
self._adfs_authority_url = None
|
||||||
|
self._resource = None
|
||||||
|
|
||||||
self.check_mode = self.module.check_mode
|
self.check_mode = self.module.check_mode
|
||||||
self.api_profile = self.module.params.get('api_profile')
|
self.api_profile = self.module.params.get('api_profile')
|
||||||
|
@ -318,6 +324,17 @@ class AzureRMModuleBase(object):
|
||||||
self.log("setting subscription_id")
|
self.log("setting subscription_id")
|
||||||
self.subscription_id = self.credentials['subscription_id']
|
self.subscription_id = self.credentials['subscription_id']
|
||||||
|
|
||||||
|
# get authentication authority
|
||||||
|
# for adfs, user could pass in authority or not.
|
||||||
|
# for others, use default authority from cloud environment
|
||||||
|
if self.credentials.get('adfs_authority_url') is None:
|
||||||
|
self._adfs_authority_url = self._cloud_environment.endpoints.active_directory
|
||||||
|
else:
|
||||||
|
self._adfs_authority_url = self.credentials.get('adfs_authority_url')
|
||||||
|
|
||||||
|
# get resource from cloud environment
|
||||||
|
self._resource = self._cloud_environment.endpoints.active_directory_resource_id
|
||||||
|
|
||||||
if self.credentials.get('credentials') is not None:
|
if self.credentials.get('credentials') is not None:
|
||||||
# AzureCLI credentials
|
# AzureCLI credentials
|
||||||
self.azure_credentials = self.credentials['credentials']
|
self.azure_credentials = self.credentials['credentials']
|
||||||
|
@ -330,6 +347,19 @@ class AzureRMModuleBase(object):
|
||||||
cloud_environment=self._cloud_environment,
|
cloud_environment=self._cloud_environment,
|
||||||
verify=self._cert_validation_mode == 'validate')
|
verify=self._cert_validation_mode == 'validate')
|
||||||
|
|
||||||
|
elif self.credentials.get('ad_user') is not None and \
|
||||||
|
self.credentials.get('password') is not None and \
|
||||||
|
self.credentials.get('client_id') is not None and \
|
||||||
|
self.credentials.get('tenant') is not None:
|
||||||
|
|
||||||
|
self.azure_credentials = self.acquire_token_with_username_password(
|
||||||
|
self._adfs_authority_url,
|
||||||
|
self._resource,
|
||||||
|
self.credentials['ad_user'],
|
||||||
|
self.credentials['password'],
|
||||||
|
self.credentials['client_id'],
|
||||||
|
self.credentials['tenant'])
|
||||||
|
|
||||||
elif self.credentials.get('ad_user') is not None and self.credentials.get('password') is not None:
|
elif self.credentials.get('ad_user') is not None and self.credentials.get('password') is not None:
|
||||||
tenant = self.credentials.get('tenant')
|
tenant = self.credentials.get('tenant')
|
||||||
if not tenant:
|
if not tenant:
|
||||||
|
@ -342,8 +372,9 @@ class AzureRMModuleBase(object):
|
||||||
verify=self._cert_validation_mode == 'validate')
|
verify=self._cert_validation_mode == 'validate')
|
||||||
else:
|
else:
|
||||||
self.fail("Failed to authenticate with provided credentials. Some attributes were missing. "
|
self.fail("Failed to authenticate with provided credentials. Some attributes were missing. "
|
||||||
"Credentials must include client_id, secret and tenant or ad_user and password or "
|
"Credentials must include client_id, secret and tenant or ad_user and password, or "
|
||||||
"be logged using AzureCLI.")
|
"ad_user, password, client_id, tenant and adfs_authority_url(optional) for ADFS authentication, or "
|
||||||
|
"be logged in using AzureCLI.")
|
||||||
|
|
||||||
# common parameter validation
|
# common parameter validation
|
||||||
if self.module.params.get('tags'):
|
if self.module.params.get('tags'):
|
||||||
|
@ -353,6 +384,17 @@ class AzureRMModuleBase(object):
|
||||||
res = self.exec_module(**self.module.params)
|
res = self.exec_module(**self.module.params)
|
||||||
self.module.exit_json(**res)
|
self.module.exit_json(**res)
|
||||||
|
|
||||||
|
def acquire_token_with_username_password(self, authority, resource, username, password, client_id, tenant):
|
||||||
|
authority_uri = authority
|
||||||
|
|
||||||
|
if tenant is not None:
|
||||||
|
authority_uri = authority + '/' + tenant
|
||||||
|
|
||||||
|
context = AuthenticationContext(authority_uri)
|
||||||
|
token_response = context.acquire_token_with_username_password(resource, username, password, client_id)
|
||||||
|
|
||||||
|
return AADTokenCredentials(token_response)
|
||||||
|
|
||||||
def check_client_version(self, client_type):
|
def check_client_version(self, client_type):
|
||||||
# Ensure Azure modules are at least 2.0.0rc5.
|
# Ensure Azure modules are at least 2.0.0rc5.
|
||||||
package_version = AZURE_PKG_VERSIONS.get(client_type.__name__, None)
|
package_version = AZURE_PKG_VERSIONS.get(client_type.__name__, None)
|
||||||
|
|
|
@ -54,6 +54,12 @@ options:
|
||||||
the C(AZURE_CLOUD_ENVIRONMENT) environment variable.
|
the C(AZURE_CLOUD_ENVIRONMENT) environment variable.
|
||||||
default: AzureCloud
|
default: AzureCloud
|
||||||
version_added: 2.4
|
version_added: 2.4
|
||||||
|
adfs_authority_url:
|
||||||
|
description:
|
||||||
|
- Azure AD authority url. Use when authenticating with Username/password, and has your own ADFS authority.
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
version_added: 2.6
|
||||||
cert_validation_mode:
|
cert_validation_mode:
|
||||||
description:
|
description:
|
||||||
- Controls the certificate validation behavior for Azure endpoints. By default, all modules will validate the server certificate, but
|
- Controls the certificate validation behavior for Azure endpoints. By default, all modules will validate the server certificate, but
|
||||||
|
|
Loading…
Reference in a new issue