/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to mandos-ctl

  • Committer: Teddy Hogeborn
  • Date: 2019-03-04 20:39:48 UTC
  • mto: (237.7.594 trunk)
  • mto: This revision was merged to the branch mainline in revision 382.
  • Revision ID: teddy@recompile.se-20190304203948-x8cdobs47h1f89xk
mandos-ctl: Bug fix: fix client/properties confusion

* mandos-ctl (Command.run_on_one_client): Take an additional
                                          "properties" argument.  All
                                          callers and users changed.
  (IsEnabledCmd.is_enabled): Don't run client.Get(); just look at the
                             "Enabled" property key.
  (TestCmd.setUp): Set self.clients to the correct form of dict, and
                   set self.one_client to be a dict with only one
                   client.  Also set self.other_client to other client
                   object.  All users of these attributes changed.
  (TestCmd.setUp.MockClient.__getitem__): Removed.
  (TestCmd.setUp.MockClient.__setitem__): - '' -
  (TestIsEnabled.test_is_enabled_does_get_attribute): Removed.
  (TestIsEnabled.test_is_enabled_run_exits_with_failure): Don't use []
  to alter client attribute; modify client.attributes dict directly.
  (TestRemoveCmd.test_remove): Run on full client list.
  (TestApproveCmd.test_approve): - '' -
  (TestDenyCmd.test_approve): - '' - and rename to "test_deny".

Show diffs side-by-side

added added

removed removed

Lines of Context:
278
278
        commands which want to operate on all clients at the same time
279
279
        can override this run() method instead."""
280
280
        self.mandos = mandos
281
 
        for client in clients:
282
 
            self.run_on_one_client(client)
 
281
        for client, properties in clients.items():
 
282
            self.run_on_one_client(client, properties)
283
283
 
284
284
class PrintCmd(Command):
285
285
    """Abstract class for commands printing client details"""
295
295
 
296
296
class PropertyCmd(Command):
297
297
    """Abstract class for Actions for setting one client property"""
298
 
    def run_on_one_client(self, client):
 
298
    def run_on_one_client(self, client, properties):
299
299
        """Set the Client's D-Bus property"""
300
300
        client.Set(client_interface, self.property, self.value_to_set,
301
301
                   dbus_interface=dbus.PROPERTIES_IFACE)
419
419
        return value
420
420
 
421
421
class IsEnabledCmd(Command):
422
 
    def run_on_one_client(self, client):
423
 
        if self.is_enabled(client):
 
422
    def run_on_one_client(self, client, properties):
 
423
        if self.is_enabled(client, properties):
424
424
            sys.exit(0)
425
425
        sys.exit(1)
426
 
    def is_enabled(self, client):
427
 
        return client.Get(client_interface, "Enabled",
428
 
                          dbus_interface=dbus.PROPERTIES_IFACE)
 
426
    def is_enabled(self, client, properties):
 
427
        return bool(properties["Enabled"])
429
428
 
430
429
class RemoveCmd(Command):
431
 
    def run_on_one_client(self, client):
 
430
    def run_on_one_client(self, client, properties):
432
431
        self.mandos.RemoveClient(client.__dbus_object_path__)
433
432
 
434
433
class ApproveCmd(Command):
435
 
    def run_on_one_client(self, client):
 
434
    def run_on_one_client(self, client, properties):
436
435
        client.Approve(dbus.Boolean(True),
437
436
                       dbus_interface=client_interface)
438
437
 
439
438
class DenyCmd(Command):
440
 
    def run_on_one_client(self, client):
 
439
    def run_on_one_client(self, client, properties):
441
440
        client.Approve(dbus.Boolean(False),
442
441
                       dbus_interface=client_interface)
443
442
 
799
798
                testcase.assertEqual(dbus_interface, client_interface)
800
799
                self.calls.append(("Approve", (approve,
801
800
                                               dbus_interface)))
802
 
            def __getitem__(self, key):
803
 
                return self.attributes[key]
804
 
            def __setitem__(self, key, value):
805
 
                self.attributes[key] = value
