Пример #1
0
    def authenticate_user(self, user: IUser, login_source:str, location: str=None):
        """Make the current session logged in session for this particular user."""
        request = self.request
        settings = request.registry.settings

        require_activation = asbool(settings.get('websauna.require_activation', True))
        allow_inactive_login = asbool(settings.get('websauna.allow_inactive_login', False))

        if (not allow_inactive_login) and require_activation and (not user.is_activated()):
            raise AuthenticationFailure('Your account is not active, please check your e-mail. If your account activation email as expired please request a password reset.')

        if not user.can_login():
            raise AuthenticationFailure('This user account cannot log in at the moment.')

        user_registry = get_user_registry(request)
        token = user_registry.get_session_token(user)
        headers = remember(request, token)
        # assert headers, "Authentication backend did not give us any session headers"

        if not location:
            location = get_config_route(request, 'websauna.login_redirect')

        self.greet_user(user)

        self.update_login_data(user)

        e = events.Login(request, user)
        request.registry.notify(e)

        return HTTPFound(location=location, headers=headers)
Пример #2
0
    def do_post_login_actions(self,
                              user: IUser,
                              headers: dict,
                              location: str = None) -> Response:
        """What happens after a successful login.

        Override this to customize e.g. where the user lands.

        :param user: User object.
        :param headers: Dictionary with headers to be added to the HTTPFound response.
        :param location: URL to redirect the user to.
        :return: Redirection to location.
        """
        request = self.request

        if not location:
            location = get_config_route(request, 'websauna.login_redirect')

        self.greet_user(user)

        self.update_login_data(user)

        e = events.Login(request, user)
        request.registry.notify(e)

        return HTTPFound(location=location, headers=headers)
    def create_forgot_password_request(self, email, location=None) -> Response:
        """Create a new email activation token for a user and produce the following screen.

        * Sets user password reset token

        * Sends out reset password email

        * The existing of user with such email should be validated beforehand

        :raise: CannotResetPasswordException if there is any reason the password cannot be reset. Usually wrong email.
        """

        request = self.request

        user_registry = get_user_registry(request)

        reset_info = user_registry.create_password_reset_token(email)
        if not reset_info:
            raise CannotResetPasswordException("Cannot reset password for email: {}".format(email))
        user, token, expiration_seconds = reset_info

        link = request.route_url('reset_password', code=token)
        context = dict(link=link, user=user, expiration_hours=int(expiration_seconds/3600))
        send_templated_mail(request, [email,], "login/email/forgot_password", context=context)

        messages.add(request, msg="Please check your email to continue password reset.", kind='success', msg_id="msg-check-email")

        if not location:
            location = get_config_route(request, 'websauna.request_password_reset_redirect')
            assert location

        return HTTPFound(location=location)
Пример #4
0
    def authenticate_user(self,
                          user: IUser,
                          login_source: str,
                          location: str = None) -> Response:
        """Make the current session logged in session for this particular user.

        How to authenticate user using the login service (assuming you have done password match or related yourself):

        .. code-block:: python

            from websauna.system.user.utils import get_login_service

            def my_view(request):

                # load user model instance from database
                # user = ...

                login_service = get_login_service(request)
                response = login_service.authenticate_user(user, "my-login-source")

        :raise AuthenticationFailure: If login cannot proceed due to disabled user account, etc.

        :return: HTTPResponse what should happen as post-login action
        """
        request = self.request
        settings = request.registry.settings

        require_activation = asbool(
            settings.get('websauna.require_activation', True))
        allow_inactive_login = asbool(
            settings.get('websauna.allow_inactive_login', False))

        if (not allow_inactive_login) and require_activation and (
                not user.is_activated()):
            raise AuthenticationFailure(
                'Your account is not active, please check your e-mail. If your account activation email as expired please request a password reset.'
            )

        if not user.can_login():
            raise AuthenticationFailure(
                'This user account cannot log in at the moment.')

        user_registry = get_user_registry(request)
        token = user_registry.get_session_token(user)
        headers = remember(request, token)
        # assert headers, "Authentication backend did not give us any session headers"

        if not location:
            location = get_config_route(request, 'websauna.login_redirect')

        self.greet_user(user)

        self.update_login_data(user)

        e = events.Login(request, user)
        request.registry.notify(e)

        return HTTPFound(location=location, headers=headers)
