aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mediagoblin.ini5
-rw-r--r--mediagoblin/app.py7
-rw-r--r--mediagoblin/auth/__init__.py41
-rw-r--r--mediagoblin/auth/forms.py26
-rw-r--r--mediagoblin/auth/tools.py90
-rw-r--r--mediagoblin/auth/views.py52
-rw-r--r--mediagoblin/db/migrations.py11
-rw-r--r--mediagoblin/db/models.py2
-rw-r--r--mediagoblin/edit/views.py6
-rw-r--r--mediagoblin/gmg_commands/users.py6
-rw-r--r--mediagoblin/plugins/basic_auth/__init__.py98
-rw-r--r--mediagoblin/plugins/basic_auth/forms.py45
-rw-r--r--mediagoblin/plugins/basic_auth/tools.py (renamed from mediagoblin/auth/lib.py)38
-rw-r--r--mediagoblin/templates/mediagoblin/auth/change_fp.html3
-rw-r--r--mediagoblin/templates/mediagoblin/auth/forgot_password.html2
-rw-r--r--mediagoblin/templates/mediagoblin/auth/login.html4
-rw-r--r--mediagoblin/templates/mediagoblin/auth/register.html4
-rw-r--r--mediagoblin/templates/mediagoblin/base.html2
-rw-r--r--mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html36
-rw-r--r--mediagoblin/templates/mediagoblin/user_pages/media.html2
-rw-r--r--mediagoblin/tests/appconfig_context_modified.ini1
-rw-r--r--mediagoblin/tests/appconfig_plugin_specs.ini4
-rw-r--r--mediagoblin/tests/appconfig_static_plugin.ini1
-rw-r--r--mediagoblin/tests/auth_configs/__init__.py0
-rw-r--r--mediagoblin/tests/auth_configs/no_auth_false_no_auth_plugin_appconfig.ini26
-rw-r--r--mediagoblin/tests/auth_configs/no_auth_true_no_auth_plugin_appconfig.ini26
-rw-r--r--mediagoblin/tests/test_auth.py106
-rw-r--r--mediagoblin/tests/test_basic_auth.py59
-rw-r--r--mediagoblin/tests/test_edit.py7
-rw-r--r--mediagoblin/tests/test_mgoblin_app.ini2
-rw-r--r--mediagoblin/tests/tools.py4
-rw-r--r--mediagoblin/tools/template.py1
32 files changed, 548 insertions, 169 deletions
diff --git a/mediagoblin.ini b/mediagoblin.ini
index 4906546a..4799b248 100644
--- a/mediagoblin.ini
+++ b/mediagoblin.ini
@@ -33,6 +33,10 @@ allow_registration = true
## install other themes.
# theme = airy
+# Set to true to run an instance with no authentication plugins enabled.
+# You will not be able to login or register
+no_auth = false
+
[storage:queuestore]
base_dir = %(here)s/user_dev/media/queue
@@ -47,3 +51,4 @@ base_url = /mgoblin_media/
# documentation for details.
[plugins]
[[mediagoblin.plugins.geolocation]]
+[[mediagoblin.plugins.basic_auth]]
diff --git a/mediagoblin/app.py b/mediagoblin/app.py
index 1984ce77..982e570c 100644
--- a/mediagoblin/app.py
+++ b/mediagoblin/app.py
@@ -37,6 +37,7 @@ from mediagoblin.init import (get_jinja_loader, get_staticdirector,
setup_storage)
from mediagoblin.tools.pluginapi import PluginManager, hook_transform
from mediagoblin.tools.crypto import setup_crypto
+from mediagoblin.auth.tools import check_auth_enabled, no_auth_logout
_log = logging.getLogger(__name__)
@@ -97,6 +98,9 @@ class MediaGoblinApp(object):
PluginManager().get_template_paths()
)
+ # Check if authentication plugin is enabled and respond accordingly.
+ self.auth = check_auth_enabled()
+
# Set up storage systems
self.public_store, self.queue_store = setup_storage()
@@ -188,6 +192,9 @@ class MediaGoblinApp(object):
mg_request.setup_user_in_request(request)
+ # Log user out if in no_auth mode
+ no_auth_logout(request)
+
request.controller_name = None
try:
found_rule, url_values = map_adapter.match(return_rule=True)
diff --git a/mediagoblin/auth/__init__.py b/mediagoblin/auth/__init__.py
index 621845ba..ab3d37e7 100644
--- a/mediagoblin/auth/__init__.py
+++ b/mediagoblin/auth/__init__.py
@@ -13,3 +13,44 @@
#
# 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/>.
+from mediagoblin.tools.pluginapi import hook_handle, hook_runall
+
+
+def get_user(**kwargs):
+ """ Takes a kwarg such as username and returns a user object """
+ return hook_handle("auth_get_user", **kwargs)
+
+
+def create_user(register_form):
+ results = hook_runall("auth_create_user", register_form)
+ return results[0]
+
+
+def extra_validation(register_form):
+ from mediagoblin.auth.tools import basic_extra_validation
+
+ extra_validation_passes = basic_extra_validation(register_form)
+ if False in hook_runall("auth_extra_validation", register_form):
+ extra_validation_passes = False
+ return extra_validation_passes
+
+
+def get_login_form(request):
+ return hook_handle("auth_get_login_form", request)
+
+
+def get_registration_form(request):
+ return hook_handle("auth_get_registration_form", request)
+
+
+def gen_password_hash(raw_pass, extra_salt=None):
+ return hook_handle("auth_gen_password_hash", raw_pass, extra_salt)
+
+
+def check_password(raw_pass, stored_hash, extra_salt=None):
+ return hook_handle("auth_check_password",
+ raw_pass, stored_hash, extra_salt)
+
+
+def fake_login_attempt():
+ return hook_handle("auth_fake_login_attempt")
diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py
index 0a391d67..7a67285b 100644
--- a/mediagoblin/auth/forms.py
+++ b/mediagoblin/auth/forms.py
@@ -20,32 +20,6 @@ from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
from mediagoblin.auth.tools import normalize_user_or_email_field
-class RegistrationForm(wtforms.Form):
- username = wtforms.TextField(
- _('Username'),
- [wtforms.validators.Required(),
- normalize_user_or_email_field(allow_email=False)])
- password = wtforms.PasswordField(
- _('Password'),
- [wtforms.validators.Required(),
- wtforms.validators.Length(min=5, max=1024)])
- email = wtforms.TextField(
- _('Email address'),
- [wtforms.validators.Required(),
- normalize_user_or_email_field(allow_user=False)])
-
-
-class LoginForm(wtforms.Form):
- username = wtforms.TextField(
- _('Username or Email'),
- [wtforms.validators.Required(),
- normalize_user_or_email_field()])
- password = wtforms.PasswordField(
- _('Password'),
- [wtforms.validators.Required(),
- wtforms.validators.Length(min=5, max=1024)])
-
-
class ForgotPassForm(wtforms.Form):
username = wtforms.TextField(
_('Username or email'),
diff --git a/mediagoblin/auth/tools.py b/mediagoblin/auth/tools.py
index db6b6e37..22da54d0 100644
--- a/mediagoblin/auth/tools.py
+++ b/mediagoblin/auth/tools.py
@@ -14,19 +14,17 @@
# 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.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()
diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py
index bb7bda77..22120d10 100644
--- a/mediagoblin/auth/views.py
+++ b/mediagoblin/auth/views.py
@@ -22,11 +22,11 @@ from mediagoblin.db.models import User
from mediagoblin.tools.response import render_to_response, redirect, render_404
from mediagoblin.tools.translate import pass_to_ugettext as _
from mediagoblin.tools.mail import email_debug_message
-from mediagoblin.auth import lib as auth_lib
from mediagoblin.auth import forms as auth_forms
-from mediagoblin.auth.lib import send_fp_verification_email
from mediagoblin.auth.tools import (send_verification_email, register_user,
+ send_fp_verification_email,
check_login_simple)
+from mediagoblin import auth
def register(request):
@@ -35,15 +35,20 @@ def register(request):
Note that usernames will always be lowercased. Email domains are lowercased while
the first part remains case-sensitive.
"""
- # Redirects to indexpage if registrations are disabled
- if not mg_globals.app_config["allow_registration"]:
+ # Redirects to indexpage if registrations are disabled or no authentication
+ # is enabled
+ if not mg_globals.app_config["allow_registration"] or not mg_globals.app.auth:
messages.add_message(
request,
messages.WARNING,
_('Sorry, registration is disabled on this instance.'))
return redirect(request, "index")
- register_form = auth_forms.RegistrationForm(request.form)
+ if 'pass_auth' not in request.template_env.globals:
+ if 'openid' in request.template_env.globals:
+ return redirect(request, 'mediagoblin.plugins.openid.register')
+
+ register_form = auth.get_registration_form(request)
if request.method == 'POST' and register_form.validate():
# TODO: Make sure the user doesn't exist already
@@ -59,7 +64,9 @@ def register(request):
return render_to_response(
request,
'mediagoblin/auth/register.html',
- {'register_form': register_form})
+ {'register_form': register_form,
+ 'focus': 'username',
+ 'post_url': request.urlgen('mediagoblin.auth.register')})
def login(request):
@@ -68,16 +75,32 @@ def login(request):
If you provide the POST with 'next', it'll redirect to that view.
"""
- login_form = auth_forms.LoginForm(request.form)
+ # Redirects to index page if no authentication is enabled
+ if not mg_globals.app.auth:
+ messages.add_message(
+ request,
+ messages.WARNING,
+ _('Sorry, authentication is disabled on this instance.'))
+ return redirect(request, 'index')
+
+ if 'pass_auth' not in request.template_env.globals:
+ if 'openid' in request.template_env.globals:
+ return redirect(request, 'mediagoblin.plugins.openid.login')
+
+ login_form = auth.get_login_form(request)
login_failed = False
if request.method == 'POST':
+ username = login_form.username.data
+
+ if login_form.validate():
+ user = check_login_simple(username, login_form.password.data)
username = login_form.data['username']
if login_form.validate():
- user = check_login_simple(username, login_form.password.data, True)
+ user = check_login_simple(username, login_form.password.data)
if user:
# set up login in session
@@ -97,6 +120,8 @@ def login(request):
{'login_form': login_form,
'next': request.GET.get('next') or request.form.get('next'),
'login_failed': login_failed,
+ 'focus': 'username',
+ 'post_url': request.urlgen('mediagoblin.auth.login'),
'allow_registration': mg_globals.app_config["allow_registration"]})
@@ -188,13 +213,17 @@ def forgot_password(request):
Sends an email with an url to renew forgotten password.
Use GET querystring parameter 'username' to pre-populate the input field
"""
+ if not 'pass_auth' in request.template_env.globals:
+ return redirect(request, 'index')
+
fp_form = auth_forms.ForgotPassForm(request.form,
username=request.args.get('username'))
if not (request.method == 'POST' and fp_form.validate()):
# Either GET request, or invalid form submitted. Display the template
return render_to_response(request,
- 'mediagoblin/auth/forgot_password.html', {'fp_form': fp_form})
+ 'mediagoblin/auth/forgot_password.html', {'fp_form': fp_form,
+ 'focus': 'username'})
# If we are here: method == POST and form is valid. username casing
# has been sanitized. Store if a user was found by email. We should
@@ -275,7 +304,7 @@ def verify_forgot_password(request):
cp_form = auth_forms.ChangePassForm(formdata_vars)
if request.method == 'POST' and cp_form.validate():
- user.pw_hash = auth_lib.bcrypt_gen_password_hash(
+ user.pw_hash = auth.gen_password_hash(
cp_form.password.data)
user.fp_verification_key = None
user.fp_token_expire = None
@@ -290,7 +319,8 @@ def verify_forgot_password(request):
return render_to_response(
request,
'mediagoblin/auth/change_fp.html',
- {'cp_form': cp_form})
+ {'cp_form': cp_form,
+ 'focus': 'password'})
# in case there is a valid id but no user with that id in the db
# or the token expired
diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py
index 2c553396..1f92417e 100644
--- a/mediagoblin/db/migrations.py
+++ b/mediagoblin/db/migrations.py
@@ -287,3 +287,14 @@ def unique_collections_slug(db):
constraint.create()
db.commit()
+
+
+@RegisterMigration(11, MIGRATIONS)
+def pw_hash_nullable(db):
+ """Make pw_hash column nullable"""
+ metadata = MetaData(bind=db.bind)
+ user_table = inspect_table(metadata, "core__users")
+
+ user_table.c.pw_hash.alter(nullable=True)
+
+ db.commit()
diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py
index 2b925983..323ed4d7 100644
--- a/mediagoblin/db/models.py
+++ b/mediagoblin/db/models.py
@@ -61,7 +61,7 @@ class User(Base, UserMixin):
# point.
email = Column(Unicode, nullable=False)
created = Column(DateTime, nullable=False, default=datetime.datetime.now)
- pw_hash = Column(Unicode, nullable=False)
+ pw_hash = Column(Unicode)
email_verified = Column(Boolean, default=False)
status = Column(Unicode, default=u"needs_email_verification", nullable=False)
# Intented to be nullable=False, but migrations would not work for it
diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py
index 508c380d..161285a2 100644
--- a/mediagoblin/edit/views.py
+++ b/mediagoblin/edit/views.py
@@ -22,7 +22,7 @@ from werkzeug.utils import secure_filename
from mediagoblin import messages
from mediagoblin import mg_globals
-from mediagoblin.auth import lib as auth_lib
+from mediagoblin import auth
from mediagoblin.edit import forms
from mediagoblin.edit.lib import may_edit_media
from mediagoblin.decorators import (require_active_login, active_user_from_url,
@@ -342,7 +342,7 @@ def change_pass(request):
if request.method == 'POST' and form.validate():
- if not auth_lib.bcrypt_check_password(
+ if not auth.check_password(
form.old_password.data, user.pw_hash):
form.old_password.errors.append(
_('Wrong password'))
@@ -354,7 +354,7 @@ def change_pass(request):
'user': user})
# Password matches
- user.pw_hash = auth_lib.bcrypt_gen_password_hash(
+ user.pw_hash = auth.gen_password_hash(
form.new_password.data)
user.save()
diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py
index 024c8498..1f329459 100644
--- a/mediagoblin/gmg_commands/users.py
+++ b/mediagoblin/gmg_commands/users.py
@@ -15,7 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from mediagoblin.gmg_commands import util as commands_util
-from mediagoblin.auth import lib as auth_lib
+from mediagoblin import auth
from mediagoblin import mg_globals
def adduser_parser_setup(subparser):
@@ -52,7 +52,7 @@ def adduser(args):
entry = db.User()
entry.username = unicode(args.username.lower())
entry.email = unicode(args.email)
- entry.pw_hash = auth_lib.bcrypt_gen_password_hash(args.password)
+ entry.pw_hash = auth.gen_password_hash(args.password)
entry.status = u'active'
entry.email_verified = True
entry.save()
@@ -96,7 +96,7 @@ def changepw(args):
user = db.User.one({'username': unicode(args.username.lower())})
if user:
- user.pw_hash = auth_lib.bcrypt_gen_password_hash(args.password)
+ user.pw_hash = auth.gen_password_hash(args.password)
user.save()
print 'Password successfully changed'
else:
diff --git a/mediagoblin/plugins/basic_auth/__init__.py b/mediagoblin/plugins/basic_auth/__init__.py
new file mode 100644
index 00000000..71e96d73
--- /dev/null
+++ b/mediagoblin/plugins/basic_auth/__init__.py
@@ -0,0 +1,98 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# 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
+
+from mediagoblin.plugins.basic_auth import forms as auth_forms
+from mediagoblin.plugins.basic_auth import tools as auth_tools
+from mediagoblin.db.models import User
+from mediagoblin.tools import pluginapi
+from sqlalchemy import or_
+
+
+def setup_plugin():
+ config = pluginapi.get_config('mediagoblin.pluginapi.basic_auth')
+
+
+def get_user(**kwargs):
+ username = kwargs.pop('username', None)
+ if username:
+ user = User.query.filter(
+ or_(
+ User.username == username,
+ User.email == username,
+ )).first()
+ return user
+
+
+def create_user(registration_form):
+ user = get_user(username=registration_form.username.data)
+ if not user and 'password' in registration_form:
+ user = User()
+ user.username = registration_form.username.data
+ user.email = registration_form.email.data
+ user.pw_hash = gen_password_hash(
+ registration_form.password.data)
+ user.verification_key = unicode(uuid.uuid4())
+ user.save()
+ return user
+
+
+def get_login_form(request):
+ return auth_forms.LoginForm(request.form)
+
+
+def get_registration_form(request):
+ return auth_forms.RegistrationForm(request.form)
+
+
+def gen_password_hash(raw_pass, extra_salt=None):
+ return auth_tools.bcrypt_gen_password_hash(raw_pass, extra_salt)
+
+
+def check_password(raw_pass, stored_hash, extra_salt=None):
+ return auth_tools.bcrypt_check_password(raw_pass, stored_hash, extra_salt)
+
+
+def auth():
+ return True
+
+
+def append_to_global_context(context):
+ context['pass_auth'] = True
+ return context
+
+
+def add_to_form_context(context):
+ context['pass_auth_link'] = True
+ return context
+
+
+hooks = {
+ 'setup': setup_plugin,
+ 'authentication': auth,
+ 'auth_get_user': get_user,
+ 'auth_create_user': create_user,
+ 'auth_get_login_form': get_login_form,
+ 'auth_get_registration_form': get_registration_form,
+ 'auth_gen_password_hash': gen_password_hash,
+ 'auth_check_password': check_password,
+ 'auth_fake_login_attempt': auth_tools.fake_login_attempt,
+ 'template_global_context': append_to_global_context,
+ ('mediagoblin.plugins.openid.register',
+ 'mediagoblin/auth/register.html'): add_to_form_context,
+ ('mediagoblin.plugins.openid.login',
+ 'mediagoblin/auth/login.html'): add_to_form_context,
+}
diff --git a/mediagoblin/plugins/basic_auth/forms.py b/mediagoblin/plugins/basic_auth/forms.py
new file mode 100644
index 00000000..f389b21e
--- /dev/null
+++ b/mediagoblin/plugins/basic_auth/forms.py
@@ -0,0 +1,45 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# 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 wtforms
+
+from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
+from mediagoblin.auth.tools import normalize_user_or_email_field
+
+
+class RegistrationForm(wtforms.Form):
+ username = wtforms.TextField(
+ _('Username'),
+ [wtforms.validators.Required(),
+ normalize_user_or_email_field(allow_email=False)])
+ password = wtforms.PasswordField(
+ _('Password'),
+ [wtforms.validators.Required(),
+ wtforms.validators.Length(min=5, max=1024)])
+ email = wtforms.TextField(
+ _('Email address'),
+ [wtforms.validators.Required(),
+ normalize_user_or_email_field(allow_user=False)])
+
+
+class LoginForm(wtforms.Form):
+ username = wtforms.TextField(
+ _('Username or Email'),
+ [wtforms.validators.Required(),
+ normalize_user_or_email_field()])
+ password = wtforms.PasswordField(
+ _('Password'),
+ [wtforms.validators.Required(),
+ wtforms.validators.Length(min=5, max=1024)])
diff --git a/mediagoblin/auth/lib.py b/mediagoblin/plugins/basic_auth/tools.py
index bfc36b28..1300bb9a 100644
--- a/mediagoblin/auth/lib.py
+++ b/mediagoblin/plugins/basic_auth/tools.py
@@ -13,14 +13,8 @@
#
# 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 random
-
import bcrypt
-
-from mediagoblin.tools.mail import send_email
-from mediagoblin.tools.template import render_template
-from mediagoblin import mg_globals
+import random
def bcrypt_check_password(raw_pass, stored_hash, extra_salt=None):
@@ -88,33 +82,3 @@ def fake_login_attempt():
randplus_hashed_pass = bcrypt.hashpw(hashed_pass, rand_salt)
randplus_stored_hash == randplus_hashed_pass
-
-
-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)
diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/templates/mediagoblin/auth/change_fp.html
index 1f7d9aca..afffeadd 100644
--- a/mediagoblin/templates/mediagoblin/auth/change_fp.html
+++ b/mediagoblin/templates/mediagoblin/auth/change_fp.html
@@ -39,6 +39,7 @@
<input type="submit" value="{% trans %}Set password{% endtrans %}" class="button_form"/>
</div>
</div>
- </form>
+</form><!-- Focus the field passed in with the focus arg-->
+<script>$(document).ready(function(){$({{ focus }}).focus();});</script>
{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/auth/forgot_password.html b/mediagoblin/templates/mediagoblin/auth/forgot_password.html
index 46aeddef..a6c9e1e9 100644
--- a/mediagoblin/templates/mediagoblin/auth/forgot_password.html
+++ b/mediagoblin/templates/mediagoblin/auth/forgot_password.html
@@ -35,4 +35,6 @@
</div>
</div>
</form>
+<!-- Focus the field passed in with the focus arg-->
+<script>$(document).ready(function(){$({{ focus }}).focus();});</script>
{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html
index 4a39059d..2adbe547 100644
--- a/mediagoblin/templates/mediagoblin/auth/login.html
+++ b/mediagoblin/templates/mediagoblin/auth/login.html
@@ -46,10 +46,12 @@
</p>
{% endif %}
{{ wtforms_util.render_divs(login_form) }}
+ {% if pass_auth %}
<p>
<a href="{{ request.urlgen('mediagoblin.auth.forgot_password') }}" id="forgot_password">
{% trans %}Forgot your password?{% endtrans %}</a>
</p>
+ {% endif %}
<div class="form_submit_buttons">
<input type="submit" value="{% trans %}Log in{% endtrans %}" class="button_form"/>
</div>
@@ -59,4 +61,6 @@
{% endif %}
</div>
</form>
+<!-- Focus the field passed in with the focus arg-->
+<script>$(document).ready(function(){$({{ focus }}).focus();});</script>
{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html
index 6dff0207..755d5418 100644
--- a/mediagoblin/templates/mediagoblin/auth/register.html
+++ b/mediagoblin/templates/mediagoblin/auth/register.html
@@ -42,6 +42,6 @@
</div>
</div>
</form>
-<!-- Focus the username field by default -->
-<script>$(document).ready(function(){$("#username").focus();});</script>
+<!-- Focus the field passed in with the focus arg-->
+<script>$(document).ready(function(){$({{ focus }}).focus();});</script>
{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html
index 6c7c07d0..fc4f420f 100644
--- a/mediagoblin/templates/mediagoblin/base.html
+++ b/mediagoblin/templates/mediagoblin/base.html
@@ -67,7 +67,7 @@
{% trans %}Verify your email!{% endtrans %}</a>
or <a href="{{ request.urlgen('mediagoblin.auth.logout') }}">{% trans %}log out{% endtrans %}</a>
{% endif %}
- {%- else %}
+ {%- elif auth %}
<a href="{{ request.urlgen('mediagoblin.auth.login') }}?next={{
request.base_url|urlencode }}">
{%- trans %}Log in{% endtrans -%}
diff --git a/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html b/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html
index 544ee146..26153694 100644
--- a/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html
+++ b/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html
@@ -17,19 +17,25 @@
#}
{% if request.user %}
- <h1>{% trans %}Explore{% endtrans %}</h1>
-{% else %}
- <h1>{% trans %}Hi there, welcome to this MediaGoblin site!{% endtrans %}</h1>
- <img class="right_align" src="{{ request.staticdirect('/images/frontpage_image.png') }}" />
- <p>{% trans %}This site is running <a href="http://mediagoblin.org">MediaGoblin</a>, an extraordinarily great piece of media hosting software.{% endtrans %}</p>
- <p>{% trans %}To add your own media, place comments, and more, you can log in with your MediaGoblin account.{% endtrans %}</p>
- {% if allow_registration %}
- <p>{% trans %}Don't have one yet? It's easy!{% endtrans %}</p>
- {% trans register_url=request.urlgen('mediagoblin.auth.register') -%}
- <a class="button_action_highlight" href="{{ register_url }}">Create an account at this site</a>
- or
- <a class="button_action" href="http://wiki.mediagoblin.org/HackingHowto">Set up MediaGoblin on your own server</a>
- {%- endtrans %}
+ <h1>{% trans %}Explore{% endtrans %}</h1>
+ {% else %}
+ <h1>{% trans %}Hi there, welcome to this MediaGoblin site!{% endtrans %}</h1>
+ <img class="right_align" src="{{ request.staticdirect('/images/frontpage_image.png') }}" />
+ <p>{% trans %}This site is running <a href="http://mediagoblin.org">MediaGoblin</a>, an extraordinarily great piece of media hosting software.{% endtrans %}</p>
+ {% if auth %}
+ <p>{% trans %}To add your own media, place comments, and more, you can log in with your MediaGoblin account.{% endtrans %}</p>
+ {% if allow_registration %}
+ <p>{% trans %}Don't have one yet? It's easy!{% endtrans %}</p>
+ {% trans register_url=request.urlgen('mediagoblin.auth.register') -%}
+ <a class="button_action_highlight" href="{{ register_url }}">Create an account at this site</a>
+ or
+ {%- endtrans %}
+ {% endif %}
+ {% endif %}
+ {% trans %}
+ <a class="button_action" href="http://wiki.mediagoblin.org/HackingHowto">Set up MediaGoblin on your own server</a>
+ {%- endtrans %}
+
+ <div class="clear"></div>
{% endif %}
- <div class="clear"></div>
-{% endif %}
+
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html
index fb892fd7..5420752f 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/media.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/media.html
@@ -86,7 +86,7 @@
<p>{{ media.description_html }}</p>
{% endautoescape %}
{% if comments %}
- {% if app_config['allow_comments'] %}
+ {% if app_config['allow_comments'] and auth %}
<a
{% if not request.user %}
href="{{ request.urlgen('mediagoblin.auth.login') }}"
diff --git a/mediagoblin/tests/appconfig_context_modified.ini b/mediagoblin/tests/appconfig_context_modified.ini
index 80ca69b1..23efa3bd 100644
--- a/mediagoblin/tests/appconfig_context_modified.ini
+++ b/mediagoblin/tests/appconfig_context_modified.ini
@@ -2,6 +2,7 @@
direct_remote_path = /test_static/
email_sender_address = "notice@mediagoblin.example.org"
email_debug_mode = true
+no_auth = true
# TODO: Switch to using an in-memory database
sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db"
diff --git a/mediagoblin/tests/appconfig_plugin_specs.ini b/mediagoblin/tests/appconfig_plugin_specs.ini
index 5511cd97..2029aa81 100644
--- a/mediagoblin/tests/appconfig_plugin_specs.ini
+++ b/mediagoblin/tests/appconfig_plugin_specs.ini
@@ -12,6 +12,10 @@ email_debug_mode = true
# Set to false to disable registrations
allow_registration = true
+# Set to true to run an instance with no authentication plugins enabled.
+# You will not be able to login or register
+no_auth = true
+
[plugins]
[[mediagoblin.tests.testplugins.pluginspec]]
some_string = "not blork"
diff --git a/mediagoblin/tests/appconfig_static_plugin.ini b/mediagoblin/tests/appconfig_static_plugin.ini
index dc251171..053a77c1 100644
--- a/mediagoblin/tests/appconfig_static_plugin.ini
+++ b/mediagoblin/tests/appconfig_static_plugin.ini
@@ -2,6 +2,7 @@
direct_remote_path = /test_static/
email_sender_address = "notice@mediagoblin.example.org"
email_debug_mode = true
+no_auth = true
# TODO: Switch to using an in-memory database
sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db"
diff --git a/mediagoblin/tests/auth_configs/__init__.py b/mediagoblin/tests/auth_configs/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/mediagoblin/tests/auth_configs/__init__.py
diff --git a/mediagoblin/tests/auth_configs/no_auth_false_no_auth_plugin_appconfig.ini b/mediagoblin/tests/auth_configs/no_auth_false_no_auth_plugin_appconfig.ini
new file mode 100644
index 00000000..49f9e9de
--- /dev/null
+++ b/mediagoblin/tests/auth_configs/no_auth_false_no_auth_plugin_appconfig.ini
@@ -0,0 +1,26 @@
+[mediagoblin]
+direct_remote_path = /test_static/
+email_sender_address = "notice@mediagoblin.example.org"
+email_debug_mode = true
+no_auth = false
+
+# TODO: Switch to using an in-memory database
+sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db"
+
+# Celery shouldn't be set up by the application as it's setup via
+# mediagoblin.init.celery.from_celery
+celery_setup_elsewhere = true
+
+[storage:publicstore]
+base_dir = %(here)s/user_dev/media/public
+base_url = /mgoblin_media/
+
+[storage:queuestore]
+base_dir = %(here)s/user_dev/media/queue
+
+[celery]
+CELERY_ALWAYS_EAGER = true
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
+
+[plugins]
diff --git a/mediagoblin/tests/auth_configs/no_auth_true_no_auth_plugin_appconfig.ini b/mediagoblin/tests/auth_configs/no_auth_true_no_auth_plugin_appconfig.ini
new file mode 100644
index 00000000..5e6cfde6
--- /dev/null
+++ b/mediagoblin/tests/auth_configs/no_auth_true_no_auth_plugin_appconfig.ini
@@ -0,0 +1,26 @@
+[mediagoblin]
+direct_remote_path = /test_static/
+email_sender_address = "notice@mediagoblin.example.org"
+email_debug_mode = true
+no_auth = true
+
+# TODO: Switch to using an in-memory database
+sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db"
+
+# Celery shouldn't be set up by the application as it's setup via
+# mediagoblin.init.celery.from_celery
+celery_setup_elsewhere = true
+
+[storage:publicstore]
+base_dir = %(here)s/user_dev/media/public
+base_url = /mgoblin_media/
+
+[storage:queuestore]
+base_dir = %(here)s/user_dev/media/queue
+
+[celery]
+CELERY_ALWAYS_EAGER = true
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
+
+[plugins]
diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py
index 755727f9..8a828303 100644
--- a/mediagoblin/tests/test_auth.py
+++ b/mediagoblin/tests/test_auth.py
@@ -13,54 +13,18 @@
#
# 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 urlparse
import datetime
+import pkg_resources
+import pytest
from mediagoblin import mg_globals
-from mediagoblin.auth import lib as auth_lib
from mediagoblin.db.models import User
-from mediagoblin.tests.tools import fixture_add_user
+from mediagoblin.tests.tools import get_app, fixture_add_user
from mediagoblin.tools import template, mail
-
-
-########################
-# Test bcrypt auth funcs
-########################
-
-def test_bcrypt_check_password():
- # Check known 'lollerskates' password against check function
- assert auth_lib.bcrypt_check_password(
- 'lollerskates',
- '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
-
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword',
- '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
-
- # Same thing, but with extra fake salt.
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword',
- '$2a$12$ELVlnw3z1FMu6CEGs/L8XO8vl0BuWSlUHgh0rUrry9DUXGMUNWwl6',
- '3><7R45417')
-
-
-def test_bcrypt_gen_password_hash():
- pw = 'youwillneverguessthis'
-
- # Normal password hash generation, and check on that hash
- hashed_pw = auth_lib.bcrypt_gen_password_hash(pw)
- assert auth_lib.bcrypt_check_password(
- pw, hashed_pw)
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword', hashed_pw)
-
- # Same thing, extra salt.
- hashed_pw = auth_lib.bcrypt_gen_password_hash(pw, '3><7R45417')
- assert auth_lib.bcrypt_check_password(
- pw, hashed_pw, '3><7R45417')
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword', hashed_pw, '3><7R45417')
+from mediagoblin.auth.tools import AuthError
+from mediagoblin.auth import tools as auth_tools
+from mediagoblin import auth
def test_register_views(test_app):
@@ -394,3 +358,61 @@ def test_authentication_views(test_app):
'password': 'toast',
'next' : '/u/chris/'})
assert urlparse.urlsplit(response.location)[2] == '/u/chris/'
+
+
+# App with no_auth=false and no auth plugin enabled
+def no_auth_false_no_auth_plugin_app(request):
+ return get_app(
+ request,
+ mgoblin_config=pkg_resources.resource_filename(
+ 'mediagoblin.tests.auth_configs',
+ 'no_auth_false_no_auth_plugin_appconfig.ini'))
+
+
+def test_no_auth_false_no_auth_plugin_raises(request):
+ with pytest.raises(AuthError):
+ no_auth_false_no_auth_plugin_app(request)
+
+
+@pytest.fixture()
+def no_auth_true_no_auth_plugin_app(request):
+ return get_app(
+ request,
+ mgoblin_config=pkg_resources.resource_filename(
+ 'mediagoblin.tests.auth_configs',
+ 'no_auth_true_no_auth_plugin_appconfig.ini'))
+
+
+def test_no_auth_true_no_auth_plugin_app(no_auth_true_no_auth_plugin_app):
+ # app.auth should = false
+ assert mg_globals.app.auth is False
+
+ # Try to visit register page
+ template.clear_test_template_context()
+ response = no_auth_true_no_auth_plugin_app.get('/auth/register/')
+ response.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # Try to vist login page
+ template.clear_test_template_context()
+ response = no_auth_true_no_auth_plugin_app.get('/auth/login/')
+ response.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
+
+ ## Test check_login_simple should return None
+ assert auth_tools.check_login_simple('test', 'simple') is None
+
+ # Try to visit the forgot password page
+ template.clear_test_template_context()
+ response = no_auth_true_no_auth_plugin_app.get('/auth/register/')
+ response.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
diff --git a/mediagoblin/tests/test_basic_auth.py b/mediagoblin/tests/test_basic_auth.py
new file mode 100644
index 00000000..cdd80fca
--- /dev/null
+++ b/mediagoblin/tests/test_basic_auth.py
@@ -0,0 +1,59 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# 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/>.
+from mediagoblin.plugins.basic_auth import tools as auth_tools
+from mediagoblin.tools.testing import _activate_testing
+
+_activate_testing()
+
+
+########################
+# Test bcrypt auth funcs
+########################
+
+
+def test_bcrypt_check_password():
+ # Check known 'lollerskates' password against check function
+ assert auth_tools.bcrypt_check_password(
+ 'lollerskates',
+ '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
+
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword',
+ '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
+
+ # Same thing, but with extra fake salt.
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword',
+ '$2a$12$ELVlnw3z1FMu6CEGs/L8XO8vl0BuWSlUHgh0rUrry9DUXGMUNWwl6',
+ '3><7R45417')
+
+
+def test_bcrypt_gen_password_hash():
+ pw = 'youwillneverguessthis'
+
+ # Normal password hash generation, and check on that hash
+ hashed_pw = auth_tools.bcrypt_gen_password_hash(pw)
+ assert auth_tools.bcrypt_check_password(
+ pw, hashed_pw)
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword', hashed_pw)
+
+ # Same thing, extra salt.
+ hashed_pw = auth_tools.bcrypt_gen_password_hash(pw, '3><7R45417')
+ assert auth_tools.bcrypt_check_password(
+ pw, hashed_pw, '3><7R45417')
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword', hashed_pw, '3><7R45417')
diff --git a/mediagoblin/tests/test_edit.py b/mediagoblin/tests/test_edit.py
index 08b4f8cf..b6ec7a29 100644
--- a/mediagoblin/tests/test_edit.py
+++ b/mediagoblin/tests/test_edit.py
@@ -21,7 +21,8 @@ from mediagoblin import mg_globals
from mediagoblin.db.models import User
from mediagoblin.tests.tools import fixture_add_user
from mediagoblin.tools import template
-from mediagoblin.auth.lib import bcrypt_check_password
+from mediagoblin import auth
+
class TestUserEdit(object):
def setup(self):
@@ -74,7 +75,7 @@ class TestUserEdit(object):
# test_user has to be fetched again in order to have the current values
test_user = User.query.filter_by(username=u'chris').first()
- assert bcrypt_check_password('123456', test_user.pw_hash)
+ assert auth.check_password('123456', test_user.pw_hash)
# Update current user passwd
self.user_password = '123456'
@@ -88,7 +89,7 @@ class TestUserEdit(object):
})
test_user = User.query.filter_by(username=u'chris').first()
- assert not bcrypt_check_password('098765', test_user.pw_hash)
+ assert not auth.check_password('098765', test_user.pw_hash)
def test_change_bio_url(self, test_app):
diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini
index 0466b53b..180eea19 100644
--- a/mediagoblin/tests/test_mgoblin_app.ini
+++ b/mediagoblin/tests/test_mgoblin_app.ini
@@ -2,6 +2,7 @@
direct_remote_path = /test_static/
email_sender_address = "notice@mediagoblin.example.org"
email_debug_mode = true
+no_auth = true
# TODO: Switch to using an in-memory database
sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db"
@@ -31,3 +32,4 @@ BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
[[mediagoblin.plugins.oauth]]
[[mediagoblin.plugins.httpapiauth]]
[[mediagoblin.plugins.piwigo]]
+[[mediagoblin.plugins.basic_auth]]
diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py
index 2ee39e89..35c2c3e9 100644
--- a/mediagoblin/tests/tools.py
+++ b/mediagoblin/tests/tools.py
@@ -31,7 +31,7 @@ from mediagoblin.tools import testing
from mediagoblin.init.config import read_mediagoblin_config
from mediagoblin.db.base import Session
from mediagoblin.meddleware import BaseMeddleware
-from mediagoblin.auth.lib import bcrypt_gen_password_hash
+from mediagoblin.auth import gen_password_hash
from mediagoblin.gmg_commands.dbupdate import run_dbupdate
@@ -179,7 +179,7 @@ def fixture_add_user(username=u'chris', password=u'toast',
test_user.username = username
test_user.email = username + u'@example.com'
if password is not None:
- test_user.pw_hash = bcrypt_gen_password_hash(password)
+ test_user.pw_hash = gen_password_hash(password)
if active_user:
test_user.email_verified = True
test_user.status = u'active'
diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py
index 3d651a6e..615ce129 100644
--- a/mediagoblin/tools/template.py
+++ b/mediagoblin/tools/template.py
@@ -71,6 +71,7 @@ def get_jinja_env(template_loader, locale):
template_env.globals['app_config'] = mg_globals.app_config
template_env.globals['global_config'] = mg_globals.global_config
template_env.globals['version'] = _version.__version__
+ template_env.globals['auth'] = mg_globals.app.auth
template_env.filters['urlencode'] = url_quote_plus