Example #1
0
    def generate_data_key(self, name, key_type, context="", nonce="", bits=256, mount_point=DEFAULT_MOUNT_POINT):
        """Generates a new high-entropy key and the value encrypted with the named key.

        Optionally return the plaintext of the key as well. Whether plaintext is returned depends on the path; as a
        result, you can use Vault ACL policies to control whether a user is allowed to retrieve the plaintext value of a
        key. This is useful if you want an untrusted user or operation to generate keys that are then made available to
        trusted users.

        Supported methods:
            POST: /{mount_point}/datakey/{key_type}/{name}. Produces: 200 application/json

        :param name: Specifies the name of the encryption key to use to encrypt the datakey. This is specified as part
            of the URL.
        :type name: str | unicode
        :param key_type: Specifies the type of key to generate. If plaintext, the plaintext key will be returned along
            with the ciphertext. If wrapped, only the ciphertext value will be returned. This is specified as part of
            the URL.
        :type key_type: str | unicode
        :param context: Specifies the key derivation context, provided as a base64-encoded string. This must be provided
            if derivation is enabled.
        :type context: str | unicode
        :param nonce: Specifies a nonce value, provided as base64 encoded. Must be provided if convergent encryption is
            enabled for this key and the key was generated with Vault 0.6.1. Not required for keys created in 0.6.2+.
            The value must be exactly 96 bits (12 bytes) long and the user must ensure that for any given context (and
            thus, any given encryption key) this nonce value is never reused.
        :type nonce: str | unicode
        :param bits: Specifies the number of bits in the desired key. Can be 128, 256, or 512.
        :type bits: int
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The JSON response of the request.
        :rtype: requests.Response
        """
        if key_type not in transit_constants.ALLOWED_DATA_KEY_TYPES:
            error_msg = 'invalid key_type argument provided "{arg}", supported types: "{allowed_types}"'
            raise exceptions.ParamValidationError(error_msg.format(
                arg=key_type,
                allowed_types=', '.join(transit_constants.ALLOWED_DATA_KEY_TYPES),
            ))
        if bits not in transit_constants.ALLOWED_DATA_KEY_BITS:
            error_msg = 'invalid bits argument provided "{arg}", supported values: "{allowed_values}"'
            raise exceptions.ParamValidationError(error_msg.format(
                arg=bits,
                allowed_values=', '.join([str(b) for b in transit_constants.ALLOWED_DATA_KEY_BITS]),
            ))
        params = {
            'context': context,
            'nonce': nonce,
            'bits': bits,
        }
        api_path = '/v1/{mount_point}/datakey/{key_type}/{name}'.format(
            mount_point=mount_point,
            key_type=key_type,
            name=name,
        )
        response = self._adapter.post(
            url=api_path,
            json=params,
        )
        return response.json()
Example #2
0
    def create_or_update_group_by_name(self, name, group_type=None, metadata=None, policies=None, member_group_ids=None,
                                       member_entity_ids=None, mount_point=DEFAULT_MOUNT_POINT):
        """Create or update a group by its name.

        Supported methods:
            POST: /{mount_point}/group/name/{name}. Produces: 200 application/json

        :param name: Name of the group.
        :type name: str | unicode
        :param group_type: Type of the group, internal or external. Defaults to internal.
        :type group_type: str | unicode
        :param metadata: Metadata to be associated with the group.
        :type metadata: dict
        :param policies: Policies to be tied to the group.
        :type policies: str | unicode
        :param member_group_ids: Group IDs to be assigned as group members.
        :type member_group_ids: str | unicode
        :param member_entity_ids: Entity IDs to be assigned as group members.
        :type member_entity_ids: str | unicode
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The response of the request.
        :rtype: requests.Response
        """

        if metadata is not None and not isinstance(metadata, dict):
            error_msg = 'unsupported metadata argument provided "{arg}" ({arg_type}), required type: dict"'
            raise exceptions.ParamValidationError(error_msg.format(
                arg=metadata,
                arg_type=type(metadata),
            ))
        if group_type not in ALLOWED_GROUP_TYPES:
            error_msg = 'unsupported group_type argument provided "{arg}", allowed values: ({allowed_values})'
            raise exceptions.ParamValidationError(error_msg.format(
                arg=group_type,
                allowed_values=ALLOWED_GROUP_TYPES,
            ))
        params = utils.remove_nones({
            'type': group_type,
            'metadata': metadata,
            'policies': policies,
            'member_group_ids': member_group_ids,
            'member_entity_ids': member_entity_ids,
        })
        api_path = utils.format_url(
            '/v1/{mount_point}/group/name/{name}',
            mount_point=mount_point,
            name=name,
        )
        response = self._adapter.post(
            url=api_path,
            json=params,
        )
        return response
Example #3
0
    def hash_data(self,
                  hash_input,
                  algorithm=None,
                  output_format=None,
                  mount_point=DEFAULT_MOUNT_POINT):
        """Return the cryptographic hash of given data using the specified algorithm.

        Supported methods:
            POST: /{mount_point}/hash(/{algorithm}). Produces: 200 application/json

        :param hash_input: Specifies the base64 encoded input data.
        :type hash_input: str | unicode
        :param algorithm: Specifies the hash algorithm to use. This can also be specified as part of the URL.
            Currently-supported algorithms are: sha2-224, sha2-256, sha2-384, sha2-512
        :type algorithm: str | unicode
        :param output_format: Specifies the output encoding. This can be either hex or base64.
        :type output_format: str | unicode
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The JSON response of the request.
        :rtype: requests.Response
        """
        if algorithm is not None and algorithm not in transit_constants.ALLOWED_HASH_DATA_ALGORITHMS:
            error_msg = 'invalid algorithm argument provided "{arg}", supported types: "{allowed_types}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=algorithm,
                    allowed_types=', '.join(
                        transit_constants.ALLOWED_HASH_DATA_ALGORITHMS),
                ))
        if output_format is not None and output_format not in transit_constants.ALLOWED_HASH_DATA_FORMATS:
            error_msg = 'invalid output_format argument provided "{arg}", supported types: "{allowed_types}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=output_format,
                    allowed_types=', '.join(
                        transit_constants.ALLOWED_HASH_DATA_FORMATS),
                ))
        params = {
            'input': hash_input,
        }
        params.update(
            utils.remove_nones({
                'algorithm': algorithm,
                'format': output_format,
            }))
        api_path = utils.format_url('/v1/{mount_point}/hash',
                                    mount_point=mount_point)
        response = self._adapter.post(
            url=api_path,
            json=params,
        )
        return response.json()
