Skip to content

Commit 47d475a

Browse files
Merge pull request #7 from minos-framework/0.2.0
v0.2.0
2 parents f5b65bf + a7f793c commit 47d475a

File tree

11 files changed

+269
-15
lines changed

11 files changed

+269
-15
lines changed

HISTORY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,10 @@
33
## 0.1.0 (2022-02-03)
44

55
* First release on PyPI.
6+
7+
## 0.2.0 (2022-02-16)
8+
9+
* Set roles on config file.
10+
* Set default role on config file.
11+
* Populate roles into database.
12+
* On auth creation assign default role (defined in config file).

minos/auth/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__author__ = """Clariteia Devs"""
22
__email__ = "[email protected]"
3-
__version__ = "0.1.0"
3+
__version__ = "0.2.0"
44

55
from .config import (
66
AuthConfig,

minos/auth/config.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
from pathlib import (
1313
Path,
1414
)
15+
from typing import (
16+
Any,
17+
)
1518

1619
import yaml
1720

@@ -24,6 +27,8 @@
2427
USER_SERVICE = collections.namedtuple("UserService", "host port path")
2528
CREDENTIAL_SERVICE = collections.namedtuple("CredentialService", "host port path create_token")
2629
TOKEN_SERVICE = collections.namedtuple("TokenService", "host port path create_token")
30+
ROLES = collections.namedtuple("Roles", "roles default")
31+
ROLE = collections.namedtuple("Role", "code name")
2732

2833
_ENVIRONMENT_MAPPER = {
2934
"rest.host": "AUTH_REST_HOST",
@@ -168,3 +173,20 @@ def token_service(self) -> TOKEN_SERVICE:
168173
path=str(self._get("token-service.path")),
169174
create_token=self._get("token-service.create-token"),
170175
)
176+
177+
@property
178+
def roles(self) -> ROLES:
179+
"""Get the rest config.
180+
181+
:return: A ``REST`` NamedTuple instance.
182+
"""
183+
return ROLES(roles=self._roles, default=str(self._get("roles.default")),)
184+
185+
@property
186+
def _roles(self) -> list[ROLE]:
187+
info = self._get("roles.roles")
188+
roles = [self._role_entry(role) for role in info]
189+
return roles
190+
191+
def _role_entry(self, service: dict[str, Any]) -> ROLE:
192+
return ROLE(name=service["name"], code=service["code"],)

minos/auth/database/models.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from sqlalchemy import (
77
TIMESTAMP,
88
Column,
9+
ForeignKey,
910
Integer,
1011
String,
1112
)
@@ -15,6 +16,9 @@
1516
from sqlalchemy.ext.declarative import (
1617
declarative_base,
1718
)
19+
from sqlalchemy.orm import (
20+
relationship,
21+
)
1822

1923
Base = declarative_base()
2024

@@ -32,6 +36,8 @@ class Authentication(Base):
3236
user_uuid = Column(String)
3337
user_id = Column(String)
3438
token = Column(String)
39+
role_code = Column(Integer, ForeignKey("roles.code"))
40+
role = relationship("Role", backref="parents")
3541
created_at = Column(TIMESTAMP)
3642
updated_at = Column(TIMESTAMP)
3743

@@ -42,3 +48,33 @@ def __repr__(self):
4248
self.uuid, AuthType(self.auth_type), self.auth_uuid, self.created_at, self.updated_at
4349
)
4450
)
51+
52+
def to_serializable_dict(self):
53+
return {
54+
"uuid": str(self.uuid),
55+
"auth_type": AuthType(self.auth_type).value,
56+
"auth_name": AuthType(self.auth_type).name,
57+
"auth_uuid": self.auth_uuid,
58+
"user_uuid": self.user_uuid,
59+
"user_id": self.user_id,
60+
"token": self.token,
61+
"role": self.role.to_serializable_dict(),
62+
"created_at": str(self.created_at),
63+
"updated_at": str(self.updated_at),
64+
}
65+
66+
67+
class Role(Base):
68+
__tablename__ = "roles"
69+
code = Column(Integer, primary_key=True)
70+
role_name = Column(String)
71+
created_at = Column(TIMESTAMP)
72+
updated_at = Column(TIMESTAMP)
73+
74+
def to_serializable_dict(self):
75+
return {
76+
"code": self.code,
77+
"role_name": self.role_name,
78+
"created_at": str(self.created_at),
79+
"updated_at": str(self.updated_at),
80+
}

minos/auth/handler.py

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from .database.models import (
2828
Authentication,
2929
AuthType,
30+
Role,
3031
)
3132

3233
logger = logging.getLogger(__name__)
@@ -59,7 +60,7 @@ async def register_credentials(request: web.Request) -> web.Response:
5960
request, token, content["username"], user_uuid, credential_uuid, AuthType.CREDENTIAL.value
6061
)
6162
else:
62-
return credentials_response
63+
return credentials_response # pragma: no cover
6364

6465
return user_creation
6566

@@ -94,7 +95,7 @@ async def register_token(request: web.Request) -> web.Response:
9495
)
9596
return token_response
9697

97-
return user_creation
98+
return user_creation # pragma: no cover
9899

99100

100101
async def credentials_login(request: web.Request) -> web.Response:
@@ -141,7 +142,7 @@ async def validate_credentials(request: web.Request):
141142
token = await get_credential_token(request, credential_uuid)
142143
return web.json_response({"token": token}), token
143144

144-
return response, None
145+
return response, None # pragma: no cover
145146

146147

147148
async def get_credential_token(request: web.Request, credential_uuid: str):
@@ -177,22 +178,28 @@ async def get_token_user(request: web.Request, token: str, auth_type: AuthType):
177178
s = session()
178179

