Browse Source

Continuing refractor

Ralfp 12 years ago
parent
commit
67cd93910b

+ 125 - 0
misago/auth.py

@@ -0,0 +1,125 @@
+from datetime import timedelta
+from django.conf import settings
+from django.utils import timezone
+from django.utils.translation import ugettext_lazy as _
+from misago.banning.models import check_ban
+from misago.bruteforce.models import SignInAttempt
+from misago.sessions.models import Token
+from misago.users.models import User
+
+"""
+Exception constants
+"""
+CREDENTIALS = 0
+ACTIVATION_USER = 1
+ACTIVATION_ADMIN = 2
+BANNED = 3
+NOT_ADMIN = 4
+
+
+class AuthException(Exception):
+    """
+    Auth Exception is thrown when auth_* method finds problem with allowing user to sign-in
+    """
+    def __init__(self, type=None, error=None, password=False, activation=False, ban=False):
+        self.type = type
+        self.error = error
+        self.password = password
+        self.activation = activation
+        self.ban = ban
+
+    def __str__(self):
+        return self.error
+
+
+def get_user(email, password, admin=False):
+    """
+    Fetch user from DB using email/pass pair, scream if either of data is incorrect
+    """
+    try:
+        user = User.objects.get_by_email(email)
+        if not user.check_password(password):
+            raise AuthException(CREDENTIALS, _("Your e-mail address or password is incorrect. Please try again."), password=True)
+        if not admin:
+            if user.activation == User.ACTIVATION_ADMIN:
+                # Only admin can activate your account.
+                raise AuthException(ACTIVATION_ADMIN, _("Board Administrator has not yet accepted your account."))
+            if user.activation != User.ACTIVATION_NONE:
+                # You have to activate your account - new member
+                raise AuthException(ACTIVATION_USER, _("You have to activate your account before you will be able to sign-in."), activation=True)
+
+    except User.DoesNotExist:
+        raise AuthException(CREDENTIALS, _("Your e-mail address or password is incorrect. Please try again."), password=True)
+    return user;
+
+
+def auth_forum(request, email, password):
+    """
+    Forum auth - check bans and if we are in maintenance - maintenance access
+    """
+    user = get_user(email, password)
+    user_ban = check_ban(username=user.username, email=user.email)
+    if user_ban:
+        if user_ban.reason_user:
+            raise AuthException(BANNED, _("Your account has been banned for following reason:"), ban=user_ban)
+        raise AuthException(BANNED, _("Your account has been banned."), ban=user_ban)
+    return user;
+
+
+def auth_remember(request, ip):
+    """
+    Remember-me auth - check if token is valid
+    Dont worry about AuthException being empty, it doesnt have to have anything
+    """
+    if request.firewall.admin:
+        raise AuthException()
+    if SignInAttempt.objects.is_jammed(request.settings, ip):
+        raise AuthException()
+    cookie_token = settings.COOKIES_PREFIX + 'TOKEN'
+    try:
+        cookie_token = request.COOKIES[cookie_token]
+        if len(cookie_token) != 42:
+            raise AuthException()
+        try:
+            token_rk = Token.objects.select_related().get(pk=cookie_token)
+        except Token.DoesNotExist:
+            request.cookie_jar.delete('TOKEN')
+            raise AuthException()
+
+        # See if token is not expired
+        token_expires = timezone.now() - timedelta(days=request.settings['remember_me_lifetime'])
+        if request.settings['remember_me_extensible'] and token_rk.accessed < token_expires:
+            # Token expired because it's last use is smaller than expiration date
+            raise AuthException()
+
+        if not request.settings['remember_me_extensible'] and token_rk.created < token_expires:
+            # Token expired because it was created before expiration date
+            raise AuthException()
+
+        # Update token date
+        token_rk.accessed = timezone.now()
+        token_rk.save(force_update=True)
+        request.cookie_jar.set('TOKEN', token_rk.id, True)
+    except (AttributeError, KeyError):
+        raise AuthException()
+    return token_rk
+
+
+def auth_admin(request, email, password):
+    """
+    Admin auth - check ACP permissions
+    """
+    user = get_user(email, password, True)
+    if not user.is_god() and not user.get_acl(request).admin.is_admin():
+        raise AuthException(NOT_ADMIN, _("Your account does not have admin privileges."))
+    return user;
+
+
+def sign_user_in(request, user):
+    user.set_last_visit(
+                        request.session.get_ip(request),
+                        request.META.get('HTTP_USER_AGENT', ''),
+                        )
+    user.save(force_update=True)
+    request.session.set_user(user)
+    request.session.set_hidden(user.hide_activity > 0)