Example #4
0
    def configure_identity_integration(self,
                                       iam_alias=None,
                                       ec2_alias=None,
                                       mount_point=AWS_DEFAULT_MOUNT_POINT):
        """Configure the way that Vault interacts with the Identity store.

        The default (as of Vault 1.0.3) is role_id for both values.

        Supported methods:
            POST: /auth/{mount_point}/config/identity Produces: 204 (empty body)

        :param iam_alias: How to generate the identity alias when using the iam auth method. Valid choices are role_id,
            unique_id, and full_arn When role_id is selected, the randomly generated ID of the role is used. When
            unique_id is selected, the IAM Unique ID of the IAM principal (either the user or role) is used as the
            identity alias name. When full_arn is selected, the ARN returned by the sts:GetCallerIdentity call is used
            as the alias name. This is either arn:aws:iam::<account_id>:user/<optional_path/><user_name> or
            arn:aws:sts::<account_id>:assumed-role/<role_name_without_path>/<role_session_name>. Note: if you
            select full_arn and then delete and recreate the IAM role, Vault won't be aware and any identity aliases
            set up for the role name will still be valid
        :type iam_alias: str | unicode
        :param ec2_alias: Configures how to generate the identity alias when using the ec2 auth method. Valid choices
            are role_id, instance_id, and image_id. When role_id is selected, the randomly generated ID of the role is
            used. When instance_id is selected, the instance identifier is used as the identity alias name. When
            image_id is selected, AMI ID of the instance is used as the identity alias name
        :type ec2_alias: str | unicode
        :param mount_point: The path the AWS auth method was mounted on.
        :type mount_point: str | unicode
        :return: The response of the request
        :rtype: request.Response
        """
        if iam_alias is not None and iam_alias not in ALLOWED_IAM_ALIAS_TYPES:
            error_msg = 'invalid iam alias type provided: "{arg}"; supported iam alias types: "{alias_types}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=iam_alias,
                    environments=','.join(ALLOWED_IAM_ALIAS_TYPES)))
        if ec2_alias is not None and ec2_alias not in ALLOWED_EC2_ALIAS_TYPES:
            error_msg = 'invalid ec2 alias type provided: "{arg}"; supported ec2 alias types: "{alias_types}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=ec2_alias,
                    environments=','.join(ALLOWED_EC2_ALIAS_TYPES)))
        params = utils.remove_nones({
            'iam_alias': iam_alias,
            'ec2_alias': ec2_alias,
        })
        api_auth = '/v1/auth/{mount_point}/config/identity'.format(
            mount_point=mount_point)
        return self._adapter.post(
            url=api_auth,
            json=params,
        )
Example #5
0
    def undelete_secret_versions(self,
                                 path,
                                 versions,
                                 mount_point=DEFAULT_MOUNT_POINT):
        """Undelete the data for the provided version and path in the key-value store.

        This restores the data, allowing it to be returned on get requests.

        Supported methods:
            POST: /{mount_point}/undelete/{path}. Produces: 204 (empty body)


        :param path: Specifies the path of the secret to undelete. This is specified as part of the URL.
        :type path: str | unicode
        :param versions: The versions to undelete. The versions will be restored and their data will be returned on
            normal get requests.
        :type versions: list of int
        :param mount_point: The "path" the secret engine was mounted on.
        :type mount_point: str | unicode
        :return: The response of the request.
        :rtype: requests.Response
        """
        if not isinstance(versions, list) or len(versions) == 0:
            error_msg = 'argument to "versions" must be a list containing one or more integers, "{versions}" provided.'.format(
                versions=versions)
            raise exceptions.ParamValidationError(error_msg)
        params = {
            'versions': versions,
        }
        api_path = '/v1/{mount_point}/undelete/{path}'.format(
            mount_point=mount_point, path=path)
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #6
0
    def read_health_status(self, standby_ok=False, active_code=200, standby_code=429, dr_secondary_code=472,
                           performance_standby_code=473, sealed_code=503, uninit_code=501, method='HEAD'):
        """Read the health status of Vault.

        This matches the semantics of a Consul HTTP health check and provides a simple way to monitor the health of a
        Vault instance.


        :param standby_ok: Specifies if being a standby should still return the active status code instead of the
            standby status code. This is useful when Vault is behind a non-configurable load balance that just wants a
            200-level response.
        :type standby_ok: bool
        :param active_code: The status code that should be returned for an active node.
        :type active_code: int
        :param standby_code: Specifies the status code that should be returned for a standby node.
        :type standby_code: int
        :param dr_secondary_code: Specifies the status code that should be returned for a DR secondary node.
        :type dr_secondary_code: int
        :param performance_standby_code: Specifies the status code that should be returned for a performance standby
            node.
        :type performance_standby_code: int
        :param sealed_code: Specifies the status code that should be returned for a sealed node.
        :type sealed_code: int
        :param uninit_code: Specifies the status code that should be returned for a uninitialized node.
        :type uninit_code: int
        :param method: Supported methods:
            HEAD: /sys/health. Produces: 000 (empty body)
            GET: /sys/health. Produces: 000 application/json
        :type method: str | unicode
        :return: The JSON response of the request.
        :rtype: requests.Response
        """
        params = {
            'standby_ok': standby_ok,
            'active_code': active_code,
            'standby_code': standby_code,
            'dr_secondary_code': dr_secondary_code,
            'performance_standby_code': performance_standby_code,
            'sealed_code': sealed_code,
            'uninit_code': uninit_code,
        }

        if method == 'HEAD':
            api_path = utils.format_url('/v1/sys/health')
            response = self._adapter.head(
                url=api_path,
                raise_exception=False,
            )
            return response
        elif method == 'GET':
            api_path = utils.format_url('/v1/sys/health')
            response = self._adapter.get(
                url=api_path,
                json=params,
                raise_exception=False,
            )
            return response.json()
        else:
            error_message = '"method" parameter provided invalid value; HEAD or GET allowed, "{method}" provided'.format(method=method)
            raise exceptions.ParamValidationError(error_message)
