1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3"""Multi-factor authentication methods module.""" 4from hvac.api.vault_api_base import VaultApiBase 5from hvac import exceptions, utils 6 7SUPPORTED_MFA_TYPES = [ 8 "duo", 9] 10SUPPORTED_AUTH_METHODS = ["ldap", "okta", "radius", "userpass"] 11 12 13class Mfa(VaultApiBase): 14 """Multi-factor authentication Auth Method (API). 15 16 .. warning:: 17 This class's methods correspond to a legacy / unsupported set of Vault API routes. Please see the reference link 18 for additional context. 19 20 Reference: https://www.vaultproject.io/docs/auth/mfa.html 21 """ 22 23 def configure(self, mount_point, mfa_type="duo", force=False): 24 """Configure MFA for a supported method. 25 26 This endpoint allows you to turn on multi-factor authentication with a given backend. 27 Currently only Duo is supported. 28 29 Supported methods: 30 POST: /auth/{mount_point}/mfa_config. Produces: 204 (empty body) 31 32 :param mount_point: The "path" the method/backend was mounted on. 33 :type mount_point: str | unicode 34 :param mfa_type: Enables MFA with given backend (available: duo) 35 :type mfa_type: str | unicode 36 :param force: If True, make the "mfa_config" request regardless of circumstance. If False (the default), verify 37 the provided mount_point is available and one of the types of methods supported by this feature. 38 :type force: bool 39 :return: The response of the configure MFA request. 40 :rtype: requests.Response 41 """ 42 if mfa_type != "duo" and not force: 43 # The situation described via this exception is not likely to change in the future. 44 # However we provided that flexibility here just in case. 45 error_msg = 'Unsupported mfa_type argument provided "{arg}", supported types: "{mfa_types}"' 46 raise exceptions.ParamValidationError( 47 error_msg.format( 48 mfa_types=",".join(SUPPORTED_MFA_TYPES), 49 arg=mfa_type, 50 ) 51 ) 52 params = { 53 "type": mfa_type, 54 } 55 56 api_path = utils.format_url( 57 "/v1/auth/{mount_point}/mfa_config", mount_point=mount_point 58 ) 59 return self._adapter.post( 60 url=api_path, 61 json=params, 62 ) 63 64 def read_configuration(self, mount_point): 65 """Read the MFA configuration. 66 67 Supported methods: 68 GET: /auth/{mount_point}/mfa_config. Produces: 200 application/json 69 70 71 :param mount_point: The "path" the method/backend was mounted on. 72 :type mount_point: str | unicode 73 :return: The JSON response of the read_configuration request. 74 :rtype: dict 75 """ 76 api_path = utils.format_url( 77 "/v1/auth/{mount_point}/mfa_config", 78 mount_point=mount_point, 79 ) 80 return self._adapter.get(url=api_path) 81 82 def configure_duo_access(self, mount_point, host, integration_key, secret_key): 83 """Configure the access keys and host for Duo API connections. 84 85 To authenticate users with Duo, the backend needs to know what host to connect to and must authenticate with an 86 integration key and secret key. This endpoint is used to configure that information. 87 88 Supported methods: 89 POST: /auth/{mount_point}/duo/access. Produces: 204 (empty body) 90 91 :param mount_point: The "path" the method/backend was mounted on. 92 :type mount_point: str | unicode 93 :param host: Duo API host 94 :type host: str | unicode 95 :param integration_key: Duo integration key 96 :type integration_key: Duo secret key 97 :param secret_key: The "path" the method/backend was mounted on. 98 :type secret_key: str | unicode 99 :return: The response of the configure_duo_access request. 100 :rtype: requests.Response 101 """ 102 params = { 103 "host": host, 104 "ikey": integration_key, 105 "skey": secret_key, 106 } 107 api_path = utils.format_url( 108 "/v1/auth/{mount_point}/duo/access", 109 mount_point=mount_point, 110 ) 111 return self._adapter.post( 112 url=api_path, 113 json=params, 114 ) 115 116 def configure_duo_behavior( 117 self, mount_point, push_info=None, user_agent=None, username_format="%s" 118 ): 119 """Configure Duo second factor behavior. 120 121 This endpoint allows you to configure how the original auth method username maps to the Duo username by 122 providing a template format string. 123 124 Supported methods: 125 POST: /auth/{mount_point}/duo/config. Produces: 204 (empty body) 126 127 128 :param mount_point: The "path" the method/backend was mounted on. 129 :type mount_point: str | unicode 130 :param push_info: A string of URL-encoded key/value pairs that provides additional context about the 131 authentication attempt in the Duo Mobile app 132 :type push_info: str | unicode 133 :param user_agent: User agent to connect to Duo (default "") 134 :type user_agent: str | unicode 135 :param username_format: Format string given auth method username as argument to create Duo username 136 (default '%s') 137 :type username_format: str | unicode 138 :return: The response of the configure_duo_behavior request. 139 :rtype: requests.Response 140 """ 141 params = { 142 "username_format": username_format, 143 } 144 if push_info is not None: 145 params["push_info"] = push_info 146 if user_agent is not None: 147 params["user_agent"] = user_agent 148 api_path = utils.format_url( 149 "/v1/auth/{mount_point}/duo/config", 150 mount_point=mount_point, 151 ) 152 return self._adapter.post( 153 url=api_path, 154 json=params, 155 ) 156 157 def read_duo_behavior_configuration(self, mount_point): 158 """Read the Duo second factor behavior configuration. 159 160 Supported methods: 161 GET: /auth/{mount_point}/duo/config. Produces: 200 application/json 162 163 164 :param mount_point: The "path" the method/backend was mounted on. 165 :type mount_point: str | unicode 166 :return: The JSON response of the read_duo_behavior_configuration request. 167 :rtype: dict 168 """ 169 api_path = utils.format_url( 170 "/v1/auth/{mount_point}/duo/config", 171 mount_point=mount_point, 172 ) 173 return self._adapter.get(url=api_path) 174