Exemplo n.º 1
0
def assert_tokens(response_data: dict, user: User, session_id: str = None):
    """ Allows to check access- and refresh-tokens in the response body """

    access_token = response_data.get("access_token")
    refresh_token = response_data.get("refresh_token")
    assert access_token, f"No access_token in response: {response_data}"
    assert refresh_token, f"No refresh_token in response: {response_data}"

    decoded_access_token = decode_jwt(access_token)
    access_exp_dt = datetime.fromisoformat(decoded_access_token.pop("exp_iso"))
    assert access_exp_dt > datetime.utcnow()
    assert decoded_access_token.get("user_id") == user.id, decoded_access_token
    assert decoded_access_token.get(
        "token_type") == "access", decoded_access_token

    decoded_refresh_token = decode_jwt(refresh_token)
    refresh_exp_dt = datetime.fromisoformat(
        decoded_refresh_token.pop("exp_iso"))
    assert refresh_exp_dt > datetime.utcnow()
    assert decoded_refresh_token.get(
        "user_id") == user.id, decoded_refresh_token
    assert decoded_refresh_token.get(
        "token_type") == "refresh", decoded_refresh_token
    assert refresh_exp_dt > access_exp_dt

    if session_id:
        assert decoded_refresh_token.get("session_id") == session_id
Exemplo n.º 2
0
    def test_reset_password__ok(self, client, user, mocked_auth_send, dbs):
        request_user = user
        await_(request_user.update(dbs, is_superuser=True))
        target_user = await_(
            User.async_create(dbs,
                              db_commit=True,
                              email=self.email,
                              password="******"))

        client.login(user)
        response = client.post(self.url, json={"email": target_user.email})
        response_data = self.assert_ok_response(response)
        token = response_data.get("token")

        assert response_data["user_id"] == target_user.id
        assert token is not None, response_data
        assert decode_jwt(response_data["token"])["user_id"] == target_user.id

        link = f"{settings.SITE_URL}/change-password/?t={token}"
        expected_body = (
            f"<p>You can reset your password for {settings.SITE_URL}</p>"
            f"<p>Please follow the link </p>"
            f"<p><a href={link}>{link}</a></p>")
        mocked_auth_send.assert_awaited_once_with(
            recipient_email=target_user.email,
            subject=f"Welcome back to {settings.SITE_URL}",
            html_content=expected_body,
        )
Exemplo n.º 3
0
    async def test_reset_by_email__ok(self, client, user, db_objects,
                                      mocked_auth_send, reset_by):
        if reset_by == "id":
            data = {"user_id": user.id}
        else:
            data = {"email": user.email}

        user.is_superuser = True
        await user.async_update(db_objects)

        response = await client.post(self.path, json=data)
        response_data = await response.json()
        assert response.status == 200
        token = response_data["token"]

        assert response_data["user_id"] == user.id
        assert token is not None
        assert decode_jwt(response_data["token"])["user_id"] == user.id

        link = f"{settings.SITE_URL}/change-password/?t={token}"
        expected_body = (
            f"<p>You can reset your password for {settings.SITE_URL}</p>"
            f"<p>Please follow the link </p>"
            f"<p><a href={link}>{link}</a></p>")
        mocked_auth_send.assert_called_once_with(
            recipient_email=user.email,
            subject=f"Welcome back to {settings.SITE_URL}",
            html_content=expected_body,
        )
Exemplo n.º 4
0
    async def authenticate_user(
        self,
        jwt_token: str,
        token_type: str = TOKEN_TYPE_ACCESS,
    ) -> Tuple[User, dict, str]:
        """ Allows to find active user by jwt_token """

        logger.debug("Logging via JWT auth. Got token: %s", jwt_token)
        try:
            jwt_payload = decode_jwt(jwt_token)
        except ExpiredSignatureError:
            logger.debug("JWT signature has been expired for token %s", jwt_token)
            raise SignatureExpiredError("JWT signature has been expired for token")
        except InvalidTokenError as error:
            msg = "Token could not be decoded: %s"
            logger.exception(msg, error)
            raise AuthenticationFailedError(msg % (error,))

        if jwt_payload["token_type"] != token_type:
            raise AuthenticationFailedError(
                f"Token type '{token_type}' expected, got '{jwt_payload['token_type']}' instead."
            )

        user_id = jwt_payload.get("user_id")
        user = await User.get_active(self.db_session, user_id)
        if not user:
            msg = "Couldn't found active user with id=%s."
            logger.warning(msg, user_id)
            raise AuthenticationFailedError(details=(msg % (user_id,)))

        session_id = jwt_payload.get("session_id")
        if not session_id:
            raise AuthenticationFailedError("Incorrect data in JWT: session_id is missed")

        user_session = await UserSession.async_get(
            self.db_session, public_id=session_id, is_active=True
        )
        if not user_session:
            raise AuthenticationFailedError(
                f"Couldn't found active session: {user_id=} | {session_id=}."
            )

        return user, jwt_payload, session_id
Exemplo n.º 5
0
    async def authenticate_user(db_objects, jwt_token) -> User:
        logger.info("Logging via JWT auth. Got token: %s", jwt_token)

        try:
            jwt_payload = decode_jwt(jwt_token)
        except PyJWTError as err:
            msg = _("Invalid token header. Token could not be decoded as JWT.")
            logger.exception("Bad jwt token: %s", err)
            raise AuthenticationFailedError(details=msg)

        user_id = str(jwt_payload.get("user_id", 0))
        try:
            assert user_id.isdigit()
            user = await User.async_get(db_objects, id=jwt_payload["user_id"], is_active=True)
        except (AssertionError, User.DoesNotExist):
            raise AuthenticationFailedError(
                details=f"Active user #{user_id} not found or token is invalid."
            )

        return user
Exemplo n.º 6
0
    def test_sign_in__check_user_session__ok(self, client, dbs):
        self._create_user(dbs)
        response = client.post(self.url,
                               json={
                                   "email": self.email,
                                   "password": self.raw_password
                               })
        response_data = self.assert_ok_response(response)

        refresh_token = response_data.get("refresh_token")
        decoded_refresh_token = decode_jwt(refresh_token)
        refresh_exp_dt = datetime.fromisoformat(
            decoded_refresh_token.pop("exp_iso"))

        user_session: UserSession = await_(
            UserSession.async_get(dbs, user_id=self.user.id))
        assert user_session.refresh_token == refresh_token
        assert user_session.is_active is True
        assert user_session.expired_at == refresh_exp_dt
        assert user_session.refreshed_at is not None
        assert decoded_refresh_token.get(
            "session_id") == user_session.public_id