Example #7
0
    def create_or_update_role(self,
                              name,
                              policy=None,
                              policies=None,
                              token_type=None,
                              local=None,
                              ttl=None,
                              max_ttl=None,
                              mount_point=DEFAULT_MOUNT_POINT):
        """This endpoint creates or updates the Consul role definition.
        If the role does not exist, it will be created.
        If the role already exists, it will receive updated attributes.

        :param name: Specifies the name of an existing role against which to create this Consul credential.
        :type name: str | unicode
        :param token_type:  Specifies the type of token to create when using this role.
        Valid values are "client" or "management".
        :type token_type: str | unicode
        :param policy: Specifies the base64 encoded ACL policy.
        The ACL format can be found in the Consul ACL documentation (https://www.consul.io/docs/internals/acl.html).
        This is required unless the token_type is management.
        :type policy: str | unicode
        :param policies: The list of policies to assign to the generated token.
        This is only available in Consul 1.4 and greater.
        :type policies: list
        :param local: Indicates that the token should not be replicated globally
        and instead be local to the current datacenter. Only available in Consul 1.4 and greater.
        :type local: bool
        :param ttl: Specifies the TTL for this role.
        This is provided as a string duration with a time suffix like "30s" or "1h" or as seconds.
        If not provided, the default Vault TTL is used.
        :type ttl: str | unicode
        :param max_ttl: Specifies the max TTL for this role.
        This is provided as a string duration with a time suffix like "30s" or "1h" or as seconds.
        If not provided, the default Vault Max TTL is used.
        :type max_ttl: str | unicode
        :param mount_point: Specifies the place where the secrets engine will be accessible (default: consul).
        :type mount_point: str | unicode
        :return: The response of the request.
        :rtype: requests.Response
        """
        api_path = utils.format_url("/v1/{}/roles/{}", mount_point, name)

        if not policy and token_type != "management":
            error_msg = 'policy must be specified unless token_type is management'
            raise exceptions.ParamValidationError(error_msg)

        params = utils.remove_nones({
            "token_type": token_type,
            "policy": policy,
            "policies": policies,
            "local": local,
            "ttl": ttl,
            "max_ttl": max_ttl
        })

        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #8
0
    def delete_secret_versions(self, path, versions, mount_point=DEFAULT_MOUNT_POINT):
        """Issue a soft delete of the specified versions of the secret.

        This marks the versions as deleted and will stop them from being returned from reads,
        but the underlying data will not be removed. A delete can be undone using the
        undelete path.

        Supported methods:
            POST: /{mount_point}/delete/{path}. Produces: 204 (empty body)


        :param path: Specifies the path of the secret to delete. This is specified as part of the URL.
        :type path: str | unicode
        :param versions: The versions to be deleted. The versioned data will not be deleted, but it will no longer be
            returned in normal get requests.
        :type versions: int
        :param mount_point: The "path" the secret engine was mounted on.
        :type mount_point: str | unicode
        :return: The response of the request.
        :rtype: requests.Response
        """
        if not isinstance(versions, list) or len(versions) == 0:
            error_msg = 'argument to "versions" must be a list containing one or more integers, "{versions}" provided.'.format(
                versions=versions
            )
            raise exceptions.ParamValidationError(error_msg)
        params = {
            'versions': versions,
        }
        api_path = utils.format_url('/v1/{mount_point}/delete/{path}', mount_point=mount_point, path=path)
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #9
0
    def list_groups_by_name(self,
                            method='LIST',
                            mount_point=DEFAULT_MOUNT_POINT):
        """List available groups by their names.

        :param method: Supported methods:
            LIST: /{mount_point}/group/name. Produces: 200 application/json
            GET: /{mount_point}/group/name?list=true. Produces: 200 application/json
        :type method: str | unicode
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The JSON response of the request.
        :rtype: dict
        """

        if method == 'LIST':
            api_path = '/v1/{mount_point}/group/name'.format(
                mount_point=mount_point)
            response = self._adapter.list(url=api_path, )

        elif method == 'GET':
            api_path = '/v1/{mount_point}/group/name?list-true'.format(
                mount_point=mount_point)
            response = self._adapter.list(url=api_path, )
        else:
            error_message = '"method" parameter provided invalid value; LIST or GET allowed, "{method}" provided'.format(
                method=method)
            raise exceptions.ParamValidationError(error_message)

        return response.json()
Example #10
0
    def list_entity_aliases(self,
                            method='LIST',
                            mount_point=DEFAULT_MOUNT_POINT):
        """List available entity aliases by their identifiers.

        :param method: Supported methods:
            LIST: /{mount_point}/entity-alias/id. Produces: 200 application/json
            GET: /{mount_point}/entity-alias/id?list=true. Produces: 200 application/json
        :type method: str | unicode
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The the JSON response of the request.
        :rtype: dict
        """

        if method == 'LIST':
            api_path = utils.format_url('/v1/{mount_point}/entity-alias/id',
                                        mount_point=mount_point)
            response = self._adapter.list(url=api_path, )

        elif method == 'GET':
            api_path = utils.format_url(
                '/v1/{mount_point}/entity-alias/id?list=true',
                mount_point=mount_point)
            response = self._adapter.get(url=api_path, )
        else:
            error_message = '"method" parameter provided invalid value; LIST or GET allowed, "{method}" provided'.format(
                method=method)
            raise exceptions.ParamValidationError(error_message)

        return response
