Skip to content
Snippets Groups Projects
Commit f5f9a8d7 authored by Pavel Kácha's avatar Pavel Kácha
Browse files

Clients are now authorized by client= argument in URL, schema and client lib...

Clients are now authorized by client= argument in URL, schema and client lib is updated accordingly. Method authentication defined in "expose" decorator. Added Client container class for deterministic logging. Schema update to consistent InnoDB and utf8mb4 everywhere.
parent f50d1104
No related branches found
No related tags found
No related merge requests found
...@@ -211,7 +211,7 @@ class Client(object): ...@@ -211,7 +211,7 @@ class Client(object):
Error("Unable to setup syslog logging", self.logger, exc=exc_info()) Error("Unable to setup syslog logging", self.logger, exc=exc_info())
if not (errlog or filelog or syslog): if not (errlog or filelog or syslog):
# User wants explicitly no logging, so let him shoot its socks off. # User wants explicitly no logging, so let him shoot his socks off.
# This silences complaining of logging module about no suitable # This silences complaining of logging module about no suitable
# handler. # handler.
self.logger.addHandler(logging.NullHandler()) self.logger.addHandler(logging.NullHandler())
...@@ -252,6 +252,8 @@ class Client(object): ...@@ -252,6 +252,8 @@ class Client(object):
def sendRequest(self, func="", payload=None, **kwargs): def sendRequest(self, func="", payload=None, **kwargs):
kwargs["client"] = self.name
if kwargs: if kwargs:
for k in kwargs.keys(): for k in kwargs.keys():
if kwargs[k] is None: if kwargs[k] is None:
......
...@@ -6,7 +6,8 @@ ...@@ -6,7 +6,8 @@
keyfile='key.pem' keyfile='key.pem'
certfile='cert.pem' certfile='cert.pem'
cafile='tcs-ca-bundle.pem' cafile='tcs-ca-bundle.pem'
url='https://warden.example.com/warden3' url="$1"
client="$2"
# --fail \ # --fail \
# --show-error \ # --show-error \
...@@ -19,7 +20,7 @@ curl \ ...@@ -19,7 +20,7 @@ curl \
--cacert $cafile \ --cacert $cafile \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
$url/blefub "$url/blefub?client=$2"
echo echo
echo "Test 404" echo "Test 404"
...@@ -29,7 +30,27 @@ curl \ ...@@ -29,7 +30,27 @@ curl \
--cacert $cafile \ --cacert $cafile \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
$url/ "$url/?client=$2"
echo
echo "Test 403 - no client"
curl \
--key $keyfile \
--cert $certfile \
--cacert $cafile \
--connect-timeout 3 \
--request POST \
"$url/getEvents"
echo
echo "Test 403 - wrong client"
curl \
--key $keyfile \
--cert $certfile \
--cacert $cafile \
--connect-timeout 3 \
--request POST \
"$url/getEvents?client=asdf.blefub"
echo echo
echo "Test Deserialization" echo "Test Deserialization"
...@@ -40,7 +61,7 @@ curl \ ...@@ -40,7 +61,7 @@ curl \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
--data '{#$%^' \ --data '{#$%^' \
$url/getEvents "$url/getEvents?client=$2"
echo echo
echo "Test Called with unknown category" echo "Test Called with unknown category"
...@@ -50,7 +71,7 @@ curl \ ...@@ -50,7 +71,7 @@ curl \
--cacert $cafile \ --cacert $cafile \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
$url/getEvents?cat=bflm "$url/getEvents?client=$2&cat=bflm"
echo echo
echo "Test Called with both cat and nocat" echo "Test Called with both cat and nocat"
...@@ -60,7 +81,7 @@ curl \ ...@@ -60,7 +81,7 @@ curl \
--cacert $cafile \ --cacert $cafile \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
"$url/getEvents?cat=Other&nocat=Test" "$url/getEvents?client=$2&cat=Other&nocat=Test"
echo echo
echo "Test Invalid data for getEvents - silently discarded" echo "Test Invalid data for getEvents - silently discarded"
...@@ -71,7 +92,7 @@ curl \ ...@@ -71,7 +92,7 @@ curl \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
--data '[1]' \ --data '[1]' \
$url/getEvents "$url/getEvents?client=$2"
echo echo
echo "Test Called with internal args - just in log" echo "Test Called with internal args - just in log"
...@@ -81,7 +102,7 @@ curl \ ...@@ -81,7 +102,7 @@ curl \
--cacert $cafile \ --cacert $cafile \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
$url/getEvents?self=test "$url/getEvents?client=$2&self=test"
echo echo
echo "Test Called with superfluous args - just in log" echo "Test Called with superfluous args - just in log"
...@@ -91,7 +112,7 @@ curl \ ...@@ -91,7 +112,7 @@ curl \
--cacert $cafile \ --cacert $cafile \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
$url/getEvents?bad=guy "$url/getEvents?client=$2&bad=guy"
echo echo
echo "Test getEvents with no args - should be OK" echo "Test getEvents with no args - should be OK"
...@@ -101,7 +122,7 @@ curl \ ...@@ -101,7 +122,7 @@ curl \
--cacert $cafile \ --cacert $cafile \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
$url/getEvents "$url/getEvents?client=$2"
echo echo
echo "Test getEvents - should be OK" echo "Test getEvents - should be OK"
...@@ -111,7 +132,7 @@ curl \ ...@@ -111,7 +132,7 @@ curl \
--cacert $cafile \ --cacert $cafile \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
"$url/getEvents?count=3&id=10" "$url/getEvents?client=$2&count=3&id=10"
echo echo
echo "Test getDebug" echo "Test getDebug"
...@@ -121,7 +142,7 @@ curl \ ...@@ -121,7 +142,7 @@ curl \
--cacert $cafile \ --cacert $cafile \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
$url/getDebug "$url/getDebug?client=$2"
echo echo
echo "Test getInfo" echo "Test getInfo"
...@@ -131,7 +152,7 @@ curl \ ...@@ -131,7 +152,7 @@ curl \
--cacert $cafile \ --cacert $cafile \
--connect-timeout 3 \ --connect-timeout 3 \
--request POST \ --request POST \
$url/getInfo "$url/getInfo?client=$2"
echo echo
#curl \ #curl \
......
...@@ -32,7 +32,7 @@ CREATE TABLE IF NOT EXISTS `categories` ( ...@@ -32,7 +32,7 @@ CREATE TABLE IF NOT EXISTS `categories` (
`subcategory` varchar(64) DEFAULT NULL, `subcategory` varchar(64) DEFAULT NULL,
`cat_subcat` varchar(129) NOT NULL, `cat_subcat` varchar(129) NOT NULL,
KEY `cat_sub` (`cat_subcat`) KEY `cat_sub` (`cat_subcat`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
-- --
-- Dumping data for table `categories` -- Dumping data for table `categories`
...@@ -90,37 +90,56 @@ INSERT INTO `categories` (`id`, `category`, `subcategory`, `cat_subcat`) VALUES ...@@ -90,37 +90,56 @@ INSERT INTO `categories` (`id`, `category`, `subcategory`, `cat_subcat`) VALUES
CREATE TABLE IF NOT EXISTS `clients` ( CREATE TABLE IF NOT EXISTS `clients` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`hostname` varchar(256) NOT NULL,
`registered` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `registered` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`requestor` varchar(256) NOT NULL, `requestor` varchar(256) NOT NULL,
`hostname` varchar(256) NOT NULL,
`service` varchar(256) NOT NULL,
`note` text NOT NULL, `note` text NOT NULL,
`valid` tinyint(1) NOT NULL DEFAULT '1', `valid` tinyint(1) NOT NULL DEFAULT '1',
`read` tinyint(1) NOT NULL DEFAULT '0', `identity` varchar(64) NOT NULL,
`read` tinyint(1) NOT NULL DEFAULT '1',
`debug` tinyint(1) NOT NULL DEFAULT '0', `debug` tinyint(1) NOT NULL DEFAULT '0',
`write` tinyint(1) NOT NULL DEFAULT '0',
`test` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=29 ; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci AUTO_INCREMENT=31 ;
-- --
-- Dumping data for table `clients` -- Dumping data for table `clients`
-- --
INSERT INTO `clients` (`id`, `hostname`, `registered`, `requestor`, `note`, `valid`, `read`, `debug`) VALUES INSERT INTO `clients` (`id`, `registered`, `requestor`, `hostname`, `service`, `note`, `valid`, `identity`, `read`, `debug`, `write`, `test`) VALUES
(1, 'afrodita.civ.zcu.cz', '0000-00-00 00:00:00', '', '', 1, 1, 1), (1, '0000-00-00 00:00:00', '', 'afrodita.civ.zcu.cz', 'hihat', '', 1, 'cz.zcu.civ.afrodita.hihat', 1, 0, 1, 0),
(3, 'au1.cesnet.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (2, '0000-00-00 00:00:00', '', 'afrodita.civ.zcu.cz', 'labrea', '', 1, 'cz.zcu.civ.afrodita.labrea', 1, 0, 1, 0),
(12, 'au2.cesnet.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (3, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'cesnet_ids', '', 1, 'cz.cesnet.au1.cesnet_ids', 1, 0, 1, 0),
(13, 'bee.net.vutbr.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (4, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'cesnet_sserv', '', 1, 'cz.cesnet.au1.cesnet_sserv', 1, 0, 1, 0),
(14, 'buldog.vsb.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (5, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6d-dorkbot', '', 1, 'cz.cesnet.au1.n6d-dorkbot', 1, 0, 1, 0),
(15, 'collector-nemea.liberouter.org', '0000-00-00 00:00:00', '', '', 1, 1, 0), (6, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6e-certplsinkhole', '', 1, 'cz.cesnet.au1.n6e-certplsinkhole', 1, 0, 1, 0),
(17, 'collector.liberouter.org', '0000-00-00 00:00:00', '', '', 1, 1, 0), (7, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6i-citadelsinkhole', '', 1, 'cz.cesnet.au1.n6i-citadelsinkhole', 1, 0, 1, 0),
(18, 'holly.cesnet.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (8, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6i-citadelsinkholeqd', '', 1, 'cz.cesnet.au1.n6i-citadelsinkholeqd', 1, 0, 1, 0),
(19, 'kryten.cesnet.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (9, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6n-openntp', '', 1, 'cz.cesnet.au1.n6n-openntp', 1, 0, 1, 0),
(20, 'mentat.cesnet.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (10, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6o-botszeroaccess', '', 1, 'cz.cesnet.au1.n6o-botszeroaccess', 1, 0, 1, 0),
(21, 'miel.opf.slu.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (11, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'report_n6v-virut', '', 1, 'cz.cesnet.au1.report_n6v-virut', 1, 0, 1, 0),
(23, 'nfsen.ics.muni.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (12, '0000-00-00 00:00:00', '', 'au2.cesnet.cz', 'ids-cz', '', 1, 'cz.cesnet.au2.ids-cz', 1, 0, 1, 0),
(25, 'vinovago.cesnet.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (13, '0000-00-00 00:00:00', '', 'bee.net.vutbr.cz', 'hpscan', '', 1, 'cz.vutbr.net.bee.hpscan', 1, 0, 1, 0),
(26, 'ward.tul.cz', '0000-00-00 00:00:00', '', '', 1, 1, 0), (14, '0000-00-00 00:00:00', '', 'buldog.vsb.cz', 'kippo', '', 1, 'cz.vsb.buldog.kippo', 1, 0, 1, 0),
(28, 'kostik.zcu.cz', '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', '', 1, 1, 1), (15, '0000-00-00 00:00:00', '', 'collector-nemea.liberouter.org', 'nemea', '', 1, 'org.liberouter.collector-nemea.nemea', 1, 0, 1, 0),
(29, 'grey.cesnet.cz', '2014-12-11 13:51:14', 'ph@cesnet.cz', '', 1, 1, 1); (16, '0000-00-00 00:00:00', '', 'collector.liberouter.org', 'hoststats', '', 1, 'org.liberouter.collector.hoststats', 1, 0, 1, 0),
(17, '0000-00-00 00:00:00', '', 'collector.liberouter.org', 'synscandetector_1_0', '', 1, 'org.liberouter.collector.synscandetector_1_0', 1, 0, 1, 0),
(18, '0000-00-00 00:00:00', '', 'holly.cesnet.cz', 'kippohoneypot', '', 1, 'cz.cesnet.holly.kippohoneypot', 1, 0, 1, 0),
(19, '0000-00-00 00:00:00', '', 'kryten.cesnet.cz', 'dionaeahoneypot', '', 1, 'cz.cesnet.kryten.dionaeahoneypot', 1, 0, 1, 0),
(20, '0000-00-00 00:00:00', '', 'mentat.cesnet.cz', 'mentat', '', 1, 'cz.cesnet.mentat.mentat', 1, 0, 1, 0),
(21, '0000-00-00 00:00:00', '', 'miel.opf.slu.cz', 'kippo', '', 1, 'cz.slu.opf.miel.kippo', 1, 0, 1, 0),
(22, '0000-00-00 00:00:00', '', 'nfsen.ics.muni.cz', 'honeyscan', '', 1, 'cz.muni.ics.nfsen.honeyscan', 1, 0, 1, 0),
(23, '0000-00-00 00:00:00', '', 'nfsen.ics.muni.cz', 'scandetector_1_0', '', 1, 'cz.muni.ics.nfsen.scandetector_1_0', 1, 0, 1, 0),
(24, '0000-00-00 00:00:00', '', 'nfsen.ics.muni.cz', 'sshbruteforce-1_n', '', 1, 'cz.muni.ics.nfsen.sshbruteforce-1_n', 1, 0, 1, 0),
(25, '0000-00-00 00:00:00', '', 'vinovago.cesnet.cz', 'fail2ban', '', 1, 'cz.cesnet.vinovago.fail2ban', 1, 0, 1, 0),
(26, '0000-00-00 00:00:00', '', 'ward.tul.cz', 'dionaeatul', '', 1, 'cz.tul.ward.dionaeatul', 1, 0, 1, 0),
(27, '0000-00-00 00:00:00', '', 'ward.tul.cz', 'kippo', '', 1, 'cz.tul.ward.kippo', 1, 0, 1, 0),
(28, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'kostik.zcu.cz', 'com.example.test-node', '', 1, 'com.example.test-node', 1, 0, 0, 0),
(29, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'kostik.zcu.cz', 'com.example.test-node2', '', 1, 'com.example.test-node2', 1, 0, 0, 0),
(30, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'kostik.zcu.cz', 'Test', '', 1, 'com.example.test-node3', 1, 0, 0, 0),
(31, '2014-12-11 13:51:18', 'ph@cesnet.cz', 'grey.cesnet.cz', 'Test', '', 1, 'cz.cesnet.grey.test', 1, 1, 1, 0);
-- -------------------------------------------------------- -- --------------------------------------------------------
...@@ -131,13 +150,12 @@ INSERT INTO `clients` (`id`, `hostname`, `registered`, `requestor`, `note`, `val ...@@ -131,13 +150,12 @@ INSERT INTO `clients` (`id`, `hostname`, `registered`, `requestor`, `note`, `val
CREATE TABLE IF NOT EXISTS `events` ( CREATE TABLE IF NOT EXISTS `events` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`received` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `received` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`service_id` int(11) NOT NULL, `client_id` int(11) NOT NULL,
`data` text NOT NULL, `data` text NOT NULL,
`valid` tinyint(1) NOT NULL DEFAULT '1', `valid` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `detected` (`detected`), KEY `id` (`id`,`client_id`)
KEY `id` (`id`,`service_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci AUTO_INCREMENT=1 ;
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
-- -------------------------------------------------------- -- --------------------------------------------------------
...@@ -149,7 +167,7 @@ CREATE TABLE IF NOT EXISTS `event_category_mapping` ( ...@@ -149,7 +167,7 @@ CREATE TABLE IF NOT EXISTS `event_category_mapping` (
`event_id` int(11) NOT NULL, `event_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL, `category_id` int(11) NOT NULL,
KEY `event_id_2` (`event_id`,`category_id`) KEY `event_id_2` (`event_id`,`category_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
-- -------------------------------------------------------- -- --------------------------------------------------------
...@@ -161,7 +179,7 @@ CREATE TABLE IF NOT EXISTS `event_tag_mapping` ( ...@@ -161,7 +179,7 @@ CREATE TABLE IF NOT EXISTS `event_tag_mapping` (
`event_id` int(11) NOT NULL, `event_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL, `tag_id` int(11) NOT NULL,
KEY `event_id_2` (`event_id`,`tag_id`) KEY `event_id_2` (`event_id`,`tag_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
-- -------------------------------------------------------- -- --------------------------------------------------------
...@@ -176,64 +194,7 @@ CREATE TABLE IF NOT EXISTS `last_events` ( ...@@ -176,64 +194,7 @@ CREATE TABLE IF NOT EXISTS `last_events` (
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `client_id` (`client_id`,`event_id`) KEY `client_id` (`client_id`,`event_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci AUTO_INCREMENT=1 ;
-- --------------------------------------------------------
--
-- Table structure for table `services`
--
CREATE TABLE IF NOT EXISTS `services` (
`service_id` int(11) NOT NULL AUTO_INCREMENT,
`client_id` int(11) NOT NULL,
`registered` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`requestor` varchar(256) NOT NULL,
`service` varchar(256) NOT NULL,
`note` text NOT NULL,
`valid` tinyint(1) NOT NULL DEFAULT '1',
`identity` varchar(64) NOT NULL,
`write` tinyint(1) NOT NULL DEFAULT '0',
`test` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`service_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=31 ;
--
-- Dumping data for table `services`
--
INSERT INTO `services` (`service_id`, `client_id`, `registered`, `requestor`, `service`, `note`, `valid`, `identity`, `write`, `test`) VALUES
(1, 1, '0000-00-00 00:00:00', '', 'hihat', '', 1, 'cz.zcu.civ.afrodita.hihat', 1, 0),
(2, 1, '0000-00-00 00:00:00', '', 'labrea', '', 1, 'cz.zcu.civ.afrodita.labrea', 1, 0),
(3, 3, '0000-00-00 00:00:00', '', 'cesnet_ids', '', 1, 'cz.cesnet.au1.cesnet_ids', 1, 0),
(4, 3, '0000-00-00 00:00:00', '', 'cesnet_sserv', '', 1, 'cz.cesnet.au1.cesnet_sserv', 1, 0),
(5, 3, '0000-00-00 00:00:00', '', 'n6d-dorkbot', '', 1, 'cz.cesnet.au1.n6d-dorkbot', 1, 0),
(6, 3, '0000-00-00 00:00:00', '', 'n6e-certplsinkhole', '', 1, 'cz.cesnet.au1.n6e-certplsinkhole', 1, 0),
(7, 3, '0000-00-00 00:00:00', '', 'n6i-citadelsinkhole', '', 1, 'cz.cesnet.au1.n6i-citadelsinkhole', 1, 0),
(8, 3, '0000-00-00 00:00:00', '', 'n6i-citadelsinkholeqd', '', 1, 'cz.cesnet.au1.n6i-citadelsinkholeqd', 1, 0),
(9, 3, '0000-00-00 00:00:00', '', 'n6n-openntp', '', 1, 'cz.cesnet.au1.n6n-openntp', 1, 0),
(10, 3, '0000-00-00 00:00:00', '', 'n6o-botszeroaccess', '', 1, 'cz.cesnet.au1.n6o-botszeroaccess', 1, 0),
(11, 3, '0000-00-00 00:00:00', '', 'report_n6v-virut', '', 1, 'cz.cesnet.au1.report_n6v-virut', 1, 0),
(12, 12, '0000-00-00 00:00:00', '', 'ids-cz', '', 1, 'cz.cesnet.au2.ids-cz', 1, 0),
(13, 13, '0000-00-00 00:00:00', '', 'hpscan', '', 1, 'cz.vutbr.net.bee.hpscan', 1, 0),
(14, 14, '0000-00-00 00:00:00', '', 'kippo', '', 1, 'cz.vsb.buldog.kippo', 1, 0),
(15, 15, '0000-00-00 00:00:00', '', 'nemea', '', 1, 'org.liberouter.collector-nemea.nemea', 1, 0),
(16, 16, '0000-00-00 00:00:00', '', 'hoststats', '', 1, 'org.liberouter.collector.hoststats', 1, 0),
(17, 17, '0000-00-00 00:00:00', '', 'synscandetector_1_0', '', 1, 'org.liberouter.collector.synscandetector_1_0', 1, 0),
(18, 18, '0000-00-00 00:00:00', '', 'kippohoneypot', '', 1, 'cz.cesnet.holly.kippohoneypot', 1, 0),
(19, 19, '0000-00-00 00:00:00', '', 'dionaeahoneypot', '', 1, 'cz.cesnet.kryten.dionaeahoneypot', 1, 0),
(20, 20, '0000-00-00 00:00:00', '', 'mentat', '', 1, 'cz.cesnet.mentat.mentat', 1, 0),
(21, 21, '0000-00-00 00:00:00', '', 'kippo', '', 1, 'cz.slu.opf.miel.kippo', 1, 0),
(22, 23, '0000-00-00 00:00:00', '', 'honeyscan', '', 1, 'cz.muni.ics.nfsen.honeyscan', 1, 0),
(23, 23, '0000-00-00 00:00:00', '', 'scandetector_1_0', '', 1, 'cz.muni.ics.nfsen.scandetector_1_0', 1, 0),
(24, 23, '0000-00-00 00:00:00', '', 'sshbruteforce-1_n', '', 1, 'cz.muni.ics.nfsen.sshbruteforce-1_n', 1, 0),
(25, 25, '0000-00-00 00:00:00', '', 'fail2ban', '', 1, 'cz.cesnet.vinovago.fail2ban', 1, 0),
(26, 26, '0000-00-00 00:00:00', '', 'dionaeatul', '', 1, 'cz.tul.ward.dionaeatul', 1, 0),
(27, 26, '0000-00-00 00:00:00', '', 'kippo', '', 1, 'cz.tul.ward.kippo', 1, 0),
(28, 28, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'com.example.test-node', '', 1, 'com.example.test-node', 0, 0),
(29, 28, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'com.example.test-node2', '', 1, 'com.example.test-node2', 0, 0),
(30, 28, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'Test', '', 1, 'com.example.test-node3', 0, 0),
(31, 29, '2014-12-11 13:51:18', 'ph@cesnet.cz', 'Test', '', 1, 'cz.cesnet.grey.test', 1, 0);
-- -------------------------------------------------------- -- --------------------------------------------------------
...@@ -246,7 +207,7 @@ CREATE TABLE IF NOT EXISTS `tags` ( ...@@ -246,7 +207,7 @@ CREATE TABLE IF NOT EXISTS `tags` (
`tag` varchar(64) NOT NULL, `tag` varchar(64) NOT NULL,
KEY `id_tag_name` (`id`,`tag`), KEY `id_tag_name` (`id`,`tag`),
KEY `tag_name` (`tag`) KEY `tag_name` (`tag`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
-- --
-- Dumping data for table `tags` -- Dumping data for table `tags`
......
...@@ -14,6 +14,7 @@ import M2Crypto.X509 ...@@ -14,6 +14,7 @@ import M2Crypto.X509
import json import json
import MySQLdb as my import MySQLdb as my
import MySQLdb.cursors as mycursors import MySQLdb.cursors as mycursors
from collections import namedtuple
from uuid import uuid4 from uuid import uuid4
from time import time, gmtime from time import time, gmtime
from math import trunc from math import trunc
...@@ -57,7 +58,7 @@ class Error(Exception): ...@@ -57,7 +58,7 @@ class Error(Exception):
def info_str(self): def info_str(self):
return ("Detail: %s" % self.detail) or "" return ("Detail: %s" % self.detail) if self.detail else ""
def debug_str(self): def debug_str(self):
...@@ -173,6 +174,13 @@ class Object(object): ...@@ -173,6 +174,13 @@ class Object(object):
# Simple container class definition shortcut
Client = namedtuple("Client",
["id", "registered", "requestor", "hostname", "service", "note",
"identity", "read", "debug", "write", "test"])
class Request(Object): class Request(Object):
""" Simple container for info about ongoing request. """ Simple container for info about ongoing request.
One instance gets created before server startup, and all other One instance gets created before server startup, and all other
...@@ -200,9 +208,9 @@ class Request(Object): ...@@ -200,9 +208,9 @@ class Request(Object):
def reset(self, env=None, client=None, path=None, req_id=None): def reset(self, env=None, client=None, path=None, req_id=None):
self.env = {} if env is None else env self.env = env
self.client = {} if client is None else client self.client = client
self.path = "" if path is None else path self.path = path or ""
if req_id is not None: if req_id is not None:
self.req_id = req_id self.req_id = req_id
else: else:
...@@ -214,7 +222,6 @@ class Request(Object): ...@@ -214,7 +222,6 @@ class Request(Object):
class ObjectReq(Object): class ObjectReq(Object):
def __init__(self, req): def __init__(self, req):
...@@ -226,17 +233,18 @@ class ObjectReq(Object): ...@@ -226,17 +233,18 @@ class ObjectReq(Object):
return "%s(req=%s)" % (type(self).__name__, type(self.req).__name__) return "%s(req=%s)" % (type(self).__name__, type(self.req).__name__)
class NoAuthenticator(ObjectReq): class NoAuthenticator(ObjectReq):
def __init__(self, req): def __init__(self, req):
ObjectReq.__init__(self, req) ObjectReq.__init__(self, req)
def authenticate (self, env): def authenticate (self, env, args):
return "anybody" # or None return "anybody" # or None
def authorize(self, env, client, path, event): def authorize(self, env, client, path, method):
return (client is not None) return (client is not None)
...@@ -268,49 +276,44 @@ class X509Authenticator(NoAuthenticator): ...@@ -268,49 +276,44 @@ class X509Authenticator(NoAuthenticator):
return [firstcommon] + list(set(altnames+commons) - set([firstcommon])) return [firstcommon] + list(set(altnames+commons) - set([firstcommon]))
def authenticate (self, env): def authenticate (self, env, args):
names = self.get_cert_dns_names(env["SSL_CLIENT_CERT"]) try:
return self.db.get_client_by_name(names) identity = args["client"][0]
except KeyError:
logging.info("authenticate: bad or missing client argument")
return None
def authorize(self, env, client, path, event): try:
# Authorize for debug cert_names = self.get_cert_dns_names(env["SSL_CLIENT_CERT"])
if (path == 'getDebug'): except:
if not client["debug"]: logging.info("authenticate: cannot get or parse certificate from env")
logging.info("Auth failed: client does not have debug enabled")
return None return None
return client
if path in ['getInfo', 'getEvents']: client = self.db.get_client_by_name(identity, cert_names)
if not client:
logging.info("authenticate: client not found")
logging.info("authenticate: ok, client=%s" % str(client))
return client return client
try:
identity = event['Node'][0]['Name'].lower()
except (KeyError, TypeError):
# Event does not bear valid Node attribute
logging.info("Auth failed: event does not bear valid Node attribute")
return None
try: def authorize(self, env, client, path, method):
service = client["services"][identity] if method.debug:
except KeyError: if not client.debug:
# We are unable to pair service in message to service in db logging.info("authorize: failed, client does not have debug enabled")
logging.info("authorize: failed, '%s' from event not found in services for client %i" % (identity, client["id"]))
return None return None
return client
client["service"] = service if method.read:
if not client.read:
# Authorize for sending events logging.info("authorize: failed, client does not have read enabled")
if (path == "sendEvents"):
if not (service["write"] or service["test"]):
logging.info("authorize: failed, service %i (%s) is not allowed to write or test" % (service["service_id"], identity))
return None return None
return client
test = 'Test' in event.get('Category', []) if method.write:
# if not test: if not (client.write or client.test):
# logging.info("authorize: failed, service %i (%s) does not send Test category in event" % (service["service_id"], identity)) logging.info("authorize: failed, client is not allowed to write or test")
if test and not service['test']:
logging.info("authorize: failed, service %i (%s) is not allowed to send Test category in event" % (service["service_id"], identity))
return None return None
return client return client
...@@ -393,27 +396,18 @@ class MySQL(ObjectReq): ...@@ -393,27 +396,18 @@ class MySQL(ObjectReq):
type(self).__name__, type(self.req).__name__, self.host, self.user, self.dbname, self.port, self.catmap_filename, self.tagmap_filename) type(self).__name__, type(self.req).__name__, self.host, self.user, self.dbname, self.port, self.catmap_filename, self.tagmap_filename)
def get_client_by_name(self, name): def get_client_by_name(self, identity, cert_names):
format_strings = ','.join(['%s'] * len(name)) format_strings = ','.join(['%s'] * len(cert_names))
self.crs.execute("SELECT cl.`id`, cl.`hostname`, s.`service`, s.`service_id`, s.`identity`, cl.`read`, s.`write`, s.`test`, cl.`debug` FROM `clients` cl LEFT JOIN `services` s ON cl.`id` = s.`client_id` WHERE cl.`valid` = 1 AND s.`valid` = 1 AND `hostname` IN (%s)" % format_strings, tuple(name)) query = "SELECT id, registered, requestor, hostname, service, note, identity, `read`, debug, `write`, test FROM clients WHERE valid = 1 AND identity = %%s AND hostname IN (%s)" % format_strings
self.crs.execute(query, [identity] + cert_names)
rows = self.crs.fetchall() rows = self.crs.fetchall()
if not rows:
return None
client = {}
for n in ["id", "hostname", "read", "debug"]:
client[n] = rows[0][n]
services = {} if len(rows)>1:
for row in rows: logging.warn("get_client_by_name: query returned more than one result: %s" % str(rows))
service = {} return None
for n in ["service", "service_id", "identity", "write", "test"]:
service[n] = row[n]
services[row["identity"]] = service
client["services"] = services client = Client(**rows[0]) if rows else None
logging.debug("get_client_by_name: %s", str(client))
return client return client
...@@ -475,7 +469,7 @@ class MySQL(ObjectReq): ...@@ -475,7 +469,7 @@ class MySQL(ObjectReq):
sqlwhere = [] sqlwhere = []
sqlparams = [] sqlparams = []
sqlwhere.append("SELECT e.id, e.data FROM services s RIGHT JOIN events e ON s.service_id = e.service_id WHERE e.id > %s") sqlwhere.append("SELECT e.id, e.data FROM clients c RIGHT JOIN events e ON c.id = e.client_id WHERE e.id > %s")
sqlparams.append(id or 0) sqlparams.append(id or 0)
if cat or nocat: if cat or nocat:
...@@ -497,7 +491,7 @@ class MySQL(ObjectReq): ...@@ -497,7 +491,7 @@ class MySQL(ObjectReq):
not_op = "" if group else "NOT" not_op = "" if group else "NOT"
for identity in (group or nogroup): for identity in (group or nogroup):
sqlwhere.append(" AND s.identity %s LIKE %%s" % not_op) sqlwhere.append(" AND c.identity %s LIKE %%s" % not_op)
sqlparams.append(identity + "%") sqlparams.append(identity + "%")
sqlwhere.append(" AND e.valid = 1 LIMIT %s") sqlwhere.append(" AND e.valid = 1 LIMIT %s")
...@@ -525,7 +519,7 @@ class MySQL(ObjectReq): ...@@ -525,7 +519,7 @@ class MySQL(ObjectReq):
def store_event(self, client, event): def store_event(self, client, event):
try: try:
self.crs.execute("INSERT INTO events (received,service_id,data) VALUES (NOW(), %s, %s)", (client["service"]["service_id"], json.dumps(event))) self.crs.execute("INSERT INTO events (received,client_id,data) VALUES (NOW(), %s, %s)", (client.id, json.dumps(event)))
lastid = self.crs.lastrowid lastid = self.crs.lastrowid
logging.debug("store_event: Last ID in events - %i" % lastid) logging.debug("store_event: Last ID in events - %i" % lastid)
...@@ -552,8 +546,8 @@ class MySQL(ObjectReq): ...@@ -552,8 +546,8 @@ class MySQL(ObjectReq):
def insertLastReceivedId(self, client, id): def insertLastReceivedId(self, client, id):
logging.debug("insertLastReceivedId: id %i for client %i(%s)" % (id, client["id"], client["hostname"])) logging.debug("insertLastReceivedId: id %i for client %i(%s)" % (id, client.id, client.hostname))
self.crs.execute("INSERT INTO last_events(client_id, event_id, timestamp) VALUES(%s, %s, NOW())", (client["id"], id)) self.crs.execute("INSERT INTO last_events(client_id, event_id, timestamp) VALUES(%s, %s, NOW())", (client.id, id))
def getLastEventId(self): def getLastEventId(self):
self.crs.execute("SELECT MAX(id) as id FROM events") self.crs.execute("SELECT MAX(id) as id FROM events")
...@@ -562,20 +556,27 @@ class MySQL(ObjectReq): ...@@ -562,20 +556,27 @@ class MySQL(ObjectReq):
return row['id'] if row['id'] is not None else 0 return row['id'] if row['id'] is not None else 0
def getLastReceivedId(self, client): def getLastReceivedId(self, client):
self.crs.execute("SELECT MAX(event_id) as id FROM last_events WHERE client_id = %s", client["id"]) self.crs.execute("SELECT MAX(event_id) as id FROM last_events WHERE client_id = %s", client.id)
row = self.crs.fetchone() row = self.crs.fetchone()
id = row['id'] if row is not None else 0 id = row['id'] if row is not None else 0
logging.debug("getLastReceivedId: id %i for client %i(%s)" % (id, client["id"], client["hostname"])) logging.debug("getLastReceivedId: id %i for client %i(%s)" % (id, client.id, client.hostname))
return id return id
def expose(meth): def expose(read=1, write=0, debug=0):
def expose_deco(meth):
meth.exposed = True meth.exposed = True
meth.read = read
meth.write = write
meth.debug = debug
return meth return meth
return expose_deco
class Server(ObjectReq): class Server(ObjectReq):
...@@ -629,21 +630,26 @@ class Server(ObjectReq): ...@@ -629,21 +630,26 @@ class Server(ObjectReq):
except Exception: except Exception:
raise self.req.error("You've fallen of the cliff.", 404) raise self.req.error("You've fallen of the cliff.", 404)
self.req.client = client = self.auth.authenticate(environ) self.req.args = args = parse_qs(environ.get('QUERY_STRING', ""))
logging.debug("arguments: %s" % str(args))
self.req.client = client = self.auth.authenticate(environ, args)
if not client: if not client:
raise self.req.error("I'm watching. Authenticate.", 403) raise self.req.error("I'm watching. Authenticate.", 403)
try: try:
events = json.loads(injson) if injson else None events = json.loads(injson) if injson else None
except Exception as e: except Exception as e:
raise self.req.error("Deserialization error", 400, raise self.req.error("Deserialization error.", 400,
sys.exc_info(), detail={"args": injson, "parser": str(e)}) sys.exc_info(), detail={"args": injson, "parser": str(e)})
args = parse_qs(environ.get('QUERY_STRING', ""))
logging.debug("calling handler with %s" % str(args))
if events: if events:
args["events"] = events args["events"] = events
auth = self.auth.authorize(self.req.env, self.req.client, self.req.path, method)
if not auth:
raise self.req.error("I'm watching. Not authorized.", 403, detail={"client": client.identity})
args.pop("client", None)
args = self.sanitize_args(path, method, args) args = self.sanitize_args(path, method, args)
result = method(**args) # call requested method result = method(**args) # call requested method
...@@ -709,15 +715,11 @@ class WardenHandler(ObjectReq): ...@@ -709,15 +715,11 @@ class WardenHandler(ObjectReq):
self.get_events_limit, self.send_events_limit, self.description) self.get_events_limit, self.send_events_limit, self.description)
@expose @expose(read=1, debug=1)
def getDebug(self): def getDebug(self):
auth = self.auth.authorize(self.req.env, self.req.client, self.req.path, None)
if not auth:
raise self.req.error("I'm watching. Authorize.", 403, detail={"client": self.req.client["hostname"]})
return { return {
"environment": self.req.env, "environment": self.req.env,
"client": self.req.client, "client": self.req.client.__dict__,
"database": self.db.get_debug(), "database": self.db.get_debug(),
"system": { "system": {
"uname": os.uname() "uname": os.uname()
...@@ -736,12 +738,8 @@ class WardenHandler(ObjectReq): ...@@ -736,12 +738,8 @@ class WardenHandler(ObjectReq):
} }
@expose @expose(read=1)
def getInfo(self): def getInfo(self):
auth = self.auth.authorize(self.req.env, self.req.client, self.req.path, None)
if not auth:
raise self.req.error("I'm watching. Authorize.", 403, detail={"client": self.req.client["hostname"]})
info = { info = {
"version": VERSION, "version": VERSION,
"send_events_limit": self.send_events_limit, "send_events_limit": self.send_events_limit,
...@@ -752,16 +750,12 @@ class WardenHandler(ObjectReq): ...@@ -752,16 +750,12 @@ class WardenHandler(ObjectReq):
return info return info
@expose @expose(read=1)
def getEvents(self, id=None, count=None, def getEvents(self, id=None, count=None,
cat=None, nocat=None, cat=None, nocat=None,
tag=None, notag=None, tag=None, notag=None,
group=None, nogroup=None): group=None, nogroup=None):
auth = self.auth.authorize(self.req.env, self.req.client, self.req.path, None)
if not auth:
raise self.req.error("I'm watching. Authorize.", 403, detail={"client": self.req.client["hostname"]})
try: try:
id = int(id[0]) id = int(id[0])
except (ValueError, TypeError, IndexError): except (ValueError, TypeError, IndexError):
...@@ -799,7 +793,18 @@ class WardenHandler(ObjectReq): ...@@ -799,7 +793,18 @@ class WardenHandler(ObjectReq):
return res return res
@expose def checkNode(self, event, identity):
try:
ev_id = event['Node'][0]['Name'].lower()
except (KeyError, TypeError):
# Event does not bear valid Node attribute
return ["Event does not bear valid Node attribute"]
if ev_id != identity:
return ["Node does not correspond with saving client"]
return []
@expose(write=1)
def sendEvents(self, events=[]): def sendEvents(self, events=[]):
if not isinstance(events, list): if not isinstance(events, list):
raise self.req.error("List of events expected.", 400) raise self.req.error("List of events expected.", 400)
...@@ -811,19 +816,20 @@ class WardenHandler(ObjectReq): ...@@ -811,19 +816,20 @@ class WardenHandler(ObjectReq):
saved = 0 saved = 0
errs = {} errs = {}
for i, event in enumerate(events): for i, event in enumerate(events):
ev_errs = []
auth_cl = self.auth.authorize(self.req.env, self.req.client, self.req.path, event)
if not auth_cl:
errs[i] = ["Client %i(%s) does not correspond with event Node info or is not allowed to write" % (self.req.client["service"]["service_id"], self.req.client["service"]["identity"])]
continue
v_errs = self.validator.check(event) v_errs = self.validator.check(event)
if v_errs: if v_errs:
errs[i] = v_errs errs[i] = v_errs
continue continue
db_errs = self.db.store_event(auth_cl, event) node_errs = self.checkNode(event, self.req.client.identity)
if node_errs:
errs[i] = node_errs
continue
if self.req.client.test and not 'Test' in event.get('Category', []):
errs[i] = ["You're allowed to send only messages, containing \"Test\" among categories."]
db_errs = self.db.store_event(self.req.client, event)
if db_errs: if db_errs:
errs[i] = db_errs errs[i] = db_errs
continue continue
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment