Merge remote-tracking branch 'upstream/master' into basic_auth
[mediagoblin.git] / mediagoblin / auth / tools.py
index db6b6e3708c88a50b0c06dac2eb0db2c633d8dc4..adcf07fe0689aa56ebe5d96c5f1906738babca84 100644 (file)
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-import uuid
 import logging
-
 import wtforms
-from sqlalchemy import or_
 
 from mediagoblin import mg_globals
-from mediagoblin.auth import lib as auth_lib
 from mediagoblin.db.models import User
 from mediagoblin.tools.mail import (normalize_email, send_email,
                                     email_debug_message)
-from mediagoblin.tools.template import render_template
 from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
+from mediagoblin.tools.template import render_template
+from mediagoblin.tools.pluginapi import hook_handle
+from mediagoblin import auth
 
 _log = logging.getLogger(__name__)
 
@@ -96,11 +94,41 @@ def send_verification_email(user, request):
         rendered_email)
 
 
+EMAIL_FP_VERIFICATION_TEMPLATE = (
+    u"http://{host}{uri}?"
+    u"userid={userid}&token={fp_verification_key}")
+
+
+def send_fp_verification_email(user, request):
+    """
+    Send the verification email to users to change their password.
+
+    Args:
+    - user: a user object
+    - request: the request
+    """
+    rendered_email = render_template(
+        request, 'mediagoblin/auth/fp_verification_email.txt',
+        {'username': user.username,
+         'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format(
+                host=request.host,
+                uri=request.urlgen('mediagoblin.auth.verify_forgot_password'),
+                userid=unicode(user.id),
+                fp_verification_key=user.fp_verification_key)})
+
+    # TODO: There is no error handling in place
+    send_email(
+        mg_globals.app_config['email_sender_address'],
+        [user.email],
+        'GNU MediaGoblin - Change forgotten password!',
+        rendered_email)
+
+
 def basic_extra_validation(register_form, *args):
     users_with_username = User.query.filter_by(
-        username=register_form.data['username']).count()
+        username=register_form.username.data).count()
     users_with_email = User.query.filter_by(
-        email=register_form.data['email']).count()
+        email=register_form.email.data).count()
 
     extra_validation_passes = True
 
@@ -118,17 +146,11 @@ def basic_extra_validation(register_form, *args):
 
 def register_user(request, register_form):
     """ Handle user registration """
-    extra_validation_passes = basic_extra_validation(register_form)
+    extra_validation_passes = auth.extra_validation(register_form)
 
     if extra_validation_passes:
         # Create the user
-        user = User()
-        user.username = register_form.data['username']
-        user.email = register_form.data['email']
-        user.pw_hash = auth_lib.bcrypt_gen_password_hash(
-            register_form.password.data)
-        user.verification_key = unicode(uuid.uuid4())
-        user.save()
+        user = auth.create_user(register_form)
 
         # log the user in
         request.session['user_id'] = unicode(user.id)
@@ -143,17 +165,43 @@ def register_user(request, register_form):
     return None
 
 
-def check_login_simple(username, password, username_might_be_email=False):
-    search = (User.username == username)
-    if username_might_be_email and ('@' in username):
-        search = or_(search, User.email == username)
-    user = User.query.filter(search).first()
+def check_login_simple(username, password):
+    user = auth.get_user(username=username)
     if not user:
         _log.info("User %r not found", username)
-        auth_lib.fake_login_attempt()
+        auth.fake_login_attempt()
         return None
-    if not auth_lib.bcrypt_check_password(password, user.pw_hash):
+    if not auth.check_password(password, user.pw_hash):
         _log.warn("Wrong password for %r", username)
         return None
     _log.info("Logging %r in", username)
     return user
+
+
+class AuthError(Exception):
+    def __init__(self):
+        self.value = 'No Authentication Plugin is enabled and no_auth = false'\
+                     ' in config!'
+
+    def __str__(self):
+        return repr(self.value)
+
+
+def check_auth_enabled():
+    no_auth = mg_globals.app_config['no_auth']
+    auth_plugin = hook_handle('authentication')
+
+    if no_auth == 'false' and not auth_plugin:
+        raise AuthError
+
+    if no_auth == 'true' and not auth_plugin:
+        _log.warning('No authentication is enabled')
+        return False
+    else:
+        return True
+
+
+def no_auth_logout(request):
+    """Log out the user if in no_auth mode"""
+    if not mg_globals.app.auth:
+        request.session.delete()