Example #11
0
    def destroy_secret_versions(self, path, versions, mount_point=DEFAULT_MOUNT_POINT):
        """Permanently remove the specified version data and numbers for the provided path from the key-value store.

        Supported methods:
            POST: /{mount_point}/destroy/{path}. Produces: 204 (empty body)


        :param path: Specifies the path of the secret to destroy.
            This is specified as part of the URL.
        :type path: str | unicode
        :param versions: The versions to destroy. Their data will be
            permanently deleted.
        :type versions: list of int
        :param mount_point: The "path" the secret engine was mounted on.
        :type mount_point: str | unicode
        :return: The response of the request.
        :rtype: requests.Response
        """
        if not isinstance(versions, list) or len(versions) == 0:
            error_msg = 'argument to "versions" must be a list containing one or more integers, "{versions}" provided.'.format(
                versions=versions
            )
            raise exceptions.ParamValidationError(error_msg)
        params = {
            'versions': versions,
        }
        api_path = utils.format_url('/v1/{mount_point}/destroy/{path}', mount_point=mount_point, path=path)
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #12
0
    def update_metadata(self, path, max_versions=None, cas_required=None, mount_point=DEFAULT_MOUNT_POINT):
        """Updates the max_versions of cas_required setting on an existing path.

        Supported methods:
            POST: /{mount_point}/metadata/{path}. Produces: 204 (empty body)


        :param path: Path
        :type path: str | unicode
        :param max_versions: The number of versions to keep per key. If not set, the backend's configured max version is
            used. Once a key has more than the configured allowed versions the oldest version will be permanently
            deleted.
        :type max_versions: int
        :param cas_required: If true the key will require the cas parameter to be set on all write requests. If false,
            the backend's configuration will be used.
        :type cas_required: bool
        :param mount_point: The "path" the secret engine was mounted on.
        :type mount_point: str | unicode
        :return: The response of the request.
        :rtype: requests.Response
        """
        params = {}
        if max_versions is not None:
            params['max_versions'] = max_versions
        if cas_required is not None:
            if not isinstance(cas_required, bool):
                error_msg = 'bool expected for cas_required param, {type} received'.format(type=type(cas_required))
                raise exceptions.ParamValidationError(error_msg)
            params['cas_required'] = cas_required
        api_path = utils.format_url('/v1/{mount_point}/metadata/{path}', mount_point=mount_point, path=path)
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #13
0
    def configure(self,
                  host,
                  secret,
                  port=None,
                  unregistered_user_policies=None,
                  dial_timeout=None,
                  nas_port=None,
                  mount_point=DEFAULT_MOUNT_POINT):
        """
        Configure the RADIUS auth method.

        Supported methods:
            POST: /auth/{mount_point}/config. Produces: 204 (empty body)

        :param host: The RADIUS server to connect to. Examples: radius.myorg.com, 127.0.0.1
        :type host: str | unicode
        :param secret: The RADIUS shared secret.
        :type secret: str | unicode
        :param port: The UDP port where the RADIUS server is listening on. Defaults is 1812.
        :type port: int
        :param unregistered_user_policies: A comma-separated list of policies to be granted to unregistered users.
        :type unregistered_user_policies: list
        :param dial_timeout: Number of second to wait for a backend connection before timing out. Default is 10.
        :type dial_timeout: int
        :param nas_port: The NAS-Port attribute of the RADIUS request. Defaults is 10.
        :type nas_port: int
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The response of the configure request.
        :rtype: requests.Response
        """
        params = {
            'host': host,
            'secret': secret,
        }
        params.update(
            utils.remove_nones({
                'port': port,
                'dial_timeout': dial_timeout,
                'nas_port': nas_port,
            }))
        # Fill out params dictionary with any optional parameters provided
        if unregistered_user_policies is not None:
            if not isinstance(unregistered_user_policies, list):
                error_msg = (
                    '"unregistered_user_policies" argument must be an instance of list or None, '
                    '"{unregistered_user_policies}" provided.').format(
                        unregistered_user_policies=type(
                            unregistered_user_policies))
                raise exceptions.ParamValidationError(error_msg)

            params['unregistered_user_policies'] = ','.join(
                unregistered_user_policies)

        api_path = utils.format_url('/v1/auth/{mount_point}/config',
                                    mount_point=mount_point)
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #14
0
def validate_pem_format(param_name, param_argument):
    """Validate that an argument is a PEM-formatted public key or certificate

    :param param_name: The name of the parameter being validate. Used in any resulting exception messages.
    :type param_name: str | unicode
    :param param_argument: The argument to validate
    :type param_argument: str | unicode
    :return: True if the argument is validate False otherwise
    :rtype: bool
    """
    def _check_pem(arg):
        arg = arg.strip()
        if not arg.startswith('-----BEGIN CERTIFICATE-----') \
                or not arg.endswith('-----END CERTIFICATE-----'):
            return False
        return True

    if isinstance(param_argument, str):
        param_argument = [param_argument]

    if not isinstance(param_argument, list) or not all(
            _check_pem(p) for p in param_argument):
        error_msg = 'unsupported {param} public key / certificate format, required type: PEM'
        raise exceptions.ParamValidationError(
            error_msg.format(param=param_name))
Example #15
0
    def generate_credentials(self,
                             name,
                             role_arn=None,
                             ttl="3600s",
                             endpoint='creds',
                             mount_point=DEFAULT_MOUNT_POINT):
        """Generates credential based on the named role.

        This role must be created before queried.

        The /aws/creds and /aws/sts endpoints are almost identical. The exception is when retrieving credentials for a
        role that was specified with the legacy arn or policy parameter. In this case, credentials retrieved through
        /aws/sts must be of either the assumed_role or federation_token types, and credentials retrieved through
        /aws/creds must be of the iam_user type.

        :param name: Specifies the name of the role to generate credentials against. This is part of the request URL.
        :type name: str | unicode
        :param role_arn: The ARN of the role to assume if credential_type on the Vault role is assumed_role. Must match
            one of the allowed role ARNs in the Vault role. Optional if the Vault role only allows a single AWS role
            ARN; required otherwise.
        :type role_arn: str | unicode
        :param ttl: Specifies the TTL for the use of the STS token. This is specified as a string with a duration
            suffix. Valid only when credential_type is assumed_role or federation_token. When not specified, the default
            sts_ttl set for the role will be used. If that is also not set, then the default value of 3600s will be
            used. AWS places limits on the maximum TTL allowed. See the AWS documentation on the DurationSeconds
            parameter for AssumeRole (for assumed_role credential types) and GetFederationToken (for federation_token
            credential types) for more details.
        :type ttl: str | unicode
        :param endpoint: Supported endpoints:
            GET: /{mount_point}/creds/{name}. Produces: 200 application/json
            GET: /{mount_point}/sts/{name}. Produces: 200 application/json
        :type endpoint: str | unicode
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The JSON response of the request.
        :rtype: dict
        """
        if endpoint not in ALLOWED_CREDS_ENDPOINTS:
            error_msg = 'invalid endpoint argument provided "{arg}", supported types: "{allowed_endpoints}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=endpoint,
                    allowed_endpoints=', '.join(ALLOWED_CREDS_ENDPOINTS),
                ))
        params = {
            'name': name,
            'role_arn': role_arn,
            'ttl': ttl,
        }
        api_path = '/v1/{mount_point}/{endpoint}/{name}'.format(
            mount_point=mount_point,
            endpoint=endpoint,
            name=name,
        )

        response = self._adapter.post(
            url=api_path,
            json=params,
        )
        return response.json()
