Permalink
Browse files

Improving the authentication mechanism in flask-peewee, cribbed from

django.  Refs issue 6, #6
  • Loading branch information...
coleifer committed Oct 4, 2011
1 parent 5b98c49 commit c92b61e4ef6a5361151b3ece3e496b6c1e074b87
View
@@ -1,17 +1,17 @@
-from hashlib import sha1
import functools
import os
from flask import Blueprint, render_template, abort, request, session, flash, redirect, url_for, g
from peewee import *
from wtforms import Form, TextField, PasswordField, validators
-from flaskext.utils import get_next
+from flaskext.utils import get_next, make_password, check_password
current_dir = os.path.dirname(__file__)
+
class LoginForm(Form):
username = TextField('Username', validators=[validators.Required()])
password = PasswordField('Password', validators=[validators.Required()])
@@ -46,7 +46,7 @@ def __unicode__(self):
return self.username
def set_password(self, password):
- self.password = sha1(password).hexdigest()
+ self.password = make_password(password)
return User
@@ -109,10 +109,12 @@ def authenticate(self, username, password):
try:
user = active.get(
username=username,
- password=sha1(password).hexdigest()
)
except self.User.DoesNotExist:
return False
+ else:
+ if not check_password(password, user.password):
+ return False
return user
View
@@ -1,5 +1,4 @@
import functools
-import hashlib
try:
import simplejson as json
except ImportError:
View
@@ -1,11 +1,11 @@
-from hashlib import sha1
import datetime
from flask import request, session, url_for
from flaskext.admin import ModelAdmin, AdminPanel
from flaskext.tests.base import FlaskPeeweeTestCase
from flaskext.tests.test_app import User, Message, Note, admin
+from flaskext.utils import get_next, make_password, check_password
from wtfpeewee.orm import model_form
@@ -150,11 +150,11 @@ def test_model_admin_add(self):
# check they have the correct data on the new instance
user = User.get(username='new')
- self.assertEqual(user.password, sha1('new').hexdigest())
self.assertEqual(user.active, True)
self.assertEqual(user.admin, False)
self.assertEqual(user.email, 'new@new.new')
self.assertEqual(user.join_date, datetime.datetime(2011, 1, 1))
+ self.assertTrue(check_password('new', user.password))
# check the redirect was correct
self.assertTrue(resp.headers['location'].endswith('/admin/user/%d/' % user.id))
@@ -195,7 +195,7 @@ def test_model_admin_edit(self):
# check the form pulled the right data off the model
self.assertEqual(frm.data, {
'username': 'normal',
- 'password': sha1('normal').hexdigest(),
+ 'password': frm.password.data, # skip this
'email': '',
'admin': False,
'active': True,
@@ -243,7 +243,7 @@ def test_model_admin_edit(self):
user = User.get(username='edited')
self.assertEqual(user.id, self.normal.id) # it is the same user
- self.assertEqual(user.password, sha1('edited').hexdigest())
+ self.assertTrue(check_password('edited', user.password))
self.assertEqual(user.active, True)
self.assertEqual(user.admin, False)
self.assertEqual(user.email, 'x@x.x')
@@ -269,7 +269,7 @@ def test_model_admin_edit(self):
self.assertEqual(user.id, self.normal.id) # it is the same user
# the password has not changed
- self.assertEqual(user.password, sha1('edited').hexdigest())
+ self.assertTrue(check_password('edited', user.password))
def test_model_admin_delete(self):
self.create_users()
View
@@ -1,4 +1,3 @@
-from hashlib import sha1
import datetime
from flask import request, session, url_for, get_flashed_messages
View
@@ -3,14 +3,14 @@
except ImportError:
import json
-from hashlib import sha1
import base64
import datetime
import unittest
from flaskext.rest import RestAPI, RestResource, Authentication, UserAuthentication
from flaskext.tests.base import FlaskPeeweeTestCase
from flaskext.tests.test_app import User, Message, Note
+from flaskext.utils import get_next, make_password, check_password
class RestApiTestCase(FlaskPeeweeTestCase):
@@ -543,7 +543,9 @@ def test_detail_get(self):
def test_auth_create(self):
self.create_users()
- user_data = {'username': 'test', 'password': sha1('test').hexdigest()}
+ new_pass = make_password('test')
+
+ user_data = {'username': 'test', 'password': new_pass}
serialized = json.dumps(user_data)
# this request is not authorized
@@ -565,14 +567,17 @@ def test_auth_create(self):
def test_create(self):
self.create_users()
- user_data = {'username': 'test', 'password': sha1('test').hexdigest()}
+ new_pass = make_password('test')
+
+ user_data = {'username': 'test', 'password': new_pass}
serialized = json.dumps(user_data)
# authorized as an admin
resp = self.app.post('/api/user/', data=serialized, headers=self.auth_headers('admin', 'admin'))
self.assertEqual(resp.status_code, 200)
new_user = User.get(username='test')
+ self.assertTrue(check_password('test', new_user.password))
resp_json = self.response_json(resp)
self.assertAPIUser(resp_json, new_user)
@@ -1,7 +1,6 @@
import datetime
from flask import Flask, request, redirect, url_for, render_template, flash, g, Response
-from hashlib import md5, sha1
from peewee import *
@@ -10,7 +9,7 @@
from flaskext.auth import Auth
from flaskext.db import Database
from flaskext.rest import RestAPI, RestResource, RestrictOwnerResource, UserAuthentication, AdminAuthentication
-from flaskext.utils import get_object_or_404, object_list
+from flaskext.utils import get_object_or_404, object_list, make_password
class TestFlask(Flask):
@@ -45,7 +44,7 @@ def message_count(self):
return self.message_set.count()
def set_password(self, password):
- self.password = sha1(password).hexdigest()
+ self.password = make_password(password)
class Message(db.Model):
View
@@ -8,7 +8,7 @@
from flask import request
from werkzeug.exceptions import NotFound
-from flaskext.utils import get_object_or_404
+from flaskext.utils import get_object_or_404, make_password, check_password
from flaskext.tests.base import FlaskPeeweeTestCase
from flaskext.tests.test_app import User, Message, Note, app as flask_app
@@ -30,3 +30,13 @@ def test_get_object_or_404(self):
self.assertRaises(NotFound, get_object_or_404, active, username='not-here')
self.assertRaises(NotFound, get_object_or_404, inactive, username='test')
self.assertEqual(user, get_object_or_404(active, username='test'))
+
+ def test_passwords(self):
+ p = make_password('testing')
+ self.assertTrue(check_password('testing', p))
+ self.assertFalse(check_password('testing ', p))
+ self.assertFalse(check_password('Testing', p))
+ self.assertFalse(check_password('', p))
+
+ p2 = make_password('Testing')
+ self.assertFalse(p == p2)
View
@@ -1,6 +1,8 @@
import math
+import random
import re
import sys
+from hashlib import sha1
from flask import abort, request, render_template
from peewee import Model, DoesNotExist, SelectQuery
@@ -54,3 +56,17 @@ def load_class(s):
__import__(path)
mod = sys.modules[path]
return getattr(mod, klass)
+
+
+# borrowing these methods, slightly modified, from django.contrib.auth
+def get_hexdigest(salt, raw_password):
+ return sha1(salt + raw_password).hexdigest()
+
+def make_password(raw_password):
+ salt = get_hexdigest(str(random.random()), str(random.random()))[:5]
+ hsh = get_hexdigest(salt, raw_password)
+ return '%s$%s' % (salt, hsh)
+
+def check_password(raw_password, enc_password):
+ salt, hsh = enc_password.split('$', 1)
+ return hsh == get_hexdigest(salt, raw_password)

0 comments on commit c92b61e

Please sign in to comment.