##// END OF EJS Templates
login: Make register views more robust if some POST parameters are missing....
login: Make register views more robust if some POST parameters are missing. We fail to delete passsword/password confirm parameters if they are not part of the POST parameters. But failing to delete them if they are not present seems wrong. Better silently ignore if they are not present.

File last commit:

r1065:64aae6b3 default
r1065:64aae6b3 default
Show More
views.py
355 lines | 13.9 KiB | text/x-python | PythonLexer
login: Migrate login controller to pyramid view.
r30 # -*- coding: utf-8 -*-
# Copyright (C) 2016-2016 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# 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 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/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 import collections
login: Migrate login controller to pyramid view.
r30 import datetime
import formencode
import logging
import urlparse
from pylons import url
from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config
from recaptcha.client.captcha import submit
authn: Fix container auth in login view.
r104 from rhodecode.authentication.base import authenticate, HTTP_TYPE
event: Fire event when user sucessfully registered.
r43 from rhodecode.events import UserRegistered
settings: prevent form from updating w/post request fix #3944
r1037 from rhodecode.lib import helpers as h
login: Migrate login controller to pyramid view.
r30 from rhodecode.lib.auth import (
AuthUser, HasPermissionAnyDecorator, CSRFRequired)
from rhodecode.lib.base import get_ip_addr
from rhodecode.lib.exceptions import UserCreationError
from rhodecode.lib.utils2 import safe_str
from rhodecode.model.db import User
from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
from rhodecode.model.login_session import LoginSession
from rhodecode.model.meta import Session
from rhodecode.model.settings import SettingsModel
from rhodecode.model.user import UserModel
i18n: Use new translation string factory....
r51 from rhodecode.translation import _
login: Migrate login controller to pyramid view.
r30
log = logging.getLogger(__name__)
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 CaptchaData = collections.namedtuple(
'CaptchaData', 'active, private_key, public_key')
login: Migrate login controller to pyramid view.
r30
def _store_user_in_session(session, username, remember=False):
user = User.get_by_username(username, case_insensitive=True)
auth_user = AuthUser(user.user_id)
auth_user.set_authenticated()
cs = auth_user.get_cookie_store()
session['rhodecode_user'] = cs
user.update_lastlogin()
Session().commit()
# If they want to be remembered, update the cookie
if remember:
_year = (datetime.datetime.now() +
datetime.timedelta(seconds=60 * 60 * 24 * 365))
session._set_cookie_expires(_year)
session.save()
log.info('user %s is now authenticated and stored in '
'session, session attrs %s', username, cs)
# dumps session attrs back to cookie
session._update_cookie_out()
# we set new cookie
headers = None
if session.request['set_cookie']:
# send set-cookie headers back to response to update cookie
headers = [('Set-Cookie', session.request['cookie_out'])]
return headers
login: Moved method out of login view.
r57 def get_came_from(request):
came_from = safe_str(request.GET.get('came_from', ''))
parsed = urlparse.urlparse(came_from)
allowed_schemes = ['http', 'https']
if parsed.scheme and parsed.scheme not in allowed_schemes:
log.error('Suspicious URL scheme detected %s for url %s' %
(parsed.scheme, parsed))
came_from = url('home')
elif parsed.netloc and request.host != parsed.netloc:
log.error('Suspicious NETLOC detected %s for url %s server url '
'is: %s' % (parsed.netloc, parsed, request.host))
came_from = url('home')
elif any(bad_str in parsed.path for bad_str in ('\r', '\n')):
log.error('Header injection detected `%s` for url %s server url ' %
(parsed.path, parsed))
came_from = url('home')
login: Fix login redirection when came_from not set.
r58 return came_from or url('home')
login: Moved method out of login view.
r57
login: Migrate login controller to pyramid view.
r30 class LoginView(object):
def __init__(self, context, request):
self.request = request
self.context = context
self.session = request.session
self._rhodecode_user = request.user
def _get_template_context(self):
return {
login: Moved method out of login view.
r57 'came_from': get_came_from(self.request),
login: Migrate login controller to pyramid view.
r30 'defaults': {},
'errors': {},
}
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 def _get_captcha_data(self):
settings = SettingsModel().get_all_settings()
private_key = settings.get('rhodecode_captcha_private_key')
public_key = settings.get('rhodecode_captcha_public_key')
active = bool(private_key)
return CaptchaData(
active=active, private_key=private_key, public_key=public_key)
login: Migrate login controller to pyramid view.
r30 @view_config(
route_name='login', request_method='GET',
renderer='rhodecode:templates/login.html')
def login(self):
authn: Fix container auth in login view.
r104 came_from = get_came_from(self.request)
login: Migrate login controller to pyramid view.
r30 user = self.request.user
# redirect if already logged in
if user.is_authenticated and not user.is_default and user.ip_allowed:
authn: Fix container auth in login view.
r104 raise HTTPFound(came_from)
authn: Rename 'container' -> 'headers' in authentication.
r106 # check if we use headers plugin, and try to login using it.
authn: Fix container auth in login view.
r104 try:
authn: Rename 'container' -> 'headers' in authentication.
r106 log.debug('Running PRE-AUTH for headers based authentication')
authn: Fix container auth in login view.
r104 auth_info = authenticate(
'', '', self.request.environ, HTTP_TYPE, skip_missing=True)
if auth_info:
headers = _store_user_in_session(
self.session, auth_info.get('username'))
raise HTTPFound(came_from, headers=headers)
except UserCreationError as e:
log.error(e)
self.session.flash(e, queue='error')
login: Migrate login controller to pyramid view.
r30
return self._get_template_context()
@view_config(
route_name='login', request_method='POST',
renderer='rhodecode:templates/login.html')
def login_post(self):
login: Moved method out of login view.
r57 came_from = get_came_from(self.request)
login: Migrate login controller to pyramid view.
r30 session = self.request.session
login_form = LoginForm()()
try:
session.invalidate()
form_result = login_form.to_python(self.request.params)
# form checks for username/password, now we're authenticated
headers = _store_user_in_session(
self.session,
username=form_result['username'],
remember=form_result['remember'])
login: Log redirection target on debug level...
r180 log.debug('Redirecting to "%s" after login.', came_from)
login: Migrate login controller to pyramid view.
r30 raise HTTPFound(came_from, headers=headers)
except formencode.Invalid as errors:
defaults = errors.value
# remove password from filling in form again
Martin Bornhold
login: Make register views more robust if some POST parameters are missing....
r1065 defaults.pop('password', None)
login: Migrate login controller to pyramid view.
r30 render_ctx = self._get_template_context()
render_ctx.update({
'errors': errors.error_dict,
'defaults': defaults,
})
return render_ctx
except UserCreationError as e:
authn: Rename 'container' -> 'headers' in authentication.
r106 # headers auth or other auth functions that create users on
login: Migrate login controller to pyramid view.
r30 # the fly can throw this exception signaling that there's issue
# with user creation, explanation should be provided in
# Exception itself
session.flash(e, queue='error')
return self._get_template_context()
@CSRFRequired()
@view_config(route_name='logout', request_method='POST')
def logout(self):
LoginSession().destroy_user_session()
return HTTPFound(url('home'))
@HasPermissionAnyDecorator(
'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')
@view_config(
route_name='register', request_method='GET',
renderer='rhodecode:templates/register.html',)
login: don't use mutable globals as defauls
r78 def register(self, defaults=None, errors=None):
defaults = defaults or {}
errors = errors or {}
login: Migrate login controller to pyramid view.
r30 settings = SettingsModel().get_all_settings()
login: Remove social auth fragments from register views.
r38 register_message = settings.get('rhodecode_register_message') or ''
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 captcha = self._get_captcha_data()
login: Migrate login controller to pyramid view.
r30 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
.AuthUser.permissions['global']
login: Remove social auth fragments from register views.
r38
login: Migrate login controller to pyramid view.
r30 render_ctx = self._get_template_context()
render_ctx.update({
login: Bring recaptcha back to work....
r46 'defaults': defaults,
'errors': errors,
login: Migrate login controller to pyramid view.
r30 'auto_active': auto_active,
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 'captcha_active': captcha.active,
'captcha_public_key': captcha.public_key,
login: Remove social auth fragments from register views.
r38 'register_message': register_message,
login: Migrate login controller to pyramid view.
r30 })
return render_ctx
Martin Bornhold
permissions: Fix permissions for authentication plugin settings view.
r173 @HasPermissionAnyDecorator(
'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')
login: Migrate login controller to pyramid view.
r30 @view_config(
route_name='register', request_method='POST',
renderer='rhodecode:templates/register.html')
def register_post(self):
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 captcha = self._get_captcha_data()
login: Migrate login controller to pyramid view.
r30 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
.AuthUser.permissions['global']
register_form = RegisterForm()()
try:
form_result = register_form.to_python(self.request.params)
form_result['active'] = auto_active
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 if captcha.active:
login: Migrate login controller to pyramid view.
r30 response = submit(
self.request.params.get('recaptcha_challenge_field'),
self.request.params.get('recaptcha_response_field'),
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 private_key=captcha.private_key,
login: Fix error when getting remote IP address during registration....
r45 remoteip=get_ip_addr(self.request.environ))
Martin Bornhold
login: Removed superfluos if condition.
r1063 if not response.is_valid:
login: Migrate login controller to pyramid view.
r30 _value = form_result
Martin Bornhold
login: Start error message with uppercase letter....
r1064 _msg = _('Bad captcha')
login: Migrate login controller to pyramid view.
r30 error_dict = {'recaptcha_field': _msg}
raise formencode.Invalid(_msg, _value, None,
error_dict=error_dict)
event: Fire event when user sucessfully registered.
r43 new_user = UserModel().create_registration(form_result)
event = UserRegistered(user=new_user, session=self.session)
self.request.registry.notify(event)
login: Migrate login controller to pyramid view.
r30 self.session.flash(
_('You have successfully registered with RhodeCode'),
queue='success')
Session().commit()
redirect_ro = self.request.route_path('login')
raise HTTPFound(redirect_ro)
except formencode.Invalid as errors:
Martin Bornhold
login: Make register views more robust if some POST parameters are missing....
r1065 errors.value.pop('password', None)
errors.value.pop('password_confirmation', None)
login: Bring recaptcha back to work....
r46 return self.register(
defaults=errors.value, errors=errors.error_dict)
login: Migrate login controller to pyramid view.
r30
except UserCreationError as e:
# container auth or other auth functions that create users on
# the fly can throw this exception signaling that there's issue
# with user creation, explanation should be provided in
# Exception itself
self.session.flash(e, queue='error')
login: Bring recaptcha back to work....
r46 return self.register()
login: Migrate login controller to pyramid view.
r30
@view_config(
route_name='reset_password', request_method=('GET', 'POST'),
renderer='rhodecode:templates/password_reset.html')
def password_reset(self):
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 captcha = self._get_captcha_data()
login: Migrate login controller to pyramid view.
r30
render_ctx = {
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 'captcha_active': captcha.active,
'captcha_public_key': captcha.public_key,
login: Migrate login controller to pyramid view.
r30 'defaults': {},
'errors': {},
}
if self.request.POST:
password_reset_form = PasswordResetForm()()
try:
form_result = password_reset_form.to_python(
self.request.params)
settings: prevent form from updating w/post request fix #3944
r1037 if h.HasPermissionAny('hg.password_reset.disabled')():
log.error('Failed attempt to reset password for %s.', form_result['email'] )
self.session.flash(
_('Password reset has been disabled.'),
queue='error')
return HTTPFound(self.request.route_path('reset_password'))
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 if captcha.active:
login: Migrate login controller to pyramid view.
r30 response = submit(
self.request.params.get('recaptcha_challenge_field'),
self.request.params.get('recaptcha_response_field'),
Martin Bornhold
login: Fix recaptcha. #4279...
r1062 private_key=captcha.private_key,
login: Migrate login controller to pyramid view.
r30 remoteip=get_ip_addr(self.request.environ))
Martin Bornhold
login: Removed superfluos if condition.
r1063 if not response.is_valid:
login: Migrate login controller to pyramid view.
r30 _value = form_result
Martin Bornhold
login: Start error message with uppercase letter....
r1064 _msg = _('Bad captcha')
login: Migrate login controller to pyramid view.
r30 error_dict = {'recaptcha_field': _msg}
raise formencode.Invalid(_msg, _value, None,
error_dict=error_dict)
login: Fix password reset mail link....
r37
# Generate reset URL and send mail.
user_email = form_result['email']
user = User.get_by_email(user_email)
password_reset_url = self.request.route_url(
'reset_password_confirmation',
_query={'key': user.api_key})
UserModel().reset_password_link(
form_result, password_reset_url)
# Display success message and redirect.
login: Migrate login controller to pyramid view.
r30 self.session.flash(
_('Your password reset link was sent'),
queue='success')
return HTTPFound(self.request.route_path('login'))
except formencode.Invalid as errors:
render_ctx.update({
'defaults': errors.value,
'errors': errors.error_dict,
})
return render_ctx
@view_config(route_name='reset_password_confirmation',
request_method='GET')
def password_reset_confirmation(self):
if self.request.GET and self.request.GET.get('key'):
try:
user = User.get_by_auth_token(self.request.GET.get('key'))
emails: fixed password reset confirmation that was broken because of undefied variable.
r531 password_reset_url = self.request.route_url(
'reset_password_confirmation',
_query={'key': user.api_key})
login: Migrate login controller to pyramid view.
r30 data = {'email': user.email}
emails: fixed password reset confirmation that was broken because of undefied variable.
r531 UserModel().reset_password(data, password_reset_url)
login: Migrate login controller to pyramid view.
r30 self.session.flash(
_('Your password reset was successful, '
'a new password has been sent to your email'),
queue='success')
except Exception as e:
log.error(e)
return HTTPFound(self.request.route_path('reset_password'))
return HTTPFound(self.request.route_path('login'))