Example #16
0
    def update_key_configuration(self,
                                 name,
                                 min_decryption_version=0,
                                 min_encryption_version=0,
                                 deletion_allowed=False,
                                 exportable=False,
                                 allow_plaintext_backup=False,
                                 mount_point=DEFAULT_MOUNT_POINT):
        """Tune configuration values for a given key.

        These values are returned during a read operation on the named key.

        Supported methods:
            POST: /{mount_point}/keys/{name}/config. Produces: 204 (empty body)

        :param name: Specifies the name of the encryption key to update configuration for.
        :type name: str | unicode
        :param min_decryption_version: Specifies the minimum version of ciphertext allowed to be decrypted. Adjusting
            this as part of a key rotation policy can prevent old copies of ciphertext from being decrypted, should they
            fall into the wrong hands. For signatures, this value controls the minimum version of signature that can be
            verified against. For HMACs, this controls the minimum version of a key allowed to be used as the key for
            verification.
        :type min_decryption_version: int
        :param min_encryption_version: Specifies the minimum version of the key that can be used to encrypt plaintext,
            sign payloads, or generate HMACs. Must be 0 (which will use the latest version) or a value greater or equal
            to min_decryption_version.
        :type min_encryption_version: int
        :param deletion_allowed: Specifies if the key is allowed to be deleted.
        :type deletion_allowed: bool
        :param exportable: Enables keys to be exportable. This allows for all the valid keys in the key ring to be
            exported. Once set, this cannot be disabled.
        :type exportable: bool
        :param allow_plaintext_backup: If set, enables taking backup of named key in the plaintext format. Once set,
            this cannot be disabled.
        :type allow_plaintext_backup: bool
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The response of the request.
        :rtype: requests.Response
        """
        if min_encryption_version != 0 and min_encryption_version <= min_decryption_version:
            raise exceptions.ParamValidationError(
                'min_encryption_version must be 0 or > min_decryption_version')
        params = {
            'min_decryption_version': min_decryption_version,
            'min_encryption_version': min_encryption_version,
            'deletion_allowed': deletion_allowed,
            'exportable': exportable,
            'allow_plaintext_backup': allow_plaintext_backup,
        }
        api_path = utils.format_url(
            '/v1/{mount_point}/keys/{name}/config',
            mount_point=mount_point,
            name=name,
        )
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #17
0
    def create_or_update_roleset(self,
                                 name,
                                 project,
                                 bindings,
                                 secret_type='access_token',
                                 token_scopes=None,
                                 mount_point=DEFAULT_MOUNT_POINT):
        """Create a roleset or update an existing roleset.

        See roleset docs for the GCP secrets backend to learn more about what happens when you create or update a
            roleset.

        Supported methods:
            POST: /{mount_point}/roleset/{name}. Produces: 204 (empty body)

        :param name: Name of the role. Cannot be updated.
        :type name: str | unicode
        :param project: Name of the GCP project that this roleset's service account will belong to. Cannot be updated.
        :type project: str | unicode
        :param bindings: Bindings configuration string (expects HCL or JSON format in raw or base64-encoded string)
        :type bindings: str | unicode
        :param secret_type: Cannot be updated.
        :type secret_type: str | unicode
        :param token_scopes: List of OAuth scopes to assign to access_token secrets generated under this role set
            (access_token role sets only)
        :type token_scopes: list[str]
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The response of the request.
        :rtype: requests.Response
        """
        if secret_type not in ALLOWED_SECRETS_TYPES:
            error_msg = 'unsupported secret_type argument provided "{arg}", supported types: "{secret_type}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=secret_type,
                    secret_type=','.join(ALLOWED_SECRETS_TYPES),
                ))

        if isinstance(bindings, dict):
            bindings = json.dumps(bindings).replace(' ', '')
            logging.debug('bindings: %s' % bindings)

        params = {
            'project': project,
            'bindings': bindings,
            'secret_type': secret_type,
            'token_scopes': token_scopes,
        }
        api_path = utils.format_url(
            '/v1/{mount_point}/roleset/{name}',
            mount_point=mount_point,
            name=name,
        )
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #18
0
    def generate_hmac(self,
                      name,
                      hash_input,
                      key_version=None,
                      algorithm=None,
                      mount_point=DEFAULT_MOUNT_POINT):
        """Return the digest of given data using the specified hash algorithm and the named key.

        The key can be of any type supported by transit; the raw key will be marshaled into bytes to be used for the
        HMAC function. If the key is of a type that supports rotation, the latest (current) version will be used.

        Supported methods:
            POST: /{mount_point}/hmac/{name}(/{algorithm}). Produces: 200 application/json

        :param name: Specifies the name of the encryption key to generate hmac against. This is specified as part of the
            URL.
        :type name: str | unicode
        :param hash_input: Specifies the base64 encoded input data.
        :type input: str | unicode
        :param key_version: Specifies the version of the key to use for the operation. If not set, uses the latest
            version. Must be greater than or equal to the key's min_encryption_version, if set.
        :type key_version: int
        :param algorithm: Specifies the hash algorithm to use. This can also be specified as part of the URL.
            Currently-supported algorithms are: sha2-224, sha2-256, sha2-384, sha2-512
        :type algorithm: str | unicode
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The JSON response of the request.
        :rtype: requests.Response
        """
        if algorithm is not None and algorithm not in transit_constants.ALLOWED_HASH_DATA_ALGORITHMS:
            error_msg = 'invalid algorithm argument provided "{arg}", supported types: "{allowed_types}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=algorithm,
                    allowed_types=', '.join(
                        transit_constants.ALLOWED_HASH_DATA_ALGORITHMS),
                ))
        params = {
            'input': hash_input,
        }
        params.update(
            utils.remove_nones({
                'key_version': key_version,
                'algorithm': algorithm,
            }))
        api_path = utils.format_url(
            '/v1/{mount_point}/hmac/{name}',
            mount_point=mount_point,
            name=name,
        )
        resposne = self._adapter.post(
            url=api_path,
            json=params,
        )
        return resposne.json()
