summaryrefslogtreecommitdiffstats
path: root/custodia/custodia
blob: 8d69dea4a969f4a5c32be99c9b165415dbecc896 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/python
#
# Copyright (C) 2015  Custodia Project Contributors - see LICENSE file

try:
    from ConfigParser import RawConfigParser
    from urllib import quote as url_escape
except ImportError:
    from configparser import RawConfigParser
    from urllib.parse import quote as url_escape
from custodia.httpd.server import HTTPServer
from custodia import log
import importlib
import logging
import os
import six
import sys

logger = logging.getLogger('custodia')


def source_config():
    cfgfile = None
    if (len(sys.argv) > 1):
        cfgfile = sys.argv[-1]
    elif os.path.isfile('custodia.conf'):
        cfgfile = 'custodia.conf'
    elif os.path.isfile('/etc/custodia/custodia.conf'):
        cfgfile = '/etc/custodia/custodia.conf'
    else:
        raise IOError("Configuration file not found")
    return os.path.abspath(cfgfile)

def attach_store(typename, plugins, stores):
    for name, c in six.iteritems(plugins):
        if getattr(c, 'store_name', None) is None:
            continue
        try:
            c.store = stores[c.store_name]
        except KeyError:
            raise ValueError('[%s%s] references unexisting store '
                             '"%s"' % (typename, name, c.store_name))

CONFIG_SPECIALS = ['authenticators', 'authorizers', 'consumers', 'stores']

def parse_config(cfgfile):
    parser = RawConfigParser()
    parser.optionxform = str
    files = parser.read(cfgfile)
    if len(files) == 0:
        raise IOError("Failed to read config file")

    config = dict()
    for s in CONFIG_SPECIALS:
        config[s] = dict()
    for s in parser.sections():
        if s == 'global':
            for opt, val in parser.items(s):
                if opt in CONFIG_SPECIALS:
                    raise ValueError('"%s" is an invalid '
                                     '[global] option' % opt)
                config[opt] = val
            continue

        if s.startswith('/'):
            menu = 'consumers'
            name = s
        else:
            if s.startswith('auth:'):
                menu = 'authenticators'
                name = s[5:]
            elif s.startswith('authz:'):
                menu = 'authorizers'
                name = s[6:]
            elif s.startswith('store:'):
                menu = 'stores'
                name = s[6:]
            else:
                raise ValueError('Invalid section name [%s].\n' % s)

        if not parser.has_option(s, 'handler'):
            raise ValueError('Invalid section, missing "handler"')

        handler = None
        hconf = {'facility_name': s}
        for opt, val in parser.items(s):
            if opt == 'handler':
                try:
                    module, classname = val.rsplit('.', 1)
                    m = importlib.import_module(module)
                    handler = getattr(m, classname)
                    hconf['facility_name'] = '%s-[%s]' % (classname, s)
                except Exception as e:  # pylint: disable=broad-except
                    raise ValueError('Invalid format for "handler" option '
                                     '[%r]: %s' % (e, val))

            else:
                hconf[opt] = val
        config[menu][name] = handler(hconf)

    # Attach stores to other plugins
    attach_store('auth:', config['authenticators'], config['stores'])
    attach_store('authz:', config['authorizers'], config['stores'])
    attach_store('', config['consumers'], config['stores'])

    return config

if __name__ == '__main__':
    cfgfile = source_config()
    config = parse_config(cfgfile)
    debug = config.get('debug', 'false').lower() == 'true'
    auditlog = os.path.abspath(config.get('auditlog', 'custodia.audit.log'))
    log.setup_logging(debug, auditlog)
    logger.debug('Config file %s loaded', cfgfile)

    url = config.get('server_url', None)
    if url is None:
        address = config.get('server_socket',
                             os.path.join(os.getcwd(), 'server_socket'))
        url = 'http+unix://%s/' % url_escape(address, '')

    httpd = HTTPServer(url, config)
    httpd.serve()