Exemplo n.º 1
0
def confirm_login_success(request):
    session = DBSession()
    result = session.query(CheckIdRequest)\
                .filter_by(key=request.environ.get('repoze.browserid', ''))\
                .first()

    if result is not None:
        openid_request = result.request
        session.delete(result)
        return auth_decision(request, openid_request)

    raise NotFound('Unknown OpenID request')
Exemplo n.º 2
0
class PasswordResetView(object):
    """Password reset logic."""

    def __init__(self, request):
        self.request = request
        self.session = DBSession()
        self.prune_expired()

    def prune_expired(self):
        """Prunes password reset requests that have expired."""
        self.session.query(PasswordReset)\
                .filter(PasswordReset.expires < datetime.now())\
                .delete()

    def render_form(self):
        """Renders the password reset form."""
        return {
            'action_url': route_url('reset_password_initiate', self.request),
            'title': _(u'Reset password'),
        }

    def password_change_form(self):
        """Renders the form for changing a password for a valid token."""
        reset = self.session.query(PasswordReset)\
            .filter(PasswordReset.token == self.request.matchdict['token'])\
            .filter(PasswordReset.expires >= datetime.now())\
            .first()
        if reset is None:
            # No matching password reset found
            raise NotFound()

        user = self.session.query(User).get(reset.user_id)
        if user is None:
            raise NotFound()

        return {
            'action_url': route_url('reset_password_process', self.request),
            'title': _(u'Change password'),
            'token': reset.token,
            }

    def send_confirmation_message(self):
        """Sends an email confirmation message to the user."""
        username = self.request.POST.get('username', '').strip()
        redirect_url = route_url('reset_password', self.request)
        if not username:
            self.request.session.flash(_(u'Please supply a username.'))
        else:
            user = self.session.query(User).filter(User.username == username).first()
            if user is None:
                self.request.session.flash(_(u'The given username does not match any account.'))
            else:
                # Create a password reset request that is valid for 24 hours
                reset = PasswordReset(user.id, datetime.now() + timedelta(hours=24))
                self.session.add(reset)
                message = self.create_message(user, reset)
                from_address = self.request.registry.settings['webidentity_from_address'].strip()
                send_mail(from_address, [user.email], message)
                self.request.session.flash(_(u'Password retrieval instructions have been emailed to you.'))
                redirect_url = self.request.application_url

        return HTTPFound(location=redirect_url)

    def create_message(self, user, reset):
        """Returns an email.message.Message object representing the password
        reset message.
        """
        from_address = self.request.registry.settings['webidentity_from_address'].strip()
        date_format = self.request.registry.settings['webidentity_date_format'].strip()
        locale = get_localizer(self.request)
        subject = locale.translate(
            _(u'Password reset for ${identity}',
            mapping={'identity': identity_url(self.request, user.username)}))

        message = Message()
        message['From'] = Header(from_address, 'utf-8')
        message['To'] = Header(u'{0} <{1}>'.format(user.username, user.email), 'utf-8')
        message['Subject'] = Header(subject, 'utf-8')

        message.set_payload(locale.translate(_(
            u'password-reset-email',
            default=textwrap.dedent(u'''
            Hi ${username}

            A password retrieval process has been initiated for your OpenID
            identity

              ${identity}

            If the process was initiated by you you can continue the process
            of resetting your password by opening the following link in your
            browser

              ${reset_url}

            The link will will expire at ${expiration}.

            If you did not initiate this request you can just ignore this
            email. Your password has not been changed.
            ''').lstrip(),
            mapping=dict(
                username=user.username,
                identity=identity_url(self.request, user.username),
                expiration=reset.expires.strftime(date_format),
                reset_url=route_url('reset_password_token', self.request, token=reset.token)))))

        return message

    def change_password(self):
        """Changes the password for a user."""
        token = self.request.POST.get('token', '').strip()

        if token:
            password = self.request.POST.get('password', '')
            confirm_password = self.request.POST.get('confirm_password', '')
            if len(password.strip()) < 5:
                self.request.session.flash(_(u'Password must be at least five characters long'))
                return HTTPFound(
                    location=route_url('reset_password_token', self.request, token=token))
            elif password != confirm_password:
                self.request.session.flash(_(u'Given passwords do not match'))
                return HTTPFound(
                    location=route_url('reset_password_token', self.request, token=token))
            else:
                reset = self.session.query(PasswordReset)\
                    .filter(PasswordReset.token == token)\
                    .filter(PasswordReset.expires >= datetime.now())\
                    .first()
                if reset is None:
                    raise NotFound()

                user = self.session.query(User).get(reset.user_id)
                if user is None:
                    raise NotFound()

                # Update the user password
                user.password = password
                self.session.add(user)
                self.session.delete(reset)

                self.request.session.flash(_(u'Password changed.'))
                headers = remember(self.request, user.username)
                return HTTPFound(location=self.request.application_url, headers=headers)

        raise NotFound()
Exemplo n.º 3
0
def confirm(request):
    """Confirmation for an OpenID authentication request."""
    user = authenticated_user(request)
    if user is not None and 'form.submitted' in request.params:
        if request.POST.get('csrf_token') != request.session.get_csrf_token():
            raise Forbidden

        session = DBSession()
        result = session.query(CheckIdRequest)\
                    .filter_by(key=request.environ.get('repoze.browserid', ''))\
                    .first()

        if result is not None:
            openid_request = result.request
            session.delete(result)
        else:
            # TODO: Return an error message
            return HTTPBadRequest('Invalid confirmation request')

        if 'accept' in request.params:
            ax_attributes = get_ax_attributes(request)

            visit = session.query(VisitedSite)\
                        .join(User)\
                        .filter(User.id == user.id)\
                        .filter(VisitedSite.trust_root == openid_request.trust_root)\
                        .first()
            if visit is None:
                # This is the first time the user is visiting this RP
                visit = VisitedSite(openid_request.trust_root)
                user.visited_sites.append(visit)

            visit.remember = 'remember' in request.params

            try:
                persona_id = int(request.params.get('persona'))
                # Make sure that the referenced persona actually belongs to the user
                persona = session.query(Persona)\
                            .join(User)\
                            .filter(User.id == user.id)\
                            .filter(Persona.id == persona_id)\
                            .first()
                if persona is not None:
                    visit.persona = persona
            except (TypeError, ValueError):
                pass

            session.add(visit)

            identity = identity_url(request, user.username)
            openid_response = openid_request.answer(True, identity=identity)
            add_ax_response(openid_request, openid_response, ax_attributes)
            add_sreg_response(openid_request, openid_response, ax_attributes)

            if visit.remember:
                log_activity(request, Activity.AUTHORIZE, openid_request.trust_root)
            else:
                log_activity(request, Activity.AUTHORIZE_ONCE, openid_request.trust_root)

        else:
            log_activity(request, Activity.DENY, openid_request.trust_root)
            openid_response = openid_request.answer(False)

        store = AlchemyStore(session)
        openid_server = server.Server(store, route_url('openid_endpoint', request))

        response = webob_response(openid_server.encodeResponse(openid_response), request)
        response.headerlist.extend(forget(request))

        return response

    return HTTPBadRequest('Invalid confirmation request')