Example #19
0
    def update_entity(self,
                      entity_id,
                      name=None,
                      metadata=None,
                      policies=None,
                      disabled=False,
                      mount_point=DEFAULT_MOUNT_POINT):
        """Update an existing entity.

        Supported methods:
            POST: /{mount_point}/entity/id/{id}. Produces: 200 application/json

        :param entity_id: Identifier of the entity.
        :type entity_id: str | unicode
        :param name: Name of the entity.
        :type name: str | unicode
        :param metadata: Metadata to be associated with the entity.
        :type metadata: dict
        :param policies: Policies to be tied to the entity.
        :type policies: str | unicode
        :param disabled: Whether the entity is disabled. Disabled entities' associated tokens cannot be used, but
            are not revoked.
        :type disabled: bool
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The JSON response where available, otherwise the generic response object, of the request.
        :rtype: dict | requests.Response
        """
        if metadata is None:
            metadata = {}
        if not isinstance(metadata, dict):
            error_msg = 'unsupported metadata argument provided "{arg}" ({arg_type}), required type: dict"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=metadata,
                    arg_type=type(metadata),
                ))
        params = {
            'name': name,
            'metadata': metadata,
            'policies': policies,
            'disabled': disabled,
        }
        api_path = '/v1/{mount_point}/entity/id/{id}'.format(
            mount_point=mount_point,
            id=entity_id,
        )
        response = self._adapter.post(
            url=api_path,
            json=params,
        )
        if response.status_code == 204:
            return response
        else:
            return response.json()
    def create_custom_secret_id(self,
                                role_name,
                                secret_id,
                                metadata=None,
                                cidr_list=None,
                                token_bound_cidrs=None,
                                mount_point=DEFAULT_MOUNT_POINT):
        """
        Generates and issues a new Secret ID on a role in the auth method.

        Supported methods:
            POST: /auth/{mount_point}/role/{role_name}/custom-secret-id. Produces: 200 application/json

        :param role_name: The name for the role.
        :type role_name: str | unicode
        :param secret_id: The Secret ID to read.
        :type secret_id: str | unicode
        :param metadata: Metadata to be tied to the Secret ID.
        :type metadata: dict
        :param cidr_list: Blocks of IP addresses which can perform login operations.
        :type cidr_list: list
        :param token_bound_cidrs: Blocks of IP addresses which can authenticate successfully.
        :type token_bound_cidrs: list
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The JSON response of the read_role_id request.
        :rtype: dict
        """
        if metadata is not None and not isinstance(metadata, dict):
            error_msg = 'unsupported metadata argument provided "{arg}" ({arg_type}), required type: dict"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=metadata,
                    arg_type=type(metadata),
                ))

        params = {'secret_id': secret_id, 'metadata': metadata}

        list_of_strings_params = {
            'cidr_list': cidr_list,
            'token_bound_cidrs': token_bound_cidrs
        }
        for param_name, param_argument in list_of_strings_params.items():
            validate_list_of_strings_param(
                param_name=param_name,
                param_argument=param_argument,
            )
            if param_argument is not None:
                params[param_name] = list_to_comma_delimited(param_argument)

        api_path = utils.format_url(
            '/v1/auth/{mount_point}/role/{role_name}/custom-secret-id',
            mount_point=mount_point,
            role_name=role_name)
        return self._adapter.post(url=api_path, json=params)
Example #21
0
    def create_or_update_secret(self, path, secret, method=None, mount_point=DEFAULT_MOUNT_POINT):
        """Store a secret at the specified location.

        If the value does not yet exist, the calling token must have an ACL policy granting the create capability.
        If the value already exists, the calling token must have an ACL policy granting the update capability.

        Supported methods:
            POST: /{mount_point}/{path}. Produces: 204 (empty body)
            PUT: /{mount_point}/{path}. Produces: 204 (empty body)

        :param path: Specifies the path of the secrets to create/update. This is specified as part of the URL.
        :type path: str | unicode
        :param secret: Specifies keys, paired with associated values, to be held at the given location. Multiple
            key/value pairs can be specified, and all will be returned on a read operation. A key called ttl will
            trigger some special behavior. See the Vault KV secrets engine documentation for details.
        :type secret: dict
        :param method: Optional parameter to explicitly request a POST (create) or PUT (update) request to the selected
            kv secret engine. If no argument is provided for this parameter, hvac attempts to intelligently determine
            which method is appropriate.
        :type method: str | unicode
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The response of the create_or_update_secret request.
        :rtype: requests.Response
        """
        if method is None:
            # If no method was selected by the caller, use the result of a `read_secret()` call to determine if we need
            # to perform an update (PUT) or creation (POST) request.
            try:
                self.read_secret(
                    path=path,
                    mount_point=mount_point,
                )
                method = 'PUT'
            except exceptions.InvalidPath:
                method = 'POST'

        if method == 'POST':
            api_path = '/v1/{mount_point}/{path}'.format(mount_point=mount_point, path=path)
            return self._adapter.post(
                url=api_path,
                json=secret,
            )

        elif method == 'PUT':
            api_path = '/v1/{mount_point}/{path}'.format(mount_point=mount_point, path=path)
            return self._adapter.post(
                url=api_path,
                json=secret,
            )

        else:
            error_message = '"method" parameter provided invalid value; POST or PUT allowed, "{method}" provided'.format(method=method)
            raise exceptions.ParamValidationError(error_message)