+ 1 - 1
misago/sessions.py

@@ -5,7 +5,7 @@ from django.db.models.loading import cache as model_cache
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.crypto import salted_hmac
 from django.utils.crypto import salted_hmac
 from django.utils.encoding import force_unicode
 from django.utils.encoding import force_unicode
-from misago.authn.methods import auth_remember, AuthException
+from misago.auth.methods import auth_remember, AuthException
 from misago.models import Session, Token, Guest, User
 from misago.models import Session, Token, Guest, User
 from misago.utils.string import random_string
 from misago.utils.string import random_string
 
 

+ 0 - 0
misago/shared/signin/__init__.py


+ 30 - 0
misago/shared/signin/forms.py

@@ -0,0 +1,30 @@
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+from misago.forms import Form
+
+class SignInForm(Form):
+    user_email = forms.EmailField(max_length=255, label=_("Your email"))
+    user_password = forms.CharField(widget=forms.PasswordInput, max_length=255, label=_("Your password"))
+    user_remember_me = forms.BooleanField(label=_("Stay Signed In"), help_text=_("Sign me In automatically next time"), required=False)
+
+    layout = [
+              (
+               None,
+               (
+                ('user_email', {'attrs': {'placeholder': _("Enter your e-mail")}}),
+                ('user_password', {'has_value': False, 'placeholder': _("Enter your password")}),
+                )
+               ),
+              (
+               None,
+               ['user_remember_me'],
+               ),
+              ]
+
+    def __init__(self, *args, **kwargs):
+        show_remember_me = kwargs['show_remember_me']
+        del kwargs['show_remember_me']
+
+        super(SignInForm, self).__init__(*args, **kwargs)
+        if not show_remember_me:
+            del self.fields['user_remember_me']

+ 13 - 0
misago/shared/signin/urls.py

@@ -0,0 +1,13 @@
+from django.conf.urls import patterns, url
+from misago.admin import ADMIN_PATH
+
+urlpatterns = patterns('misago.shared.signin.views',
+    url(r'^signin/$', 'signin', name="sign_in"),
+    url(r'^signout/$', 'signout', name="sign_out"),
+)
+
+# Include admin patterns
+if ADMIN_PATH:
+    urlpatterns += patterns('misago.shared.signin.views',
+        url(r'^' + ADMIN_PATH + 'signout/$', 'signout', name="admin_sign_out"),
+    )

+ 110 - 0
misago/shared/signin/views.py

