Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • Pavel.Valach/warden
1 result
Show changes
Showing
with 377 additions and 96 deletions
+---------------------------------------+
| Warden Filer 3.0-beta2 for Warden 3.X |
| Warden Filer 3.0-beta3 for Warden 3.X |
+---------------------------------------+
Content
......
......@@ -18,9 +18,15 @@ import resource
import atexit
import argparse
from os import path, mkdir
from random import choice, randint;
from random import choice, randint
VERSION = "3.0-beta2"
# for py2/py3 compatibility
try:
basestring
except NameError:
basestring = str
VERSION = "3.0-beta3"
class NamedFile(object):
""" Wrapper class for file objects, which allows and tracks filename
......@@ -181,7 +187,7 @@ def receiver(config, wclient, sdir, oneshot):
nf = sdir.newfile()
with nf.f as f:
data = json.dumps(event)
f.write(data)
f.write(data.encode('utf-8'))
nf.moveto(sdir.incoming)
count_ok += 1
except Exception as e:
......@@ -291,7 +297,7 @@ def sender(config, wclient, sdir, oneshot):
continue # Silently go to next filename, somebody else might have interfered
try:
with nf.open("rb") as fd:
data = fd.read()
data = fd.read().decode('utf-8')
event = json.loads(data)
if not match_event(event, **filt):
wclient.logger.debug("Unmatched event: %s" % data)
......@@ -392,7 +398,7 @@ def daemonize(
# PID file
if pidfile is not None:
pidd = os.open(pidfile, os.O_RDWR|os.O_CREAT|os.O_EXCL|os.O_TRUNC)
os.write(pidd, str(os.getpid())+"\n")
os.write(pidd, (str(os.getpid())+"\n").encode())
os.close(pidd)
# Define and setup atexit closure
@atexit.register
......@@ -464,6 +470,18 @@ def get_configs():
def get_uid_gid(str_id, get_nam_func):
if str_id:
try:
id = int(str_id)
except ValueError:
id = get_nam_func(str_id)[2]
else:
id = None
return id
if __name__ == "__main__":
args = get_args()
......@@ -476,12 +494,17 @@ if __name__ == "__main__":
try:
if args.daemon:
from pwd import getpwnam
from grp import getgrnam
uid = get_uid_gid(fconfig.get("uid"), getpwnam)
gid = get_uid_gid(fconfig.get("gid"), getgrnam)
daemonize(
work_dir = fconfig.get("work_dir", "."),
chroot_dir = fconfig.get("chroot_dir"),
umask = fconfig.get("umask"),
uid = fconfig.get("uid"),
gid = fconfig.get("gid"),
uid = uid,
gid = gid,
pidfile = args.pid_file,
files_preserve = get_logger_files(wclient.logger),
signals = {
......
......@@ -27,6 +27,8 @@ done
function log_daemon_msg () { echo -n "$@"; }
function log_end_msg () { [ $1 -eq 0 ] && echo " OK" || echo " Failed"; }
function status_of_proc () { [ -f "$PID" ] && ps u -p $(<"$PID") || echo "$PID not found."; }
function start_daemon () { shift; shift; $* ; }
function killproc () { kill $(cat $PID) ; }
[ -f /lib/lsb/init-functions ] && . /lib/lsb/init-functions
......
......@@ -27,6 +27,8 @@ done
function log_daemon_msg () { echo -n "$@"; }
function log_end_msg () { [ $1 -eq 0 ] && echo " OK" || echo " Failed"; }
function status_of_proc () { [ -f "$PID" ] && ps u -p $(<"$PID") || echo "$PID not found."; }
function start_daemon () { shift; shift; $* ; }
function killproc () { kill $(cat $PID) ; }
[ -f /lib/lsb/init-functions ] && . /lib/lsb/init-functions
......
......@@ -36,7 +36,6 @@ Dependencies
Python 2.7+
Apache 2.2+
mod_wsgi 3.3+
EJBCA_ 3.9+
Registration process
......@@ -78,10 +77,6 @@ the Warden RA web service, where it obtains the new complete certificate.
Installation
------------
As for now, correctly configured and running EJBCA_ PKI is necessary. PKI part
of the RA is however pluggable, so simple openssl backend is also planned.
This depends heavily on your distribution and Apache configuration.
Basically you need to create and include apache.conf:
......@@ -103,6 +98,8 @@ Also, for warden_server.wsgi, you can use warden_server.wsgi.dist as
a template. You will possibly need to change at least configuration
file path.
* Now install and/or configure RA backend (see README.openssl or README.ejbca)
* Configure Warden RA (see next chapter)
* Reload Apache
......@@ -133,7 +130,7 @@ Sections and their "type" objects can be:
Log: FileLogger, SysLogger
Auth: OptionalAuthenticator
Registry: EjbcaRegistry
Registry: EjbcaRegistry, OpenSSLRegistry
Handler: CertHandler
"type" keyword is not mandatory, if not specified, first implementation
......@@ -156,21 +153,14 @@ Object function and configuration keys are as follows:
CertHandler: the main certificate requestor implementation
EjbcaRegistry: EJBCA connector configuration
url: EJBCA API URL, for example "https://ejbca.example.org/ejbca/ejbcaws/ejbcaws?wsdl"
cert: certificate for authentication to EJBCA, defaults to "warden_ra.cert.pem"
key: key for authentication to EJBCA, defaults to "warden_ra.key.pem"
ca_name: name of the CA, dedicated for Warden, defaults to "Example CA"
certificate_profile_name: name of the EJBCA certificate profile, defaults to "Example"
end_entity_profile_name: name of the EJBCA entity profile, defaults to "Example EE"
subject_dn_template: template for the DN generation, defaults to "DC=cz,DC=example-ca,DC=warden,CN=%s"
username_suffix: suffix, which will be added to EJBCA entities, defaults to "@warden"
For OpenSSLRegistry or EJBCARegistry configuration please see
README.openssl or README.ejbca respectively.
Command line
------------
Whe run from the command line, RA allows for client and request management.
When run from the command line, RA allows for client and request management.
warden_ra.py [--help] [-c CONFIG] [-v]
......@@ -226,7 +216,6 @@ Whe run from the command line, RA allows for client and request management.
.. _Warden: https://warden.cesnet.cz/
.. _EJBCA: https://www.ejbca.org/
------------------------------------------------------------------------------
......
EJBCA backend for Warden 3.# Registration Authority
===================================================
Introduction
------------
EJBCA_ is an open source CA management software. To use this backend
with Warden RA, you need to have it already installed and running.
Tested with EJBCA_ 3.9.
.. _EJBCA: https://www.ejbca.org/
Configuration
-------------
Options for "Registry: EjbcaRegistry" section.
url: EJBCA API URL, for example "https://ejbca.example.org/ejbca/ejbcaws/ejbcaws?wsdl"
cert: certificate for authentication to EJBCA, defaults to "warden_ra.cert.pem"
key: key for authentication to EJBCA, defaults to "warden_ra.key.pem"
ca_name: name of the CA, dedicated for Warden, defaults to "Example CA"
certificate_profile_name: name of the EJBCA certificate profile, defaults to "Example"
end_entity_profile_name: name of the EJBCA entity profile, defaults to "Example EE"
subject_dn_template: template for the DN generation, defaults to "DC=cz,DC=example-ca,DC=warden,CN=%s"
username_suffix: suffix, which will be added to EJBCA entities, defaults to "@warden"
------------------------------------------------------------------------------
Copyright (C) 2017 Cesnet z.s.p.o
OpenSSL local backed for Warden 3.# Registration Authority
==========================================================
Introduction
------------
This backend allows using basic `openssl ca`_ facility for certificate
emission. Client information is kept as plain config files within "clients"
subdirectory. Also, received CSRs and issued certificates are saved in "csr"
and "newcerts" subdirectories, respectively. File "lock" is used to conduct
concurrent access to running openssl binary.
.. _openssl ca: https://www.openssl.org/docs/manmaster/man1/openssl-ca.html
Installation
------------
Choose directory where OpenSSL CA structure will reside (for example
"ca").
# mkdir ca
# cd ca/
/ca# mkdir certs crl newcerts private clients csr
/ca# chmod 700 private
/ca# touch index.txt
/ca# echo 1024 > serial
Adjust permissions.
# s-bit, so newly created files receive permissions of parent
# directory, not of creator
ca# find . -type d | xargs chmod g+s
# owner - apache group (this is for Debian, adjust accordingly for
# different distribution)
ca# chgrp -R www-data .
Generate CA root certificate.
ca# openssl genrsa -out private/ca.key.pem 4096
ca# openssl req -config openssl.cnf \
-key private/ca.key.pem \
-new -x509 -days 7300 -sha256 -extensions v3_ca \
-out certs/ca.cert.pem
ca# chmod 444 private/ca.key.pem certs/ca.cert.pem
Create "openssl.cnf" in base directory. You can use "openssl.cnf.example" as
a basis.
Configuration
-------------
Options for "Registry: OpenSSLRegistry" section.
base_dir: Base directory where OpenSSL CA environment is managed
subject_dn_template: Template for DN of issued certs, defaults to "DC=cz,DC=example-ca,DC=warden,CN=%s"
openssl_sign: OpenSSL command and arguments to run for signing, defaults to "openssl ca -config %(cnf)s -batch -extensions server_cert -days 375 -notext -md sha256 -in %(csr)s -subj '%(dn)s'"
------------------------------------------------------------------------------
Copyright (C) 2017 Cesnet z.s.p.o
......@@ -3,9 +3,9 @@ SSLEngine on
SSLVerifyClient optional
SSLOptions +StdEnvVars +ExportCertData
SSLCertificateFile /opt/warden_server_3/cert.pem
SSLCertificateKeyFile /opt/warden_server_3/key.pem
SSLCACertificateFile /opt/warden_server_3/chain_TERENA_SSL_CA_3.pem
SSLCertificateFile /opt/warden_server/cert.pem
SSLCertificateKeyFile /opt/warden_server/key.pem
SSLCACertificateFile /opt/warden_server/chain_TERENA_SSL_CA_3.pem
WSGIScriptAlias /warden_ra /opt/warden-ra/warden_ra.wsgi
......
......@@ -3,9 +3,9 @@ SSLEngine on
SSLVerifyClient optional
SSLOptions +StdEnvVars +ExportCertData
SSLCertificateFile /opt/warden_server_3/cert.pem
SSLCertificateKeyFile /opt/warden_server_3/key.pem
SSLCACertificateFile /opt/warden_server_3/chain_TERENA_SSL_CA_3.pem
SSLCertificateFile /opt/warden_server/cert.pem
SSLCertificateKeyFile /opt/warden_server/key.pem
SSLCACertificateFile /opt/warden_server/chain_TERENA_SSL_CA_3.pem
WSGIScriptAlias /warden_ra /opt/warden-ra/warden_ra.wsgi
......
......@@ -4,8 +4,7 @@
# Copyright (c) 2016, CESNET, z. s. p. o.
# Use of this source is governed by an ISC license, see LICENSE file.
import urllib2
import httplib
import sys
import socket
import base64
import suds.transport.http
......@@ -13,6 +12,20 @@ import suds.client
import M2Crypto
if sys.version_info[0] >= 3:
import urllib.request, urllib.error, urllib.parse
import http.client
def get_https_handler():
return urllib.request.HTTPSHandler
else:
import urllib2
import httplib
def get_https_handler():
return urllib2.HTTPSHandler
STATUS_FAILED = 11
STATUS_GENERATED = 40
STATUS_HISTORICAL = 60
......@@ -139,10 +152,10 @@ REVOKATION_REASON_PRIVILEGESWITHDRAWN = 9
REVOKATION_REASON_AACOMPROMISE = 10
class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
class HTTPSClientAuthHandler(get_https_handler()):
def __init__(self, key, cert):
urllib2.HTTPSHandler.__init__(self)
get_https_handler().__init__(self)
self.key = key
self.cert = cert
......@@ -150,7 +163,10 @@ class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
return self.do_open(self.get_connection, req)
def get_connection(self, host, timeout=5):
return httplib.HTTPSConnection(host, key_file=self.key, cert_file=self.cert, timeout=timeout)
if sys.version_info[0] >= 3:
return http.client.HTTPSConnection(host, key_file=self.key, cert_file=self.cert, timeout=timeout)
else:
return httplib.HTTPSConnection(host, key_file=self.key, cert_file=self.cert, timeout=timeout)
class HTTPSClientCertTransport(suds.transport.http.HttpTransport):
......@@ -160,9 +176,12 @@ class HTTPSClientCertTransport(suds.transport.http.HttpTransport):
self.key = key
self.cert = cert
def u2open(self, u2request):
tm = self.options.timeout
url = urllib2.build_opener(HTTPSClientAuthHandler(self.key, self.cert))
def u2open(self, u2request, timeout=None):
tm = timeout or self.options.timeout
if sys.version_info[0] >= 3:
url = urllib.request.build_opener(HTTPSClientAuthHandler(self.key, self.cert))
else:
url = urllib2.build_opener(HTTPSClientAuthHandler(self.key, self.cert))
if self.u2ver() < 2.6:
socket.setdefaulttimeout(tm)
return url.open(u2request)
......
# OpenSSL root CA configuration file.
# Copy to `/root/ca/openssl.cnf`.
[ ca ]
# `man ca`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = /var/spool/example-ca
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand
unique_subject = no
# The root key and root certificate.
private_key = $dir/private/ca.key.pem
certificate = $dir/certs/ca.cert.pem
# For certificate revocation lists.
crlnumber = $dir/crlnumber
crl = $dir/crl/ca.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_loose
[ policy_loose ]
# Allow the CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the `req` tool (`man req`).
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
# Extension to add when the -x509 option is used.
x509_extensions = v3_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
# Optionally, specify some defaults.
countryName_default = CZ
stateOrProvinceName_default = Czech Republic
localityName_default =
0.organizationName_default = Example
organizationalUnitName_default =
emailAddress_default =
[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client
nsComment = "OpenSSL Generate Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
......@@ -13,8 +13,8 @@ fi
url="$1"
client="$2"
password="$3"
incert="$4"
inkey="$5"
incert="$3"
inkey="$4"
trap 'rm -f "$config $result"' INT TERM HUP EXIT
......@@ -41,6 +41,10 @@ openssl req -new -nodes -batch -keyout "$key" -out "$csr" -config "$config" || f
if [ -z "$inkey" ]; then
curl --progress-bar $cacert --request POST --data-binary '@-' "$url?name=$client&password=$password" < "$csr" > "$result"
else
# local cert file name may be interpreted as a "nickname", add "./" to force interpretation as a file
if [[ ! "$incert" =~ "/" ]]; then
incert="./$incert"
fi
curl --progress-bar $cacert --request POST --data-binary '@-' --cert "$incert" --key "$inkey" "$url?name=$client" < "$csr" > "$result"
fi
......
......@@ -4,14 +4,22 @@
"level": "info"
},
"Registry": {
"type": "EjbcaRegistry",
"url": "https://ejbca.example.org/ejbca/ejbcaws/ejbcaws?wsdl",
"cert": "warden_ra.cert.pem",
"key": "warden_ra.key.pem",
"ca_name": "Example CA",
"certificate_profile_name": "Example",
"end_entity_profile_name": "Example EE",
"subject_dn_template": "DC=cz,DC=example-ca,DC=warden,CN=%s",
"username_suffix": "@warden"
// Example configuration for OpenSSL CA backend
// "type": "OpenSSLRegistry",
// "base_dir": "/var/spool/example-ca",
// "subject_dn_template": "DC=cz,DC=example-ca,DC=warden,CN=%s"
// Example configuration for EJBCA backend
// "type": "EjbcaRegistry",
// "url": "https://ejbca.example.org/ejbca/ejbcaws/ejbcaws?wsdl",
// "cert": "warden_ra.cert.pem",
// "key": "warden_ra.key.pem",
// "ca_name": "Example CA",
// "certificate_profile_name": "Example",
// "end_entity_profile_name": "Example EE",
// "subject_dn_template": "DC=cz,DC=example-ca,DC=warden,CN=%s",
// "username_suffix": "@warden"
}
}
......@@ -4,6 +4,8 @@
# Copyright (c) 2016, CESNET, z. s. p. o.
# Use of this source is governed by an ISC license, see LICENSE file.
from __future__ import print_function
import sys
import os
import time
......@@ -21,18 +23,20 @@ import subprocess
import shlex
import tempfile
import M2Crypto
import ConfigParser
# *ph* server vulnerable to logjam, local openssl too new, use hammer to disable Diffie-Helmann
import ssl
ssl._DEFAULT_CIPHERS += ":!DH"
import ejbcaws
if sys.version_info[0] >= 3:
import configparser as ConfigParser
else:
import ConfigParser
# usual path to warden server
sys.path.append(pth.join(pth.dirname(__file__), "..", "warden-server"))
sys.path.append(pth.join(pth.dirname(__file__), "..", "warden_server"))
import warden_server
from warden_server import Request, ObjectBase, FileLogger, SysLogger, Server, expose, read_cfg
VERSION = "3.0-beta3"
class ClientDisabledError(Exception): pass
class ClientNotIssuableError(Exception): pass
......@@ -120,7 +124,7 @@ class OpenSSLRegistry(object):
except OSError as e:
if e.errno != errno.EEXIST:
raise
with tempfile.NamedTemporaryFile(dir=client_path, delete=False) as cf:
with tempfile.NamedTemporaryFile(dir=client_path, delete=False, mode="w") as cf:
config.write(cf)
os.chmod(cf.name, 0o660) # read privilege for usual apache group
os.rename(cf.name, pth.join(client_path, "state")) # atomic + rewrite, so no need for locking
......@@ -210,7 +214,14 @@ class EjbcaRegistry(OpenSSLRegistry):
def client_data(self, ejbca_data):
ejbca_username = ejbca_data["username"]
username = ejbca_username[:-len(self.username_suffix)] if ejbca_username.endswith(self.username_suffix) else ejbca_username
admins = [u if not u.startswith("RFC822NAME") else u[11:] for u in ejbca_data["subjectAltName"].split(",")]
try:
alt_name = ejbca_data["subjectAltName"]
except KeyError:
alt_name = None
if alt_name:
admins = [u if not u.startswith("RFC822NAME") else u[11:] for u in alt_name.split(",")]
else:
admins = []
status = self.status_ejbca_to_str.get(ejbca_data["status"], "Other")
return username, admins, status, None, ejbca_data
......@@ -239,7 +250,13 @@ class EjbcaRegistry(OpenSSLRegistry):
subjectDN = self.subject_dn_template % client.name
)
edata["subjectAltName"] = ",".join(("RFC822NAME=%s" % a for a in client.admins))
edata["status"] = self.status_str_to_ejbca.get(client.status, edata["status"])
try:
edata["status"] = self.status_str_to_ejbca.get(client.status)
except KeyError:
# Unknown status - either came from EJBCA and translated to
# "Other", or something wrong came in later. Let's just
# keep original EJBCA status unchanged.
pass
if client.pwd:
edata["password"] = client.pwd
edata["clearPwd"] = True
......@@ -258,6 +275,14 @@ class EjbcaRegistry(OpenSSLRegistry):
return self.ejbca.get_version()
def relaxed_ord(c):
# Compatibility wrapper for py2/py3
try:
return ord(c)
except TypeError:
return c
def format_cert(cert):
return (
"Subject: %s\n"
......@@ -269,7 +294,7 @@ def format_cert(cert):
cert.get_subject().as_text(),
cert.get_not_before().get_datetime().isoformat(),
cert.get_not_after().get_datetime().isoformat(),
":".join(["%02x" % ord(c) for c in struct.pack('!Q', cert.get_serial_number())]),
":".join(["%02x" % relaxed_ord(c) for c in struct.pack('!Q', cert.get_serial_number())]),
cert.get_fingerprint("md5"),
cert.get_fingerprint("sha1"),
cert.get_issuer().as_text()
......@@ -309,7 +334,7 @@ class OptionalAuthenticator(ObjectBase):
try:
args["password"][0]
return "pwd" # Ok, pass on, but getCert will have to rely on certificate registry password
except KeyError, IndexError:
except (KeyError, IndexError):
exception = self.req.error(message="authenticate: no certificate nor password present", error=403, cn = cert_name, args = args)
exception.log(self.log)
return None
......@@ -346,7 +371,7 @@ class CertHandler(ObjectBase):
if not password:
raise self.req.error(message="Missing password and certificate validation failed", error=403, name=name, password=password)
try:
newcert = self.registry.new_cert(client, csr_data, password[0])
newcert = self.registry.new_cert(client, csr_data.decode('latin1'), password[0])
except Exception as e:
raise self.req.error(message="Processing error", error=403, exc=sys.exc_info())
self.log.info("Generated.")
......@@ -414,7 +439,7 @@ def list_clients(registry, name=None, verbose=False, show_cert=True):
if name is not None:
client = registry.get_client(name)
if client is None:
print "No such client."
print("No such client.")
return
else:
print(client.str(verbose))
......@@ -442,14 +467,14 @@ def register_client(registry, name, admins=None, verbose=False):
def applicant(registry, name, password=None, verbose=False):
client = registry.get_client(name)
if not client:
print "No such client."
print("No such client.")
return
if password is None:
password = "".join((random.choice(string.ascii_letters + string.digits) for dummy in range(16)))
try:
client.update(status="Issuable", pwd=password)
except ClientDisabledError:
print "This client is disabled. Use 'enable' first."
print("This client is disabled. Use 'enable' first.")
return
registry.save_client(client)
list_clients(registry, name, verbose, show_cert=False)
......@@ -459,7 +484,7 @@ def applicant(registry, name, password=None, verbose=False):
def enable(registry, name, verbose=False):
client = registry.get_client(name)
if not client:
print "No such client."
print("No such client.")
return
client.update(status="Passive")
registry.save_client(client)
......@@ -469,7 +494,7 @@ def enable(registry, name, verbose=False):
def disable(registry, name, verbose=False):
client = registry.get_client(name)
if not client:
print "No such client."
print("No such client.")
return
client.update(status="Disabled")
registry.save_client(client)
......@@ -490,7 +515,7 @@ def request(registry, key, csr, verbose=False):
"prompt=no\n"
"\n"
"[req_distinguished_name]\n"
"commonName=dummy"
"commonName=dummy".encode("ascii")
)
openssl.stdin.close()
openssl.wait()
......@@ -510,7 +535,7 @@ def gen_cert(registry, name, csr, cert, password, verbose=False):
print(newcert.as_pem())
with open(cert, "w") as f:
f.write(newcert.as_text())
f.write(newcert.as_pem())
f.write(newcert.as_pem().decode("ascii"))
def get_args():
......
+-------------------------+
| Warden Server 3.0-beta2 |
| Warden Server 3.0-beta3 |
+-------------------------+
Content
......@@ -46,6 +46,10 @@ B. Dependencies
python-m2crypto 0.20+
jsonschema 2.4+
3. Database
MySQL | MariaDB >= 5.5
------------------------------------------------------------------------------
C. Installation
......@@ -54,29 +58,32 @@ C. Installation
# cd /opt
# tar xjf warden_server_3.0.tar.bz2
# ls
warden_server_3.0
# mv warden_server_3.0 warden_server
* Create database and desired database users
(We're using db "warden3" and user "warden@localhost" as an example.)
# mysql -p
mysql> CREATE DATABASE warden3;
mysql> GRANT ALL ON warden3.* TO `warden`@`localhost`;
mysql> SET PASSWORD FOR 'warden'@'localhost' = PASSWORD('example');
mysql> FLUSH PRIVILEGES;
> CREATE DATABASE warden3;
> CREATE USER 'warden'@'localhost' IDENTIFIED BY 'example';
> GRANT ALL ON warden3.* TO `warden`@`localhost`;
> FLUSH PRIVILEGES;
* Create necessary table structure
mysql -p -u warden warden3 < warden_3.0.sql
* Get up to date Idea schema
wget -O warden_server/idea.schema https://idea.cesnet.cz/_media/en/idea0.schema
* Enable mod_wsgi, mod_ssl, include Warden configuration
This depends heavily on your distribution and Apache configuration.
Basically you need to create and include apache.conf:
Include /opt/warden_server_3.0/apache.conf
Include /opt/warden_server/apache.conf
or paste the contents into whichever Directory, Location or VirtualHost
you dedicate for Warden. You can use apache22.conf.dist or
......
......@@ -6,13 +6,13 @@ SSLOptions +StdEnvVars +ExportCertData
#SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /opt/warden_server_3/etc/cert.pem
SSLCertificateKeyFile /opt/warden_server_3/etc/key.pem
SSLCACertificateFile /opt/warden_server_3/etc/tcs-ca-bundle.pem
SSLCertificateFile /opt/warden_server/etc/cert.pem
SSLCertificateKeyFile /opt/warden_server/etc/key.pem
SSLCACertificateFile /opt/warden_server/etc/tcs-ca-bundle.pem
WSGIScriptAlias /warden3 /opt/warden_server_3/warden_server.wsgi
WSGIScriptAlias /warden3 /opt/warden_server/warden_server.wsgi
<Directory /opt/warden_server_3/warden_server.wsgi>
<Directory /opt/warden_server/warden_server.wsgi>
Order allow,deny
Allow from all
</Directory>
......@@ -6,12 +6,12 @@ SSLOptions +StdEnvVars +ExportCertData
#SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /opt/warden_server_3/etc/cert.pem
SSLCertificateKeyFile /opt/warden_server_3/etc/key.pem
SSLCACertificateFile /opt/warden_server_3/etc/tcs-ca-bundle.pem
SSLCertificateFile /opt/warden_server/etc/cert.pem
SSLCertificateKeyFile /opt/warden_server/etc/key.pem
SSLCACertificateFile /opt/warden_server/etc/tcs-ca-bundle.pem
WSGIScriptAlias /warden3 /opt/warden_server_3/warden_server.wsgi
WSGIScriptAlias /warden3 /opt/warden_server/warden_server.wsgi
<DirectoryMatch /opt/warden_server_3/warden_server.wsgi>
<DirectoryMatch /opt/warden_server/warden_server.wsgi>
Require all granted
</DirectoryMatch>
......@@ -8,11 +8,15 @@ import sys
import warnings
from os import path
from copy import deepcopy
import unittest2 as unittest
import MySQLdb as my
from warden_server import build_server
import warden_server
if sys.version_info >= (3, 10):
import unittest
else:
import unittest2 as unittest
if sys.version_info[0] >= 3:
from io import StringIO
else:
......@@ -408,8 +412,9 @@ def init_user():
conn = None
try:
conn = my.connect(user='root', passwd=getpass.getpass('Enter MySQL Root password:'))
with conn as cur: # Not a canonical connector implementation, for sure
cur.execute("GRANT SELECT, INSERT, UPDATE, CREATE, DELETE, DROP ON *.* TO %s@'localhost' IDENTIFIED BY %s", (USER, PASSWORD))
with conn.cursor() as cur:
cur.execute("CREATE USER IF NOT EXISTS %s@'localhost' IDENTIFIED BY %s", (USER, PASSWORD))
cur.execute("GRANT SELECT, INSERT, UPDATE, CREATE, DELETE, DROP ON *.* TO %s@'localhost'", (USER,))
conn.commit()
print("DB User set up successfuly")
except my.OperationalError as ex:
......
......@@ -7,5 +7,10 @@
"send_events_limit": 500,
"get_events_limit": 1000,
"description": "Warden 3 distribution config"
},
"DB": {
"user": "warden",
"password": "EXAMPLE",
"dbname": "warden3"
}
}
\ No newline at end of file
......@@ -44,7 +44,7 @@ sys.path.append(path.join(path.dirname(__file__), "..", "lib"))
from jsonschema import Draft4Validator
VERSION = "3.0-beta2"
VERSION = "3.0-beta3"
class Error(Exception):
......@@ -493,7 +493,7 @@ class MySQL(ObjectBase):
with io.open(tagmap_filename, "r", encoding="utf-8") as tagmap_fd:
self.tagmap = json.load(tagmap_fd)
self.tagmap_other = self.catmap["Other"] # Catch error soon, avoid lookup later
self.tagmap_other = self.tagmap["Other"] # Catch error soon, avoid lookup later
self.con = None
......@@ -714,10 +714,11 @@ class MySQL(ObjectBase):
if group or nogroup:
subquery = []
for name in (group or nogroup):
subquery.append("c.name = %s") # exact client
escaped_name = name.replace('&', '&&').replace("_", "&_").replace("%", "&%") # escape for LIKE
subquery.append("c.name = %s") # exact client
params.append(name)
subquery.append("c.name LIKE %s") # whole subtree
params.append(name + ".%")
subquery.append("c.name LIKE CONCAT(%s, '.%%') ESCAPE '&'") # whole subtree
params.append(escaped_name)
query.append(" AND %s (%s)" % (self._get_not(group), " OR ".join(subquery)))
......@@ -863,7 +864,7 @@ def expose(read=1, write=0, debug=0):
meth.write = write
meth.debug = debug
if not hasattr(meth, "arguments"):
meth.arguments = meth.func_code.co_varnames[:meth.func_code.co_argcount]
meth.arguments = get_method_params(meth)
return meth
return expose_deco
......@@ -1095,6 +1096,7 @@ class WardenHandler(ObjectBase):
if self.get_events_limit:
count = min(count, self.get_events_limit)
count = max(0, count)
res = self.db.fetch_events(self.req.client, id, count, cat, nocat, tag, notag, group, nogroup)
......@@ -1244,7 +1246,7 @@ section_order = ("log", "db", "auth", "validator", "handler", "server")
section_def = {
"log": [FileLogger, SysLogger],
"db": [MySQL],
"auth": [X509Authenticator, PlainAuthenticator, X509NameAuthenticator, X509MixMatchAuthenticator],
"auth": [X509NameAuthenticator, PlainAuthenticator, X509Authenticator, X509MixMatchAuthenticator],
"validator": [JSONSchemaValidator, NoValidator],
"handler": [WardenHandler],
"server": [Server]
......