From 1c8f5df6e22d7a34770d16050498fa95e12cb254 Mon Sep 17 00:00:00 2001 From: Harish Govindarajulu Date: Fri, 22 Jul 2022 16:18:45 -0400 Subject: [PATCH] Add Feature flag to whitelist users from recaptcha check(PROJQUAY-3697) (#1454) Signed-off-by: harishsurf --- config.py | 3 +++ endpoints/api/organization.py | 15 ++++++++------- endpoints/api/user.py | 15 +++++++++------ features/__init__.pyi | 3 +++ test/test_api_usage.py | 6 ++++++ test/testconfig.py | 1 + util/config/schema.py | 9 +++++++++ 7 files changed, 39 insertions(+), 13 deletions(-) diff --git a/config.py b/config.py index 60a05cf49..aa4aef27d 100644 --- a/config.py +++ b/config.py @@ -592,6 +592,9 @@ class DefaultConfig(ImmutableConfig): RECAPTCHA_SITE_KEY: Optional[str] = None RECAPTCHA_SECRET_KEY: Optional[str] = None + # List of users allowed to pass through recaptcha security check to enable org/user creation via API + RECAPTCHA_WHITELISTED_USERS: List[str] = [] + # Server where TUF metadata can be found TUF_SERVER = None diff --git a/endpoints/api/organization.py b/endpoints/api/organization.py index 4883b06ac..7ca32f6e8 100644 --- a/endpoints/api/organization.py +++ b/endpoints/api/organization.py @@ -173,13 +173,14 @@ class OrganizationList(ApiResource): # If recaptcha is enabled, then verify the user is a human. if features.RECAPTCHA: - recaptcha_response = org_data.get("recaptcha_response", "") - result = recaptcha2.verify( - app.config["RECAPTCHA_SECRET_KEY"], recaptcha_response, get_request_ip() - ) - - if not result["success"]: - return {"message": "Are you a bot? If not, please revalidate the captcha."}, 400 + # check if the user is whitelisted to bypass recaptcha security check + if user.username not in app.config["RECAPTCHA_WHITELISTED_USERS"]: + recaptcha_response = org_data.get("recaptcha_response", "") + result = recaptcha2.verify( + app.config["RECAPTCHA_SECRET_KEY"], recaptcha_response, get_request_ip() + ) + if not result["success"]: + return {"message": "Are you a bot? If not, please revalidate the captcha."}, 400 is_possible_abuser = ip_resolver.is_ip_possible_threat(get_request_ip()) try: diff --git a/endpoints/api/user.py b/endpoints/api/user.py index cfac4f6d2..0ca825c86 100644 --- a/endpoints/api/user.py +++ b/endpoints/api/user.py @@ -516,13 +516,16 @@ class User(ApiResource): # If recaptcha is enabled, then verify the user is a human. if features.RECAPTCHA: - recaptcha_response = user_data.get("recaptcha_response", "") - result = recaptcha2.verify( - app.config["RECAPTCHA_SECRET_KEY"], recaptcha_response, get_request_ip() - ) + user = get_authenticated_user() + # check if the user is whitelisted to bypass recaptcha security check + if user is None or (user.username not in app.config["RECAPTCHA_WHITELISTED_USERS"]): + recaptcha_response = user_data.get("recaptcha_response", "") + result = recaptcha2.verify( + app.config["RECAPTCHA_SECRET_KEY"], recaptcha_response, get_request_ip() + ) - if not result["success"]: - return {"message": "Are you a bot? If not, please revalidate the captcha."}, 400 + if not result["success"]: + return {"message": "Are you a bot? If not, please revalidate the captcha."}, 400 is_possible_abuser = ip_resolver.is_ip_possible_threat(get_request_ip()) try: diff --git a/features/__init__.pyi b/features/__init__.pyi index 24296b938..64dd12c68 100644 --- a/features/__init__.pyi +++ b/features/__init__.pyi @@ -128,6 +128,9 @@ REPO_MIRROR: FeatureNameValue # Site key and secret key for using recaptcha. RECAPTCHA: FeatureNameValue +# List of users allowed to pass through recaptcha security check to enable org/user creation via API +RECAPTCHA_WHITELISTED_USERS: FeatureNameValue + # Feature Flag: Whether team syncing from the backing auth is enabled. TEAM_SYNCING: FeatureNameValue diff --git a/test/test_api_usage.py b/test/test_api_usage.py index 1de766194..9fea6c3cc 100644 --- a/test/test_api_usage.py +++ b/test/test_api_usage.py @@ -814,6 +814,12 @@ class TestCreateNewUser(ApiTestCase): details["recaptcha_response"] = "somecode" self.postResponse(User, data=details, expected_code=200) + def test_recaptcha_whitelisted_users(self): + self.login(READ_ACCESS_USER) + with (self.toggleFeature("RECAPTCHA", True)): + app.config["RECAPTCHA_WHITELISTED_USERS"] = READ_ACCESS_USER + self.postResponse(User, data=NEW_USER_DETAILS, expected_code=200) + def test_createuser_withteaminvite(self): inviter = model.user.get_user(ADMIN_ACCESS_USER) team = model.team.get_organization_team(ORGANIZATION, "owners") diff --git a/test/testconfig.py b/test/testconfig.py index 07c9a666d..434ad4f5d 100644 --- a/test/testconfig.py +++ b/test/testconfig.py @@ -90,6 +90,7 @@ class TestConfig(DefaultConfig): RECAPTCHA_SITE_KEY = "somekey" RECAPTCHA_SECRET_KEY = "somesecretkey" + RECAPTCHA_WHITELISTED_USERS: List[str] = [] FEATURE_APP_REGISTRY = True FEATURE_TEAM_SYNCING = True diff --git a/util/config/schema.py b/util/config/schema.py index 0136f35be..908e71a0f 100644 --- a/util/config/schema.py +++ b/util/config/schema.py @@ -811,6 +811,15 @@ CONFIG_SCHEMA = { "type": ["string", "null"], "description": "If recaptcha is enabled, the secret key for the Recaptcha service", }, + # Pass through recaptcha for whitelisted users to support org/user creation via API + "RECAPTCHA_WHITELISTED_USERS": { + "type": "array", + "description": "Quay usernames of those users allowed to create org/user via API bypassing recaptcha security check", + "uniqueItems": True, + "items": { + "type": "string", + }, + }, # External application tokens. "FEATURE_APP_SPECIFIC_TOKENS": { "type": "boolean",