def login(dcos_url, password_str, password_env, password_file, provider, username, key_path): """ :param dcos_url: URL of DC/OS cluster :type dcos_url: str :param password_str: password :type password_str: str :param password_env: name of environment variable with password :type password_env: str :param password_file: path to file with password :type password_file: bool :param provider: name of provider to authentication with :type provider: str :param username: username :type username: str :param key_path: path to file with private key :type param: str :rtype: int """ password = _get_password(password_str, password_env, password_file) if provider is None: if username and password: auth.dcos_uid_password_auth(dcos_url, username, password) elif username and key_path: auth.servicecred_auth(dcos_url, username, key_path) else: try: providers = auth.get_providers() # Let users know if they have non-default providers configured # This is a weak check, we should check default versions per # DC/OS version since defaults will change. jj if len(providers) > 2: msg = ("\nYour cluster has several authentication " "providers enabled. Run `dcos auth " "list-providers` to see all providers and `dcos " "auth login --provider <provider-id>` to " "authenticate with a specific provider\n") emitter.publish(DefaultError(msg)) except DCOSException: pass finally: auth.header_challenge_auth(dcos_url) else: providers = auth.get_providers() if providers.get(provider): _trigger_client_method(provider, providers[provider], username, password, key_path) else: msg = "Provider [{}] not configured on your cluster" raise DCOSException(msg.format(provider)) return 0
def test_header_challenge_auth(cred_auth, oidc_auth, req): resp = create_autospec(requests.Response) resp.status_code = 401 resp.headers = {"WWW-Authenticate": "oauthjwt"} req.return_value = resp auth.header_challenge_auth("url") oidc_auth.assert_called_once() resp2 = create_autospec(requests.Response) resp2.status_code = 401 resp2.headers = {"WWW-Authenticate": "acsjwt"} req.return_value = resp2 auth.header_challenge_auth("url") cred_auth.assert_called_once()
def test_header_challenge_auth(cred_auth, oidc_auth, req): resp = create_autospec(requests.Response) resp.status_code = 401 resp.headers = {"www-authenticate": "oauthjwt"} req.return_value = resp auth.header_challenge_auth("url") oidc_auth.assert_called_once() resp2 = create_autospec(requests.Response) resp2.status_code = 401 resp2.headers = {"www-authenticate": "acsjwt"} req.return_value = resp2 auth.header_challenge_auth("url") cred_auth.assert_called_once()
def request(method, url, is_success=_default_is_success, timeout=DEFAULT_TIMEOUT, verify=None, toml_config=None, **kwargs): """Sends an HTTP request. If the server responds with a 401, ask the user for their credentials, and try request again (up to 3 times). :param method: method for the new Request object :type method: str :param url: URL for the new Request object :type url: str :param is_success: Defines successful status codes for the request :type is_success: Function from int to bool :param timeout: request timeout :type timeout: int :param verify: whether to verify SSL certs or path to cert(s) :type verify: bool | str :param toml_config: cluster config to use :type toml_config: Toml :param kwargs: Additional arguments to requests.request (see http://docs.python-requests.org/en/latest/api/#requests.request) :type kwargs: dict :rtype: Response """ if toml_config is None: toml_config = config.get_config() auth_token = config.get_config_val("core.dcos_acs_token", toml_config) prompt_login = config.get_config_val("core.prompt_login", toml_config) dcos_url = urlparse(config.get_config_val("core.dcos_url", toml_config)) # only request with DC/OS Auth if request is to DC/OS cluster if auth_token and _is_request_to_dcos(url): auth = DCOSAcsAuth(auth_token) else: auth = None response = _request(method, url, is_success, timeout, auth=auth, verify=verify, toml_config=toml_config, **kwargs) if is_success(response.status_code): return response elif response.status_code == 401: if prompt_login: # I don't like having imports that aren't at the top level, but # this is to resolve a circular import issue between shakedown.http and # dcos.auth from dcos.auth import header_challenge_auth header_challenge_auth(dcos_url.geturl()) # if header_challenge_auth succeeded, then we auth-ed correctly and # thus can safely recursively call ourselves and not have to worry # about an infinite loop return request(method=method, url=url, is_success=is_success, timeout=timeout, verify=verify, **kwargs) else: if auth_token is not None: msg = ("Your core.dcos_acs_token is invalid. " "Please run: `dcos auth login`") raise DCOSAuthenticationException(response, msg) else: raise DCOSAuthenticationException(response) elif response.status_code == 422: raise DCOSUnprocessableException(response) elif response.status_code == 403: raise DCOSAuthorizationException(response) elif response.status_code == 400: raise DCOSBadRequest(response) else: raise DCOSHTTPException(response)