Compare commits

..
13 Commits
Author SHA1 Message Date
Matt Wright 99ac732d10 Bump version number to 1.6.2 2013-04-04 10:24:03 -04:00
Matt Wright e8b0c62818 Update CHANGES and a little polish 2013-04-04 10:23:51 -04:00
Matt Wright 1108f1670c Merge pull request #104 from rodcloutier/http_auth_fix
Fixed http_auth when authorization is not provided in header
2013-04-04 07:21:27 -07:00
Rodrigue Cloutier 3575a2df18 Fixed http_auth when authorization is not provided in header 2013-04-03 21:29:04 -04:00
Matt Wright c84c485493 Bump version number to 1.6.1 2013-04-03 11:07:36 -04:00
Matt Wright 8298ac461e Update CHANGES 2013-04-03 11:07:16 -04:00
Matt Wright 105d04768e Merge pull request #103 from immon/issue94
sending signals fixed
2013-04-03 08:04:49 -07:00
Paweł Krześniak f1cca43d9c sending signals fixed 2013-04-03 12:36:53 +02:00
Matt Wright e8352fa265 Merge pull request #102 from andrewcamenga/develop
corrected link for Flask-WTF
2013-03-29 08:53:38 -07:00
Andrew J. Camenga 37d84ddd73 corrected link for Flask-WTF 2013-03-29 08:37:51 -04:00
Matt Wright 6f9869e9c2 import auth_required into top level package 2013-03-27 17:20:31 -04:00
Matt Wright abc061ba46 Change .travis.yml 2013-03-19 14:11:23 -04:00
Matt Wright 95c80e5677 See if pypy works 2013-03-19 13:28:42 -04:00
14 changed files with 61 additions and 35 deletions
+2 -1
View File
@@ -3,10 +3,11 @@ language: python
python: python:
- "2.6" - "2.6"
- "2.7" - "2.7"
- "pypy"
install: install:
- pip install . --quiet --use-mirrors - pip install . --quiet --use-mirrors
- "if [[ $TRAVIS_PYTHON_VERSION != '2.7' ]]; then pip install importlib --quiet --use-mirrors; fi" - "if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install importlib --quiet --use-mirrors; fi"
- pip install nose simplejson Flask-SQLAlchemy Flask-MongoEngine Flask-Peewee Flask-Mail py-bcrypt MySQL-python --quiet --use-mirrors - pip install nose simplejson Flask-SQLAlchemy Flask-MongoEngine Flask-Peewee Flask-Mail py-bcrypt MySQL-python --quiet --use-mirrors
before_script: before_script:
+15
View File
@@ -3,6 +3,21 @@ Flask-Security Changelog
Here you can see the full list of changes between each Flask-Security release. Here you can see the full list of changes between each Flask-Security release.
Version 1.6.2
-------------
Released April 4th 2013
- Fixed bug with http basic auth
Version 1.6.1
-------------
Released April 3rd 2013
- Fixed bug with signals
Version 1.6.0 Version 1.6.0
------------- -------------
+1 -1
View File
@@ -49,7 +49,7 @@ copyright = u'2012, Matt Wright'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '1.6.0' version = '1.6.2'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = version release = version
+1 -1
View File
@@ -21,7 +21,7 @@ and libraries. They include:
2. `Flask-Mail <http://packages.python.org/Flask-Mail/>`_ 2. `Flask-Mail <http://packages.python.org/Flask-Mail/>`_
3. `Flask-Principal <http://packages.python.org/Flask-Principal/>`_ 3. `Flask-Principal <http://packages.python.org/Flask-Principal/>`_
4. `Flask-Script <http://packages.python.org/Flask-Script/>`_ 4. `Flask-Script <http://packages.python.org/Flask-Script/>`_
5. `Flask-WTF <http://packages.python.org/Flask-Mail/>`_ 5. `Flask-WTF <http://packages.python.org/Flask-WTF/>`_
6. `itsdangerous <http://packages.python.org/itsdangerous/>`_ 6. `itsdangerous <http://packages.python.org/itsdangerous/>`_
7. `passlib <http://packages.python.org/passlib/>`_ 7. `passlib <http://packages.python.org/passlib/>`_
+2 -2
View File
@@ -10,12 +10,12 @@
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
__version__ = '1.6.0' __version__ = '1.6.2'
from .core import Security, RoleMixin, UserMixin, AnonymousUser, current_user from .core import Security, RoleMixin, UserMixin, AnonymousUser, current_user
from .datastore import SQLAlchemyUserDatastore, MongoEngineUserDatastore, PeeweeUserDatastore from .datastore import SQLAlchemyUserDatastore, MongoEngineUserDatastore, PeeweeUserDatastore
from .decorators import auth_token_required, http_auth_required, \ from .decorators import auth_token_required, http_auth_required, \
login_required, roles_accepted, roles_required login_required, roles_accepted, roles_required, auth_required
from .forms import ForgotPasswordForm, LoginForm, RegisterForm, \ from .forms import ForgotPasswordForm, LoginForm, RegisterForm, \
ResetPasswordForm, PasswordlessLoginForm, ConfirmRegisterForm ResetPasswordForm, PasswordlessLoginForm, ConfirmRegisterForm
from .signals import confirm_instructions_sent, password_reset, \ from .signals import confirm_instructions_sent, password_reset, \
+2 -2
View File
@@ -44,7 +44,7 @@ def send_confirmation_instructions(user):
'confirmation_instructions', user=user, 'confirmation_instructions', user=user,
confirmation_link=confirmation_link) confirmation_link=confirmation_link)
confirm_instructions_sent.send(user, app=app._get_current_object()) confirm_instructions_sent.send(app._get_current_object(), user=user)
return token return token
@@ -80,4 +80,4 @@ def confirm_user(user):
""" """
user.confirmed_at = datetime.utcnow() user.confirmed_at = datetime.utcnow()
_datastore.put(user) _datastore.put(user)
user_confirmed.send(user, app=app._get_current_object()) user_confirmed.send(app._get_current_object(), user=user)
+4 -1
View File
@@ -9,6 +9,7 @@
:license: MIT, see LICENSE for more details. :license: MIT, see LICENSE for more details.
""" """
from collections import namedtuple
from functools import wraps from functools import wraps
from flask import current_app, Response, request, redirect, _request_ctx_stack from flask import current_app, Response, request, redirect, _request_ctx_stack
@@ -30,6 +31,8 @@ _default_unauthorized_html = """
or your browser doesn't understand how to supply the credentials required.</p> or your browser doesn't understand how to supply the credentials required.</p>
""" """
BasicAuth = namedtuple('BasicAuth', 'username, password')
def _get_unauthorized_response(text=None, headers=None): def _get_unauthorized_response(text=None, headers=None):
text = text or _default_unauthorized_html text = text or _default_unauthorized_html
@@ -67,7 +70,7 @@ def _check_token():
def _check_http_auth(): def _check_http_auth():
auth = request.authorization or dict(username=None, password=None) auth = request.authorization or BasicAuth(username=None, password=None)
user = _security.datastore.find_user(email=auth.username) user = _security.datastore.find_user(email=auth.username)
if user and utils.verify_and_update_password(auth.password, user): if user and utils.verify_and_update_password(auth.password, user):
+2 -2
View File
@@ -36,8 +36,8 @@ def send_login_instructions(user):
send_mail(config_value('EMAIL_SUBJECT_PASSWORDLESS'), user.email, send_mail(config_value('EMAIL_SUBJECT_PASSWORDLESS'), user.email,
'login_instructions', user=user, login_link=login_link) 'login_instructions', user=user, login_link=login_link)
login_instructions_sent.send(dict(user=user, login_token=token), login_instructions_sent.send(app._get_current_object(),
app=app._get_current_object()) user=user, login_token=token)
def generate_login_token(user): def generate_login_token(user):
+3 -3
View File
@@ -36,8 +36,8 @@ def send_reset_password_instructions(user):
'reset_instructions', 'reset_instructions',
user=user, reset_link=reset_link) user=user, reset_link=reset_link)
reset_password_instructions_sent.send(dict(user=user, token=token), reset_password_instructions_sent.send(app._get_current_object(),
app=app._get_current_object()) user=user, token=token)
def send_password_reset_notice(user): def send_password_reset_notice(user):
@@ -77,4 +77,4 @@ def update_password(user, password):
user.password = encrypt_password(password) user.password = encrypt_password(password)
_datastore.put(user) _datastore.put(user)
send_password_reset_notice(user) send_password_reset_notice(user)
password_reset.send(user, app=app._get_current_object()) password_reset.send(app._get_current_object(), user=user)
+2 -2
View File
@@ -33,8 +33,8 @@ def register_user(**kwargs):
confirmation_link, token = generate_confirmation_link(user) confirmation_link, token = generate_confirmation_link(user)
do_flash(*get_message('CONFIRM_REGISTRATION', email=user.email)) do_flash(*get_message('CONFIRM_REGISTRATION', email=user.email))
user_registered.send(dict(user=user, confirm_token=token), user_registered.send(app._get_current_object(),
app=app._get_current_object()) user=user, confirm_token=token)
if config_value('SEND_REGISTER_EMAIL'): if config_value('SEND_REGISTER_EMAIL'):
send_mail(config_value('EMAIL_SUBJECT_REGISTER'), user.email, 'welcome', send_mail(config_value('EMAIL_SUBJECT_REGISTER'), user.email, 'welcome',
+4 -4
View File
@@ -273,7 +273,7 @@ def get_token_status(token, serializer, max_age=None):
def capture_passwordless_login_requests(): def capture_passwordless_login_requests():
login_requests = [] login_requests = []
def _on(data, app): def _on(app, **data):
login_requests.append(data) login_requests.append(data)
login_instructions_sent.connect(_on) login_instructions_sent.connect(_on)
@@ -293,7 +293,7 @@ def capture_registrations():
""" """
registrations = [] registrations = []
def _on(data, app): def _on(app, **data):
registrations.append(data) registrations.append(data)
user_registered.connect(_on) user_registered.connect(_on)
@@ -313,8 +313,8 @@ def capture_reset_password_requests(reset_password_sent_at=None):
""" """
reset_requests = [] reset_requests = []
def _on(request, app): def _on(app, **data):
reset_requests.append(request) reset_requests.append(data)
reset_password_instructions_sent.connect(_on) reset_password_instructions_sent.connect(_on)
+1 -1
View File
@@ -20,7 +20,7 @@ from setuptools import setup
setup( setup(
name='Flask-Security', name='Flask-Security',
version='1.6.0', version='1.6.2',
url='https://github.com/mattupstate/flask-security', url='https://github.com/mattupstate/flask-security',
license='MIT', license='MIT',
author='Matt Wright', author='Matt Wright',
+7
View File
@@ -142,6 +142,13 @@ class DefaultSecurityTests(SecurityTest):
}) })
self.assertIn('HTTP Authentication', r.data) self.assertIn('HTTP Authentication', r.data)
def test_http_auth_no_authorization(self):
r = self._get('/http', headers={})
self.assertIn('<h1>Unauthorized</h1>', r.data)
self.assertIn('WWW-Authenticate', r.headers)
self.assertEquals('Basic realm="Login Required"',
r.headers['WWW-Authenticate'])
def test_invalid_http_auth_invalid_username(self): def test_invalid_http_auth_invalid_username(self):
r = self._get('/http', headers={ r = self._get('/http', headers={
'Authorization': 'Basic ' + base64.b64encode("bogus:bogus") 'Authorization': 'Basic ' + base64.b64encode("bogus:bogus")
+15 -15
View File
@@ -31,9 +31,9 @@ class RegisterableSignalsTests(SecurityTest):
calls = mocks[user_registered] calls = mocks[user_registered]
self.assertEqual(len(calls), 1) self.assertEqual(len(calls), 1)
args, kwargs = calls[0] args, kwargs = calls[0]
self.assertTrue(compare_user(args[0]['user'], user)) self.assertTrue(compare_user(kwargs['user'], user))
self.assertIn('confirm_token', args[0]) self.assertIn('confirm_token', kwargs)
self.assertEqual(kwargs['app'], self.app) self.assertEqual(args[0], self.app)
def test_register_without_password(self): def test_register_without_password(self):
e = 'dude@lp.com' e = 'dude@lp.com'
@@ -61,8 +61,8 @@ class ConfirmableSignalsTests(SecurityTest):
calls = mocks[user_confirmed] calls = mocks[user_confirmed]
self.assertEqual(len(calls), 1) self.assertEqual(len(calls), 1)
args, kwargs = calls[0] args, kwargs = calls[0]
self.assertEqual(args[0].id, user.id) self.assertEqual(args[0], self.app)
self.assertEqual(kwargs['app'], self.app) self.assertTrue(compare_user(kwargs['user'], user))
def test_confirm_bad_token(self): def test_confirm_bad_token(self):
e = 'dude@lp.com' e = 'dude@lp.com'
@@ -94,8 +94,8 @@ class ConfirmableSignalsTests(SecurityTest):
calls = mocks[confirm_instructions_sent] calls = mocks[confirm_instructions_sent]
self.assertEqual(len(calls), 1) self.assertEqual(len(calls), 1)
args, kwargs = calls[0] args, kwargs = calls[0]
self.assertTrue(compare_user(args[0], user)) self.assertTrue(compare_user(kwargs['user'], user))
self.assertEqual(kwargs['app'], self.app) self.assertEqual(args[0], self.app)
def test_send_confirmation_bad_email(self): def test_send_confirmation_bad_email(self):
with capture_signals() as mocks: with capture_signals() as mocks:
@@ -120,9 +120,9 @@ class RecoverableSignalsTests(SecurityTest):
calls = mocks[reset_password_instructions_sent] calls = mocks[reset_password_instructions_sent]
self.assertEqual(len(calls), 1) self.assertEqual(len(calls), 1)
args, kwargs = calls[0] args, kwargs = calls[0]
self.assertTrue(compare_user(args[0]['user'], user)) self.assertTrue(compare_user(kwargs['user'], user))
self.assertIn('token', args[0]) self.assertIn('token', kwargs)
self.assertEqual(kwargs['app'], self.app) self.assertEqual(args[0], self.app)
def test_reset_password(self): def test_reset_password(self):
with capture_reset_password_requests() as requests: with capture_reset_password_requests() as requests:
@@ -137,8 +137,8 @@ class RecoverableSignalsTests(SecurityTest):
calls = mocks[password_reset] calls = mocks[password_reset]
self.assertEqual(len(calls), 1) self.assertEqual(len(calls), 1)
args, kwargs = calls[0] args, kwargs = calls[0]
self.assertTrue(compare_user(args[0], user)) self.assertTrue(compare_user(kwargs['user'], user))
self.assertEqual(kwargs['app'], self.app) self.assertEqual(args[0], self.app)
def test_reset_password_invalid_emails(self): def test_reset_password_invalid_emails(self):
with capture_signals() as mocks: with capture_signals() as mocks:
@@ -233,6 +233,6 @@ class PasswordlessTests(SecurityTest):
calls = mocks[login_instructions_sent] calls = mocks[login_instructions_sent]
self.assertEqual(len(calls), 1) self.assertEqual(len(calls), 1)
args, kwargs = calls[0] args, kwargs = calls[0]
self.assertTrue(compare_user(args[0]['user'], user)) self.assertTrue(compare_user(kwargs['user'], user))
self.assertIn('login_token', args[0]) self.assertIn('login_token', kwargs)
self.assertEqual(kwargs['app'], self.app) self.assertEqual(args[0], self.app)