Repository URL to install this package:
|
Version:
6.0.0 ▾
|
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2022, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = r"""
---
module: purefa_saml
version_added: '1.12.0'
short_description: Manage FlashArray SAML2 service and identity providers
description:
- Enable or disable FlashArray SAML2 providers
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
name:
description:
- Name of the SAML2 identity provider (IdP)
type: str
required: true
state:
description:
- Define whether the API client should exist or not.
default: present
choices: [ absent, present ]
type: str
url:
description:
- The URL of the identity provider
type: str
array_url:
description:
- The URL of the FlashArray
type: str
metadata_url:
description:
- The URL of the identity provider metadata
type: str
enabled:
description:
- Defines the enabled state of the identity provider
default: false
type: bool
encrypt_asserts:
description:
- If set to true, SAML assertions will be encrypted by the identity provider
default: false
type: bool
sign_request:
description:
- If set to true, SAML requests will be signed by the service provider.
default: false
type: bool
x509_cert:
description:
- The X509 certificate that the service provider uses to verify the SAML
response signature from the identity provider
type: str
decryption_credential:
description:
- The credential used by the service provider to decrypt encrypted SAML assertions from the identity provider
type: str
signing_credential:
description:
- The credential used by the service provider to sign SAML requests
type: str
extends_documentation_fragment:
- purestorage.flasharray.purestorage.fa
"""
EXAMPLES = r"""
- name: Create (disabled) SAML2 SSO with only metadata URL
purestorage.flasharray.purefa_saml:
name: myIDP
array_url: "https://10.10.10.2"
metadata_url: "https://myidp.acme.com/adfs/ls"
x509_cert: "{{lookup('file', 'x509_cert_file') }}"
fa_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
- name: Enable SAML2 SSO
purestorage.flasharray.purefa_saml:
name: myISO
enabled: true
fa_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
- name: Delete SAML2 SSO
purestorage.flasharray.purefa_saml:
state: absent
name: myIDP
fa_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
"""
RETURN = r"""
"""
HAS_PURESTORAGE = True
try:
from pypureclient.flasharray import (
Saml2Sso,
Saml2SsoPost,
Saml2SsoSp,
Saml2SsoIdp,
ReferenceNoId,
)
except ImportError:
HAS_PURESTORAGE = False
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.purestorage.flasharray.plugins.module_utils.purefa import (
get_system,
get_array,
purefa_argument_spec,
)
MIN_REQUIRED_API_VERSION = "2.11"
def delete_saml(module, array):
"""Delete SSO SAML2 IdP"""
changed = True
if not module.check_mode:
try:
array.delete_sso_saml2_idps(names=[module.params["name"]])
except Exception:
module.fail_json(
msg="Failed to delete SAML2 IdP {0}".format(module.params["name"])
)
module.exit_json(changed=changed)
def update_saml(module, array):
"""Update SSO SAML2 IdP"""
changed = False
current_idp = list(array.get_sso_saml2_idps(names=[module.params["name"]]).items)[0]
old_idp = {
"array_url": current_idp.array_url,
"enabled": current_idp.enabled,
"sp_sign_cred": getattr(current_idp.sp.signing_credential, "name", None),
"sp_decrypt_cred": getattr(current_idp.sp.decryption_credential, "name", None),
"id_metadata": current_idp.idp.metadata_url,
"id_url": getattr(current_idp.idp, "url", None),
"id_sign_enabled": current_idp.idp.sign_request_enabled,
"id_encrypt_enabled": current_idp.idp.encrypt_assertion_enabled,
"id_cert": current_idp.idp.verification_certificate,
}
if module.params["url"]:
new_url = module.params["url"]
else:
new_url = old_idp["id_url"]
if module.params["array_url"]:
new_array_url = module.params["array_url"]
else:
new_array_url = old_idp["array_url"]
if module.params["enabled"] != old_idp["enabled"]:
new_enabled = module.params["enabled"]
else:
new_enabled = old_idp["enabled"]
if module.params["sign_request"] != old_idp["id_sign_enabled"]:
new_sign = module.params["sign_request"]
else:
new_sign = old_idp["id_sign_enabled"]
if module.params["encrypt_asserts"] != old_idp["id_encrypt_enabled"]:
new_encrypt = module.params["encrypt_asserts"]
else:
new_encrypt = old_idp["id_encrypt_enabled"]
if module.params["signing_credential"]:
new_sign_cred = module.params["signing_credential"]
else:
new_sign_cred = old_idp["sp_sign_cred"]
if module.params["decryption_credential"]:
new_decrypt_cred = module.params["decryption_credential"]
else:
new_decrypt_cred = old_idp["sp_decrypt_cred"]
if module.params["metadata_url"]:
new_meta_url = module.params["metadata_url"]
else:
new_meta_url = old_idp["id_metadata"]
if module.params["x509_cert"]:
new_cert = module.params["x509_cert"]
else:
new_cert = old_idp["id_cert"]
new_idp = {
"array_url": new_array_url,
"enabled": new_enabled,
"sp_sign_cred": new_sign_cred,
"sp_decrypt_cred": new_decrypt_cred,
"id_metadata": new_meta_url,
"id_sign_enabled": new_sign,
"id_encrypt_enabled": new_encrypt,
"id_url": new_url,
"id_cert": new_cert,
}
if old_idp != new_idp:
changed = True
if not module.check_mode:
sp = Saml2SsoSp(
decryption_credential=ReferenceNoId(name=new_idp["sp_decrypt_cred"]),
signing_credential=ReferenceNoId(name=new_idp["sp_sign_cred"]),
)
idp = Saml2SsoIdp(
url=new_idp["id_url"],
metadata_url=new_idp["id_metadata"],
sign_request_enabled=new_idp["id_sign_enabled"],
encrypt_assertion_enabled=new_idp["id_encrypt_enabled"],
verification_certificate=new_idp["id_cert"],
)
res = array.patch_sso_saml2_idps(
idp=Saml2Sso(
array_url=new_idp["array_url"],
idp=idp,
sp=sp,
enabled=new_idp["enabled"],
),
names=[module.params["name"]],
)
if res.status_code != 200:
module.fail_json(
msg="Failed to update SAML2 IdP {0}. Error: {1}".format(
module.params["name"], res.errors[0].message
)
)
module.exit_json(changed=changed)
def create_saml(module, array):
"""Create SAML2 IdP"""
changed = True
if not module.check_mode:
sp = Saml2SsoSp(
decryption_credential=ReferenceNoId(
name=module.params["decryption_credential"]
),
signing_credential=ReferenceNoId(name=module.params["signing_credential"]),
)
idp = Saml2SsoIdp(
url=module.params["url"],
metadata_url=module.params["metadata_url"],
sign_request_enabled=module.params["sign_request"],
encrypt_assertion_enabled=module.params["encrypt_asserts"],
verification_certificate=module.params["x509_cert"],
)
if not module.check_mode:
res = array.post_sso_saml2_idps(
idp=Saml2SsoPost(array_url=module.params["array_url"], idp=idp, sp=sp),
names=[module.params["name"]],
)
if res.status_code != 200:
module.fail_json(
msg="Failed to create SAML2 Identity Provider {0}. Error message: {1}".format(
module.params["name"], res.errors[0].message
)
)
if module.params["enabled"]:
res = array.patch_sso_saml2_idps(
idp=Saml2Sso(enabled=module.params["enabled"]),
names=[module.params["name"]],
)
if res.status_code != 200:
array.delete_sso_saml2_idps(names=[module.params["name"]])
module.fail_json(
msg="Failed to create SAML2 Identity Provider {0}. Error message: {1}".format(
module.params["name"], res.errors[0].message
)
)
module.exit_json(changed=changed)
def main():
argument_spec = purefa_argument_spec()
argument_spec.update(
dict(
state=dict(type="str", default="present", choices=["absent", "present"]),
name=dict(type="str", required=True),
url=dict(type="str"),
array_url=dict(type="str"),
metadata_url=dict(type="str"),
x509_cert=dict(type="str", no_log=True),
signing_credential=dict(type="str"),
decryption_credential=dict(type="str"),
enabled=dict(type="bool", default=False),
encrypt_asserts=dict(type="bool", default=False),
sign_request=dict(type="bool", default=False),
)
)
required_if = [
["encrypt_asserts", True, ["decryption_credential"]],
["sign_request", True, ["signing_credential"]],
]
module = AnsibleModule(
argument_spec, supports_check_mode=True, required_if=required_if
)
if not HAS_PURESTORAGE:
module.fail_json(msg="py-pure-client sdk is required for this module")
array = get_system(module)
api_version = array._list_available_rest_versions()
if MIN_REQUIRED_API_VERSION not in api_version:
module.fail_json(
msg="FlashArray REST version not supported. "
"Minimum version required: {0}".format(MIN_REQUIRED_API_VERSION)
)
array = get_array(module)
state = module.params["state"]
try:
list(array.get_sso_saml2_idps(names=[module.params["name"]]).items)[0]
exists = True
except AttributeError:
exists = False
if not exists and state == "present":
create_saml(module, array)
elif exists and state == "present":
update_saml(module, array)
elif exists and state == "absent":
delete_saml(module, array)
module.exit_json(changed=False)
if __name__ == "__main__":
main()