179180
r = s.query(Authentication).filter(Authentication.token == token).order_by(desc(Authentication.updated_at)).first()
181+
role = r.role.code
180182
s.close()
181183

182184
if r is not None:
183185
if r.auth_type == auth_type.value:
184-
user_call_response = await get_user_call(request, r.user_uuid)
185-
return user_call_response
186+
response = await get_user_call(request, r.user_uuid)
187+
188+
if response.status == 200:
189+
resp_json = json.loads(response.text)
190+
resp_json["role"] = role
191+
return web.json_response(resp_json)
192+
return response # pragma: no cover
186193

187-
return web.HTTPBadRequest(text="Please provide correct Token.")
194+
return web.HTTPBadRequest(text="Please provide correct Token.") # pragma: no cover
188195

189196

190197
async def get_user_from_credentials(request: web.Request) -> web.Response:
191198
resp, token = await validate_credentials(request)
192199

193200
if resp.status == 200:
194201
return await get_token_user(request, token, AuthType.CREDENTIAL)
195-
return resp
202+
return resp # pragma: no cover
196203

197204

198205
async def validate_token(request: web.Request) -> web.Response:
@@ -207,21 +214,35 @@ async def validate_token(request: web.Request) -> web.Response:
207214
s = session()
208215

209216
r = s.query(Authentication).filter(Authentication.token == token).order_by(desc(Authentication.updated_at)).first()
217+
role = None
218+
if r is not None:
219+
role = r.role.code
210220
s.close()
211221

212222
if r is not None:
223+
213224
if r.auth_type == AuthType.TOKEN.value:
214225
token_resp = await validate_token_call(request)
215226

216227
if token_resp.status == 200:
217-
return await get_user_call(request, r.user_uuid)
228+
return await user_call(request, r.user_uuid, role)
218229

219230
if r.auth_type == AuthType.CREDENTIAL.value:
220-
return await get_user_call(request, r.user_uuid)
231+
return await user_call(request, r.user_uuid, role)
221232

222233
return web.json_response({"error": "Please provide correct Token."}, status=400)
223234

224235

236+
async def user_call(request: web.Request, user_uuid, role):
237+
response = await get_user_call(request, user_uuid)
238+
239+
if response.status == 200:
240+
resp_json = json.loads(response.text)
241+
resp_json["role"] = role
242+
return web.json_response(resp_json)
243+
return response # pragma: no cover
244+
245+
225246
async def get_user_call(request: web.Request, user_uuid: str) -> web.Response:
226247
""" Get User by Session token """
227248
user_host = request.app["config"].user_service.host
@@ -339,6 +360,7 @@ async def create_authentication(
339360
user_id=user_id,
340361
token=token,
341362
auth_type=auth_type,
363+
role_code=int(request.app["config"].roles.default),
342364
created_at=now,
343365
updated_at=now,
344366
)
@@ -359,3 +381,31 @@ async def _get_authorization_token(request: web.Request):
359381
raise Exception
360382
except Exception as e:
361383
raise e
384+
385+
386+
class RoleRest:
387+
@staticmethod
388+
async def get_roles(request: web.Request):
389+
session = sessionmaker(bind=request.app["db_engine"])
390+
391+
s = session()
392+
records = s.query(Role).all()
393+
res = list()
394+
for record in records:
395+
res.append(record.to_serializable_dict())
396+
s.close()
397+
return web.json_response(res)
398+
399+
400+
class AuthenticationRest:
401+
@staticmethod
402+
async def get_all(request: web.Request):
403+
session = sessionmaker(bind=request.app["db_engine"])
404+
405+
s = session()
406+
records = s.query(Authentication).all()
407+
res = list()
408+
for record in records:
409+
res.append(record.to_serializable_dict())
410+
s.close()
411+
return web.json_response(res)

minos/auth/service.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import logging
2+
from datetime import (
3+
datetime,
4+
)
25

36
from aiohttp import (
47
web,
@@ -9,14 +12,20 @@
912
from sqlalchemy import (
1013
create_engine,
1114
)
15+
from sqlalchemy.orm import (
16+
sessionmaker,
17+
)
1218

1319
from .config import (
1420
AuthConfig,
1521
)
1622
from .database.models import (
1723
Base,
24+
Role,
1825
)
1926
from .handler import (
27+
AuthenticationRest,
28+
RoleRest,
2029
credentials_login,
2130
get_user_from_credentials,
2231
get_user_from_token,
@@ -41,6 +50,7 @@ async def create_application(self) -> web.Application:
4150
app["config"] = self.config
4251
self.engine = await self.create_engine()
4352
await self.create_database()
53+
await self.populate_database()
4454

4555
app["db_engine"] = self.engine
4656

@@ -54,6 +64,10 @@ async def create_application(self) -> web.Application:
5464

5565
app.router.add_route("POST", "/auth/validate-token", validate_token)
5666

67+
app.router.add_route("GET", "/auth/roles", RoleRest.get_roles)
68+
69+
app.router.add_route("GET", "/auth/all", AuthenticationRest.get_all)
70+
5771
return app
5872

5973
async def create_engine(self):
@@ -66,3 +80,16 @@ async def create_engine(self):
6680

6781
async def create_database(self):
6882
Base.metadata.create_all(self.engine)
83+
84+
async def populate_database(self):
85+
session = sessionmaker(bind=self.engine)
86+
s = session()
87+
now = datetime.now()
88+
89+
for role in self.config.roles.roles:
90+
instance = s.query(Role).filter(Role.code == role.code, Role.role_name == role.name).one_or_none()
91+
if instance is None: # pragma: no cover
92+
r = Role(code=role.code, role_name=role.name, created_at=now, updated_at=now,)
93+
s.add(r)
94+
s.commit()
95+
s.close()

0 commit comments

Comments
 (0)