pyramid-fullauth 0.4.0__py3.4.egg
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- EGG-INFO/PKG-INFO +184 -0
- EGG-INFO/SOURCES.txt +93 -0
- EGG-INFO/dependency_links.txt +1 -0
- EGG-INFO/not-zip-safe +1 -0
- EGG-INFO/requires.txt +13 -0
- EGG-INFO/top_level.txt +2 -0
- pyramid_fullauth/__init__.py +106 -0
- pyramid_fullauth/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/auth.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/events.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/exceptions.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/request.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/tools.cpython-34.pyc +0 -0
- pyramid_fullauth/auth.py +67 -0
- pyramid_fullauth/config/default.yaml +26 -0
- pyramid_fullauth/events.py +281 -0
- pyramid_fullauth/exceptions.py +47 -0
- pyramid_fullauth/models/__init__.py +190 -0
- pyramid_fullauth/models/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/models/extensions/__init__.py +39 -0
- pyramid_fullauth/models/extensions/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/__init__.py +9 -0
- pyramid_fullauth/models/mixins/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/__pycache__/email.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/__pycache__/password.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/email.py +128 -0
- pyramid_fullauth/models/mixins/password.py +141 -0
- pyramid_fullauth/request.py +70 -0
- pyramid_fullauth/resources/helpers/social.mako +17 -0
- pyramid_fullauth/resources/locale/pyramid_fullauth.pot +216 -0
- pyramid_fullauth/resources/templates/403.mako +11 -0
- pyramid_fullauth/resources/templates/_form.login.mako +44 -0
- pyramid_fullauth/resources/templates/_form.register.mako +47 -0
- pyramid_fullauth/resources/templates/_social.login.mako +17 -0
- pyramid_fullauth/resources/templates/activate.mako +14 -0
- pyramid_fullauth/resources/templates/email_change.mako +33 -0
- pyramid_fullauth/resources/templates/layout.mako +13 -0
- pyramid_fullauth/resources/templates/login.mako +17 -0
- pyramid_fullauth/resources/templates/register.mako +22 -0
- pyramid_fullauth/resources/templates/reset.mako +34 -0
- pyramid_fullauth/resources/templates/reset.proceed.mako +41 -0
- pyramid_fullauth/routing/__init__.py +5 -0
- pyramid_fullauth/routing/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/routing/__pycache__/predicates.cpython-34.pyc +0 -0
- pyramid_fullauth/routing/predicates.py +86 -0
- pyramid_fullauth/tools.py +69 -0
- pyramid_fullauth/views/__init__.py +15 -0
- pyramid_fullauth/views/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/views/__pycache__/social.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__init__.py +5 -0
- pyramid_fullauth/views/basic/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/activate.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/forbidden.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/login.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/logout.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/register.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/activate.py +44 -0
- pyramid_fullauth/views/basic/forbidden.py +46 -0
- pyramid_fullauth/views/basic/login.py +128 -0
- pyramid_fullauth/views/basic/logout.py +28 -0
- pyramid_fullauth/views/basic/profile/__init__.py +5 -0
- pyramid_fullauth/views/basic/profile/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/profile/__pycache__/email.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/profile/__pycache__/password.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/profile/email.py +108 -0
- pyramid_fullauth/views/basic/profile/password.py +129 -0
- pyramid_fullauth/views/basic/register.py +111 -0
- pyramid_fullauth/views/social.py +221 -0
- tests/__init__.py +1 -0
- tests/__pycache__/__init__.cpython-34.pyc +0 -0
- tests/__pycache__/conftest.cpython-34.pyc +0 -0
- tests/__pycache__/tools.cpython-34.pyc +0 -0
- tests/conftest.py +201 -0
- tests/tools.py +54 -0
- tests/unit/__pycache__/test_default_settings.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_groupfinder.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_social_view.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_tools.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_active.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_admin.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_email.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_password.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_providers.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_repr.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_validators.cpython-34.pyc +0 -0
- tests/unit/test_default_settings.py +15 -0
- tests/unit/test_groupfinder.py +20 -0
- tests/unit/test_social_view.py +69 -0
- tests/unit/test_tools.py +24 -0
- tests/unit/test_user_active.py +31 -0
- tests/unit/test_user_admin.py +61 -0
- tests/unit/test_user_email.py +37 -0
- tests/unit/test_user_password.py +52 -0
- tests/unit/test_user_providers.py +24 -0
- tests/unit/test_user_repr.py +29 -0
- tests/unit/test_validators.py +44 -0
- tests/views/__init__.py +1 -0
- tests/views/__pycache__/__init__.cpython-34.pyc +0 -0
- tests/views/__pycache__/conftest.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_activation.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_email.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_events.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_login.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_login_social.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_logout.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_register.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_reset.cpython-34.pyc +0 -0
- tests/views/conftest.py +20 -0
- tests/views/test_activation.py +86 -0
- tests/views/test_email.py +175 -0
- tests/views/test_events.py +558 -0
- tests/views/test_login.py +172 -0
- tests/views/test_login_social.py +289 -0
- tests/views/test_logout.py +42 -0
- tests/views/test_register.py +138 -0
- tests/views/test_reset.py +105 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
<%namespace name="social" file="../helpers/social.mako" import="social_auth_uri"/>
|
|
9
|
+
<h1>${_('Social login', domain='pyramid_fullauth')}</h1>
|
|
10
|
+
% if 'social' in request.registry['config'].fullauth:
|
|
11
|
+
% if 'facebook' in request.registry['config'].fullauth.social:
|
|
12
|
+
<a href="${social.social_auth_uri('facebook', scope=request.registry['config'].fullauth.social.facebook.scope)}">${_('Connect with facebook', domain='pyramid_fullauth')}</a>
|
|
13
|
+
% endif
|
|
14
|
+
% if 'twitter' in request.registry['config'].fullauth.social:
|
|
15
|
+
<a href="${social.social_auth_uri('twitter')}">${_('Connect with twitter', domain='pyramid_fullauth')}</a>
|
|
16
|
+
% endif
|
|
17
|
+
% endif
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
<%inherit file="pyramid_fullauth:resources/templates/layout.mako" />
|
|
9
|
+
% if not status:
|
|
10
|
+
<h1>${_('Invalid activation code', domain='pyramid_fullauth')}</h1>
|
|
11
|
+
% else:
|
|
12
|
+
<h1>${_('Thank you for activating your account!', domain='pyramid_fullauth')}</h1>
|
|
13
|
+
<p>${_('And welcome to our site!', domain='pyramid_fullauth')}</p>
|
|
14
|
+
% endif
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
<%inherit file="pyramid_fullauth:resources/templates/layout.mako" />
|
|
9
|
+
|
|
10
|
+
<h1>${_('Change your email', domain='pyramid_fullauth')}</h1>
|
|
11
|
+
<div class="row-fluid">
|
|
12
|
+
<div class="span2"></div>
|
|
13
|
+
<div class="span8">
|
|
14
|
+
% if not status:
|
|
15
|
+
<div class="alert alert-error">${_('Error!', domain='pyramid_fullauth')} ${msg}</div>
|
|
16
|
+
% endif
|
|
17
|
+
<form class="form-horizontal" name="reset_password" method="POST" action="${request.current_route_path()}">
|
|
18
|
+
<fieldset>
|
|
19
|
+
<div class="control-group">
|
|
20
|
+
<label class="control-label" for="reset[email]">${_('Your e-mail address', domain='pyramid_fullauth')}:</label>
|
|
21
|
+
<div class="controls">
|
|
22
|
+
<input type="email" placeholder="username@hostname.com" name="email" id="change[email]"/>
|
|
23
|
+
<input type="hidden" name="csrf_token" value="${csrf_token}" />
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="form-actions">
|
|
27
|
+
<button type="submit" class="btn btn-large">${_('Change email', domain='pyramid_fullauth')}</button>
|
|
28
|
+
</div>
|
|
29
|
+
</fieldset>
|
|
30
|
+
</form>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="span2"></div>
|
|
33
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
<html>
|
|
9
|
+
<body>
|
|
10
|
+
<h1>${_('Welcome, to pyramid_fullauth!', domain='pyramid_fullauth')}</h1>
|
|
11
|
+
${next.body()}
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<% import sys %>
|
|
3
|
+
<%doc>
|
|
4
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
5
|
+
|
|
6
|
+
This module is part of pyramid_fullauth and is released under
|
|
7
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
8
|
+
</%doc>
|
|
9
|
+
<%inherit file="pyramid_fullauth:resources/templates/layout.mako" />
|
|
10
|
+
<h1>${_('Please, log in', domain='pyramid_fullauth')}:</h1>
|
|
11
|
+
% if not status:
|
|
12
|
+
<div class="alert alert-error">${_('Error!', domain='pyramid_fullauth')} ${msg}</div>
|
|
13
|
+
% endif
|
|
14
|
+
<%include file="_form.login.mako"/>
|
|
15
|
+
% if sys.version_info.major == 2:
|
|
16
|
+
<%include file="_social.login.mako"/>
|
|
17
|
+
% endif
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
<%inherit file="pyramid_fullauth:resources/templates/layout.mako" />
|
|
9
|
+
<h1>${_('Please, register', domain='pyramid_fullauth')}:</h1>
|
|
10
|
+
% if errors:
|
|
11
|
+
<div class="alert alert-error">
|
|
12
|
+
<button type="button" class="close" data-dismiss="alert">x</button>
|
|
13
|
+
<strong>${_('Error!', domain='pyramid_fullauth')}</strong> ${msg}
|
|
14
|
+
</div>
|
|
15
|
+
% elif not request.method == 'GET':
|
|
16
|
+
<div class="alert alert-success">
|
|
17
|
+
<button type="button" class="close" data-dismiss="alert">x</button>
|
|
18
|
+
<strong>${_('Success!', domain='pyramid_fullauth')}</strong> ${_('You have sucessfully registered', domain='pyramid_fullauth')}
|
|
19
|
+
</div>
|
|
20
|
+
% endif
|
|
21
|
+
<%include file="_form.register.mako"/>
|
|
22
|
+
<%include file="_social.login.mako"/>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
<%inherit file="pyramid_fullauth:resources/templates/layout.mako" />
|
|
9
|
+
|
|
10
|
+
<h1>${_('Recover your password', domain='pyramid_fullauth')}</h1>
|
|
11
|
+
<div class="row-fluid">
|
|
12
|
+
<div class="span2"></div>
|
|
13
|
+
<div class="span8">
|
|
14
|
+
% if not status:
|
|
15
|
+
<div class="alert alert-error">${_('Error!', domain='pyramid_fullauth')} ${msg}</div>
|
|
16
|
+
% endif
|
|
17
|
+
<form class="form-horizontal" name="reset_password" method="POST" action="${request.current_route_path()}">
|
|
18
|
+
<fieldset>
|
|
19
|
+
<div class="control-group">
|
|
20
|
+
<label class="control-label" for="reset[email]">${_('Your e-mail address', domain='pyramid_fullauth')}:</label>
|
|
21
|
+
<div class="controls">
|
|
22
|
+
<input type="email" placeholder="username@hostname.com" name="email" id="reset[email]"/>
|
|
23
|
+
<input type="hidden" name="csrf_token" value="${csrf_token}" />
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="form-actions">
|
|
27
|
+
<button type="submit" class="btn btn-large">${_('Reset Password', domain='pyramid_fullauth')}</button>
|
|
28
|
+
</div>
|
|
29
|
+
</fieldset>
|
|
30
|
+
</form>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="span2"></div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
<%inherit file="pyramid_fullauth:resources/templates/layout.mako" />
|
|
9
|
+
|
|
10
|
+
<h1>${_('Recover your password - choose new password', domain='pyramid_fullauth')}</h1>
|
|
11
|
+
<div class="row-fluid">
|
|
12
|
+
<div class="span8">
|
|
13
|
+
% if not status:
|
|
14
|
+
<div class="alert alert-error">${_('Error!', domain='pyramid_fullauth')} ${msg}</div>
|
|
15
|
+
% endif
|
|
16
|
+
<form class="form-horizontal" id="reset_password" name="reset_password" method="POST" action="${request.current_route_path()}">
|
|
17
|
+
<input type="hidden" name="csrf_token" value="${csrf_token}" />
|
|
18
|
+
<fieldset>
|
|
19
|
+
<div class="control-group">
|
|
20
|
+
<label class="control-label" for="password">${_('Password', domain='pyramid_fullauth')}:</label>
|
|
21
|
+
<div class="controls">
|
|
22
|
+
<input type="password" id="password" name="password" placeholder="minimum 6 characters"/>
|
|
23
|
+
<span class="help-inline" id="password_status"></span>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="control-group">
|
|
27
|
+
<label class="control-label" for="confirm_password">${_('Confirm password', domain='pyramid_fullauth')}:</label>
|
|
28
|
+
<div class="controls">
|
|
29
|
+
<input type="password" name="confirm_password" id="confirm_password"/>
|
|
30
|
+
<span class="help-inline" id="confirm_password_status"></span>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="form-actions">
|
|
34
|
+
<button type="submit" class="btn btn-large">${_('Reset Password', domain='pyramid_fullauth')}</button>
|
|
35
|
+
</div>
|
|
36
|
+
</fieldset>
|
|
37
|
+
</form>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="span2"></div>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_fullauth and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""Routing predicate definitions."""
|
|
6
|
+
|
|
7
|
+
from sqlalchemy.orm.exc import NoResultFound
|
|
8
|
+
from pyramid.config.predicates import CheckCSRFTokenPredicate
|
|
9
|
+
from pyramid.httpexceptions import HTTPUnauthorized
|
|
10
|
+
import pyramid_basemodel
|
|
11
|
+
|
|
12
|
+
from pyramid_fullauth.models import User
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def reset_hash(info, request):
|
|
16
|
+
"""
|
|
17
|
+
Check whether reset hash is correct.
|
|
18
|
+
|
|
19
|
+
:param dict info: pyramid info dict with path fragments and info
|
|
20
|
+
:param pyramid.request.Request request: request object
|
|
21
|
+
|
|
22
|
+
:returns: whether reset hash exists or not
|
|
23
|
+
:rtype: bool
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
reset_hash = info['match'].get('hash', None)
|
|
27
|
+
if reset_hash:
|
|
28
|
+
try:
|
|
29
|
+
info['match']['user'] = pyramid_basemodel.Session.query(User).filter(User.reset_key == reset_hash).one()
|
|
30
|
+
return True
|
|
31
|
+
except NoResultFound:
|
|
32
|
+
pass
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def change_email_hash(info, request):
|
|
37
|
+
"""
|
|
38
|
+
Check whether change email hash is correct.
|
|
39
|
+
|
|
40
|
+
:param dict info: pyramid info dict with path fragments and info
|
|
41
|
+
:param pyramid.request.Request request: request object
|
|
42
|
+
|
|
43
|
+
:returns: whether change email hash exists or not
|
|
44
|
+
:rtype: bool
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
change_email_hash = info['match'].get('hash', None)
|
|
48
|
+
if change_email_hash:
|
|
49
|
+
try:
|
|
50
|
+
info['match']['user'] = pyramid_basemodel.Session.query(User).filter(User.email_change_key == change_email_hash).one()
|
|
51
|
+
return True
|
|
52
|
+
except NoResultFound:
|
|
53
|
+
pass
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class CSRFCheckPredicate(CheckCSRFTokenPredicate):
|
|
58
|
+
|
|
59
|
+
"""
|
|
60
|
+
Run csrf check dependant on configuration.
|
|
61
|
+
|
|
62
|
+
.. note::
|
|
63
|
+
|
|
64
|
+
Raises HTTPUnauthorized exception if check fails.
|
|
65
|
+
|
|
66
|
+
:raises: pyramid.httpexceptions.HTTPUnauthorized
|
|
67
|
+
|
|
68
|
+
:returns: True if check succeeds or turned off.
|
|
69
|
+
:rtype: bool
|
|
70
|
+
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
def __call__(self, context, request):
|
|
74
|
+
"""
|
|
75
|
+
Run predicate check.
|
|
76
|
+
|
|
77
|
+
:param context:
|
|
78
|
+
:param pyramid.request.Request request:
|
|
79
|
+
|
|
80
|
+
"""
|
|
81
|
+
if request.registry['config'].fullauth.check_csrf:
|
|
82
|
+
result = CheckCSRFTokenPredicate.__call__(self, context, request)
|
|
83
|
+
if not result:
|
|
84
|
+
raise HTTPUnauthorized
|
|
85
|
+
|
|
86
|
+
return True
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_fullauth and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""Additional tools used in pyramid_fullauth."""
|
|
6
|
+
|
|
7
|
+
import string
|
|
8
|
+
from random import choice
|
|
9
|
+
|
|
10
|
+
from pyramid.compat import text_type
|
|
11
|
+
|
|
12
|
+
from pyramid_fullauth.exceptions import (
|
|
13
|
+
EmptyError, ShortPasswordError, PasswordConfirmMismatchError
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def password_generator(length, chars=(string.ascii_letters + string.digits + string.punctuation)):
|
|
18
|
+
"""
|
|
19
|
+
Generate random password.
|
|
20
|
+
|
|
21
|
+
.. warning::
|
|
22
|
+
|
|
23
|
+
TODO: tests!
|
|
24
|
+
|
|
25
|
+
:param int length: length of a password to Generates
|
|
26
|
+
:param list chars: list of characters from which to choose
|
|
27
|
+
:returns: password
|
|
28
|
+
:rtype: str
|
|
29
|
+
"""
|
|
30
|
+
return text_type(''.join([choice(chars) for i in range(length)]))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def validate_passsword(request, password, user=None):
|
|
34
|
+
"""
|
|
35
|
+
Validate password properly.
|
|
36
|
+
|
|
37
|
+
.. note::
|
|
38
|
+
|
|
39
|
+
If no user provided, password is just validated
|
|
40
|
+
|
|
41
|
+
:param pyramid.request.Request request: request object
|
|
42
|
+
:param str password: password to be set
|
|
43
|
+
:param pyramid_fullauth.models.User user: user object
|
|
44
|
+
|
|
45
|
+
:raises: pyramid_fullauth.exceptions.ValidateError
|
|
46
|
+
"""
|
|
47
|
+
password_config = request.registry['config'].fullauth.register.password
|
|
48
|
+
if not password:
|
|
49
|
+
raise EmptyError(
|
|
50
|
+
request._('Please enter your password',
|
|
51
|
+
domain='pyramid_fullauth'))
|
|
52
|
+
|
|
53
|
+
if password_config['length_min'] and\
|
|
54
|
+
len(password) < password_config['length_min']:
|
|
55
|
+
raise ShortPasswordError(
|
|
56
|
+
request._('Password is too short',
|
|
57
|
+
domain='pyramid_fullauth'))
|
|
58
|
+
|
|
59
|
+
# here if password doesn't match
|
|
60
|
+
if password_config['confirm']:
|
|
61
|
+
confirm_password = request.POST.get('confirm_password', text_type(''))
|
|
62
|
+
if password != confirm_password:
|
|
63
|
+
raise PasswordConfirmMismatchError(
|
|
64
|
+
request._('password-mismatch',
|
|
65
|
+
default='Passwords don\'t match',
|
|
66
|
+
domain='pyramid_fullauth'))
|
|
67
|
+
|
|
68
|
+
if user:
|
|
69
|
+
user.password = password
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_fullauth and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""Views submodule."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BaseView(object):
|
|
9
|
+
|
|
10
|
+
"""basic view class."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, request):
|
|
13
|
+
"""Common init for views."""
|
|
14
|
+
self.request = request
|
|
15
|
+
self.config = request.registry['config'].fullauth
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_fullauth and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""Registration related views."""
|
|
6
|
+
|
|
7
|
+
from pyramid.view import view_config
|
|
8
|
+
from pyramid.httpexceptions import HTTPRedirection
|
|
9
|
+
from pyramid.security import NO_PERMISSION_REQUIRED
|
|
10
|
+
|
|
11
|
+
from sqlalchemy.orm.exc import NoResultFound
|
|
12
|
+
import pyramid_basemodel
|
|
13
|
+
|
|
14
|
+
from pyramid_fullauth.views import BaseView
|
|
15
|
+
from pyramid_fullauth.models import User
|
|
16
|
+
from pyramid_fullauth.events import AfterActivate
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@view_config(route_name='register:activate', permission=NO_PERMISSION_REQUIRED,
|
|
20
|
+
renderer="pyramid_fullauth:resources/templates/activate.mako")
|
|
21
|
+
class ActivateView(BaseView):
|
|
22
|
+
|
|
23
|
+
"""Activate account views."""
|
|
24
|
+
|
|
25
|
+
def __call__(self):
|
|
26
|
+
"""Process account activation."""
|
|
27
|
+
activate_hash = self.request.matchdict.get('hash')
|
|
28
|
+
user = None
|
|
29
|
+
response = {}
|
|
30
|
+
response['status'] = True
|
|
31
|
+
if activate_hash:
|
|
32
|
+
try:
|
|
33
|
+
user = pyramid_basemodel.Session.query(User).filter(User.activate_key == activate_hash).one()
|
|
34
|
+
if not user.is_active:
|
|
35
|
+
user.is_active = True
|
|
36
|
+
except NoResultFound:
|
|
37
|
+
response['status'] = False
|
|
38
|
+
try:
|
|
39
|
+
self.request.registry.notify(AfterActivate(self.request, user))
|
|
40
|
+
except HTTPRedirection as e:
|
|
41
|
+
# it's a redirect, let's follow it!
|
|
42
|
+
return e
|
|
43
|
+
|
|
44
|
+
return response
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_fullauth and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""Forbidden views."""
|
|
6
|
+
|
|
7
|
+
from pyramid.view import forbidden_view_config
|
|
8
|
+
from pyramid.httpexceptions import HTTPFound
|
|
9
|
+
|
|
10
|
+
from pyramid_fullauth.views import BaseView
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ForbiddenViews(BaseView):
|
|
14
|
+
|
|
15
|
+
"""Forbidden related views."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, request):
|
|
18
|
+
"""Set all responses status to 403 by default."""
|
|
19
|
+
super(ForbiddenViews, self).__init__(request)
|
|
20
|
+
self.request.response.status_code = 403
|
|
21
|
+
|
|
22
|
+
@forbidden_view_config(renderer='pyramid_fullauth:resources/templates/403.mako')
|
|
23
|
+
def forbidden(self):
|
|
24
|
+
"""Forbidden page view."""
|
|
25
|
+
# do not allow a user to login if they are already logged in
|
|
26
|
+
if self.request.authenticated_userid:
|
|
27
|
+
return {}
|
|
28
|
+
|
|
29
|
+
loc = self.request.route_path('login', _query=(('after', self.request.path),))
|
|
30
|
+
return HTTPFound(location=loc)
|
|
31
|
+
|
|
32
|
+
@forbidden_view_config(xhr=True, renderer='json')
|
|
33
|
+
def forbidden_json(self):
|
|
34
|
+
"""Forbidden xhr response."""
|
|
35
|
+
# do not allow a user to login if they are already logged in
|
|
36
|
+
if self.request.authenticated_userid:
|
|
37
|
+
return {'status': False, 'msg':
|
|
38
|
+
self.request._('forbidden-notallowed',
|
|
39
|
+
default='You are not allowed to use this function',
|
|
40
|
+
domain='pyramid_fullauth')}
|
|
41
|
+
|
|
42
|
+
return {'status': False,
|
|
43
|
+
'msg': self.request._('forbidden-login',
|
|
44
|
+
default='You have to be logged in to use this function',
|
|
45
|
+
domain='pyramid_fullauth'),
|
|
46
|
+
'login_url': self.request.route_path('login')}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_fullauth and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""Authorisation related views."""
|
|
6
|
+
|
|
7
|
+
from pyramid.view import view_config
|
|
8
|
+
from pyramid.view import view_defaults
|
|
9
|
+
from pyramid.httpexceptions import HTTPSeeOther, HTTPRedirection
|
|
10
|
+
from pyramid.security import NO_PERMISSION_REQUIRED
|
|
11
|
+
|
|
12
|
+
from sqlalchemy.orm.exc import NoResultFound
|
|
13
|
+
from pyramid.compat import text_type
|
|
14
|
+
import pyramid_basemodel
|
|
15
|
+
|
|
16
|
+
from pyramid_fullauth.views import BaseView
|
|
17
|
+
from pyramid_fullauth.models import User
|
|
18
|
+
from pyramid_fullauth.events import BeforeLogIn
|
|
19
|
+
from pyramid_fullauth.events import AfterLogIn
|
|
20
|
+
from pyramid_fullauth.events import AlreadyLoggedIn
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@view_defaults(route_name='login', permission=NO_PERMISSION_REQUIRED,
|
|
24
|
+
renderer='pyramid_fullauth:resources/templates/login.mako')
|
|
25
|
+
class BaseLoginView(BaseView):
|
|
26
|
+
|
|
27
|
+
"""Basic logic for login views."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, request):
|
|
30
|
+
"""Prepare login views."""
|
|
31
|
+
super(BaseLoginView, self).__init__(request)
|
|
32
|
+
|
|
33
|
+
self.response = {
|
|
34
|
+
'status': False,
|
|
35
|
+
'msg': self.request._('Login error', domain='pyramid_fullauth'),
|
|
36
|
+
'after': self.request.params.get(
|
|
37
|
+
'after', self.request.referer or '/'),
|
|
38
|
+
'csrf_token': self.request.session.get_csrf_token()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
def _redirect_authenticated_user(self):
|
|
42
|
+
"""Redirect already logged in user away from login page."""
|
|
43
|
+
redirect = HTTPSeeOther(location=self.response['after'])
|
|
44
|
+
try:
|
|
45
|
+
self.request.registry.notify(AlreadyLoggedIn(self.request))
|
|
46
|
+
except HTTPRedirection as e_redirect:
|
|
47
|
+
redirect = e_redirect
|
|
48
|
+
|
|
49
|
+
if self.request.is_xhr:
|
|
50
|
+
self.response['status'] = True
|
|
51
|
+
self.response['msg'] = self.request._(
|
|
52
|
+
'Already logged in!',
|
|
53
|
+
domain='pyramid_fullauth')
|
|
54
|
+
self.response['after'] = redirect.location
|
|
55
|
+
return self.response
|
|
56
|
+
else:
|
|
57
|
+
return redirect
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@view_config(request_method='GET')
|
|
61
|
+
class LoginView(BaseLoginView):
|
|
62
|
+
|
|
63
|
+
"""Login view."""
|
|
64
|
+
|
|
65
|
+
def __call__(self):
|
|
66
|
+
"""Display login page."""
|
|
67
|
+
if self.request.authenticated_userid:
|
|
68
|
+
return self._redirect_authenticated_user()
|
|
69
|
+
|
|
70
|
+
self.request.registry.notify(BeforeLogIn(self.request, None))
|
|
71
|
+
|
|
72
|
+
self.response['status'] = True
|
|
73
|
+
del self.response['msg']
|
|
74
|
+
return self.response
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@view_config(request_method='POST', check_csrf=True)
|
|
78
|
+
@view_config(request_method='POST', check_csrf=True, xhr=True, renderer="json")
|
|
79
|
+
class LoginViewPost(BaseLoginView):
|
|
80
|
+
|
|
81
|
+
"""Login view POST method."""
|
|
82
|
+
|
|
83
|
+
def __call__(self):
|
|
84
|
+
"""Login action."""
|
|
85
|
+
if self.request.authenticated_userid:
|
|
86
|
+
return self._redirect_authenticated_user()
|
|
87
|
+
|
|
88
|
+
email = self.request.POST.get('email', '')
|
|
89
|
+
password = self.request.POST.get('password', '')
|
|
90
|
+
try:
|
|
91
|
+
user = pyramid_basemodel.Session.query(User).filter(User.email == email).one()
|
|
92
|
+
except NoResultFound:
|
|
93
|
+
self.request.registry.notify(BeforeLogIn(self.request, None))
|
|
94
|
+
|
|
95
|
+
self.response['msg'] = self.request._('Wrong e-mail or password.',
|
|
96
|
+
domain='pyramid_fullauth')
|
|
97
|
+
return self.response
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
self.request.registry.notify(BeforeLogIn(self.request, user))
|
|
101
|
+
except AttributeError as e:
|
|
102
|
+
self.response['msg'] = text_type(e)
|
|
103
|
+
return self.response
|
|
104
|
+
|
|
105
|
+
if user.check_password(password):
|
|
106
|
+
|
|
107
|
+
login_kwargs = {'remember_me': self.request.POST.get('remember')}
|
|
108
|
+
try:
|
|
109
|
+
# if remember in POST set cookie timeout to one month
|
|
110
|
+
self.request.registry.notify(AfterLogIn(self.request, user))
|
|
111
|
+
except AttributeError as e:
|
|
112
|
+
self.response['msg'] = text_type(e)
|
|
113
|
+
return self.response
|
|
114
|
+
except HTTPRedirection as redirect:
|
|
115
|
+
login_kwargs['location'] = redirect.location
|
|
116
|
+
|
|
117
|
+
redirect = self.request.login_perform(user, **login_kwargs)
|
|
118
|
+
if self.request.is_xhr:
|
|
119
|
+
self.response['status'] = True
|
|
120
|
+
del self.response['msg']
|
|
121
|
+
self.response['after'] = redirect.location
|
|
122
|
+
return self.response
|
|
123
|
+
else:
|
|
124
|
+
return redirect
|
|
125
|
+
else:
|
|
126
|
+
self.response['msg'] = self.request._('Wrong e-mail or password.',
|
|
127
|
+
domain='pyramid_fullauth')
|
|
128
|
+
return self.response
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_fullauth and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""De-authentication related view."""
|
|
6
|
+
|
|
7
|
+
from pyramid.view import view_config
|
|
8
|
+
from pyramid.httpexceptions import HTTPSeeOther
|
|
9
|
+
from pyramid.security import NO_PERMISSION_REQUIRED
|
|
10
|
+
|
|
11
|
+
from pyramid_fullauth.views import BaseView
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@view_config(route_name='logout', permission=NO_PERMISSION_REQUIRED)
|
|
15
|
+
class LogoutView(BaseView):
|
|
16
|
+
|
|
17
|
+
"""Logout view."""
|
|
18
|
+
|
|
19
|
+
def __call__(self):
|
|
20
|
+
"""Logout action."""
|
|
21
|
+
location = '/'
|
|
22
|
+
if self.config.redirects.logout:
|
|
23
|
+
location = self.request.route_path(self.config.redirects.logout)
|
|
24
|
+
# forget headers
|
|
25
|
+
self.request.logout()
|
|
26
|
+
|
|
27
|
+
return HTTPSeeOther(location=location,
|
|
28
|
+
headers=self.request.response.headers)
|