aboutsummaryrefslogtreecommitdiffstats
path: root/moon_interface/moon_interface/authz_requests.py
blob: c809053b28dcc679ac4724bdeae3df6f5f114983 (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
# This software is distributed under the terms and conditions of the 'Apache-2.0'
# license which can be found in the file 'LICENSE' in this package distribution
# or at 'http://www.apache.org/licenses/LICENSE-2.0'.

import logging
import itertools
import pickle
import requests
import sys
from python_moonutilities import exceptions
from python_moonutilities.context import Context
from python_moonutilities.cache import Cache

logger = logging.getLogger("moon.interface.authz_requests")


CACHE = Cache()
CACHE.update()


class AuthzRequest:

    result = None
    final_result = "Deny"
    req_max_delay = 2

    def __init__(self, ctx, args=None):
        self.context = Context(ctx, CACHE)
        self.args = args
        self.request_id = ctx["request_id"]
        if ctx['project_id'] not in CACHE.container_chaining:
            raise exceptions.KeystoneProjectError("Unknown Project ID {}".format(ctx['project_id']))
        self.container_chaining = CACHE.container_chaining[ctx['project_id']]

        if len(self.container_chaining) == 0 or not all(k in self.container_chaining[0] for k in ("container_id", "hostname", "hostip", "port")):
            raise exceptions.MoonError('Void container chaining')

        self.pdp_container = self.container_chaining[0]["container_id"]
        self.run()

    def run(self):
        self.context.delete_cache()
        req = None
        tries = 0
        success = False

        if "hostip" in self.container_chaining[0]:
            hostname = self.container_chaining[0]["hostip"]
        elif "hostname" in self.container_chaining[0]:
            hostname = self.container_chaining[0]["hostname"]
        else:
            raise exceptions.AuthzException(
                "error in address no hostname or hostip"
            )
        while tries < 2:
            try:
                req = requests.post("http://{}:{}/authz".format(
                    hostname,
                    self.container_chaining[0]["port"],
                ), data=pickle.dumps(self.context))
                if req.status_code != 200:
                    raise exceptions.AuthzException(
                        "Receive bad response from Authz function "
                        "(with address - {})".format(req.status_code)
                    )
                success = True
                break
            except requests.exceptions.ConnectionError:
                logger.error("Cannot connect to {}".format(
                    "http://{}:{}/authz".format(
                        hostname,
                        self.container_chaining[0]["port"]
                    )))
            except:
                logger.error("Unexpected error:", sys.exc_info()[0])
            hostname = self.container_chaining[0]["hostname"],
            tries += 1

        if not success:
            raise exceptions.AuthzException("Cannot connect to Authz function")

        self.context.set_cache(CACHE)
        if req and len(self.container_chaining) == 1:
            self.result = pickle.loads(req.content)

    # def __exec_next_state(self, rule_found):
    #     index = self.context.index
    #     current_meta_rule = self.context.headers[index]
    #     current_container = self.__get_container_from_meta_rule(current_meta_rule)
    #     current_container_genre = current_container["genre"]
    #     try:
    #         next_meta_rule = self.context.headers[index + 1]
    #     except IndexError:
    #         next_meta_rule = None
    #     if current_container_genre == "authz":
    #         if rule_found:
    #             return True
    #         pass
    #         if next_meta_rule:
    #             # next will be session if current is deny and session is unset
    #             if self.payload["authz_context"]['pdp_set'][next_meta_rule]['effect'] == "unset":
    #                 return notify(
    #                     request_id=self.payload["authz_context"]["request_id"],
    #                     container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'],
    #                     payload=self.payload)
    #             # next will be delegation if current is deny and session is passed or deny and delegation is unset
    #             else:
    #                 LOG.error("Delegation is not developed!")
    #
    #         else:
    #             # else next will be None and the request is sent to router
    #             return self.__return_to_router()
    #     elif current_container_genre == "session":
    #         pass
    #         # next will be next container in headers if current is passed
    #         if self.payload["authz_context"]['pdp_set'][current_meta_rule]['effect'] == "passed":
    #             return notify(
    #                 request_id=self.payload["authz_context"]["request_id"],
    #                 container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'],
    #                 payload=self.payload)
    #         # next will be None if current is grant and the request is sent to router
    #         else:
    #             return self.__return_to_router()
    #     elif current_container_genre == "delegation":
    #         LOG.error("Delegation is not developed!")
    #         # next will be authz if current is deny
    #         # next will be None if current is grant and the request is sent to router

    def set_result(self, result):
        self.result = result

    def is_authz(self):
        if not self.result:
            return False
        authz_results = []
        for key in self.result.pdp_set:
            if "effect" in self.result.pdp_set[key]:

                if self.result.pdp_set[key]["effect"] == "grant":
                    # the pdp is a authorization PDP and grant the request
                    authz_results.append(True)
                elif self.result.pdp_set[key]["effect"] == "passed":
                    # the pdp is not a authorization PDP (session or delegation) and had run normally
                    authz_results.append(True)
                elif self.result.pdp_set[key]["effect"] == "unset":
                    # the pdp is not a authorization PDP (session or delegation) and had not yep run
                    authz_results.append(True)
                else:
                    # the pdp is (or not) a authorization PDP and had run badly
                    authz_results.append(False)
        if list(itertools.accumulate(authz_results, lambda x, y: x & y))[-1]:
            self.result.pdp_set["effect"] = "grant"
        if self.result:
            if self.result.pdp_set["effect"] == "grant":
                self.final_result = "Grant"
                return True
        self.final_result = "Deny"
        return True