diff --git a/src/sentry/utils/auth.py b/src/sentry/utils/auth.py index 7c349d1c53213b..cbd89f3292ba84 100644 --- a/src/sentry/utils/auth.py +++ b/src/sentry/utils/auth.py @@ -23,7 +23,7 @@ from sentry.users.models.user import User from sentry.users.services.user import RpcUser from sentry.users.services.user.service import user_service -from sentry.utils import metrics +from sentry.utils import demo_mode, metrics from sentry.utils.http import absolute_uri logger = logging.getLogger("sentry.auth") @@ -417,6 +417,8 @@ def authenticate( if users: for user in users: try: + if demo_mode.is_readonly_user(user): + return user if user.password: # XXX(joshuarli): This is checked before (and therefore, regardless of outcome) # password checking as a mechanism to drop old password hashers immediately and diff --git a/src/sentry/utils/demo_mode.py b/src/sentry/utils/demo_mode.py new file mode 100644 index 00000000000000..56bb83eb609eb6 --- /dev/null +++ b/src/sentry/utils/demo_mode.py @@ -0,0 +1,36 @@ +from sentry import options +from sentry.models.organization import Organization +from sentry.users.models.user import User + + +def is_readonly_user(user: User | None) -> bool: + if not options.get("demo-mode.enabled"): + return False + + if not user: + return False + + email = getattr(user, "email", None) + + if email: + return True + + return email in options.get("demo-mode.users") + + +def is_demo_org(organization: Organization | None): + if not options.get("demo-mode.enabled"): + return False + + if not organization: + return False + + return organization.id in options.get("demo-mode.orgs") + + +def get_readonly_user(): + if not options.get("demo-mode.enabled"): + return None + + email = options.get("demo-mode.users")[0] + return User.objects.get(email=email) diff --git a/src/sentry/web/frontend/auth_login.py b/src/sentry/web/frontend/auth_login.py index cf19698091d73c..98a80cbcc3b9e2 100644 --- a/src/sentry/web/frontend/auth_login.py +++ b/src/sentry/web/frontend/auth_login.py @@ -28,7 +28,7 @@ from sentry.signals import join_request_link_viewed, user_signup from sentry.types.ratelimit import RateLimit, RateLimitCategory from sentry.users.models.user import User -from sentry.utils import auth, json, metrics +from sentry.utils import auth, demo_mode, json, metrics from sentry.utils.auth import ( construct_link_with_query, get_login_redirect, @@ -562,6 +562,11 @@ def handle_basic_auth(self, request: Request, **kwargs) -> HttpResponseBase: op = request.POST.get("op") organization = kwargs.pop("organization", None) + if demo_mode.is_demo_org(organization): + user = demo_mode.get_readonly_user() + self._handle_login(request, user, organization) + return self.redirect(get_login_redirect(request)) + if request.method == "GET" and request.subdomain and self.org_exists(request): urls = [ reverse("sentry-auth-organization", args=[request.subdomain]),