예제 #1
0
파일: __init__.py 프로젝트: NotAFile/Ultros
class AuthPlugin(plugin.PluginObject):
    """
    Auth plugin. In charge of logins and permissions.
    """

    config = None
    passwords = None
    permissions = None
    blacklist = None

    commands = None
    events = None
    storage = None

    auth_h = None
    perms_h = None

    def setup(self):
        """
        Called when the plugin is loaded. Performs initial setup.
        """

        reload(auth_handler)
        reload(permissions_handler)

        self.logger.trace(_("Entered setup method."))

        self.storage = StorageManager()
        try:
            self.config = self.storage.get_file(self, "config", YAML,
                                                "plugins/auth.yml")
        except Exception:
            self.logger.exception(_("Error loading configuration!"))
            self.logger.error(_("Disabling.."))
            self._disable_self()
            return
        if not self.config.exists:
            self.logger.error(_("Unable to find config/plugins/auth.yml"))
            self.logger.error(_("Disabling.."))
            self._disable_self()
            return

        self.commands = CommandManager()
        self.events = EventManager()

        if self.config["use-permissions"]:
            try:
                self.permissions = self.storage.get_file(self, "data", YAML,
                                                         "plugins/auth/"  # PEP
                                                         "permissions.yml")
            except Exception:
                self.logger.exception(_("Unable to load permissions. They "
                                        "will be unavailable!"))
            else:
                self.perms_h = permissions_handler.permissionsHandler(
                    self, self.permissions)
                result = self.commands.set_permissions_handler(self.perms_h)
                if not result:
                    self.logger.warn(_("Unable to set permissions handler!"))

        if self.config["use-auth"]:
            try:
                self.passwords = self.storage.get_file(self, "data", YAML,
                                                       "plugins/auth/"  # PEP!
                                                       "passwords.yml")
                self.blacklist = self.storage.get_file(self, "data", YAML,
                                                       "plugins/auth/"  # PEP!
                                                       "blacklist.yml")
            except Exception:
                self.logger.exception(_("Unable to load user accounts. They "
                                        "will be unavailable!"))
            else:
                self.auth_h = auth_handler.authHandler(self, self.passwords,
                                                       self.blacklist)
                result = self.commands.set_auth_handler(self.auth_h)
                if not result:
                    self.logger.warn(_("Unable to set auth handler!"))

        self.logger.debug(_("Registering commands."))
        self.commands.register_command("login", self.login_command,
                                       self, "auth.login", default=True)
        self.commands.register_command("logout", self.logout_command,
                                       self, "auth.login", default=True)
        self.commands.register_command("register", self.register_command,
                                       self, "auth.register", default=True)
        self.commands.register_command("passwd", self.passwd_command, self,
                                       "auth.passwd", default=True)

        self.events.add_callback("PreCommand", self, self.pre_command, 10000)

    def pre_command(self, event=PreCommand):
        """
        Pre-command hook to remove passwords from the log output.
        """

        self.logger.trace(_("Command: %s") % event.command)
        if event.command.lower() in ["login", "register"]:
            if len(event.args) >= 2:
                split_ = event.printable.split("%s " % event.command)
                second_split = split_[1].split()
                second_split[1] = _("[REDACTED]")
                split_[1] = " ".join(second_split)
                donestr = "%s " % event.command
                done = donestr.join(split_)
                event.printable = done
        elif event.command.lower() == "passwd":
            split_ = event.printable.split("%s " % event.command)
            second_split = split_[1].split()

            dsplit = []
            for x in second_split:
                dsplit.append(_("[REDACTED]"))

            split_[1] = " ".join(dsplit)
            donestr = "%s " % event.command
            done = donestr.join(split_)
            event.printable = done

    def login_command(self, protocol, caller, source, command, raw_args,
                      parsed_args):
        """
        Command handler for the login command - for logging users in.
        """

        args = raw_args.split()  # Quick fix for new command handler signature
        if len(args) < 2:
            caller.respond(__("Usage: {CHARS}login <username> <password>"))
        else:
            if self.auth_h.authorized(caller, source, protocol):
                caller.respond(__("You're already logged in. "
                                  "Try logging out first!"))
                return
            username = args[0]
            password = args[1]

            result = self.auth_h.login(caller, protocol, username, password)
            if not result:
                self.logger.warn(_("%s failed to login as %s")
                                 % (caller.nickname, username))
                caller.respond(__("Invalid username or password!"))
            else:
                self.logger.info(_("%s logged in as %s")
                                 % (caller.nickname, username))
                caller.respond(__("You are now logged in as %s.")
                               % username)

    def logout_command(self, protocol, caller, source, command, raw_args,
                       parsed_args):
        """
        Command handler for the logout command - for logging users out.
        """

        if self.auth_h.authorized(caller, source, protocol):
            self.auth_h.logout(caller, protocol)
            caller.respond(__("You have been logged out successfully."))
        else:
            caller.respond(__("You're not logged in."))

    def register_command(self, protocol, caller, source, command, raw_args,
                         parsed_args):
        """
        Command handler for the register command - for creating new user
        accounts.
        """

        args = raw_args.split()  # Quick fix for new command handler signature
        if len(args) < 2:
            caller.respond(__("Usage: {CHARS}register <username> <password>"))
            return
        username = args[0]
        password = args[1]

        if isinstance(source, Channel):
            source.respond(__("You can't create an account in a channel."))
            caller.respond(__("Don't use this command in a channel!"))
            caller.respond(__("You should only use it in a private message."))
            caller.respond(__("For your security, the password you used has "
                              "been blacklisted."))
            self.auth_h.blacklist_password(password, username)
            return

        if self.auth_h.user_exists(username):
            caller.respond(__("That username already exists!"))
            return

        if self.auth_h.password_backlisted(password, username):
            caller.respond(__("That password has been blacklisted. "
                              "Try another!"))
            return

        if self.auth_h.create_user(username, password):
            caller.respond(__("Your account has been created and you will now "
                              "be logged in. Thanks for registering!"))
            self.perms_h.create_user(username)
            self.login_command(caller, source, [username, password], protocol,
                               raw_args, parsed_args)
        else:
            caller.respond(__("Something went wrong when creating your "
                              "account! You should ask the bot operators "
                              "about this."))

    def passwd_command(self, protocol, caller, source, command, raw_args,
                       parsed_args):
        """
        Command handler for the passwd command - for changing passwords.
        """

        args = raw_args.split()  # Quick fix for new command handler signature
        if len(args) < 2:
            caller.respond(__("Usage: {CHARS}passwd <old password> "
                              "<new password>"))
            return
        if not self.auth_h.authorized(caller, source, protocol):
            caller.respond(__("You must be logged in to change your "
                              "password."))
            return

        username = caller.auth_name

        old = args[0]
        new = args[1]

        if self.auth_h.password_backlisted(new, username):
            caller.respond(__("That password has been blacklisted. Try "
                              "another!"))
            return

        if self.auth_h.change_password(username, old, new):
            caller.respond(__("Your password has been changed successfully."))
        else:
            caller.respond(__("Old password incorrect - please try again!"))
            self.logger.warn(_("User %s failed to change the password for %s")
                             % (caller, username))

    def get_auth_handler(self):
        """
        API function for getting the auth handler.

        This will return None if no handler is registered.
        """

        if self.config["use-auth"]:
            return self.auth_h
        return None

    def get_permissions_handler(self):
        """
        API function for getting the permissions handler.

        This will return None if no handler is registered.
        """
        if self.config["use-permissions"]:
            return self.perms_h
        return None

    def deactivate(self):
        """
        Called when the plugin is deactivated. Does nothing right now.
        """
        if self.config["use-auth"]:
            if isinstance(
                    self.commands.auth_handler, auth_handler.authHandler
            ):
                self.commands.auth_handler = None

        if self.config["use-permissions"]:
            if isinstance(
                    self.commands.perm_handler,
                    permissions_handler.permissionsHandler
            ):
                self.commands.perm_handler = None
