# -*- coding: utf-8 -*- # Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import datetime import logging import uuid import pyramid.security as security from pyramid.view import view_config from pyramid.httpexceptions import HTTPFound from pyramid.response import Response from pyramid.security import NO_PERMISSION_REQUIRED from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignInSuccess from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignInBadAuth from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignOut from ziggurat_foundations.models.services.user import UserService from appenlight.lib.social import handle_social_data from appenlight.models import DBSession from appenlight.models.user import User from appenlight.models.services.user import UserService from appenlight.subscribers import _ from appenlight import forms from webob.multidict import MultiDict log = logging.getLogger(__name__) @view_config(context=ZigguratSignInSuccess, permission=NO_PERMISSION_REQUIRED) def sign_in(request): """ Performs sign in by sending proper user identification headers Regenerates CSRF token """ user = request.context.user if user.status == 1: request.session.new_csrf_token() user.last_login_date = datetime.datetime.utcnow() social_data = request.session.get("zigg.social_auth") if social_data: handle_social_data(request, user, social_data) else: request.session.flash(_("Account got disabled")) if request.context.came_from != "/": return HTTPFound( location=request.context.came_from, headers=request.context.headers ) else: return HTTPFound( location=request.route_url("/"), headers=request.context.headers ) @view_config(context=ZigguratSignInBadAuth, permission=NO_PERMISSION_REQUIRED) def bad_auth(request): """ Handles incorrect login flow """ request.session.flash(_("Incorrect username or password"), "warning") return HTTPFound( location=request.route_url("register"), headers=request.context.headers ) @view_config(context=ZigguratSignOut, permission=NO_PERMISSION_REQUIRED) def sign_out(request): """ Removes user identification cookie """ return HTTPFound( location=request.route_url("register"), headers=request.context.headers ) @view_config( route_name="lost_password", renderer="appenlight:templates/user/lost_password.jinja2", permission=NO_PERMISSION_REQUIRED, ) def lost_password(request): """ Presents lost password page - sends password reset link to specified email address. This link is valid only for 10 minutes """ form = forms.LostPasswordForm(request.POST, csrf_context=request) if request.method == "POST" and form.validate(): user = UserService.by_email(form.email.data) if user: UserService.regenerate_security_code(user) user.security_code_date = datetime.datetime.utcnow() email_vars = { "user": user, "request": request, "email_title": "AppEnlight :: New password request", } UserService.send_email( request, recipients=[user.email], variables=email_vars, template="/email_templates/lost_password.jinja2", ) msg = ( "Password reset email had been sent. " "Please check your mailbox for further instructions." ) request.session.flash(_(msg)) return HTTPFound(location=request.route_url("lost_password")) return {"form": form} @view_config( route_name="lost_password_generate", permission=NO_PERMISSION_REQUIRED, renderer="appenlight:templates/user/lost_password_generate.jinja2", ) def lost_password_generate(request): """ Shows new password form - perform time check and set new password for user """ user = UserService.by_user_name_and_security_code( request.GET.get("user_name"), request.GET.get("security_code") ) if user: delta = datetime.datetime.utcnow() - user.security_code_date if user and delta.total_seconds() < 600: form = forms.NewPasswordForm(request.POST, csrf_context=request) if request.method == "POST" and form.validate(): UserService.set_password(user, form.new_password.data) request.session.flash(_("You can sign in with your new password.")) return HTTPFound(location=request.route_url("register")) else: return {"form": form} else: return Response("Security code expired") @view_config( route_name="register", renderer="appenlight:templates/user/register.jinja2", permission=NO_PERMISSION_REQUIRED, ) def register(request): """ Render register page with form Also handles oAuth flow for registration """ login_url = request.route_url("ziggurat.routes.sign_in") if request.query_string: query_string = "?%s" % request.query_string else: query_string = "" referrer = "%s%s" % (request.path, query_string) if referrer in [login_url, "/register", "/register?sign_in=1"]: referrer = "/" # never use the login form itself as came_from sign_in_form = forms.SignInForm( came_from=request.params.get("came_from", referrer), csrf_context=request ) # populate form from oAuth session data returned by authomatic social_data = request.session.get("zigg.social_auth") if request.method != "POST" and social_data: log.debug(social_data) user_name = social_data["user"].get("user_name", "").split("@")[0] form_data = {"user_name": user_name, "email": social_data["user"].get("email")} form_data["user_password"] = str(uuid.uuid4()) form = forms.UserRegisterForm(MultiDict(form_data), csrf_context=request) form.user_password.widget.hide_value = False else: form = forms.UserRegisterForm(request.POST, csrf_context=request) if request.method == "POST" and form.validate(): log.info("registering user") # insert new user here if request.registry.settings["appenlight.disable_registration"]: request.session.flash(_("Registration is currently disabled.")) return HTTPFound(location=request.route_url("/")) new_user = User() DBSession.add(new_user) form.populate_obj(new_user) UserService.regenerate_security_code(new_user) new_user.status = 1 UserService.set_password(new_user, new_user.user_password) new_user.registration_ip = request.environ.get("REMOTE_ADDR") if social_data: handle_social_data(request, new_user, social_data) email_vars = { "user": new_user, "request": request, "email_title": "AppEnlight :: Start information", } UserService.send_email( request, recipients=[new_user.email], variables=email_vars, template="/email_templates/registered.jinja2", ) request.session.flash(_("You have successfully registered.")) DBSession.flush() headers = security.remember(request, new_user.id) return HTTPFound(location=request.route_url("/"), headers=headers) settings = request.registry.settings social_plugins = {} if settings.get("authomatic.pr.twitter.key", ""): social_plugins["twitter"] = True if settings.get("authomatic.pr.google.key", ""): social_plugins["google"] = True if settings.get("authomatic.pr.github.key", ""): social_plugins["github"] = True if settings.get("authomatic.pr.bitbucket.key", ""): social_plugins["bitbucket"] = True return { "form": form, "sign_in_form": sign_in_form, "social_plugins": social_plugins, } @view_config( route_name="/", renderer="appenlight:templates/app.jinja2", permission=NO_PERMISSION_REQUIRED, ) @view_config( route_name="angular_app_ui", renderer="appenlight:templates/app.jinja2", permission=NO_PERMISSION_REQUIRED, ) @view_config( route_name="angular_app_ui_ix", renderer="appenlight:templates/app.jinja2", permission=NO_PERMISSION_REQUIRED, ) def app_main_index(request): """ Render dashoard/report browser page page along with: - flash messages - application list - assigned reports - latest events (those last two come from subscribers.py that sets global renderer variables) """ return {}