Skip to content

Commit 9f462f9

Browse files
ISSUE #92
1 parent 3276904 commit 9f462f9

File tree

4 files changed

+162
-10
lines changed

4 files changed

+162
-10
lines changed

minos/api_gateway/rest/database/models.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,51 @@ def __init__(self, model: AuthRule):
5656
self.methods = model.methods
5757
self.created_at = str(model.created_at)
5858
self.updated_at = str(model.updated_at)
59+
60+
61+
class AutzRule(Base):
62+
__tablename__ = "autz_rules"
63+
id = Column(Integer, Sequence("item_id_seq"), nullable=False, primary_key=True)
64+
service = Column(String, primary_key=True, nullable=False)
65+
rule = Column(String, primary_key=True, nullable=False)
66+
roles = Column(JSON)
67+
methods = Column(JSON)
68+
created_at = Column(TIMESTAMP)
69+
updated_at = Column(TIMESTAMP)
70+
71+
def __repr__(self):
72+
return (
73+
"<AuthRule(id='{}', service='{}', rule='{}',"
74+
"methods={}, created_at={}, updated_at={})>".format( # pragma: no cover
75+
self.id, self.service, self.roles, self.methods, self.created_at, self.updated_at
76+
)
77+
)
78+
79+
def to_serializable_dict(self):
80+
return {
81+
"id": self.id,
82+
"service": self.service,
83+
"roles": self.roles,
84+
"methods": self.methods,
85+
"created_at": str(self.created_at),
86+
"updated_at": str(self.updated_at),
87+
}
88+
89+
90+
class AutzRuleDTO:
91+
id: int
92+
service: str
93+
rule: str
94+
roles: list
95+
methods: list
96+
created_at: str
97+
updated_at: str
98+
99+
def __init__(self, model: AutzRule):
100+
self.id = model.id
101+
self.rule = model.rule
102+
self.service = model.service
103+
self.roles = model.roles
104+
self.methods = model.methods
105+
self.created_at = str(model.created_at)
106+
self.updated_at = str(model.updated_at)

minos/api_gateway/rest/database/repository.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from .models import (
99
AuthRule,
1010
AuthRuleDTO,
11+
AutzRule,
12+
AutzRuleDTO,
1113
)
1214

1315

@@ -17,28 +19,49 @@ def __init__(self, engine):
1719
self.s = sessionmaker(bind=engine)
1820
self.session = self.s()
1921

20-
def create(self, record: AuthRule):
22+
def create_auth_rule(self, record: AuthRule):
2123
self.session.add(record)
2224
self.session.commit()
2325
return record.to_serializable_dict()
2426

25-
def get_all(self):
27+
def create_autz_rule(self, record: AutzRule):
28+
self.session.add(record)
29+
self.session.commit()
30+
return record.to_serializable_dict()
31+
32+
def get_auth_rules(self):
2633
r = self.session.query(AuthRule).all()
2734

2835
records = list()
2936
for record in r:
3037
records.append(AuthRuleDTO(record).__dict__)
3138
return records
3239

33-
def update(self, id: int, **kwargs):
40+
def get_autz_rules(self):
41+
r = self.session.query(AutzRule).all()
42+
43+
records = list()
44+
for record in r:
45+
records.append(AutzRuleDTO(record).__dict__)
46+
return records
47+
48+
def update_auth_rule(self, id: int, **kwargs):
3449
self.session.query(AuthRule).filter(AuthRule.id == id).update(kwargs)
3550
self.session.commit()
3651

37-
def delete(self, id: int):
52+
def update_autz_rule(self, id: int, **kwargs):
53+
self.session.query(AutzRule).filter(AutzRule.id == id).update(kwargs)
54+
self.session.commit()
55+
56+
def delete_auth_rule(self, id: int):
3857
self.session.query(AuthRule).filter(AuthRule.id == id).delete()
3958
self.session.commit()
4059

41-
def get_by_service(self, service: str):
60+
def delete_autz_rule(self, id: int):
61+
self.session.query(AutzRule).filter(AutzRule.id == id).delete()
62+
self.session.commit()
63+
64+
def get_auth_rule_by_service(self, service: str):
4265
r = self.session.query(AuthRule).filter(or_(AuthRule.service == service, AuthRule.service == "*")).all()
4366

4467
records = list()

minos/api_gateway/rest/handler.py

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from minos.api_gateway.rest.database.models import (
2323
AuthRule,
24+
AutzRule,
2425
)
2526
from minos.api_gateway.rest.urlmatch.authmatch import (
2627
AuthMatch,
@@ -56,7 +57,7 @@ async def orchestrate(request: web.Request) -> web.Response:
5657

5758

5859
async def check_auth(request: web.Request, service: str, url: str, method: str) -> bool:
59-
records = Repository(request.app["db_engine"]).get_by_service(service)
60+
records = Repository(request.app["db_engine"]).get_auth_rule_by_service(service)
6061
return AuthMatch.match(url=url, method=method, records=records)
6162

6263

@@ -239,9 +240,26 @@ async def get_endpoints(request: web.Request) -> web.Response:
239240
{"error": "The requested endpoint is not available."}, status=web.HTTPServiceUnavailable.status_code
240241
)
241242