Пример #5
0
def login(request: Request) -> [HTTPFound, dict]:
    """Default login view implementation.

    :param request: Pyramid request.
    :return: Context to be used by the renderer or a HTTPFound redirect if user is already logged in.
    """
    login_redirect_view = get_config_route(request, "websauna.login_redirect")

    # Create login form schema
    schema = request.registry.getUtility(ILoginSchema)
    schema = schema().bind(request=request)

    # Create login form
    form = request.registry.getUtility(ILoginForm)
    form = form(schema)
    settings = request.registry.settings

    social_logins = aslist(settings.get("websauna.social_logins", ""))

    # Process form
    if request.method == "POST":
        try:
            controls = request.POST.items()
            captured = form.validate(controls)
        except deform.ValidationFailure as e:
            return {'form': e.render(), 'errors': e.error.children}

        username = captured['username']
        password = captured['password']
        login_service = get_login_service(request)

        try:
            return login_service.authenticate_credentials(
                username, password, login_source="login_form")
        except AuthenticationFailure as e:
            # Tell user they cannot login at the moment
            messages.add(request,
                         msg=str(e),
                         msg_id="msg-authentication-failure",
                         kind="error")

            return {
                'form': form.render(appstruct=captured),
                'errors': [e],
                "social_logins": social_logins
            }
    else:
        # HTTP get, display login form
        if request.user:
            # Already logged in
            return HTTPFound(location=login_redirect_view)

        # Display login form
        return {'form': form.render(), "social_logins": social_logins}
Пример #6
0
def login(request):
    """Default login view implementation."""

    login_redirect_view = get_config_route(request, "websauna.login_redirect")

    # Create login form schema
    schema = request.registry.getUtility(ILoginSchema)
    schema = schema().bind(request=request)

    # Create login form
    form = request.registry.getUtility(ILoginForm)
    form = form(schema)
    settings = request.registry.settings

    social_logins = aslist(settings.get("websauna.social_logins", ""))

    # Process form
    if request.method == "POST":

        try:
            controls = request.POST.items()
            captured = form.validate(controls)
        except deform.ValidationFailure as e:
            return {
                'form': e.render(),
                'errors': e.error.children
            }

        username = captured['username']
        password = captured['password']
        login_service = get_login_service(request)

        try:
            return login_service.authenticate_credentials(username, password, login_source="login_form")
        except AuthenticationFailure as e:

            # Tell user they cannot login at the moment
            messages.add(request, msg=str(e), msg_id="msg-authentication-failure", kind="error")

            return {
                'form': form.render(appstruct=captured),
                'errors': [e],
                "social_logins": social_logins
            }
    else:
        # HTTP get, display login form
        if request.user:
            # Already logged in
            return HTTPFound(location=login_redirect_view)

        # Display login form
        return {'form': form.render(), "social_logins": social_logins}
