def __init__(self): self.commands = {} self.variables = Env.load_variables_group(prefix="telegram") if not self.variables.get("api_key"): # pragma: no cover raise ServiceUnavailable("Missing API KEY") self.updater = Updater( self.variables.get("api_key"), # Starting from v13 use_context is True by default # use_context=True, workers=Env.to_int(self.variables.get("workers"), default=1), ) # Inline keyboard callback self.updater.dispatcher.add_handler( CallbackQueryHandler(self.inline_keyboard_button)) # Errors self.updater.dispatcher.add_error_handler(self.error_callback) self.admins = Bot.get_ids(self.variables.get("admins")) if not self.admins: # pragma: no cover print_and_exit("No admin list") self.users = Bot.get_ids(self.variables.get("users")) self.api = BotApiClient(self.variables)
def launch() -> None: # pragma: no cover """Launch the RAPyDo-based HTTP API server""" mywait() if initializing(): print_and_exit( "Please wait few more seconds: initialization is still in progress" ) current_app = Env.get("FLASK_APP", "").strip() if not current_app: os.environ["FLASK_APP"] = f"{current_package}.__main__" args = [ "run", "--host", BIND_INTERFACE, "--port", Env.get("FLASK_PORT", "8080"), "--reload", "--no-debugger", "--eager-loading", "--with-threads", ] # Call to untyped function "FlaskGroup" in typed context fg_cli = FlaskGroup() # type: ignore # Call to untyped function "main" in typed context fg_cli.main(prog_name="restapi", args=args) # type: ignore log.warning("Server shutdown")
def test_auth(self, client: FlaskClient) -> None: if not Env.get_bool("AUTH_ENABLE"): log.warning("Skipping authentication tests") return r = client.get(f"{API_URI}/tests/authentication") assert r.status_code == 401 r = client.get( f"{API_URI}/tests/authentication", headers={"Authorization": "Bearer invalid"}, ) assert r.status_code == 401 headers, token = self.do_login(client, None, None) r = client.get(f"{API_URI}/tests/authentication", headers=headers) assert r.status_code == 200 content = self.get_content(r) assert isinstance(content, dict) assert len(content) == 1 assert "email" in content assert content["email"] == BaseAuthentication.default_user if not Env.get_bool("ALLOW_ACCESS_TOKEN_PARAMETER"): # access token parameter is not allowed by default r = client.get(f"{API_URI}/tests/authentication", query_string={"access_token": token}) assert r.status_code == 401
def load_default_user() -> None: BaseAuthentication.default_user = Env.get("AUTH_DEFAULT_USERNAME", "") BaseAuthentication.default_password = Env.get("AUTH_DEFAULT_PASSWORD", "") if (not BaseAuthentication.default_user or not BaseAuthentication.default_password): # pragma: no cover print_and_exit("Default credentials are unavailable!")
def test_05_login_failures(self, client: FlaskClient) -> None: if Env.get_bool("MAIN_LOGIN_ENABLE") and Env.get_bool("AUTH_ENABLE"): # Create a new user on the fly to test the cached endpoint _, data = self.create_user(client) headers, _ = self.do_login( client, data["email"], data["password"], test_failures=True ) r = client.get(f"{AUTH_URI}/logout", headers=headers) assert r.status_code == 204
def send_notification( subject: str, template: str, # if None will be sent to the administrator to_address: Optional[str] = None, data: Optional[Dict[str, Any]] = None, user: Optional[User] = None, send_async: bool = False, ) -> bool: # Always enabled during tests if not Connector.check_availability("smtp"): # pragma: no cover return False title = get_project_configuration("project.title", default="Unkown title") reply_to = Env.get("SMTP_NOREPLY", Env.get("SMTP_ADMIN", "")) if data is None: data = {} data.setdefault("project", title) data.setdefault("reply_to", reply_to) if user: data.setdefault("username", user.email) data.setdefault("name", user.name) data.setdefault("surname", user.surname) html_body, plain_body = get_html_template(template, data) if not html_body: # pragma: no cover log.error("Can't load {}", template) return False subject = f"{title}: {subject}" if send_async: Mail.send_async( subject=subject, body=html_body, to_address=to_address, plain_body=plain_body, ) return False smtp_client = smtp.get_instance() return smtp_client.send( subject=subject, body=html_body, to_address=to_address, plain_body=plain_body, )
def mywait() -> None: """ Wait for a service on his host:port configuration This check is merely based on a socket connection """ for name, variables in Connector.services.items(): if name == "smtp" or name == "ftp": log.info("Service {} is enabled but not tested at startup time", name) continue if name == "celery": broker = variables.get("broker_service", "N/A") if broker == "RABBIT": service_vars = Env.load_variables_group(prefix="rabbitmq") elif broker == "REDIS": service_vars = Env.load_variables_group(prefix="redis") else: print_and_exit("Invalid celery broker: {}", broker) # pragma: no cover label = f"{broker.lower()} as celery broker" host, port = get_service_address(service_vars, "host", "port", label) wait_socket(host, port, label) backend = variables.get("backend_service", "N/a") if backend == "RABBIT": service_vars = Env.load_variables_group(prefix="rabbitmq") elif backend == "REDIS": service_vars = Env.load_variables_group(prefix="redis") else: print_and_exit("Invalid celery backend: {}", backend) # pragma: no cover label = f"{backend.lower()} as celery backend" host, port = get_service_address(service_vars, "host", "port", label) wait_socket(host, port, label) else: host, port = get_service_address(variables, "host", "port", name) if host != "nohost": wait_socket(host, port, name)
def get_frontend_url() -> str: FRONTEND_URL = Env.get("FRONTEND_URL", "") if FRONTEND_URL: return FRONTEND_URL FRONTEND_PREFIX = Env.get("FRONTEND_PREFIX", "").strip("/") if FRONTEND_PREFIX: FRONTEND_PREFIX = f"/{FRONTEND_PREFIX}" protocol = "https" if PRODUCTION else "http" return f"{protocol}://{DOMAIN}{FRONTEND_PREFIX}"
def mywait(): """ Wait for a service on his host:port configuration basing the check on a socket connection. """ for name, variables in Connector.services.items(): if name == "smtp": continue if name == "celery": broker = variables.get("broker", "N/A") if broker == "RABBIT": service_vars = Env.load_variables_group(prefix="rabbitmq") elif broker == "REDIS": service_vars = Env.load_variables_group(prefix="redis") else: print_and_exit("Invalid celery broker: {}", broker) # pragma: no cover label = f"{broker.lower()} as celery broker" host, port = get_service_address(service_vars, "host", "port", label) wait_socket(host, port, label) backend = variables.get("backend", "N/a") # Rabbit is no longer used as backend due to the strong limitations if backend == "RABBIT": # pragma: no cover service_vars = Env.load_variables_group(prefix="rabbitmq") elif backend == "REDIS": service_vars = Env.load_variables_group(prefix="redis") elif backend == "MONGODB": service_vars = Env.load_variables_group(prefix="mongo") else: print_and_exit( "Invalid celery backend: {}", backend ) # pragma: no cover label = f"{backend.lower()} as celery backend" host, port = get_service_address(service_vars, "host", "port", label) wait_socket(host, port, label) else: host, port = get_service_address(variables, "host", "port", name) wait_socket(host, port, name)
def test_01_login_ban_not_enabled(self, client: FlaskClient) -> None: if not Env.get_bool("MAIN_LOGIN_ENABLE"): # pragma: no cover log.warning("Skipping admin/users tests") return uuid, data = self.create_user(client) # Login attempts are not registered, let's try to fail the login many times for _ in range(0, 10): self.do_login(client, data["email"], "wrong", status_code=401) events = self.get_last_events(1) assert events[0].event == Events.failed_login.value assert events[0].payload["username"] == data["email"] # and verify that login is still allowed headers, _ = self.do_login(client, data["email"], data["password"]) assert headers is not None events = self.get_last_events(1) assert events[0].event == Events.login.value assert events[0].user == data["email"] # Goodbye temporary user self.delete_user(client, uuid)
def test_GET_status(self, client: FlaskClient) -> None: """Test that the flask server is running and reachable""" # Check success alive_message = "Server is alive" log.info("*** VERIFY if API is online") r = client.get(f"{API_URI}/status") assert r.status_code == 200 output = self.get_content(r) assert output == alive_message # Check failure log.info("*** VERIFY if invalid endpoint gives Not Found") r = client.get(API_URI) assert r.status_code == 404 if Env.get_bool("AUTH_ENABLE"): # Check /auth/status with no token or invalid token r = client.get(f"{AUTH_URI}/status") assert r.status_code == 401 r = client.get(f"{AUTH_URI}/status", headers={"Authorization": "Bearer ABC"}) assert r.status_code == 401 else: r = client.get(f"{AUTH_URI}/status") assert r.status_code == 404
def test_04_logout(self, client: FlaskClient) -> None: """Check that you can logout with a valid token""" if not Env.get_bool("AUTH_ENABLE"): log.warning("Skipping logout tests") return # Check success log.info("*** VERIFY valid token") r = client.get(f"{AUTH_URI}/logout", headers=self.get("auth_header")) assert r.status_code == 204 events = self.get_last_events(2) assert events[0].event == Events.delete.value assert events[0].user == "-" assert events[0].target_type == "Token" assert events[0].url == "/auth/logout" assert events[1].event == Events.logout.value assert events[1].user == BaseAuthentication.default_user assert events[1].url == "/auth/logout" # Check failure log.info("*** VERIFY invalid token") r = client.get(f"{AUTH_URI}/logout") assert r.status_code == 401
def test_05_no_notification_email_for_wrong_usernames( self, client: FlaskClient, faker: Faker ) -> None: if not Env.get_bool("MAIN_LOGIN_ENABLE"): # pragma: no cover log.warning("Skipping admin/users tests") return uuid, data = self.create_user(client) self.delete_mock_email() # Just to verify that email is deleted with pytest.raises(FileNotFoundError): self.read_mock_email() email = faker.ascii_email() # Wrong credentials with a non existing email # -> No notification will be sent for _ in range(0, max_login_attempts): self.do_login(client, email, data["password"], status_code=401) # Verify the ban (i.e. status 403) headers, _ = self.do_login(client, email, data["password"], status_code=403) assert headers is None # Verify that there are no mocked email with pytest.raises(FileNotFoundError): self.read_mock_email() # Goodbye temporary user self.delete_user(client, uuid)
def create_user( cls, client: FlaskClient, data: Optional[Dict[str, Any]] = None, roles: Optional[List[Union[str, Role]]] = None, ) -> Tuple[str, Dict[str, Any]]: assert Env.get_bool("MAIN_LOGIN_ENABLE") admin_headers, _ = cls.do_login(client, None, None) assert admin_headers is not None schema = cls.getDynamicInputSchema(client, "admin/users", admin_headers) user_data = cls.buildData(schema) if Connector.check_availability("smtp"): user_data["email_notification"] = False user_data["is_active"] = True user_data["expiration"] = None if roles: for idx, role in enumerate(roles): if isinstance(role, Role): roles[idx] = role.value user_data["roles"] = json.dumps(roles) if data: user_data.update(data) r = client.post(f"{API_URI}/admin/users", data=user_data, headers=admin_headers) assert r.status_code == 200 uuid = cls.get_content(r) return uuid, user_data
def test_auth(self, client: FlaskClient) -> None: r = client.get(f"{API_URI}/tests/authentication") assert r.status_code == 401 r = client.get( f"{API_URI}/tests/authentication", headers={"Authorization": "Bearer invalid"}, ) assert r.status_code == 401 headers, token = self.do_login(client, None, None) r = client.get(f"{API_URI}/tests/authentication", headers=headers) assert r.status_code == 200 content = self.get_content(r) assert len(content) == 2 assert "token" in content assert "user" in content assert content["token"] == token assert content["user"] == BaseAuthentication.default_user if not Env.get_bool("ALLOW_ACCESS_TOKEN_PARAMETER"): # access token parameter is not allowed by default r = client.get( f"{API_URI}/tests/authentication", query_string={"access_token": token} ) assert r.status_code == 401
def api( path: str, method: str, base: str = "api", payload: Optional[Dict[str, Any]] = None, ) -> Any: host = BotApiClient.variables.get("backend_host") port = Env.get("FLASK_PORT", "8080") url = f"http://{host}:{port}/{base}/{path}" log.debug("Calling {} on {}", method, url) try: data: Optional[str] = None if payload: data = orjson.dumps(payload).decode("UTF8") response = requests.request(method, url=url, data=data, timeout=10) out = response.json() # Never raised during tests: how to test it? except Exception as e: # pragma: no cover log.error(f"API call failed: {e}") raise ServerError(str(e)) if response.status_code >= 300: raise RestApiException(out, status_code=response.status_code) return out
def get_backend_url() -> str: BACKEND_URL = Env.get("BACKEND_URL", "") if BACKEND_URL: return BACKEND_URL BACKEND_PREFIX = Env.get("BACKEND_PREFIX", "").strip("/") if BACKEND_PREFIX: BACKEND_PREFIX = f"/{BACKEND_PREFIX}" if PRODUCTION: return f"https://{DOMAIN}{BACKEND_PREFIX}" port = Env.get("FLASK_PORT", "8080") return f"http://{DOMAIN}{BACKEND_PREFIX}:{port}"
def test_authentication_with_multiple_roles(self, client: FlaskClient) -> None: if not Env.get_bool("AUTH_ENABLE"): log.warning("Skipping authentication tests") return r = client.get(f"{API_URI}/tests/manyrolesauthentication") assert r.status_code == 401 r = client.get(f"{API_URI}/tests/unknownroleauthentication") assert r.status_code == 401 admin_headers, _ = self.do_login(client, None, None) r = client.get(f"{API_URI}/tests/manyrolesauthentication", headers=admin_headers) assert r.status_code == 200 content = self.get_content(r) assert isinstance(content, dict) assert len(content) == 1 assert "email" in content assert content["email"] == BaseAuthentication.default_user r = client.get(f"{API_URI}/tests/unknownroleauthentication", headers=admin_headers) assert r.status_code == 401 if Env.get_bool("MAIN_LOGIN_ENABLE"): uuid, data = self.create_user(client, roles=[Role.USER]) user_header, _ = self.do_login(client, data.get("email"), data.get("password")) r = client.get(f"{API_URI}/tests/manyrolesauthentication", headers=user_header) assert r.status_code == 200 content = self.get_content(r) assert isinstance(content, dict) assert len(content) == 1 assert "email" in content assert content["email"] == data.get("email") r = client.get(f"{API_URI}/tests/unknownroleauthentication", headers=user_header) assert r.status_code == 401 self.delete_user(client, uuid)
def test_cached_authenticated_param_endpoint(self, client: FlaskClient) -> None: if not Env.get_bool("AUTH_ENABLE"): log.warning("Skipping cache with authentication tests") return headers1, _ = self.do_login(client, None, None) r = client.get(f"{API_URI}/tests/cache/paramauth", headers=headers1) assert r.status_code == 200 resp1 = self.get_content(r) assert isinstance(resp1, list) # counter is 1 because this is the first request to this endpoint assert resp1[COUNTER] == 1 r = client.get(f"{API_URI}/tests/cache/paramauth", headers=headers1) assert r.status_code == 200 resp2 = self.get_content(r) assert isinstance(resp2, list) assert resp2[UUID] == resp1[UUID] # Same counter as above, because the response is replied from the cache assert resp2[COUNTER] == resp1[COUNTER] assert resp2[COUNTER] == 1 headers2, token2 = self.do_login(client, None, None) # Test by using access_token parameter instead of Headers r = client.get(f"{API_URI}/tests/cache/paramauth", query_string={"access_token": token2}) assert r.status_code == 200 resp3 = self.get_content(r) assert isinstance(resp3, list) # This is the same user, uuid is unchanged assert resp3[UUID] == resp1[UUID] # but counter changed, because the response is not replied from the cache assert resp3[COUNTER] != resp1[COUNTER] assert resp3[COUNTER] == 2 r = client.get(f"{API_URI}/tests/cache/paramauth", query_string={"access_token": token2}) assert r.status_code == 200 resp4 = self.get_content(r) assert isinstance(resp4, list) assert resp4[UUID] == resp1[UUID] # Same counter as above, because the response is replied from the cache assert resp4[COUNTER] == resp3[COUNTER] assert resp4[COUNTER] == 2 # Cache is stored starting from the access_token parameter, # but the token is the same also if provided as header r = client.get(f"{API_URI}/tests/cache/paramauth", headers=headers2) assert r.status_code == 200 resp5 = self.get_content(r) assert isinstance(resp5, list) assert resp5[UUID] == resp1[UUID] # Same counter as above, because the response is replied from the cache assert resp5[COUNTER] == resp3[COUNTER] assert resp5[COUNTER] == 2
def test_optional_auth(self, client: FlaskClient) -> None: # Optional authentication can accept missing tokens r = client.get(f"{API_URI}/tests/optionalauthentication") assert r.status_code == 200 content = self.get_content(r) assert len(content) == 2 assert "token" in content assert "user" in content assert content["token"] is None assert content["user"] is None headers, token = self.do_login(client, None, None) # Or valid tokens r = client.get(f"{API_URI}/tests/optionalauthentication", headers=headers) assert r.status_code == 200 content = self.get_content(r) assert len(content) == 2 assert "token" in content assert "user" in content assert content["token"] == token assert content["user"] == BaseAuthentication.default_user # But not invalid tokens, i.e. if presented the tokens is always validated r = client.get( f"{API_URI}/tests/authentication", headers={"Authorization": "Bearer invalid"}, ) assert r.status_code == 401 if not Env.get_bool("ALLOW_ACCESS_TOKEN_PARAMETER"): # access token parameter is not allowed by default r = client.get( f"{API_URI}/tests/optionalauthentication", query_string={"access_token": token}, ) # query token is ignored but the endpoint accepts missing tokens assert r.status_code == 200 content = self.get_content(r) assert len(content) == 2 assert "token" in content assert "user" in content assert content["token"] is None assert content["user"] is None r = client.get( f"{API_URI}/tests/optionalauthentication", query_string={"access_token": "invalid"}, ) # invalid tokens should be rejected, but query token is ignored assert r.status_code == 200 content = self.get_content(r) assert len(content) == 2 assert "token" in content assert "user" in content assert content["token"] is None assert content["user"] is None
def test_caching_general_clearing(self, client: FlaskClient) -> None: if Env.get_bool("AUTH_ENABLE"): headers, _ = self.do_login(client, None, None) else: headers = None # get method is cached for 200 seconds # First response is not cached r = client.get(f"{API_URI}/tests/cache/long") assert r.status_code == 200 counter1 = self.get_content(r) # Second response is cached r = client.get(f"{API_URI}/tests/cache/long") assert r.status_code == 200 assert self.get_content(r) == counter1 # Empty all the cache Cache.clear() # Third response is no longer cached r = client.get(f"{API_URI}/tests/cache/long") assert r.status_code == 200 counter2 = self.get_content(r) assert counter2 != counter1 # Response is still cached r = client.get(f"{API_URI}/tests/cache/long") assert r.status_code == 200 assert self.get_content(r) == counter2 # Empty the endpoint cache client.delete(f"{API_URI}/tests/cache/long") # Second response is no longer cached r = client.get(f"{API_URI}/tests/cache/long") assert r.status_code == 200 counter3 = self.get_content(r) assert counter3 != counter2 # Response is still cached r = client.get(f"{API_URI}/tests/cache/long") assert r.status_code == 200 assert self.get_content(r) == counter3 # Endpoint is unauthenticated, headers are ignored when building the cache key r = client.get(f"{API_URI}/tests/cache/long", headers=headers) assert r.status_code == 200 assert self.get_content(r) == counter3 # Tokens are ignored even if invalid r = client.get(f"{API_URI}/tests/cache/long", headers={"Authorization": "Bearer invalid"}) assert r.status_code == 200 assert self.get_content(r) == counter3
def get_redis_url(variables: Dict[str, str], protocol: str) -> str: host = variables.get("host") port = Env.to_int(variables.get("port")) pwd = variables.get("password", "") creds = "" if pwd: creds = f":{pwd}@" return f"{protocol}://{creds}{host}:{port}/0"
def delete_user(cls, client: FlaskClient, uuid: str) -> None: assert Env.get_bool("MAIN_LOGIN_ENABLE") admin_headers, _ = cls.do_login(client, None, None) assert admin_headers is not None r = client.delete(f"{API_URI}/admin/users/{uuid}", headers=admin_headers) assert r.status_code == 204
def send_activation_link(user: User, url: str) -> bool: return send_notification( subject=Env.get("EMAIL_ACTIVATION_SUBJECT", "Account activation"), template="activate_account.html", to_address=user.email, data={"url": url}, user=user, )
def test_cached_semiauthenticated_endpoint(self, client: FlaskClient) -> None: if not Env.get_bool("AUTH_ENABLE"): log.warning("Skipping cache with authentication tests") return r = client.get(f"{API_URI}/tests/cache/optionalauth") assert r.status_code == 200 nonauthenticated1 = self.get_content(r) assert isinstance(nonauthenticated1, list) assert nonauthenticated1[UUID] == "N/A" # counter is 1 because this is the first request to this endpoint assert nonauthenticated1[COUNTER] == 1 r = client.get(f"{API_URI}/tests/cache/optionalauth") assert r.status_code == 200 nonauthenticated2 = self.get_content(r) assert isinstance(nonauthenticated2, list) assert nonauthenticated2[UUID] == "N/A" # Same counter as above, because the response is replied from the cache assert nonauthenticated2[COUNTER] == 1 headers, _ = self.do_login(client, None, None) r = client.get(f"{API_URI}/tests/cache/optionalauth", headers=headers) assert r.status_code == 200 authenticated1 = self.get_content(r) assert isinstance(authenticated1, list) assert authenticated1[UUID] != "N/A" # The counter changed, because the response is not replied from the cache assert authenticated1[COUNTER] == 2 # Token cached => cache should be used r = client.get(f"{API_URI}/tests/cache/optionalauth", headers=headers) assert r.status_code == 200 authenticated2 = self.get_content(r) assert isinstance(authenticated2, list) assert authenticated2[UUID] == authenticated1[UUID] # Same counter as above, because the response is replied from the cache assert authenticated2[COUNTER] == 2 # New token => no cache headers, _ = self.do_login(client, None, None) r = client.get(f"{API_URI}/tests/cache/optionalauth", headers=headers) assert r.status_code == 200 authenticated2 = self.get_content(r) assert isinstance(authenticated2, list) assert authenticated2[UUID] == authenticated1[UUID] # Counter changed assert authenticated2[COUNTER] == 3 r = client.get( f"{API_URI}/tests/cache/optionalauth", headers={"Authorization": "Bearer invalid"}, ) assert r.status_code == 401
def get_mongodb_url(variables: Dict[str, str], protocol: str) -> str: host = variables.get("host") port = Env.to_int(variables.get("port")) user = variables.get("user", "") pwd = variables.get("password", "") creds = "" if user and pwd: creds = f"{user}:{pwd}@" return f"{protocol}://{creds}{host}:{port}"
def test_caching_autocleaning(self, client: FlaskClient) -> None: if Env.get_bool("AUTH_ENABLE"): headers, _ = self.do_login(client, None, None) else: headers = None # Syncronize this test to start at the beginning of the next second and # prevent the test to overlap a change of second # Since the caching is rounded to the second, few milliseconds cann make the # difference, for example: # A first request at 00:00:00.997 is cached # A second request at 00:00:01.002 is no longer cached, even if only 5 millisec # elapsed because the second changed # Added 0.01 just to avoid to exactly start at the beginning of the second t = 1.01 - datetime.now().microsecond / 1000000.0 log.critical("Sleeping {} sec", t) time.sleep(t) # the GET method is cached for 1 second # First response is not cached r = client.get(f"{API_URI}/tests/cache/short") assert r.status_code == 200 counter1 = self.get_content(r) # Second response is cached r = client.get(f"{API_URI}/tests/cache/short") assert r.status_code == 200 assert self.get_content(r) == counter1 # Third response is no longer cached time.sleep(1) r = client.get(f"{API_URI}/tests/cache/short") assert r.status_code == 200 counter2 = self.get_content(r) assert counter2 != counter1 # Fourth response is cached again r = client.get(f"{API_URI}/tests/cache/short") assert r.status_code == 200 assert self.get_content(r) == counter2 # Endpoint is unauthenticated, headers are ignored when building the cache key r = client.get(f"{API_URI}/tests/cache/short", headers=headers) assert r.status_code == 200 assert self.get_content(r) == counter2 # Tokens are ignored even if invalid r = client.get(f"{API_URI}/tests/cache/short", headers={"Authorization": "Bearer invalid"}) assert r.status_code == 200 assert self.get_content(r) == counter2
def test_authentication_with_auth_callback(self, client: FlaskClient) -> None: if not Env.get_bool("AUTH_ENABLE"): log.warning("Skipping authentication tests") return auth = Connector.get_authentication_instance() user = auth.get_user(username=BaseAuthentication.default_user) assert user is not None VALID = f"/tests/preloadcallback/{user.uuid}" INVALID = "/tests/preloadcallback/12345678-90ab-cdef-1234-567890abcdef" admin_headers, _ = self.do_login(client, None, None) # Verify both endpoint ... r = client.get(f"{API_URI}{VALID}", query_string={"test": True}, headers=admin_headers) assert r.status_code == 200 content = self.get_content(r) assert isinstance(content, dict) assert len(content) == 1 assert "email" in content assert content["email"] == user.email r = client.get(f"{API_URI}{INVALID}", query_string={"test": True}, headers=admin_headers) assert r.status_code == 401 # and get_schema! r = client.get( f"{API_URI}{VALID}", query_string={"get_schema": True}, headers=admin_headers, ) assert r.status_code == 200 content = self.get_content(r) assert isinstance(content, list) assert len(content) == 1 assert content[0]["key"] == "test" assert content[0]["type"] == "boolean" r = client.get( f"{API_URI}{INVALID}", query_string={"get_schema": True}, headers=admin_headers, ) assert r.status_code == 401
def get_bindings(self, exchange: str) -> Optional[List[Dict[str, str]]]: if not self.exchange_exists(exchange): log.critical("Does not exist") return None host = self.variables.get("host", "") schema = "" if not host.startswith("http"): if Env.to_bool(self.variables.get("ssl_enabled")): schema = "https://" else: schema = "http://" port = self.variables.get("management_port") # url-encode unsafe characters by also including / (thanks to safe parameter) # / -> %2F vhost = urllib.parse.quote(self.variables.get("vhost", "/"), safe="") user = self.variables.get("user") password = self.variables.get("password") # API Reference: # A list of all bindings in which a given exchange is the source. r = requests.get( f"{schema}{host}:{port}/api/exchanges/{vhost}/{exchange}/bindings/source", auth=HTTPBasicAuth(user, password), verify=False, ) response = r.json() if r.status_code != 200: # pragma: no cover raise RestApiException( {"RabbitMQ": response.get("error", "Unknown error")}, status_code=r.status_code, ) bindings = [] for row in response: # row == { # 'source': exchange-name, # 'vhost': probably '/', # 'destination': queue-or-dest-exchange-name, # 'destination_type': 'queue' or 'exchange', # 'routing_key': routing_key, # 'arguments': Dict, # 'properties_key': ?? as routing_key? # } bindings.append({ "exchange": row["source"], "routing_key": row["routing_key"], "queue": row["destination"], }) return bindings
def post(self, **kwargs: Any) -> Response: """ Register new user """ email = kwargs.get("email") user = self.auth.get_user(username=email) if user is not None: raise Conflict(f"This user already exists: {email}") password_confirm = kwargs.pop("password_confirm") if kwargs.get("password") != password_confirm: raise Conflict("Your password doesn't match the confirmation") if self.auth.VERIFY_PASSWORD_STRENGTH: check, msg = self.auth.verify_password_strength( kwargs.get("password"), None) if not check: raise Conflict(msg) kwargs["is_active"] = False user = self.auth.create_user(kwargs, [self.auth.default_role]) default_group = self.auth.get_group(name=DEFAULT_GROUP_NAME) self.auth.add_user_to_group(user, default_group) self.auth.save_user(user) self.log_event(self.events.create, user, kwargs) try: smtp_client = smtp.get_instance() if Env.get_bool("REGISTRATION_NOTIFICATIONS"): # Sending an email to the administrator title = get_project_configuration("project.title", default="Unkown title") subject = f"{title} New credentials requested" body = f"New credentials request from {user.email}" smtp_client.send(body, subject) send_activation_link(smtp_client, self.auth, user) except BaseException as e: # pragma: no cover self.auth.delete_user(user) raise ServiceUnavailable( f"Errors during account registration: {e}") return self.response( "We are sending an email to your email address where " "you will find the link to activate your account")