@@ -0,0 +1,110 @@
+from django.core.urlresolvers import reverse
+from django.shortcuts import redirect
+from django.template import RequestContext
+from django.utils import timezone
+from django.utils.translation import ugettext as _
+from misago.admin import site
+from misago.forms import FormLayout
+from misago.messages import Message
+import misago.auth as auth
+from misago.auth.decorators import 
+from misago.shared.signin.forms import SignInForm
+from misago.auth import AuthException, auth_admin, auth_forum, sign_user_in
+from misago.decorators import (block_authenticated, block_banned, block_crawlers,
+                            block_guest, block_jammed, check_csrf)
+from misago.models import SignInAttempt, Token
+from misago.utils import random_string
+
+@block_crawlers
+@block_banned
+@block_authenticated
+@block_jammed
+def signin(request):
+    message = request.messages.get_message('security')
+    bad_password = False
+    not_active = False
+    banned_account = False
+
+    if request.method == 'POST':
+        form = SignInForm(
+                          request.POST,
+                          show_remember_me=not request.firewall.admin and request.settings['remember_me_allow'],
+                          request=request
+                          )
+
+        if form.is_valid():
+            try:
+                # Configure correct auth and redirect links
+                if request.firewall.admin:
+                    auth_method = auth_admin
+                    success_redirect = reverse(site.get_admin_index())
+                else:
+                    auth_method = auth_forum
+                    success_redirect = reverse('index')
+
+                # Authenticate user
+                user = auth_method(
+                                  request,
+                                  form.cleaned_data['user_email'],
+                                  form.cleaned_data['user_password'],
+                                  )
+
+                sign_user_in(request, user)
+                remember_me_token = False
+
+                if not request.firewall.admin and request.settings['remember_me_allow'] and form.cleaned_data['user_remember_me']:
+                    remember_me_token = random_string(42)
+                    remember_me = Token(
+                                        id=remember_me_token,
+                                        user=user,
+                                        created=timezone.now(),
+                                        accessed=timezone.now(),
+                                        )
+                    remember_me.save()
+                if remember_me_token:
+                    request.cookie_jar.set('TOKEN', remember_me_token, True)
+                request.messages.set_flash(Message(_("Welcome back, %(username)s!") % {'username': user.username}), 'success', 'security')
+                return redirect(success_redirect)
+            except AuthException as e:
+                message = Message(e.error, 'error')
+                bad_password = e.password
+                banned_account = e.ban
+                not_active = e.activation
+
+                # If not in Admin, register failed attempt
+                if not request.firewall.admin and e.type == auth.CREDENTIALS:
+                    SignInAttempt.objects.register_attempt(request.session.get_ip(request))
+
+                    # Have we jammed our account?
+                    if SignInAttempt.objects.is_jammed(request.settings, request.session.get_ip(request)):
+                        request.jam.expires = timezone.now()
+                        return redirect(reverse('sign_in'))
+        else:
+            message = Message(form.non_field_errors()[0], 'error')
+    else:
+        form = SignInForm(
+                          show_remember_me=not request.firewall.admin and request.settings['remember_me_allow'],
+                          request=request
+                          )
+    return request.theme.render_to_response('signin.html',
+                                            {
+                                             'message': message,
+                                             'bad_password': bad_password,
+                                             'banned_account': banned_account,
+                                             'not_active': not_active,
+                                             'form': FormLayout(form),
+                                             'hide_signin': True,
+                                             },
+                                            context_instance=RequestContext(request));
+
+
+@block_crawlers
+@block_guest
+@check_csrf
+def signout(request):
+    user = request.user
+    request.session.sign_out(request)
+    request.messages.set_flash(Message(_("You have been signed out.")), 'info', 'security')
+    if request.firewall.admin:
+        return redirect(reverse(site.get_admin_index()))
+    return redirect(reverse('index'))

+ 4 - 2
misago/urls.py

@@ -4,9 +4,9 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns
 from misago.admin import ADMIN_PATH, site
 from misago.admin import ADMIN_PATH, site
 
 
 # Include frontend patterns
 # Include frontend patterns
-"""
 urlpatterns = patterns('',
 urlpatterns = patterns('',
-    (r'^', include('misago.authn.urls')),
+    (r'^', include('misago.shared.signin.urls')),
+    """
     (r'^users/', include('misago.profiles.urls')),
     (r'^users/', include('misago.profiles.urls')),
     (r'^usercp/', include('misago.usercp.urls')),
     (r'^usercp/', include('misago.usercp.urls')),
     (r'^register/', include('misago.register.urls')),
     (r'^register/', include('misago.register.urls')),
@@ -26,8 +26,10 @@ urlpatterns = patterns('',
     url(r'^popular/(?P<page>[0-9]+)/$', 'misago.views.popular_threads', name="popular_threads"),
     url(r'^popular/(?P<page>[0-9]+)/$', 'misago.views.popular_threads', name="popular_threads"),
     url(r'^new/$', 'misago.views.new_threads', name="new_threads"),
     url(r'^new/$', 'misago.views.new_threads', name="new_threads"),
     url(r'^new/(?P<page>[0-9]+)/$', 'misago.views.new_threads', name="new_threads"),
     url(r'^new/(?P<page>[0-9]+)/$', 'misago.views.new_threads', name="new_threads"),
+    """
 )
 )
 
 
+"""
 # Include admin patterns
 # Include admin patterns
 if ADMIN_PATH:
 if ADMIN_PATH:
     urlpatterns += patterns('',
     urlpatterns += patterns('',