Browse Source

fix(auth): Remove automatic member registration

This removes the automatic membership registration designed for SINGLE_ORGANIZATION mode.
David Cramer 7 years ago
parent
commit
09f4cba7ad

+ 3 - 0
CHANGES

@@ -4,6 +4,8 @@ Version 8.22 (Unreleased)
 Version 8.21
 ------------
 
+- BREAKING: Members will no longer be automatically granted membership to the
+  default organization. You should use SSO or the invite flows.
 - Ignore querystrings when looking up release artifacts
 - Add Visual Studio authentication provider for plugins.
 - Add "team" parameter to the project details API.
@@ -17,6 +19,7 @@ Schema Changes
 - Added ``UserIdentity`` model.
 - Added ``ProjectTeam`` model
 
+
 Version 8.20
 ------------
 - Make BitBucket repositories enabled by default

+ 11 - 5
src/sentry/web/frontend/auth_login.py

@@ -53,7 +53,7 @@ class AuthLoginView(BaseView):
         )
 
     def can_register(self, request, *args, **kwargs):
-        return auth.has_user_registration() or request.session.get('can_register')
+        return bool(auth.has_user_registration() or request.session.get('can_register'))
 
     def get_next_uri(self, request, *args, **kwargs):
         return request.GET.get(REDIRECT_FIELD_NAME, None)
@@ -61,8 +61,9 @@ class AuthLoginView(BaseView):
     def respond_login(self, request, context, *args, **kwargs):
         return self.respond('sentry/login.html', context)
 
-    def handle_basic_auth(self, request, *args, **kwargs):
-        can_register = self.can_register(request, *args, **kwargs)
+    def handle_basic_auth(self, request, organization=None, *args, **kwargs):
+        can_register = self.can_register(
+            request, organization=organization, *args, **kwargs)
 
         op = request.POST.get('op')
 
@@ -86,7 +87,11 @@ class AuthLoginView(BaseView):
             # HACK: grab whatever the first backend is and assume it works
             user.backend = settings.AUTHENTICATION_BACKENDS[0]
 
-            auth.login(request, user)
+            auth.login(
+                request,
+                user,
+                organization_id=organization.id if organization else None,
+            )
 
             # can_register should only allow a single registration
             request.session.pop('can_register', None)
@@ -124,10 +129,11 @@ class AuthLoginView(BaseView):
             'op': op or 'login',
             'server_hostname': get_server_hostname(),
             'login_form': login_form,
+            'organization': organization,
             'register_form': register_form,
             'CAN_REGISTER': can_register,
         }
-        return self.respond_login(request, context, *args, **kwargs)
+        return self.respond_login(request, context, organization=organization, *args, **kwargs)
 
     def handle_sso(self, request, *args, **kwargs):
         org = request.POST.get('organization')

+ 3 - 64
src/sentry/web/frontend/auth_organization_login.py

@@ -1,6 +1,5 @@
 from __future__ import absolute_import, print_function
 
-from django.conf import settings
 from django.core.urlresolvers import reverse
 from django.db import transaction
 from django.views.decorators.cache import never_cache
@@ -9,71 +8,11 @@ from django.contrib import messages
 from sentry.auth.helper import AuthHelper
 from sentry.constants import WARN_SESSION_EXPIRED
 from sentry.models import AuthProvider, Organization, OrganizationStatus
-from sentry.utils import auth
-from sentry.web.forms.accounts import AuthenticationForm, RegistrationForm
-from sentry.web.frontend.base import BaseView
-
-
-class AuthOrganizationLoginView(BaseView):
-    auth_required = False
-
-    def get_login_form(self, request):
-        op = request.POST.get('op')
-        return AuthenticationForm(
-            request,
-            request.POST if op == 'login' else None,
-        )
-
-    def get_register_form(self, request):
-        op = request.POST.get('op')
-        return RegistrationForm(
-            request.POST if op == 'register' else None,
-        )
-
-    def handle_basic_auth(self, request, organization):
-        can_register = auth.has_user_registration() or request.session.get('can_register')
-
-        op = request.POST.get('op')
-        login_form = self.get_login_form(request)
-        if can_register:
-            register_form = self.get_register_form(request)
-        else:
-            register_form = None
-
-        if can_register and register_form.is_valid():
-            user = register_form.save()
-            user.send_confirm_emails(is_new_user=True)
-
-            defaults = {
-                'role': 'member',
-            }
-
-            organization.member_set.create(user=user, **defaults)
-
-            # HACK: grab whatever the first backend is and assume it works
-            user.backend = settings.AUTHENTICATION_BACKENDS[0]
-
-            auth.login(request, user, organization_id=organization.id)
-
-            # can_register should only allow a single registration
-            request.session.pop('can_register', None)
+from sentry.web.frontend.auth_login import AuthLoginView
 
