Esempio n. 1
0
    def test_login_post_success(self):
        from consoleme.lib.dynamo import UserDynamoHandler

        ddb = UserDynamoHandler()
        ddb.create_user("testuser2", "correctpassword",
                        ["group1", "*****@*****.**"])
        body = json.dumps({
            "username": "******",
            "password": "******",
            "after_redirect_uri": "/",
        })
        response = self.fetch("/api/v2/login", method="POST", body=body)
        self.assertEqual(response.code, 200)
        self.assertEqual(
            json.loads(response.body),
            {
                "status": "redirect",
                "reason": "authenticated_redirect",
                "redirect_url": "/",
                "status_code": 200,
                "message":
                "User has successfully authenticated. Redirecting to their intended destination.",
                "errors": None,
                "data": None,
            },
        )
Esempio n. 2
0
    def test_login_post_invalid_password(self):
        from consoleme.lib.dynamo import UserDynamoHandler

        ddb = UserDynamoHandler()
        ddb.create_user("testuser", "correctpassword",
                        ["group1", "*****@*****.**"])
        body = json.dumps({
            "username": "******",
            "password": "******",
            "after_redirect_uri": "/"
        })
        response = self.fetch("/api/v2/login", method="POST", body=body)
        self.assertEqual(response.code, 403)
        self.assertEqual(
            json.loads(response.body),
            {
                "status":
                "error",
                "reason":
                "authentication_failure",
                "redirect_url":
                None,
                "status_code":
                403,
                "message":
                None,
                "errors": [
                    "User doesn't exist, or password is incorrect. ",
                    "Your next authentication failure will result in a 1 second wait. This wait time will expire after 60 seconds of no authentication failures.",
                ],
                "data":
                None,
            },
        )
Esempio n. 3
0
class UserRegistrationHandler(tornado.web.RequestHandler):
    """
    Allows user registration if it is configured.
    """
    def initialize(self):
        self.ddb = UserDynamoHandler()

    async def post(self):
        # TODO: Send verification e-mail to proposed user

        log_data = {
            "function":
            f"{__name__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}",
            "message": "Attempting to register user",
            "user-agent": self.request.headers.get("User-Agent"),
        }

        generic_error_message: str = "User registration failed"
        # Fail if getting users by password is not enabled
        if not config.get("auth.get_user_by_password"):
            errors = [
                "Expected configuration `auth.get_user_by_password`, but it is not enabled."
            ]
            await handle_generic_error_response(self, generic_error_message,
                                                errors, 403, "not_configured",
                                                log_data)
            return
        # Fail if user registration not allowed
        if not config.get("auth.allow_user_registration"):
            errors = [
                "Expected configuration `auth.allow_user_registration`, but it is not enabled."
            ]
            await handle_generic_error_response(self, generic_error_message,
                                                errors, 403, "not_configured",
                                                log_data)
            return

        registration_attempt = RegistrationAttemptModel.parse_raw(
            self.request.body)
        log_data["username"] = registration_attempt.username
        # Fail if username not valid email address
        try:
            if not validate_email(registration_attempt.username):
                errors = ["Username must be a valid e-mail address."]
                await handle_generic_error_response(
                    self,
                    generic_error_message,
                    errors,
                    403,
                    "invalid_request",
                    log_data,
                )
                return
        except Exception as e:
            sentry_sdk.capture_exception()
            await handle_generic_error_response(self, generic_error_message,
                                                [str(e)], 403,
                                                "invalid_request", log_data)
            return
        # Fail if user already exists
        if await self.ddb.get_user(registration_attempt.username):
            errors = ["User already exists"]
            await handle_generic_error_response(self, generic_error_message,
                                                errors, 403, "invalid_request",
                                                log_data)
            return

        # Fails if password is not strong enough.
        password_strength_errors = await check_password_strength(
            registration_attempt.password)
        if password_strength_errors:
            await handle_generic_error_response(
                self,
                password_strength_errors["message"],
                password_strength_errors["errors"],
                403,
                "weak_password",
                log_data,
            )
            return

        self.ddb.create_user(registration_attempt.username,
                             registration_attempt.password)

        res = WebResponse(
            status="success",
            status_code=200,
            message=
            f"Successfully created user {registration_attempt.username}.",
        )
        self.write(res.json())
Esempio n. 4
0
class UserManagementHandler(BaseAPIV2Handler):
    """
    Handles creating and updating users. Only authorized users are allowed to access this endpoint.
    """
    def initialize(self):
        self.ddb = UserDynamoHandler()

    async def post(self):
        log_data = {
            "function":
            f"{__name__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}",
            "user": self.user,
            "message": "Create/Update User",
            "user-agent": self.request.headers.get("User-Agent"),
            "request_id": self.request_uuid,
            "ip": self.ip,
        }
        generic_error_message = "Unable to create/update user"
        log.debug(log_data)
        # Checks authz levels of current user
        if not can_admin_all(self.user, self.groups):
            errors = ["User is not authorized to access this endpoint."]
            await handle_generic_error_response(self, generic_error_message,
                                                errors, 403, "unauthorized",
                                                log_data)
            return
        request = UserManagementModel.parse_raw(self.request.body)
        log_data["requested_user"] = request.username
        if request.user_management_action.value == "create":
            log.debug({
                **log_data,
                "message": "Creating user",
                "requested_user": request.username,
                "requested_groups": request.groups,
            })

            # Fails if password is not strong enough.
            password_strength_errors = await check_password_strength(
                request.password)
            if password_strength_errors:
                await handle_generic_error_response(
                    self,
                    password_strength_errors["message"],
                    password_strength_errors["errors"],
                    403,
                    "weak_password",
                    log_data,
                )
                return

            self.ddb.create_user(
                request.username,
                request.password,
                request.groups,
            )
            res = WebResponse(
                status="success",
                status_code=200,
                message=f"Successfully created user {request.username}.",
            )
            self.write(res.json())
            return
        elif request.user_management_action.value == "update":
            log.debug({
                **log_data,
                "message": "Updating user",
                "requested_user": request.username,
                "requested_groups": request.groups,
            })

            if request.password:
                # Fails if password is not strong enough.
                password_strength_errors = await check_password_strength(
                    request.password)
                if password_strength_errors:
                    await handle_generic_error_response(
                        self,
                        password_strength_errors["message"],
                        password_strength_errors["errors"],
                        403,
                        "weak_password",
                        log_data,
                    )
                    return
            self.ddb.update_user(
                request.username,
                request.password,
                request.groups,
            )
            res = WebResponse(
                status="success",
                status_code=200,
                message=f"Successfully updated user {request.username}.",
            )
            self.write(res.json())
            return
        elif request.user_management_action.value == "delete":
            log.debug({
                **log_data,
                "message": "Deleting user",
                "requested_user": request.username,
            })
            self.ddb.delete_user(request.username, )
            res = WebResponse(
                status="success",
                status_code=200,
                message=f"Successfully deleted user {request.username}.",
            )
            self.write(res.json())
            return
        else:
            errors = ["Change type is not supported by this endpoint."]
            await handle_generic_error_response(self, generic_error_message,
                                                errors, 403, "invalid_request",
                                                log_data)
            return