Example #22
0
    def configure(self,
                  tenant_id,
                  resource,
                  environment=None,
                  client_id=None,
                  client_secret=None,
                  mount_point=DEFAULT_MOUNT_POINT):
        """Configure the credentials required for the plugin to perform API calls to Azure.

        These credentials will be used to query the metadata about the virtual machine.

        Supported methods:
            POST: /auth/{mount_point}/config. Produces: 204 (empty body)

        :param tenant_id: The tenant id for the Azure Active Directory organization.
        :type tenant_id: str | unicode
        :param resource: The configured URL for the application registered in Azure Active Directory.
        :type resource: str | unicode
        :param environment: The Azure cloud environment. Valid values: AzurePublicCloud, AzureUSGovernmentCloud,
            AzureChinaCloud, AzureGermanCloud.
        :type environment: str | unicode
        :param client_id: The client id for credentials to query the Azure APIs.  Currently read permissions to query
            compute resources are required.
        :type client_id: str | unicode
        :param client_secret: The client secret for credentials to query the Azure APIs.
        :type client_secret: str | unicode
        :param mount_point: The "path" the azure auth method was mounted on.
        :type mount_point: str | unicode
        :return: The response of the request.
        :rtype: requests.Response
        """
        if environment is not None and environment not in VALID_ENVIRONMENTS:
            error_msg = 'invalid environment argument provided: "{arg}"; supported environments: "{environments}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=environment,
                    environments=','.join(VALID_ENVIRONMENTS),
                ))
        params = {
            'tenant_id': tenant_id,
            'resource': resource,
        }
        params.update(
            utils.remove_nones({
                'environment': environment,
                'client_id': client_id,
                'client_secret': client_secret,
            }))
        api_path = utils.format_url('/v1/auth/{mount_point}/config',
                                    mount_point=mount_point)
        return self._adapter.post(
            url=api_path,
            json=params,
        )
    def configure(self,
                  subscription_id,
                  tenant_id,
                  client_id=None,
                  client_secret=None,
                  environment=None,
                  mount_point=DEFAULT_MOUNT_POINT):
        """Configure the credentials required for the plugin to perform API calls to Azure.

        These credentials will be used to query roles and create/delete service principals. Environment variables will
        override any parameters set in the config.

        Supported methods:
            POST: /{mount_point}/config. Produces: 204 (empty body)


        :param subscription_id: The subscription id for the Azure Active Directory
        :type subscription_id: str | unicode
        :param tenant_id: The tenant id for the Azure Active Directory.
        :type tenant_id: str | unicode
        :param client_id: The OAuth2 client id to connect to Azure.
        :type client_id: str | unicode
        :param client_secret: The OAuth2 client secret to connect to Azure.
        :type client_secret: str | unicode
        :param environment: The Azure environment. If not specified, Vault will use Azure Public Cloud.
        :type environment: str | unicode
        :param mount_point: The OAuth2 client secret to connect to Azure.
        :type mount_point: str | unicode
        :return: The response of the request.
        :rtype: requests.Response
        """
        if environment is not None and environment not in VALID_ENVIRONMENTS:
            error_msg = 'invalid environment argument provided "{arg}", supported environments: "{environments}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=environment,
                    environments=','.join(VALID_ENVIRONMENTS),
                ))
        params = {
            'subscription_id': subscription_id,
            'tenant_id': tenant_id,
        }
        params.update(
            utils.remove_nones({
                'client_id': client_id,
                'client_secret': client_secret,
                'environment': environment,
            }))
        api_path = utils.format_url('/v1/{mount_point}/config',
                                    mount_point=mount_point)
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #24
0
    def create_or_update_user(self,
                              username,
                              policies=None,
                              groups=None,
                              mount_point=DEFAULT_MOUNT_POINT):
        """
        Create or update LDAP users policies and group associations.

        Supported methods:
            POST: /auth/{mount_point}/users/{username}. Produces: 204 (empty body)


        :param username: The username of the LDAP user
        :type username: str | unicode
        :param policies: List of policies associated with the user. This parameter is transformed to a comma-delimited
            string before being passed to Vault.
        :type policies: str | unicode
        :param groups: List of groups associated with the user. This parameter is transformed to a comma-delimited
            string before being passed to Vault.
        :type groups: str | unicode
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The response of the create_or_update_user request.
        :rtype: requests.Response
        """
        list_required_params = {
            'policies': policies,
            'groups': groups,
        }
        for param_name, param_arg in list_required_params.items():
            if param_arg is not None and not isinstance(param_arg, list):
                error_msg = '"{param_name}" argument must be an instance of list or None, "{param_type}" provided.'.format(
                    param_name=param_name,
                    param_type=type(param_arg),
                )
                raise exceptions.ParamValidationError(error_msg)

        params = {}
        if policies is not None:
            params['policies'] = ','.join(policies)
        if groups is not None:
            params['groups'] = ','.join(groups)
        api_path = utils.format_url(
            '/v1/auth/{mount_point}/users/{username}',
            mount_point=mount_point,
            username=username,
        )
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #25
0
    def create_or_update_entity(self,
                                name,
                                entity_id=None,
                                metadata=None,
                                policies=None,
                                disabled=None,
                                mount_point=DEFAULT_MOUNT_POINT):
        """Create or update an Entity.

        Supported methods:
            POST: /{mount_point}/entity. Produces: 200 application/json

        :param entity_id: ID of the entity. If set, updates the corresponding existing entity.
        :type entity_id: str | unicode
        :param name: Name of the entity.
        :type name: str | unicode
        :param metadata: Metadata to be associated with the entity.
        :type metadata: dict
        :param policies: Policies to be tied to the entity.
        :type policies: str | unicode
        :param disabled: Whether the entity is disabled. Disabled entities' associated tokens cannot be used, but are
            not revoked.
        :type disabled: bool
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The JSON response for creates, the generic response object for updates, of the request.
        :rtype: dict | requests.Response
        """
        if metadata is not None and not isinstance(metadata, dict):
            error_msg = 'unsupported metadata argument provided "{arg}" ({arg_type}), required type: dict"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=metadata,
                    arg_type=type(metadata),
                ))
        params = utils.remove_nones({
            'id': entity_id,
            'name': name,
            'metadata': metadata,
            'policies': policies,
            'disabled': disabled,
        })
        api_path = utils.format_url('/v1/{mount_point}/entity',
                                    mount_point=mount_point)
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #26
0
    def export_key(self,
                   name,
                   key_type,
                   version=None,
                   mount_point=DEFAULT_MOUNT_POINT):
        """Return the named key.

        The keys object shows the value of the key for each version. If version is specified, the specific version will
        be returned. If latest is provided as the version, the current key will be provided. Depending on the type of
        key, different information may be returned. The key must be exportable to support this operation and the version
        must still be valid.

        Supported methods:
            GET: /{mount_point}/export/{key_type}/{name}(/{version}). Produces: 200 application/json

        :param name: Specifies the name of the key to read information about. This is specified as part of the URL.
        :type name: str | unicode
        :param key_type: Specifies the type of the key to export. This is specified as part of the URL. Valid values are:
            encryption-key
            signing-key
            hmac-key
        :type key_type: str | unicode
        :param version: Specifies the version of the key to read. If omitted, all versions of the key will be returned.
            If the version is set to latest, the current key will be returned.
        :type version: str | unicode
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The JSON response of the request.
        :rtype: requests.Response
        """
        if key_type not in transit_constants.ALLOWED_EXPORT_KEY_TYPES:
            error_msg = 'invalid key_type argument provided "{arg}", supported types: "{allowed_types}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=key_type,
                    allowed_types=', '.join(
                        transit_constants.ALLOWED_EXPORT_KEY_TYPES),
                ))
        api_path = utils.format_url(
            '/v1/{mount_point}/export/{key_type}/{name}',
            mount_point=mount_point,
            key_type=key_type,
            name=name,
        )
        if version is not None:
            api_path = self._adapter.urljoin(api_path, version)
        response = self._adapter.get(url=api_path, )
        return response.json()