-            return self.redirect(auth.get_login_redirect(request))
 
-        elif login_form.is_valid():
-            auth.login(request, login_form.get_user(), organization_id=organization.id)
-
-            return self.redirect(auth.get_login_redirect(request))
-
-        request.session.set_test_cookie()
-
-        context = {
-            'op': op or 'login',
-            'login_form': login_form,
-            'register_form': register_form,
-            'organization': organization,
-            'CAN_REGISTER': can_register,
-        }
+class AuthOrganizationLoginView(AuthLoginView):
+    def respond_login(self, request, context, *args, **kwargs):
         return self.respond('sentry/organization-login.html', context)
 
     def handle_sso(self, request, organization, auth_provider):

+ 7 - 5
src/sentry/web/frontend/oauth_authorize.py

@@ -54,11 +54,11 @@ class OAuthAuthorizeView(AuthLoginView):
             }
         )
 
-    def respond_login(self, request, context, application):
+    def respond_login(self, request, context, application, *args, **kwargs):
         context['banner'] = 'Connect Sentry to {}'.format(application.name)
         return self.respond('sentry/login.html', context)
 
-    def get(self, request):
+    def get(self, request, *args, **kwargs):
         response_type = request.GET.get('response_type')
         client_id = request.GET.get('client_id')
         redirect_uri = request.GET.get('redirect_uri')
@@ -148,7 +148,8 @@ class OAuthAuthorizeView(AuthLoginView):
         request.session['oa2'] = payload
 
         if not request.user.is_authenticated():
-            return super(OAuthAuthorizeView, self).get(request, application)
+            return super(OAuthAuthorizeView, self).get(
+                request, application=application, *args, **kwargs)
 
         if not force_prompt:
             try:
@@ -207,7 +208,7 @@ class OAuthAuthorizeView(AuthLoginView):
         }
         return self.respond('sentry/oauth-authorize.html', context)
 
-    def post(self, request):
+    def post(self, request, *args, **kwargs):
         try:
             payload = request.session['oa2']
         except KeyError:
@@ -231,7 +232,8 @@ class OAuthAuthorizeView(AuthLoginView):
             )
 
         if not request.user.is_authenticated():
-            response = super(OAuthAuthorizeView, self).post(request, application)
+            response = super(OAuthAuthorizeView, self).post(
+                request, application=application, *args, **kwargs)
             # once they login, bind their user ID
             if request.user.is_authenticated():
                 request.session['oa2']['uid'] = request.user.id

+ 4 - 1
tests/sentry/web/frontend/test_auth_login.py

@@ -7,7 +7,7 @@ from exam import fixture
 
 from sentry import options
 from sentry.testutils import TestCase
-from sentry.models import User
+from sentry.models import OrganizationMember, User
 
 
 # TODO(dcramer): need tests for SSO behavior and single org behavior
@@ -81,6 +81,9 @@ class AuthLoginTest(TestCase):
         assert user.email == 'test-a-really-long-email-address@example.com'
         assert user.check_password('foobar')
         assert user.name == 'Foo Bar'
+        assert not OrganizationMember.objects.filter(
+            user=user,
+        ).exists()
 
     def test_register_renders_correct_template(self):
         options.set('auth.allow-registration', True)

+ 8 - 5
tests/sentry/web/frontend/test_auth_organization_login.py

@@ -2,13 +2,16 @@ from __future__ import absolute_import
 
 from django.core.urlresolvers import reverse
 
-from sentry.models import AuthIdentity, AuthProvider, OrganizationMember, UserEmail
+from sentry.models import (
+    AuthIdentity, AuthProvider, OrganizationMember, UserEmail
+)
 from sentry.testutils import AuthProviderTestCase
 
 
-# TODO(dcramer): this is an integration test
+# TODO(dcramer): this is an integration test and repeats tests from
+# core auth_login
 class OrganizationAuthLoginTest(AuthProviderTestCase):
-    def test_renders_basic_login_form(self):
+    def test_renders_basic(self):
         organization = self.create_organization(name='foo', owner=self.user)
 
         path = reverse('sentry-auth-organization', args=[organization.slug])
@@ -21,9 +24,9 @@ class OrganizationAuthLoginTest(AuthProviderTestCase):
 
         self.assertTemplateUsed(resp, 'sentry/organization-login.html')
 
-        assert resp.context['form']
+        assert resp.context['login_form']
+        assert resp.context['organization'] == organization
         assert 'provider_key' not in resp.context
-        assert resp.context['CAN_REGISTER']
 
     def test_renders_session_expire_message(self):
         organization = self.create_organization(name='foo', owner=self.user)