def do_login( cls, client: FlaskClient, USER: Optional[str], PWD: Optional[str], status_code: int = 200, data: Optional[Dict[str, Any]] = None, test_failures: bool = False, ) -> Tuple[Optional[Dict[str, str]], str]: """ Make login and return both token and authorization header """ if USER is None or PWD is None: BaseAuthentication.load_default_user() BaseAuthentication.load_roles() if USER is None: USER = BaseAuthentication.default_user if PWD is None: PWD = BaseAuthentication.default_password assert USER is not None assert PWD is not None if data is None: data = {} data["username"] = USER data["password"] = PWD r = client.post(f"{AUTH_URI}/login", data=data) content = json.loads(r.data.decode("utf-8")) if r.status_code == 403: # This 403 is expected, return an invalid value or you can enter a loop! if status_code == 403: return None, content if isinstance(content, dict) and content.get("actions"): actions = content.get("actions", []) for action in actions: if action == "TOTP": continue if action == "FIRST LOGIN": continue if action == "PASSWORD EXPIRED": continue data = {} if "FIRST LOGIN" in actions or "PASSWORD EXPIRED" in actions: newpwd = cls.faker.password(strong=True) if test_failures: data["new_password"] = newpwd data["password_confirm"] = cls.faker.password( strong=True) if Env.get_bool("AUTH_SECOND_FACTOR_AUTHENTICATION"): data["totp_code"] = BaseTests.generate_totp(USER) BaseTests.do_login( client, USER, PWD, data=data, status_code=409, ) # Test failure of password change if TOTP is wrong or missing if Env.get_bool("AUTH_SECOND_FACTOR_AUTHENTICATION"): data["new_password"] = newpwd data["password_confirm"] = newpwd data.pop("totp_code", None) BaseTests.do_login( client, USER, PWD, data=data, status_code=403, ) data["new_password"] = newpwd data["password_confirm"] = newpwd # random int with 6 digits data["totp_code"] = cls.faker.pyint( min_value=100000, max_value=999999) BaseTests.do_login( client, USER, PWD, data=data, status_code=401, ) # Change the password to silence FIRST_LOGIN and PASSWORD_EXPIRED data["new_password"] = newpwd data["password_confirm"] = newpwd if Env.get_bool("AUTH_SECOND_FACTOR_AUTHENTICATION"): data["totp_code"] = BaseTests.generate_totp(USER) BaseTests.do_login( client, USER, PWD, data=data, ) # Change again to restore the default password # and keep all other tests fully working data["new_password"] = PWD data["password_confirm"] = PWD if Env.get_bool("AUTH_SECOND_FACTOR_AUTHENTICATION"): data["totp_code"] = BaseTests.generate_totp(USER) return BaseTests.do_login( client, USER, newpwd, data=data, ) # in this case FIRST LOGIN has not been executed # => login by sending the TOTP code if "TOTP" in actions: # Only directly tested => no coverage if test_failures: # pragma: no cover # random int with 6 digits data["totp_code"] = cls.faker.pyint(min_value=100000, max_value=999999) BaseTests.do_login( client, USER, PWD, data=data, status_code=401, ) data["totp_code"] = BaseTests.generate_totp(USER) return BaseTests.do_login( client, USER, PWD, data=data, ) # FOR DEBUGGING WHEN ADVANCED AUTH OPTIONS ARE ON # if r.status_code != 200: # c = json.loads(r.data.decode("utf-8")) # log.error(c) assert r.status_code == status_code # when 200 OK content is the token assert content is not None return {"Authorization": f"Bearer {content}"}, content
assert r.status_code == 200 assert content is not None headers: CaseInsensitiveDict[str] = CaseInsensitiveDict() headers["Authorization"] = f"Bearer {content}" return content, headers # No need to restore the logger after this test because # schemathesis test is the last one! # (just because in alphabetic order there are no other tests) set_logger("WARNING") app = create_app() client = werkzeug.Client(app, werkzeug.wrappers.Response) if Env.get_bool("AUTH_ENABLE"): BaseAuthentication.load_default_user() BaseAuthentication.load_roles() USER = BaseAuthentication.default_user PWD = BaseAuthentication.default_password data = {"username": USER, "password": PWD} token, auth_header = get_auth_token(client, data) # it does not handle custom headers => the endpoint will provide partial schema # due to missing authentication => skipping all private endpoints and schemas # schema = schemathesis.from_wsgi('/api/specs', app) r = client.get(f"/api/specs?access_token={token}") else: r = client.get("/api/specs") assert r.status_code == 200 schema = orjson.loads(r.get_data().decode())