243+
@staticmethod
244+
async def get_roles(request: web.Request) -> web.Response:
245+
auth_host = request.app["config"].rest.auth.host
246+
auth_port = request.app["config"].rest.auth.port
247+
auth_path = request.app["config"].rest.auth.path
248+
249+
url = URL.build(scheme="http", host=auth_host, port=auth_port, path=f"{auth_path}/roles")
250+
251+
try:
252+
async with ClientSession() as session:
253+
async with session.get(url=url) as response:
254+
return await _clone_response(response)
255+
except ClientConnectorError:
256+
return web.json_response(
257+
{"error": "The requested endpoint is not available."}, status=web.HTTPServiceUnavailable.status_code
258+
)
259+
242260
@staticmethod
243261
async def get_rules(request: web.Request) -> web.Response:
244-
records = Repository(request.app["db_engine"]).get_all()
262+
records = Repository(request.app["db_engine"]).get_auth_rules()
245263
return web.json_response(records)
246264

247265
@staticmethod
@@ -265,7 +283,7 @@ async def create_rule(request: web.Request) -> web.Response:
265283
updated_at=now,
266284
)
267285

268-
record = Repository(request.app["db_engine"]).create(rule)
286+
record = Repository(request.app["db_engine"]).create_auth_rule(rule)
269287

270288
return web.json_response(record)
271289
except Exception as e:
@@ -276,7 +294,17 @@ async def update_rule(request: web.Request) -> web.Response:
276294
try:
277295
id = int(request.url.name)
278296
content = await request.json()
279-
Repository(request.app["db_engine"]).update(id=id, **content)
297+
Repository(request.app["db_engine"]).update_auth_rule(id=id, **content)
298+
return web.json_response(status=web.HTTPOk.status_code)
299+
except Exception as e:
300+
return web.json_response({"error": str(e)}, status=web.HTTPBadRequest.status_code)
301+
302+
@staticmethod
303+
async def update_autz_rule(request: web.Request) -> web.Response:
304+
try:
305+
id = int(request.url.name)
306+
content = await request.json()
307+
Repository(request.app["db_engine"]).update_autz_rule(id=id, **content)
280308
return web.json_response(status=web.HTTPOk.status_code)
281309
except Exception as e:
282310
return web.json_response({"error": str(e)}, status=web.HTTPBadRequest.status_code)
@@ -285,7 +313,54 @@ async def update_rule(request: web.Request) -> web.Response:
285313
async def delete_rule(request: web.Request) -> web.Response:
286314
try:
287315
id = int(request.url.name)
288-
Repository(request.app["db_engine"]).delete(id)
316+
Repository(request.app["db_engine"]).delete_auth_rule(id)
317+
return web.json_response(status=web.HTTPOk.status_code)
318+
except Exception as e:
319+
return web.json_response({"error": str(e)}, status=web.HTTPBadRequest.status_code)
320+
321+
@staticmethod
322+
async def delete_autz_rule(request: web.Request) -> web.Response:
323+
try:
324+
id = int(request.url.name)
325+
Repository(request.app["db_engine"]).delete_autz_rule(id)
289326
return web.json_response(status=web.HTTPOk.status_code)
290327
except Exception as e:
291328
return web.json_response({"error": str(e)}, status=web.HTTPBadRequest.status_code)
329+
330+
@staticmethod
331+
async def create_autz_rule(request: web.Request) -> web.Response:
332+
try:
333+
content = await request.json()
334+
335+
if (
336+
"service" not in content
337+
and "rule" not in content
338+
and "roles" not in content
339+
and "methods" not in content
340+
):
341+
return web.json_response(
342+
{"error": "Wrong data. Provide 'service', 'rule', 'roles' and 'methods' parameters."},
343+
status=web.HTTPBadRequest.status_code,
344+
)
345+
346+
now = datetime.now()
347+
348+
rule = AutzRule(
349+
service=content["service"],
350+
rule=content["rule"],
351+
roles=content["roles"],
352+
methods=content["methods"],
353+
created_at=now,
354+
updated_at=now,
355+
)
356+
357+
record = Repository(request.app["db_engine"]).create_autz_rule(rule)
358+
359+
return web.json_response(record)
360+
except Exception as e:
361+
return web.json_response({"error": str(e)}, status=web.HTTPBadRequest.status_code)
362+
363+
@staticmethod
364+
async def get_autz_rules(request: web.Request) -> web.Response:
365+
records = Repository(request.app["db_engine"]).get_autz_rules()
366+
return web.json_response(records)

minos/api_gateway/rest/service.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ async def create_application(self) -> web.Application:
7070
app.router.add_route("PATCH", "/admin/rules/{id}", AdminHandler.update_rule)
7171
app.router.add_route("DELETE", "/admin/rules/{id}", AdminHandler.delete_rule)
7272

73+
app.router.add_route("GET", "/admin/roles", AdminHandler.get_roles)
74+
app.router.add_route("POST", "/admin/autz-rules", AdminHandler.create_autz_rule)
75+
app.router.add_route("GET", "/admin/autz-rules", AdminHandler.get_autz_rules)
76+
app.router.add_route("PATCH", "/admin/autz-rules/{id}", AdminHandler.update_autz_rule)
77+
app.router.add_route("DELETE", "/admin/autz-rules/{id}", AdminHandler.delete_autz_rule)
78+
7379
# Administration routes
7480
path = Path(Path.cwd())
7581
aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader(f"{path}/minos/api_gateway/rest/backend/templates"))

0 commit comments

Comments
 (0)