예제 #2
0
class AuthPlugin(plugin.PluginObject):
    """
    Auth plugin. In charge of logins and permissions.
    """

    config = None
    passwords = None
    permissions = None
    blacklist = None

    commands = None
    events = None
    storage = None

    auth_h = None
    perms_h = None

    def setup(self):
        """
        Called when the plugin is loaded. Performs initial setup.
        """

        reload(auth_handler)
        reload(permissions_handler)

        self.logger.trace(_("Entered setup method."))

        self.storage = StorageManager()
        try:
            self.config = self.storage.get_file(self, "config", YAML,
                                                "plugins/auth.yml")
        except Exception:
            self.logger.exception(_("Error loading configuration!"))
            self.logger.error(_("Disabling.."))
            self._disable_self()
            return
        if not self.config.exists:
            self.logger.error(_("Unable to find config/plugins/auth.yml"))
            self.logger.error(_("Disabling.."))
            self._disable_self()
            return

        self.commands = CommandManager()
        self.events = EventManager()

        if self.config["use-permissions"]:
            try:
                self.permissions = self.storage.get_file(
                    self,
                    "data",
                    YAML,
                    "plugins/auth/"  # PEP
                    "permissions.yml")
            except Exception:
                self.logger.exception(
                    _("Unable to load permissions. They "
                      "will be unavailable!"))
            else:
                self.perms_h = permissions_handler.permissionsHandler(
                    self, self.permissions)
                result = self.commands.set_permissions_handler(self.perms_h)
                if not result:
                    self.logger.warn(_("Unable to set permissions handler!"))

        if self.config["use-auth"]:
            try:
                self.passwords = self.storage.get_file(
                    self,
                    "data",
                    YAML,
                    "plugins/auth/"  # PEP!
                    "passwords.yml")
                self.blacklist = self.storage.get_file(
                    self,
                    "data",
                    YAML,
                    "plugins/auth/"  # PEP!
                    "blacklist.yml")
            except Exception:
                self.logger.exception(
                    _("Unable to load user accounts. They "
                      "will be unavailable!"))
            else:
                self.auth_h = auth_handler.authHandler(self, self.passwords,
                                                       self.blacklist)
                result = self.commands.set_auth_handler(self.auth_h)
                if not result:
                    self.logger.warn(_("Unable to set auth handler!"))

        self.logger.debug(_("Registering commands."))
        self.commands.register_command("login",
                                       self.login_command,
                                       self,
                                       "auth.login",
                                       default=True)
        self.commands.register_command("logout",
                                       self.logout_command,
                                       self,
                                       "auth.login",
                                       default=True)
        self.commands.register_command("register",
                                       self.register_command,
                                       self,
                                       "auth.register",
                                       default=True)
        self.commands.register_command("passwd",
                                       self.passwd_command,
                                       self,
                                       "auth.passwd",
                                       default=True)

        self.events.add_callback("PreCommand", self, self.pre_command, 10000)

    def pre_command(self, event=PreCommand):
        """
        Pre-command hook to remove passwords from the log output.
        """

        self.logger.trace(_("Command: %s") % event.command)
        if event.command.lower() in ["login", "register"]:
            if len(event.args) >= 2:
                split_ = event.printable.split("%s " % event.command)
                second_split = split_[1].split()
                second_split[1] = _("[REDACTED]")
                split_[1] = " ".join(second_split)
                donestr = "%s " % event.command
                done = donestr.join(split_)
                event.printable = done
        elif event.command.lower() == "passwd":
            split_ = event.printable.split("%s " % event.command)
            second_split = split_[1].split()

            dsplit = []
            for x in second_split:
                dsplit.append(_("[REDACTED]"))

            split_[1] = " ".join(dsplit)
            donestr = "%s " % event.command
            done = donestr.join(split_)
            event.printable = done

    def login_command(self, protocol, caller, source, command, raw_args,
                      parsed_args):
        """
        Command handler for the login command - for logging users in.
        """

        args = raw_args.split()  # Quick fix for new command handler signature
        if len(args) < 2:
            caller.respond(__("Usage: {CHARS}login <username> <password>"))
        else:
            if self.auth_h.authorized(caller, source, protocol):
                caller.respond(
                    __("You're already logged in. "
                       "Try logging out first!"))
                return
            username = args[0]
            password = args[1]

            result = self.auth_h.login(caller, protocol, username, password)
            if not result:
                self.logger.warn(
                    _("%s failed to login as %s") %
                    (caller.nickname, username))
                caller.respond(__("Invalid username or password!"))
            else:
                self.logger.info(
                    _("%s logged in as %s") % (caller.nickname, username))
                caller.respond(__("You are now logged in as %s.") % username)

    def logout_command(self, protocol, caller, source, command, raw_args,
                       parsed_args):
        """
        Command handler for the logout command - for logging users out.
        """

        if self.auth_h.authorized(caller, source, protocol):
            self.auth_h.logout(caller, protocol)
            caller.respond(__("You have been logged out successfully."))
        else:
            caller.respond(__("You're not logged in."))

    def register_command(self, protocol, caller, source, command, raw_args,
                         parsed_args):
        """
        Command handler for the register command - for creating new user
        accounts.
        """

        args = raw_args.split()  # Quick fix for new command handler signature
        if len(args) < 2:
            caller.respond(__("Usage: {CHARS}register <username> <password>"))
            return
        username = args[0]
        password = args[1]

        if isinstance(source, Channel):
            source.respond(__("You can't create an account in a channel."))
            caller.respond(__("Don't use this command in a channel!"))
            caller.respond(__("You should only use it in a private message."))
            caller.respond(
                __("For your security, the password you used has "
                   "been blacklisted."))
            self.auth_h.blacklist_password(password, username)
            return

        if self.auth_h.user_exists(username):
            caller.respond(__("That username already exists!"))
            return

        if self.auth_h.password_backlisted(password, username):
            caller.respond(
                __("That password has been blacklisted. "
                   "Try another!"))
            return

        if self.auth_h.create_user(username, password):
            caller.respond(
                __("Your account has been created and you will now "
                   "be logged in. Thanks for registering!"))
            self.perms_h.create_user(username)
            self.login_command(caller, source, [username, password], protocol,
                               raw_args, parsed_args)
        else:
            caller.respond(
                __("Something went wrong when creating your "
                   "account! You should ask the bot operators "
                   "about this."))

    def passwd_command(self, protocol, caller, source, command, raw_args,
                       parsed_args):
        """
        Command handler for the passwd command - for changing passwords.
        """

        args = raw_args.split()  # Quick fix for new command handler signature
        if len(args) < 2:
            caller.respond(
                __("Usage: {CHARS}passwd <old password> "
                   "<new password>"))
            return
        if not self.auth_h.authorized(caller, source, protocol):
            caller.respond(
                __("You must be logged in to change your "
                   "password."))
            return

        username = caller.auth_name

        old = args[0]
        new = args[1]

        if self.auth_h.password_backlisted(new, username):
            caller.respond(
                __("That password has been blacklisted. Try "
                   "another!"))
            return

        if self.auth_h.change_password(username, old, new):
            caller.respond(__("Your password has been changed successfully."))
        else:
            caller.respond(__("Old password incorrect - please try again!"))
            self.logger.warn(
                _("User %s failed to change the password for %s") %
                (caller, username))

    def get_auth_handler(self):
        """
        API function for getting the auth handler.

        This will return None if no handler is registered.
        """

        if self.config["use-auth"]:
            return self.auth_h
        return None

    def get_permissions_handler(self):
        """
        API function for getting the permissions handler.

        This will return None if no handler is registered.
        """
        if self.config["use-permissions"]:
            return self.perms_h
        return None

    def deactivate(self):
        """
        Called when the plugin is deactivated. Does nothing right now.
        """
        if self.config["use-auth"]:
            if isinstance(self.commands.auth_handler,
                          auth_handler.authHandler):
                self.commands.auth_handler = None

        if self.config["use-permissions"]:
            if isinstance(self.commands.perm_handler,
                          permissions_handler.permissionsHandler):
                self.commands.perm_handler = None