Пример #7
0
    def authenticate_user(self, user: IUser, login_source: str, location: str=None) -> Response:
        """Make the current session logged in session for this particular user.

        How to authenticate user using the login service (assuming you have done password match or related yourself):

        .. code-block:: python

            from websauna.system.user.utils import get_login_service

            def my_view(request):

                # load user model instance from database
                # user = ...

                login_service = get_login_service(request)
                response = login_service.authenticate_user(user, "my-login-source")

        :raise AuthenticationFailure: If login cannot proceed due to disabled user account, etc.

        :return: HTTPResponse what should happen as post-login action
        """
        request = self.request
        settings = request.registry.settings

        require_activation = asbool(settings.get('websauna.require_activation', True))
        allow_inactive_login = asbool(settings.get('websauna.allow_inactive_login', False))

        if (not allow_inactive_login) and require_activation and (not user.is_activated()):
            raise AuthenticationFailure('Your account is not active, please check your e-mail. If your account activation email as expired please request a password reset.')

        if not user.can_login():
            raise AuthenticationFailure('This user account cannot log in at the moment.')

        user_registry = get_user_registry(request)
        token = user_registry.get_session_token(user)
        headers = remember(request, token)
        # assert headers, "Authentication backend did not give us any session headers"

        if not location:
            location = get_config_route(request, 'websauna.login_redirect')

        self.greet_user(user)

        self.update_login_data(user)

        e = events.Login(request, user)
        request.registry.notify(e)

        return HTTPFound(location=location, headers=headers)
Пример #8
0
    def create_forgot_password_request(self,
                                       email: str,
                                       location: str = None) -> Response:
        """Create a new email activation token for a user and produce the following screen.

        * Sets user password reset token
        * Sends out reset password email
        * The existing of user with such email should be validated beforehand

        :param email: User email.
        :param location: URL to redirect the user after the password request.
        :return: Redirect to location.
        :raise: CannotResetPasswordException if there is any reason the password cannot be reset. Usually wrong email.
        """
        request = self.request

        user_registry = get_user_registry(request)

        reset_info = user_registry.create_password_reset_token(email)
        if not reset_info:
            raise CannotResetPasswordException(
                "Cannot reset password for email: {email}".format(email=email))
        user, token, expiration_seconds = reset_info

        link = request.route_url('reset_password', code=token)
        context = dict(link=link,
                       user=user,
                       expiration_hours=int(expiration_seconds / 3600))
        send_templated_mail(request, [
            email,
        ],
                            "login/email/forgot_password",
                            context=context)

        messages.add(request,
                     msg="Please check your email to continue password reset.",
                     kind='success',
                     msg_id="msg-check-email")

        if not location:
            location = get_config_route(
                request, 'websauna.request_password_reset_redirect')
            assert location

        return HTTPFound(location=location)
Пример #9
0
    def logout(self, location=None) -> Response:
        """Log out user from the site.

        * Terminate session

        * Show logged out message

        * Redirect the user to post login page
        """

        # TODO: Horus might go
        request = self.request
        logout_redirect_view = get_config_route(request, 'websauna.logout_redirect')
        location = location or logout_redirect_view

        messages.add(request, msg="You are now logged out.", kind="success", msg_id="msg-logged-out")
        headers = forget(request)
        return HTTPFound(location=location, headers=headers)
Пример #10
0
    def do_post_login_actions(self, user: IUser, headers: dict, location: str=None):
        """What happens after a succesful login.

        Override this to customize e.g. where the user lands.
        """
        request = self.request

        if not location:
            location = get_config_route(request, 'websauna.login_redirect')

        self.greet_user(user)

        self.update_login_data(user)

        e = events.Login(request, user)
        request.registry.notify(e)

        return HTTPFound(location=location, headers=headers)
Пример #11
0
    def logout(self, location: str = None) -> Response:
        """Log out user from the site.

        * Terminate session
        * Show logged out message
        * Redirect the user to post login page

        :param location: Override the redirect page. If none use ``websauna.login_redirect``. TODO - to be changed.
        :return: HTTPFound to location.
        """
        # TODO: Horus might go
        request = self.request
        logout_redirect_view = get_config_route(request, 'websauna.logout_redirect')
        location = location or logout_redirect_view

        messages.add(request, msg="You are now logged out.", kind="success", msg_id="msg-logged-out")
        headers = forget(request)
        return HTTPFound(location=location, headers=headers)
    def reset_password(self, activation_code: str, password: str, location=None) -> Response:
        """Perform actual password reset operations.

        User has following password reset link (GET) or enters the code on a form.
        """
        request = self.request
        user_registry = get_user_registry(request)
        user = user_registry.get_user_by_password_reset_token(activation_code)
        if not user:
            return HTTPNotFound("Activation code not found")

        user_registry.reset_password(user, password)

        messages.add(request, msg="The password reset complete. Please sign in with your new password.", kind='success', msg_id="msg-password-reset-complete")

        request.registry.notify(PasswordResetEvent(self.request, user, password))
        request.registry.notify(UserAuthSensitiveOperation(self.request, user, "password_reset"))

        location = location or get_config_route(request, 'websauna.reset_password_redirect')
        return HTTPFound(location=location)
