diff --git a/warden3/warden_client/warden_client.cfg b/warden3/warden_client/warden_client.cfg index 9a771b4710d6d59ef4a8ec031a62cff9f822ac23..5b9bce5d3d89979be5459a6ff59125b37f18e467 100644 --- a/warden3/warden_client/warden_client.cfg +++ b/warden3/warden_client/warden_client.cfg @@ -14,5 +14,7 @@ "idstore": "warden_client.id", - "name": "warden_client_kostik" + "name": "warden_client_kostik", + + "secret": "Phaipe5ush7p" } diff --git a/warden3/warden_client/warden_client.py b/warden3/warden_client/warden_client.py index 25e9e73a13680f3bad100d7778edae6cb6f37f45..80f5b4ac3c9052a2787fbd3cf9a52dcce75e42d8 100644 --- a/warden3/warden_client/warden_client.py +++ b/warden3/warden_client/warden_client.py @@ -134,9 +134,11 @@ class Client(object): syslog=None, filelog=None, idstore=None, - name="warden_client"): + name="warden_client", + secret=None): self.name = name + self.secret = secret # Init logging as soon as possible and make sure we don't # spit out exceptions but just log or return Error objects self.init_log(errlog, syslog, filelog) @@ -253,6 +255,8 @@ class Client(object): def sendRequest(self, func="", payload=None, **kwargs): kwargs["client"] = self.name + if self.secret is not None: + kwargs["secret"] = self.secret if kwargs: for k in kwargs.keys(): diff --git a/warden3/warden_client/warden_curl_test.sh b/warden3/warden_client/warden_curl_test.sh index bab94acacd3b05bc47f8a584b25b56ba51034594..e513ce3146d4b18c851d87728711b4b17911c78e 100755 --- a/warden3/warden_client/warden_curl_test.sh +++ b/warden3/warden_client/warden_curl_test.sh @@ -8,6 +8,7 @@ certfile='cert.pem' cafile='tcs-ca-bundle.pem' url="$1" client="$2" +secret="$3" # --fail \ # --show-error \ @@ -20,7 +21,7 @@ curl \ --cacert $cafile \ --connect-timeout 3 \ --request POST \ - "$url/blefub?client=$2" + "$url/blefub?client=$client&secret=$secret" echo echo "Test 404" @@ -30,7 +31,17 @@ curl \ --cacert $cafile \ --connect-timeout 3 \ --request POST \ - "$url/?client=$2" + "$url/?client=$client&secret=$secret" +echo + +echo "Test 403 - no secret" +curl \ + --key $keyfile \ + --cert $certfile \ + --cacert $cafile \ + --connect-timeout 3 \ + --request POST \ + "$url/getEvents?client=$client" echo echo "Test 403 - no client" @@ -61,7 +72,7 @@ curl \ --connect-timeout 3 \ --request POST \ --data '{#$%^' \ - "$url/getEvents?client=$2" + "$url/getEvents?client=$client&secret=$secret" echo echo "Test Called with unknown category" @@ -71,7 +82,7 @@ curl \ --cacert $cafile \ --connect-timeout 3 \ --request POST \ - "$url/getEvents?client=$2&cat=bflm" + "$url/getEvents?client=$client&secret=$secret&cat=bflm" echo echo "Test Called with both cat and nocat" @@ -81,7 +92,7 @@ curl \ --cacert $cafile \ --connect-timeout 3 \ --request POST \ - "$url/getEvents?client=$2&cat=Other&nocat=Test" + "$url/getEvents?client=$client&secret=$secret&cat=Other&nocat=Test" echo echo "Test Invalid data for getEvents - silently discarded" @@ -92,7 +103,7 @@ curl \ --connect-timeout 3 \ --request POST \ --data '[1]' \ - "$url/getEvents?client=$2" + "$url/getEvents?client=$client&secret=$secret" echo echo "Test Called with internal args - just in log" @@ -102,7 +113,7 @@ curl \ --cacert $cafile \ --connect-timeout 3 \ --request POST \ - "$url/getEvents?client=$2&self=test" + "$url/getEvents?client=$client&secret=$secret&self=test" echo echo "Test Called with superfluous args - just in log" @@ -112,7 +123,7 @@ curl \ --cacert $cafile \ --connect-timeout 3 \ --request POST \ - "$url/getEvents?client=$2&bad=guy" + "$url/getEvents?client=$client&secret=$secret&bad=guy" echo echo "Test getEvents with no args - should be OK" @@ -122,7 +133,7 @@ curl \ --cacert $cafile \ --connect-timeout 3 \ --request POST \ - "$url/getEvents?client=$2" + "$url/getEvents?client=$client&secret=$secret" echo echo "Test getEvents - should be OK" @@ -132,7 +143,7 @@ curl \ --cacert $cafile \ --connect-timeout 3 \ --request POST \ - "$url/getEvents?client=$2&count=3&id=10" + "$url/getEvents?client=$client&secret=$secret&count=3&id=10" echo echo "Test getDebug" @@ -142,7 +153,7 @@ curl \ --cacert $cafile \ --connect-timeout 3 \ --request POST \ - "$url/getDebug?client=$2" + "$url/getDebug?client=$client&secret=$secret" echo echo "Test getInfo" @@ -152,7 +163,7 @@ curl \ --cacert $cafile \ --connect-timeout 3 \ --request POST \ - "$url/getInfo?client=$2" + "$url/getInfo?client=$client&secret=$secret" echo #curl \ diff --git a/warden3/warden_server/warden3.0-alpha.sql b/warden3/warden_server/warden3.0-alpha.sql index 0f66f01553aef3c97c64c076341ff37d9a84455c..16d78b539dda27566524a20caa6ecbce8905ce9c 100644 --- a/warden3/warden_server/warden3.0-alpha.sql +++ b/warden3/warden_server/warden3.0-alpha.sql @@ -97,6 +97,7 @@ CREATE TABLE IF NOT EXISTS `clients` ( `note` text NOT NULL, `valid` tinyint(1) NOT NULL DEFAULT '1', `identity` varchar(64) NOT NULL, + `secret` varchar(16) NULL, `read` tinyint(1) NOT NULL DEFAULT '1', `debug` tinyint(1) NOT NULL DEFAULT '0', `write` tinyint(1) NOT NULL DEFAULT '0', @@ -108,38 +109,38 @@ CREATE TABLE IF NOT EXISTS `clients` ( -- Dumping data for table `clients` -- -INSERT INTO `clients` (`id`, `registered`, `requestor`, `hostname`, `service`, `note`, `valid`, `identity`, `read`, `debug`, `write`, `test`) VALUES -(1, '0000-00-00 00:00:00', '', 'afrodita.civ.zcu.cz', 'hihat', '', 1, 'cz.zcu.civ.afrodita.hihat', 1, 0, 1, 0), -(2, '0000-00-00 00:00:00', '', 'afrodita.civ.zcu.cz', 'labrea', '', 1, 'cz.zcu.civ.afrodita.labrea', 1, 0, 1, 0), -(3, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'cesnet_ids', '', 1, 'cz.cesnet.au1.cesnet_ids', 1, 0, 1, 0), -(4, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'cesnet_sserv', '', 1, 'cz.cesnet.au1.cesnet_sserv', 1, 0, 1, 0), -(5, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6d-dorkbot', '', 1, 'cz.cesnet.au1.n6d-dorkbot', 1, 0, 1, 0), -(6, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6e-certplsinkhole', '', 1, 'cz.cesnet.au1.n6e-certplsinkhole', 1, 0, 1, 0), -(7, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6i-citadelsinkhole', '', 1, 'cz.cesnet.au1.n6i-citadelsinkhole', 1, 0, 1, 0), -(8, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6i-citadelsinkholeqd', '', 1, 'cz.cesnet.au1.n6i-citadelsinkholeqd', 1, 0, 1, 0), -(9, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6n-openntp', '', 1, 'cz.cesnet.au1.n6n-openntp', 1, 0, 1, 0), -(10, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6o-botszeroaccess', '', 1, 'cz.cesnet.au1.n6o-botszeroaccess', 1, 0, 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), -(12, '0000-00-00 00:00:00', '', 'au2.cesnet.cz', 'ids-cz', '', 1, 'cz.cesnet.au2.ids-cz', 1, 0, 1, 0), -(13, '0000-00-00 00:00:00', '', 'bee.net.vutbr.cz', 'hpscan', '', 1, 'cz.vutbr.net.bee.hpscan', 1, 0, 1, 0), -(14, '0000-00-00 00:00:00', '', 'buldog.vsb.cz', 'kippo', '', 1, 'cz.vsb.buldog.kippo', 1, 0, 1, 0), -(15, '0000-00-00 00:00:00', '', 'collector-nemea.liberouter.org', 'nemea', '', 1, 'org.liberouter.collector-nemea.nemea', 1, 0, 1, 0), -(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); +INSERT INTO `clients` (`id`, `registered`, `requestor`, `hostname`, `service`, `note`, `valid`, `identity`, `secret`, `read`, `debug`, `write`, `test`) VALUES +(1, '0000-00-00 00:00:00', '', 'afrodita.civ.zcu.cz', 'hihat', '', 1, 'cz.zcu.civ.afrodita.hihat', NULL, 1, 0, 1, 0), +(2, '0000-00-00 00:00:00', '', 'afrodita.civ.zcu.cz', 'labrea', '', 1, 'cz.zcu.civ.afrodita.labrea', NULL, 1, 0, 1, 0), +(3, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'cesnet_ids', '', 1, 'cz.cesnet.au1.cesnet_ids', NULL, 1, 0, 1, 0), +(4, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'cesnet_sserv', '', 1, 'cz.cesnet.au1.cesnet_sserv', NULL, 1, 0, 1, 0), +(5, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6d-dorkbot', '', 1, 'cz.cesnet.au1.n6d-dorkbot', NULL, 1, 0, 1, 0), +(6, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6e-certplsinkhole', '', 1, 'cz.cesnet.au1.n6e-certplsinkhole', NULL, 1, 0, 1, 0), +(7, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6i-citadelsinkhole', '', 1, 'cz.cesnet.au1.n6i-citadelsinkhole', NULL, 1, 0, 1, 0), +(8, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6i-citadelsinkholeqd', '', 1, 'cz.cesnet.au1.n6i-citadelsinkholeqd', NULL, 1, 0, 1, 0), +(9, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6n-openntp', '', 1, 'cz.cesnet.au1.n6n-openntp', NULL, 1, 0, 1, 0), +(10, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'n6o-botszeroaccess', '', 1, 'cz.cesnet.au1.n6o-botszeroaccess', NULL, 1, 0, 1, 0), +(11, '0000-00-00 00:00:00', '', 'au1.cesnet.cz', 'report_n6v-virut', '', 1, 'cz.cesnet.au1.report_n6v-virut', NULL, 1, 0, 1, 0), +(12, '0000-00-00 00:00:00', '', 'au2.cesnet.cz', 'ids-cz', '', 1, 'cz.cesnet.au2.ids-cz', NULL, 1, 0, 1, 0), +(13, '0000-00-00 00:00:00', '', 'bee.net.vutbr.cz', 'hpscan', '', 1, 'cz.vutbr.net.bee.hpscan', NULL, 1, 0, 1, 0), +(14, '0000-00-00 00:00:00', '', 'buldog.vsb.cz', 'kippo', '', 1, 'cz.vsb.buldog.kippo', NULL, 1, 0, 1, 0), +(15, '0000-00-00 00:00:00', '', 'collector-nemea.liberouter.org', 'nemea', '', 1, 'org.liberouter.collector-nemea.nemea', NULL, 1, 0, 1, 0), +(16, '0000-00-00 00:00:00', '', 'collector.liberouter.org', 'hoststats', '', 1, 'org.liberouter.collector.hoststats', NULL, 1, 0, 1, 0), +(17, '0000-00-00 00:00:00', '', 'collector.liberouter.org', 'synscandetector_1_0', '', 1, 'org.liberouter.collector.synscandetector_1_0', NULL, 1, 0, 1, 0), +(18, '0000-00-00 00:00:00', '', 'holly.cesnet.cz', 'kippohoneypot', '', 1, 'cz.cesnet.holly.kippohoneypot', NULL, 1, 0, 1, 0), +(19, '0000-00-00 00:00:00', '', 'kryten.cesnet.cz', 'dionaeahoneypot', '', 1, 'cz.cesnet.kryten.dionaeahoneypot', NULL, 1, 0, 1, 0), +(20, '0000-00-00 00:00:00', '', 'mentat.cesnet.cz', 'mentat', '', 1, 'cz.cesnet.mentat.mentat', NULL, 1, 0, 1, 0), +(21, '0000-00-00 00:00:00', '', 'miel.opf.slu.cz', 'kippo', '', 1, 'cz.slu.opf.miel.kippo', NULL, 1, 0, 1, 0), +(22, '0000-00-00 00:00:00', '', 'nfsen.ics.muni.cz', 'honeyscan', '', 1, 'cz.muni.ics.nfsen.honeyscan', NULL, 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', NULL, 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', NULL, 1, 0, 1, 0), +(25, '0000-00-00 00:00:00', '', 'vinovago.cesnet.cz', 'fail2ban', '', 1, 'cz.cesnet.vinovago.fail2ban', NULL, 1, 0, 1, 0), +(26, '0000-00-00 00:00:00', '', 'ward.tul.cz', 'dionaeatul', '', 1, 'cz.tul.ward.dionaeatul', NULL, 1, 0, 1, 0), +(27, '0000-00-00 00:00:00', '', 'ward.tul.cz', 'kippo', '', 1, 'cz.tul.ward.kippo', NULL, 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', "Phaipe5ush7p", 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', NULL, 1, 0, 0, 0), +(30, '0000-00-00 00:00:00', 'kostenec@civ.zcu.cz', 'kostik.zcu.cz', 'Test', '', 1, 'com.example.test-node3', NULL, 1, 0, 0, 0), +(31, '2014-12-11 13:51:18', 'ph@cesnet.cz', 'grey.cesnet.cz', 'Test', '', 1, 'cz.cesnet.grey.test', "co3kaero5Ruv", 1, 1, 1, 0); -- -------------------------------------------------------- diff --git a/warden3/warden_server/warden_server.py b/warden3/warden_server/warden_server.py index b7e214dbe6d96e4cb7cb66abd2987bcad6ac80f6..404d3675f268fa0c780ca139c1de340be6782eef 100755 --- a/warden3/warden_server/warden_server.py +++ b/warden3/warden_server/warden_server.py @@ -167,17 +167,26 @@ def SysLogger(req, socket="/dev/log", facility=logging.handlers.SysLogHandler.LO -class Object(object): +class Client(namedtuple("ClientTuple", + ["id", "registered", "requestor", "hostname", "service", "note", + "identity", "secret", "read", "debug", "write", "test"])): def __str__(self): - return "%s()" % type(self).__name__ + return ( + "%s(id=%i, registered=%s, requestor=\"%s\", hostname=\"%s\", " + "service=\"%s\", note=\"%s\", identity=\"%s\", secret=%s, " + "read=%i, debug=%i, write=%i, test=%i)") % ( + type(self).__name__, self.id, self.registered.isoformat(), + self.requestor, self.hostname, self.service, self.note, + self.identity, "..." if self.secret is not None else "None", + self.read, self.debug, self.write, self.test) -# Simple container class definition shortcut -Client = namedtuple("Client", - ["id", "registered", "requestor", "hostname", "service", "note", - "identity", "read", "debug", "write", "test"]) +class Object(object): + + def __str__(self): + return "%s()" % type(self).__name__ @@ -293,8 +302,24 @@ class X509Authenticator(NoAuthenticator): if not client: logging.info("authenticate: client not found") + return None - logging.info("authenticate: ok, client=%s" % str(client)) + # Clients with 'secret' set muset get authorized by it. + # No secret turns auth off for this particular client. + if client.secret is not None: + try: + secret = args["secret"][0] + except KeyError: + logging.info("authenticate: missing secret argument") + return None + if secret != client.secret: + logging.info("authenticate: wrong credentials") + return None + # Already checked, prevent to spill it over logs + args["secret"] = ["..."] + + logging.info("authenticate: %s" % str(client)) + return client @@ -398,7 +423,7 @@ class MySQL(ObjectReq): def get_client_by_name(self, identity, cert_names): format_strings = ','.join(['%s'] * len(cert_names)) - 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 + query = "SELECT id, registered, requestor, hostname, service, note, identity, secret, `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() @@ -631,7 +656,6 @@ class Server(ObjectReq): raise self.req.error("You've fallen of the cliff.", 404) 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: @@ -649,7 +673,12 @@ class Server(ObjectReq): if not auth: raise self.req.error("I'm watching. Not authorized.", 403, detail={"client": client.identity}) + logging.debug("arguments: %s" % str(args)) + + # These args are not for handler args.pop("client", None) + args.pop("secret", None) + args = self.sanitize_args(path, method, args) result = method(**args) # call requested method