806
 
        self.clients = collections.OrderedDict([
807
 
            ("foo",
808
 
             MockClient(
809
 
                 "foo",
810
 
                 KeyID=("92ed150794387c03ce684574b1139a65"
811
 
                        "94a34f895daaaf09fd8ea90a27cddb12"),
812
 
                 Secret=b"secret",
813
 
                 Host="foo.example.org",
814
 
                 Enabled=dbus.Boolean(True),
815
 
                 Timeout=300000,
816
 
                 LastCheckedOK="2019-02-03T00:00:00",
817
 
                 Created="2019-01-02T00:00:00",
818
 
                 Interval=120000,
819
 
                 Fingerprint=("778827225BA7DE539C5A"
820
 
                              "7CFA59CFF7CDBD9A5920"),
821
 
                 CheckerRunning=dbus.Boolean(False),
822
 
                 LastEnabled="2019-01-03T00:00:00",
823
 
                 ApprovalPending=dbus.Boolean(False),
824
 
                 ApprovedByDefault=dbus.Boolean(True),
825
 
                 LastApprovalRequest="",
826
 
                 ApprovalDelay=0,
827
 
                 ApprovalDuration=1000,
828
 
                 Checker="fping -q -- %(host)s",
829
 
                 ExtendedTimeout=900000,
830
 
                 Expires="2019-02-04T00:00:00",
831
 
                 LastCheckerStatus=0)),
832
 
            ("barbar",
833
 
             MockClient(
834
 
                 "barbar",
835
 
                 KeyID=("0558568eedd67d622f5c83b35a115f79"
836
 
                        "6ab612cff5ad227247e46c2b020f441c"),
837
 
                 Secret=b"secretbar",
838
 
                 Host="192.0.2.3",
839
 
                 Enabled=dbus.Boolean(True),
840
 
                 Timeout=300000,
841
 
                 LastCheckedOK="2019-02-04T00:00:00",
842
 
                 Created="2019-01-03T00:00:00",
843
 
                 Interval=120000,
844
 
                 Fingerprint=("3E393AEAEFB84C7E89E2"
845
 
                              "F547B3A107558FCA3A27"),
846
 
                 CheckerRunning=dbus.Boolean(True),
847
 
                 LastEnabled="2019-01-04T00:00:00",
848
 
                 ApprovalPending=dbus.Boolean(False),
849
 
                 ApprovedByDefault=dbus.Boolean(False),
850
 
                 LastApprovalRequest="2019-01-03T00:00:00",
851
 
                 ApprovalDelay=30000,
852
 
                 ApprovalDuration=1000,
853
 
                 Checker=":",
854
 
                 ExtendedTimeout=900000,
855
 
                 Expires="2019-02-05T00:00:00",
856
 
                 LastCheckerStatus=-2)),
 
801
        self.client = MockClient(
 
802
            "foo",
 
803
            KeyID=("92ed150794387c03ce684574b1139a65"
 
804
                   "94a34f895daaaf09fd8ea90a27cddb12"),
 
805
            Secret=b"secret",
 
806
            Host="foo.example.org",
 
807
            Enabled=dbus.Boolean(True),
 
808
            Timeout=300000,
 
809
            LastCheckedOK="2019-02-03T00:00:00",
 
810
            Created="2019-01-02T00:00:00",
 
811
            Interval=120000,
 
812
            Fingerprint=("778827225BA7DE539C5A"
 
813
                         "7CFA59CFF7CDBD9A5920"),
 
814
            CheckerRunning=dbus.Boolean(False),
 
815
            LastEnabled="2019-01-03T00:00:00",
 
816
            ApprovalPending=dbus.Boolean(False),
 
817
            ApprovedByDefault=dbus.Boolean(True),
 
818
            LastApprovalRequest="",
 
819
            ApprovalDelay=0,
 
820
            ApprovalDuration=1000,
 
821
            Checker="fping -q -- %(host)s",
 
822
            ExtendedTimeout=900000,
 
823
            Expires="2019-02-04T00:00:00",
 
824
            LastCheckerStatus=0)
 
825
        self.other_client = MockClient(
 
826
            "barbar",
 
827
            KeyID=("0558568eedd67d622f5c83b35a115f79"
 
828
                   "6ab612cff5ad227247e46c2b020f441c"),
 
829
            Secret=b"secretbar",
 
830
            Host="192.0.2.3",
 
831
            Enabled=dbus.Boolean(True),
 
832
            Timeout=300000,
 
833
            LastCheckedOK="2019-02-04T00:00:00",
 
834
            Created="2019-01-03T00:00:00",
 
835
            Interval=120000,
 
836
            Fingerprint=("3E393AEAEFB84C7E89E2"
 
837
                         "F547B3A107558FCA3A27"),
 
838
            CheckerRunning=dbus.Boolean(True),
 
839
            LastEnabled="2019-01-04T00:00:00",
 
840
            ApprovalPending=dbus.Boolean(False),
 
841
            ApprovedByDefault=dbus.Boolean(False),
 
842
            LastApprovalRequest="2019-01-03T00:00:00",
 
843
            ApprovalDelay=30000,
 
844
            ApprovalDuration=1000,
 
845
            Checker=":",
 
846
            ExtendedTimeout=900000,
 
847
            Expires="2019-02-05T00:00:00",
 
848
            LastCheckerStatus=-2)
 
849
        self.clients =  collections.OrderedDict(
 
850
            [
 
851
                (self.client, self.client.attributes),
 
852
                (self.other_client, self.other_client.attributes),
857
853
            ])
858
 
        self.client = self.clients["foo"]
 
854
        self.one_client = {self.client: self.client.attributes}
859
855
 
860
856
class TestPrintTableCmd(TestCmd):
861
857
    def test_normal(self):
875
871
"""[1:-1]
876
872
        self.assertEqual(output, expected_output)
877
873
    def test_one_client(self):
878
 
        output = PrintTableCmd().output({"foo": self.client})
 
874
        output = PrintTableCmd().output(self.one_client)
879
875
        expected_output = """
880
876
Name Enabled Timeout  Last Successful Check
881
877
foo  Yes     00:05:00 2019-02-03T00:00:00  
939
935
        json_data = json.loads(DumpJSONCmd().output(self.clients))
940
936
        self.assertDictEqual(json_data, self.expected_json)
941
937
    def test_one_client(self):
942
 
        clients = {"foo": self.client}
 
938
        clients = self.one_client
943
939
        json_data = json.loads(DumpJSONCmd().output(clients))
944
940
        expected_json = {"foo": self.expected_json["foo"]}
945
941
        self.assertDictEqual(json_data, expected_json)
946
942
 
947
943
class TestIsEnabledCmd(TestCmd):
948
944
    def test_is_enabled(self):
949
 
        self.assertTrue(all(IsEnabledCmd().is_enabled(client)
950
 
                            for client in self.clients.values()))
951
 
    def test_is_enabled_does_get_attribute(self):
952
 
        self.assertTrue(IsEnabledCmd().is_enabled(self.client))
953
 
        self.assertListEqual(self.client.calls,
954
 
                             [("Get",
955
 
                               ("se.recompile.Mandos.Client",
956
 
                                "Enabled",
957
 
                                "org.freedesktop.DBus.Properties"))])
 
945
        self.assertTrue(all(IsEnabledCmd().is_enabled(client, properties)
 
946
                            for client, properties in self.clients.items()))
958
947
    def test_is_enabled_run_exits_successfully(self):
959
948
        with self.assertRaises(SystemExit) as e:
960
 
            IsEnabledCmd().run(None, [self.client])
 
949
            IsEnabledCmd().run(None, self.one_client)
961
950
        if e.exception.code is not None:
962
951
            self.assertEqual(e.exception.code, 0)
963
952
        else:
964
953
            self.assertIsNone(e.exception.code)
965
954
    def test_is_enabled_run_exits_with_failure(self):
966
 
        self.client["Enabled"] = dbus.Boolean(False)
 
955
        self.client.attributes["Enabled"] = dbus.Boolean(False)
967
956
        with self.assertRaises(SystemExit) as e:
968
 
            IsEnabledCmd().run(None, [self.client])
 
957
            IsEnabledCmd().run(None, self.one_client)
969
958
        if isinstance(e.exception.code, int):
970
959
            self.assertNotEqual(e.exception.code, 0)
971
960
        else:
979
968
            def RemoveClient(self, dbus_path):
980
969
                self.calls.append(("RemoveClient", (dbus_path,)))
981
970
        mandos = MockMandos()
982
 
        RemoveCmd().run(mandos, [self.client])
983
 
        self.assertEqual(len(mandos.calls), 1)
984
 
        self.assertListEqual(mandos.calls,
985
 
                             [("RemoveClient",
986
 
                               (self.client.__dbus_object_path__,))])
 
971
        super(TestRemoveCmd, self).setUp()
 
972
        RemoveCmd().run(mandos, self.clients)
 
973
        self.assertEqual(len(mandos.calls), 2)
 
974
        for client in self.clients:
 
975
            self.assertIn(("RemoveClient",
 
976
                           (client.__dbus_object_path__,)),
 
977
                          mandos.calls)
987
978
 
988
979
class TestApproveCmd(TestCmd):
989
980
    def test_approve(self):
990
 
        ApproveCmd().run(None, [self.client])
991
 
        self.assertListEqual(self.client.calls,
992
 
                             [("Approve", (True, client_interface))])
 
981
        ApproveCmd().run(None, self.clients)
 
982
        for client in self.clients:
 
983
            self.assertIn(("Approve", (True, client_interface)),
 
984
                          client.calls)
 
985
 
993
986
class TestDenyCmd(TestCmd):
994
 
    def test_approve(self):
995
 
        DenyCmd().run(None, [self.client])
996
 
        self.assertListEqual(self.client.calls,
997
 
                             [("Approve", (False, client_interface))])
 
987
    def test_deny(self):
 
988
        DenyCmd().run(None, self.clients)
 
989
        for client in self.clients:
 
990
            self.assertIn(("Approve", (False, client_interface)),
 
991
                          client.calls)
998
992
 
999
993
 
1000
994