Пример #13
0
    def do_post_login_actions(self,
                              user: IUser,
                              headers: dict,
                              location: str = None):
        """What happens after a succesful login.

        Override this to customize e.g. where the user lands.
        """
        request = self.request

        if not location:
            location = get_config_route(request, 'websauna.login_redirect')

        self.greet_user(user)

        self.update_login_data(user)

        e = events.Login(request, user)
        request.registry.notify(e)

        return HTTPFound(location=location, headers=headers)
Пример #14
0
    def authenticate_user(self,
                          user: IUser,
                          login_source: str,
                          location: str = None):
        """Make the current session logged in session for this particular user."""
        request = self.request
        settings = request.registry.settings

        require_activation = asbool(
            settings.get('websauna.require_activation', True))
        allow_inactive_login = asbool(
            settings.get('websauna.allow_inactive_login', False))

        if (not allow_inactive_login) and require_activation and (
                not user.is_activated()):
            raise AuthenticationFailure(
                'Your account is not active, please check your e-mail. If your account activation email as expired please request a password reset.'
            )

        if not user.can_login():
            raise AuthenticationFailure(
                'This user account cannot log in at the moment.')

        user_registry = get_user_registry(request)
        token = user_registry.get_session_token(user)
        headers = remember(request, token)
        # assert headers, "Authentication backend did not give us any session headers"

        if not location:
            location = get_config_route(request, 'websauna.login_redirect')

        self.greet_user(user)

        self.update_login_data(user)

        e = events.Login(request, user)
        request.registry.notify(e)

        return HTTPFound(location=location, headers=headers)
Пример #15
0
    def reset_password(self,
                       activation_code: str,
                       password: str,
                       location: str = None) -> Response:
        """Perform actual password reset operations.

        User has following password reset link (GET) or enters the code on a form.

        :param activation_code: Activation code provided by the user.
        :param password: New user password.
        :param location: URL to redirect the user after the password request.
        :return: Redirect to location.
        :raise: HTTPNotFound if activation_code is not found.
        """
        request = self.request
        user_registry = get_user_registry(request)
        user = user_registry.get_user_by_password_reset_token(activation_code)
        if not user:
            return HTTPNotFound("Activation code not found")

        user_registry.reset_password(user, password)

        messages.add(
            request,
            msg=
            "The password reset complete. Please sign in with your new password.",
            kind='success',
            msg_id="msg-password-reset-complete")

        request.registry.notify(
            PasswordResetEvent(self.request, user, password))
        request.registry.notify(
            UserAuthSensitiveOperation(self.request, user, "password_reset"),
            request)

        location = location or get_config_route(
            request, 'websauna.reset_password_redirect')
        return HTTPFound(location=location)
Пример #16
0
    def do_post_login_actions(self,
                              user: IUser,
                              headers: dict,
                              location: str = None):
        """Override what happens after login."""
        request = self.request

        self.update_login_data(user)

        e = Login(request, user)
        request.registry.notify(e)

        # Where this user was going before he or she hit login button
        login_state = get_login_state(request)

        if login_state:
            location = login_state["url"]
        else:
            # Only greet user if he/she was not continuing action
            self.greet_user(user)
            location = get_config_route(request, 'websauna.login_redirect')

        return HTTPFound(location)