summaryrefslogtreecommitdiffstats
path: root/custodia/httpd/authenticators.py
blob: bed2bc4c2e1484b4a89e91c7c32df0e9c053dfad (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
124
125
126
127
128
129
130
131
132
133
# Copyright (C) 2015  Custodia Project Contributors - see LICENSE file

import os

from cryptography.hazmat.primitives import constant_time

from custodia import log
from custodia.httpd.server import HTTPError


class HTTPAuthenticator(object):

    def __init__(self, config=None):
        self.config = config
        self._auditlog = log.AuditLog(self.config)

    def handle(self, request):
        raise HTTPError(403)


class SimpleCredsAuth(HTTPAuthenticator):

    def __init__(self, config=None):
        super(SimpleCredsAuth, self).__init__(config)
        self._uid = 0
        self._gid = 0
        if 'uid' in self.config:
            self._uid = int(self.config['uid'])
        if 'gid' in self.config:
            self._gid = int(self.config['gid'])

    def handle(self, request):
        uid = int(request['creds']['gid'])
        gid = int(request['creds']['uid'])
        if self._gid == gid or self._uid == uid:
            self._auditlog.svc_access(log.AUDIT_SVC_AUTH_PASS,
                                      request['creds']['pid'],
                                      "SCA", "%d, %d" % (uid, gid))
            return True
        else:
            self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
                                      request['creds']['pid'],
                                      "SCA", "%d, %d" % (uid, gid))
            return False


class SimpleHeaderAuth(HTTPAuthenticator):

    def __init__(self, config=None):
        super(SimpleHeaderAuth, self).__init__(config)
        self.name = 'REMOTE_USER'
        self.value = None
        if 'header' in self.config:
            self.name = self.config['header']
        if 'value' in self.config:
            self.value = self.config['value']

    def handle(self, request):
        if self.name not in request['headers']:
            return None
        value = request['headers'][self.name]
        if self.value is None:
            # Any value is accepted
            pass
        elif isinstance(self.value, str):
            if value != self.value:
                self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
                                          request['creds']['pid'],
                                          "SHA", value)
                return False
        elif isinstance(self.value, list):
            if value not in self.value:
                self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
                                          request['creds']['pid'],
                                          "SHA", value)
                return False
        else:
            self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
                                      request['creds']['pid'],
                                      "SHA", value)
            return False

        self._auditlog.svc_access(log.AUDIT_SVC_AUTH_PASS,
                                  request['creds']['pid'],
                                  "SHA", value)
        request['remote_user'] = value
        return True


class SimpleAuthKeys(HTTPAuthenticator):

    def __init__(self, config=None):
        super(SimpleAuthKeys, self).__init__(config)
        self.id_header = self.config.get('header', 'CUSTODIA_AUTH_ID')
        self.key_header = self.config.get('header', 'CUSTODIA_AUTH_KEY')
        self.store_name = self.config['store']
        self.store = None
        self.namespace = self.config.get('store_namespace', 'custodiaSAK')

    def _db_key(self, name):
        return os.path.join(self.namespace, name)

    def handle(self, request):
        name = request['headers'].get(self.id_header, None)
        key = request['headers'].get(self.key_header, None)
        if name is None and key is None:
            return None

        validated = False
        try:
            val = self.store.get(self._db_key(name))
            if val is None:
                raise Exception("No such ID")
            if constant_time.bytes_eq(val.encode('utf-8'),
                                      key.encode('utf-8')):
                validated = True
        except Exception:
            self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
                                      request['creds']['pid'],
                                      "SAK", name)
            return False

        if validated:
            self._auditlog.svc_access(log.AUDIT_SVC_AUTH_PASS,
                                      request['creds']['pid'],
                                      "SAK", name)
            request['remote_user'] = name
            return True

        self._auditlog.svc_access(log.AUDIT_SVC_AUTH_FAIL,
                                  request['creds']['pid'],
                                  "SAK", name)
        return False