예제 #3
0
class test_commands:

    def __init__(self):
        self.manager = CommandManager()
        self.manager.logger.setLevel(logging.CRITICAL)  # Shut up, logger

        self.factory_manager = Mock(name="factory_manager")
        self.plugin = Mock(name="plugin")

    @nosetools.nottest
    def teardown(self):
        # Clean up
        self.manager.commands = {}
        self.manager.aliases = {}
        self.manager.auth_handler = None
        self.manager.perm_handler = None

        self.plugin.reset_mock()
        self.plugin.handler.reset_mock()

        self.factory_manager.reset_mock()

    @nose.with_setup(teardown=teardown)
    def test_singleton(self):
        """CMNDS | Test Singleton metaclass"""
        nosetools.assert_true(self.manager is CommandManager())

    @nose.with_setup(teardown=teardown)
    def test_set_factory_manager(self):
        """CMNDS | Test setting factory manager"""
        self.manager.set_factory_manager(self.factory_manager)
        nosetools.assert_true(self.factory_manager)

    @nose.with_setup(teardown=teardown)
    def test_add_command(self):
        """CMNDS | Test adding commands"""
        r = self.manager.register_command("test", self.plugin.handler,
                                          self.plugin, "test.test",
                                          ["test2"], True)

        nosetools.assert_true(r)
        nosetools.assert_true("test" in self.manager.commands)

        command = self.manager.commands.get("test", None)

        if command:
            nosetools.assert_true("f" in command)
            nosetools.assert_true(command.get("f") is self.plugin.handler)

            nosetools.assert_true("permission" in command)
            nosetools.assert_true(command.get("permission") == "test.test")

            nosetools.assert_true("owner" in command)
            nosetools.assert_true(command.get("owner") is self.plugin)

            nosetools.assert_true("default" in command)
            nosetools.assert_true(command.get("default"))

        nosetools.assert_true("test2" in self.manager.aliases)

        alias = self.manager.aliases.get("test2", None)

        if alias:
            nosetools.assert_true(alias == "test")

        r = self.manager.register_command("test", self.plugin.handler,
                                          self.plugin, "test.test",
                                          ["test2"], True)

        nosetools.assert_false(r)

    @nose.with_setup(teardown=teardown)
    def test_unregister_commands(self):
        """CMNDS | Test unregistering commands"""
        self.manager.register_command("test1", self.plugin.handler,
                                      self.plugin, aliases=["test11"])
        self.manager.register_command("test2", self.plugin.handler,
                                      self.plugin, aliases=["test22"])
        self.manager.register_command("test3", self.plugin.handler,
                                      self.plugin, aliases=["test33"])

        nosetools.assert_equals(len(self.manager.commands), 3)
        nosetools.assert_equals(len(self.manager.aliases), 3)

        self.manager.unregister_commands_for_owner(self.plugin)

        nosetools.assert_equals(len(self.manager.commands), 0)
        nosetools.assert_equals(len(self.manager.aliases), 0)

    @nose.with_setup(teardown=teardown)
    def test_run_commands_defaults(self):
        """CMNDS | Test running commands directly | Defaults"""

        self.manager.register_command("test4", self.plugin.handler,
                                      self.plugin, aliases=["test5"],
                                      default=True)

        caller = Mock(name="caller")
        source = Mock(name="source")
        protocol = Mock(name="protocol")

        # Testing defaults

        r = self.manager.run_command("test4", caller, source, protocol, "")
        nosetools.assert_equals(r, (CommandState.Success, None))

        r = self.manager.run_command("test5", caller, source, protocol, "")
        nosetools.assert_equals(r, (CommandState.Success, None))

        nosetools.assert_equals(self.plugin.handler.call_count, 2)

    @nose.with_setup(teardown=teardown)
    def test_run_commands_aliases(self):
        """CMNDS | Test running commands directly | Aliases"""

        self.manager.register_command("test4", self.plugin.handler,
                                      self.plugin, aliases=["test5"],
                                      default=True)

        caller = Mock(name="caller")
        source = Mock(name="source")
        protocol = Mock(name="protocol")

        # Testing defaults

        r = self.manager.run_command("test4", caller, source, protocol, "")
        nosetools.assert_equals(r, (CommandState.Success, None))

        self.plugin.handler.assert_called_with(protocol, caller, source,
                                               "test4", "", [])

        # Reset mock
        self.plugin.handler.reset_mock()

        r = self.manager.run_command("test5", caller, source, protocol, "")
        nosetools.assert_equals(r, (CommandState.Success, None))

        self.plugin.handler.assert_called_with(protocol, caller, source,
                                               "test4", "", [])

        # Reset mock
        self.plugin.handler.reset_mock()

        self.manager.register_command("test5", self.plugin.handler,
                                      self.plugin, default=True)

        r = self.manager.run_command("test5", caller, source, protocol, "")
        nosetools.assert_equals(r, (CommandState.Success, None))

        self.plugin.handler.assert_called_with(protocol, caller, source,
                                               "test5", "", [])

    @nose.with_setup(teardown=teardown)
    def test_run_commands_auth(self):
        """CMNDS | Test running commands directly | Auth"""

        caller = Mock(name="caller")
        source = Mock(name="source")
        protocol = Mock(name="protocol")

        auth = Mock(name="auth")
        perms = Mock(name="perms")

        self.manager.set_auth_handler(auth)
        self.manager.set_permissions_handler(perms)

        ### COMMAND WITH PERMISSION ###
        auth.authorized.return_value = True
        perms.check.return_value = True

        self.manager.register_command("test5", self.plugin.handler,
                                      self.plugin, "test.test",
                                      aliases=["test6"])

        r = self.manager.run_command("test5", caller, source, protocol, "")

        nosetools.assert_equals(r, (CommandState.Success, None))
        nosetools.assert_equals(self.plugin.handler.call_count, 1)

        auth.authorized.reset_mock()
        perms.check.reset_mock()
        self.plugin.handler.reset_mock()

        ### ALIAS WITH PERMISSION ###

        r = self.manager.run_command("test6", caller, source, protocol, "")

        nosetools.assert_equals(r, (CommandState.Success, None))
        nosetools.assert_equals(self.plugin.handler.call_count, 1)

        auth.authorized.reset_mock()
        perms.check.reset_mock()

        auth.authorized.return_value = True
        perms.check.return_value = False
        self.plugin.handler.reset_mock()

        ### COMMAND WITHOUT PERMISSION ###

        r = self.manager.run_command("test5", caller, source, protocol, "")

        nosetools.assert_equals(r, (CommandState.NoPermission, None))
        nosetools.assert_equals(self.plugin.handler.call_count, 0)

        perms.check.return_value = True

        auth.authorized.reset_mock()
        perms.check.reset_mock()
        self.plugin.handler.reset_mock()

        ### COMMAND WITH EXCEPTION ###

        self.plugin.handler = Mock(side_effect=Exception('Boom!'))
        self.manager.unregister_commands_for_owner(self.plugin)

        self.manager.register_command("test5", self.plugin.handler,
                                      self.plugin, "test.test")

        r = self.manager.run_command("test5", caller, source, protocol, "")

        nosetools.assert_equals(r[0], CommandState.Error)
        nosetools.assert_true(isinstance(r[1], Exception))
        nosetools.assert_equals(self.plugin.handler.call_count, 1)

        auth.authorized.reset_mock()
        perms.check.reset_mock()
        self.plugin.handler.reset_mock()

        ### UNKNOWN COMMAND ###

        r = self.manager.run_command("test7", caller, source, protocol, "")
        nosetools.assert_equals(r, (CommandState.Unknown, None))
        nosetools.assert_equals(self.plugin.handler.call_count, 0)