Example #27
0
    def create_or_update_entity_by_name(self, name, metadata=None, policies=None, disabled=None,
                                        mount_point=DEFAULT_MOUNT_POINT):
        """Create or update an entity by a given name.

        Supported methods:
            POST: /{mount_point}/entity/name/{name}. Produces: 200 application/json

        :param name: Name of the entity.
        :type name: str | unicode
        :param metadata: Metadata to be associated with the entity.
        :type metadata: dict
        :param policies: Policies to be tied to the entity.
        :type policies: str | unicode
        :param disabled: Whether the entity is disabled. Disabled
            entities' associated tokens cannot be used, but are not revoked.
        :type disabled: bool
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The JSON response for creates, the generic response of the request for updates.
        :rtype: requests.Response | dict
        """
        if metadata is not None and not isinstance(metadata, dict):
            error_msg = 'unsupported metadata argument provided "{arg}" ({arg_type}), required type: dict"'
            raise exceptions.ParamValidationError(error_msg.format(
                arg=metadata,
                arg_type=type(metadata),
            ))
        params = utils.remove_nones({
            'metadata': metadata,
            'policies': policies,
            'disabled': disabled,
        })
        api_path = utils.format_url(
            '/v1/{mount_point}/entity/name/{name}',
            mount_point=mount_point,
            name=name,
        )
        response = self._adapter.post(
            url=api_path,
            json=params,
        )
        if response.status_code == 204:
            return response
        else:
            return response.json()
Example #28
0
    def map_user(self,
                 user_name,
                 policies=None,
                 mount_point=DEFAULT_MOUNT_POINT):
        """Map a list of policies to a specific GitHub user exists in the configured organization.

        Supported methods:
            POST: /auth/{mount_point}/map/users/{user_name}. Produces: 204 (empty body)


        :param user_name: GitHub user name
        :type user_name: str | unicode
        :param policies: Comma separated list of policies to assign
        :type policies: List[str]
        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :return: The response of the map_github_users request.
        :rtype: requests.Response
        """
        # First, perform parameter validation.
        if policies is None:
            policies = []
        if not isinstance(policies, list) or not all(
            [isinstance(p, str) for p in policies]):
            error_msg = 'unsupported policies argument provided "{arg}" ({arg_type}), required type: List[str]"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    arg=policies,
                    arg_type=type(policies),
                ))

        # Then, perform request.
        params = {
            'value': ','.join(policies),
        }
        api_path = utils.format_url(
            '/v1/auth/{mount_point}/map/users/{user_name}',
            mount_point=mount_point,
            user_name=user_name,
        )
        return self._adapter.post(
            url=api_path,
            json=params,
        )
Example #29
0
def validate_list_of_strings_param(param_name, param_argument):
    """Validate that an argument is a list of strings.

    :param param_name: The name of the parameter being validated. Used in any resulting exception messages.
    :type param_name: str | unicode
    :param param_argument: The argument to validate.
    :type param_argument: list
    :return: True if the argument is validated, False otherwise.
    :rtype: bool
    """
    if param_argument is None:
        param_argument = []
    if not isinstance(param_argument, list) or not all([isinstance(p, str) for p in param_argument]):
        error_msg = 'unsupported {param} argument provided "{arg}" ({arg_type}), required type: List[str]"'
        raise exceptions.ParamValidationError(error_msg.format(
            param=param_name,
            arg=param_argument,
            arg_type=type(param_argument),
        ))
Example #30
0
    def configure(self, mount_point, mfa_type='duo', force=False):
        """Configure MFA for a supported method.

        This endpoint allows you to turn on multi-factor authentication with a given backend.
        Currently only Duo is supported.

        Supported methods:
            POST: /auth/{mount_point}/mfa_config. Produces: 204 (empty body)

        :param mount_point: The "path" the method/backend was mounted on.
        :type mount_point: str | unicode
        :param mfa_type: Enables MFA with given backend (available: duo)
        :type mfa_type: str | unicode
        :param force: If True, make the "mfa_config" request regardless of circumstance. If False (the default), verify
            the provided mount_point is available and one of the types of methods supported by this feature.
        :type force: bool
        :return: The response of the configure MFA request.
        :rtype: requests.Response
        """
        if mfa_type != 'duo' and not force:
            # The situation described via this exception is not likely to change in the future.
            # However we provided that flexibility here just in case.
            error_msg = 'Unsupported mfa_type argument provided "{arg}", supported types: "{mfa_types}"'
            raise exceptions.ParamValidationError(
                error_msg.format(
                    mfa_types=','.join(SUPPORTED_MFA_TYPES),
                    arg=mfa_type,
                ))
        params = {
            'type': mfa_type,
        }

        api_path = '/v1/auth/{mount_point}/mfa_config'.format(
            mount_point=mount_point)
        return self._adapter.post(
            url=api_path,
            json=params,
        )