permission system

jwt auth
added deleted field all models
encrypyed field logging disabled
master
Mustafa Yontar 4 years ago
parent 0a98495731
commit 4f3e40a3d2
  1. 3
      .gitignore
  2. 92
      internal_lib/AuthMethots.py
  3. 15
      internal_lib/EncryptedField.py
  4. 42
      internal_lib/permission_parser.py
  5. 65
      main.py
  6. 1
      models/Account.py
  7. 2
      models/File.py
  8. 5
      models/Group.py
  9. 1
      models/Payment.py
  10. 15
      models/Union.py
  11. 27
      models/User.py
  12. 2
      restapi

3
.gitignore vendored

@ -23,4 +23,5 @@ var/
*.pem *.pem
*test.py *test.py
trash trash
mongo_data_dir/* mongo_data_dir/*
.directory

@ -0,0 +1,92 @@
from flask import request
from flask_jwt_extended.exceptions import NoAuthorizationError
from flask_jwt_extended.utils import verify_token_claims
from flask_jwt_extended.view_decorators import _decode_jwt_from_request
from werkzeug.exceptions import Unauthorized
from internal_lib.permission_parser import parse_permission, control_permission, is_admin
from models.User import User
from restapi.BaseAuthModel import BaseAuth
class AuthApi(BaseAuth):
def authorized(self):
""
class AuthJWT(BaseAuth):
user = None
def authorized(self):
try:
jwt_data, jwt_header = _decode_jwt_from_request(request_type='access')
verify_token_claims(jwt_data)
self.user = User.objects.get(id=jwt_data['identity'])
except Exception as e:
self.set_error(e)
return False
return True
def has_model_delete_permission(self, obj, model):
if self.user is None:
self.authorized()
if model.__name__.lower() == "union":
return False, obj
if control_permission(self.user.user_group, model.__name__.lower(), "delete", str(obj.id),
str(self.user.union)):
return True, obj
else:
return False, obj
def has_model_update_permission(self, obj, update: dict):
model = obj.__class__.__name__.lower()
if self.user is None:
self.authorized()
if update.get('id') or update.get('pk'):
return False, update
if not is_admin(self.user.user_group) and update.get('union'):
return False, update
if control_permission(self.user.user_group, model, "update", str(obj.id),
str(self.user.union.id)):
return True, update
return False, update
def has_model_read_permission(self, qs):
from flask import current_app
if self.user is None:
self.authorized()
unions = []
has_read = False
for right in self.user.user_group.rights:
permission = parse_permission(right)
current_app.logger.info(permission)
if permission.get('read'):
has_read = True
unions.append(permission.get('union'))
if has_read:
if qs._collection.name == "union":
qs = qs.filter(id__in=unions, deleted=False)
else:
qs = qs.filter(union__in=unions, deleted=False)
else:
raise Unauthorized()
return qs
def has_model_write_permission(self, obj):
model = obj.__class__.__name__.lower()
if self.user is None:
self.authorized()
obj.union = self.user.union.id
if control_permission(self.user.user_group, model, "write", str(obj.id),
str(self.user.union.id)):
return True, obj
return False, obj

@ -18,13 +18,10 @@ class EncryptedStringField(BaseField):
super().__init__(**kwargs) super().__init__(**kwargs)
def __get__(self, instance, owner): def __get__(self, instance, owner):
from flask import current_app as app import binascii
app.logger.error(self.name)
import binascii
if instance: if instance:
value = instance._data.get(self.name) value = instance._data.get(self.name)
if value: if value:
app.logger.error(value)
encryptor = PKCS1_OAEP.new(self.keyPair) encryptor = PKCS1_OAEP.new(self.keyPair)
return encryptor.decrypt(binascii.unhexlify(value)).decode("utf-8") return encryptor.decrypt(binascii.unhexlify(value)).decode("utf-8")
else: else:
@ -33,13 +30,6 @@ class EncryptedStringField(BaseField):
def __set__(self, instance, value): def __set__(self, instance, value):
super().__set__(instance, value) super().__set__(instance, value)
if value is not None: if value is not None:
from flask import current_app as app
app.logger.error(self.name)
app.logger.error(instance._data)
app.logger.error("data : {} ".format(value))
print(self.name)
print(instance._data)
print(value)
key = self.name key = self.name
try: try:
encryptor = PKCS1_OAEP.new(self.keyPair.publickey()) encryptor = PKCS1_OAEP.new(self.keyPair.publickey())
@ -58,8 +48,5 @@ class EncryptedStringField(BaseField):
pass pass
return value return value
def lookup_member(self, member_name):
return None
def prepare_query_value(self, op, value): def prepare_query_value(self, op, value):
return super().prepare_query_value(op, value) return super().prepare_query_value(op, value)

@ -46,39 +46,27 @@ def parse_permission(string):
} }
def control_permission(group, module, perm_type, itemid, unionid): def is_admin(group):
for right_string in group.rights: for right_string in group.rights:
right = parse_permission(right_string.strip()) right = parse_permission(right_string.strip())
print(right, right_string, group, perm_type) if right.get('union') == "*":
if right.get('module') in ["*", module]:
return True
elif right.get('union') in ['*', unionid]:
return True
elif right.get(perm_type):
return True
elif right.get('item_id') in ['*', itemid]:
return True
elif right.get('module') in ["*", module] and right.get('union') in ['*', unionid] and right.get(
perm_type) and right.get('item_id') in ['*', itemid]:
return True return True
return False return False
def control_permission(group, module, perm_type, itemid, unionid):
has_perm = False
from flask import current_app
def read_permission(module, qs): for right_string in group.rights:
union_list = [] right = parse_permission(right_string.strip())
for right_string in current_user.group.rights: if module == "union" and perm_type == "write" and right.get("union") != "*":
right = parse_permission(right_string) has_perm = False
if right.get('module') in [module, '*']: current_app.logger.info("short shut")
if right.get('read'): elif right.get('module') in ["*", module] and right.get('union') in ['*', unionid] and right.get(
if right.get('union') != "*": perm_type) and right.get('item_id') in ['*', itemid]:
union_list.append(right.get('union')) current_app.logger.info("long shut")
has_perm = True
if len(union_list) > 0: return has_perm
if module == 'union':
qs.filter(id__in=union_list, deleted=False)
else:
qs.filter(union__in=union_list, deleted=False)
return qs
def has_permission(module, obj, reqtype, oid): def has_permission(module, obj, reqtype, oid):

@ -1,27 +1,78 @@
from flask import Flask from flask import Flask, request, jsonify
from flask_admin.contrib.mongoengine import ModelView from flask_admin.contrib.mongoengine import ModelView
from flask_jwt_extended import JWTManager, create_access_token
from mongoengine import connect from mongoengine import connect
from werkzeug.security import check_password_hash
from internal_lib.AuthMethots import AuthJWT
from models.Group import Group from models.Group import Group
from models.Union import Union from models.Union import Union
from models.User import User from models.User import User
from restapi import MongoApi from restapi import MongoApi
from flask_admin import Admin from flask_admin import Admin
""" """
Mongodb connection string Mongodb connection string
""" """
connect('adunatio', host='mongo',username="xcoder",password="4dun4710", authentication_source='admin') connect('adunatio', host='mongo', username="xcoder", password="4dun4710", authentication_source='admin')
app = Flask(__name__) app = Flask(__name__)
app.secret_key = "secret_key+secret_key" app.secret_key = "secret_key+secret_key"
api = MongoApi(app) app.config["JWT_TOKEN_LOCATION"] = "headers"
api.register_model(User,uri="/api/user") app.config["JWT_HEADER_NAME"] = "Adunation_Session_Token"
api.register_model(Union,uri="/api/union") app.config["JWT_HEADER_TYPE"] = "Bearer"
"""
flask jwt extended register
"""
jwt = JWTManager(app)
"""
flask mongorester register
"""
api = MongoApi(app, authentication_methods=[AuthJWT])
api.register_model(User, uri="/api/user")
api.register_model(Union, uri="/api/union")
"""
flask admin register
"""
adm = Admin(app) adm = Admin(app)
adm.add_view(ModelView(User)) adm.add_view(ModelView(User))
adm.add_view(ModelView(Union)) adm.add_view(ModelView(Union))
adm.add_view(ModelView(Group)) adm.add_view(ModelView(Group))
"""
login function
"""
@app.route('/auth/login', methods=['POST'])
def login():
if not request.is_json:
return jsonify({"message": "Missing JSON in request", "error": "parameter_error", "status":False}), 400
username = request.json.get('username', None)
password = request.json.get('password', None)
if not username:
return jsonify({"message": "Missing username parameter", "error": "parameter_error", "status":False}), 400
if not password:
return jsonify({"message": "Missing password parameter", "error": "parameter_error", "status":False}), 400
try:
user = User.objects.get(username=username)
except Exception as e:
app.logger.error(e)
return jsonify({"message": "Bad username or password", "error": "Unauthorized", "status": False}), 401
if not check_password_hash(user.password,password):
return jsonify({"message": "Bad username or password", "error": "Unauthorized", "status":False}), 401
# Identity can be any data that is json serializable
access_token = create_access_token(identity=str(user.id))
return jsonify(access_token=access_token,status=True), 200
if __name__ == '__main__': if __name__ == '__main__':
app.run(host="0.0.0.0",port=5000,debug=True) app.run(host="0.0.0.0", port=5000, debug=True)

@ -8,3 +8,4 @@ class Account(Document):
bank = StringField() bank = StringField()
number = StringField() number = StringField()
quick_number = StringField() quick_number = StringField()
deleted = BooleanField(default=False)

@ -7,9 +7,11 @@ class Directory(Document):
path = StringField() path = StringField()
can_see_user_group = ReferenceField(Group) can_see_user_group = ReferenceField(Group)
is_system = BooleanField(default=False) is_system = BooleanField(default=False)
deleted = BooleanField(default=False)
class File(Document): class File(Document):
path = ReferenceField(Directory) path = ReferenceField(Directory)
file = FileField() file = FileField()
description = StringField() description = StringField()
deleted = BooleanField(default=False)

@ -7,6 +7,7 @@ class Group(Document):
union = ReferenceField(Union) union = ReferenceField(Union)
name = StringField() name = StringField()
rights = ListField(StringField()) rights = ListField(StringField())
deleted = BooleanField(default=False)
def __unicode__(self): def __unicode__(self):
return "{} {}".format(self.union.name,self.name) return "{} {}".format(self.union.name,self.name)
@ -14,4 +15,8 @@ class Group(Document):
class PaymentGroup(Document): class PaymentGroup(Document):
union = ReferenceField(Union) union = ReferenceField(Union)
name = StringField() name = StringField()
deleted = BooleanField(default=False)
discount_percent = IntField() discount_percent = IntField()
def __unicode__(self):
return "{} {}".format(self.union.name, self.name)

@ -17,6 +17,7 @@ class Payments(Document):
regular = BooleanField(default=False) regular = BooleanField(default=False)
regular_type = StringField(choices=('Weekly','Monthly','Yearly')) regular_type = StringField(choices=('Weekly','Monthly','Yearly'))
price = DecimalField() price = DecimalField()
deleted = BooleanField(default=False)
description = StringField() description = StringField()
reference_no = StringField() reference_no = StringField()
file = ReferenceField(File) file = ReferenceField(File)

@ -20,13 +20,17 @@ class Union(Document):
("-name"), ("-name"),
] ]
} }
name = StringField() name = StringField(required=True)
logo = ImageField(thumbnail_size=(120, 120)) logo = ImageField(thumbnail_size=(120, 120))
description = StringField() description = StringField()
legal_registration_number = StringField() legal_registration_number = StringField(required=True)
headquarter = StringField() headquarter = StringField()
email = StringField() email = StringField(required=True)
api_key = ListField(EmbeddedDocumentField(ApiKey)) api_key = ListField(EmbeddedDocumentField(ApiKey))
deleted = BooleanField(default=False)
def __unicode__(self):
return self.name
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
super(Union, self).save(*args, **kwargs) super(Union, self).save(*args, **kwargs)
@ -42,8 +46,9 @@ class Union(Document):
user.username = "{}@root".format(self.legal_registration_number) user.username = "{}@root".format(self.legal_registration_number)
user.user_group = group user.user_group = group
user.union = self user.union = self
password = ''.join(choices(ascii_letters+digits, k=10)) from flask import current_app
print("New union password : {}".format(password)) password = ''.join(choices(ascii_letters + digits, k=10))
current_app.logger.info("New union password : {}".format(password))
user.password = generate_password_hash(password) user.password = generate_password_hash(password)
# TODO: send password via mail or sms or nothing # TODO: send password via mail or sms or nothing
user.save() user.save()

@ -1,5 +1,6 @@
from flask_jwt_extended import current_user from flask_jwt_extended import current_user
from mongoengine import * from mongoengine import *
from werkzeug.security import generate_password_hash
from internal_lib.EncryptedField import EncryptedStringField from internal_lib.EncryptedField import EncryptedStringField
from models.EmbededDocuments import Descriptions from models.EmbededDocuments import Descriptions
@ -23,28 +24,29 @@ class User(Document):
'with_sub_docs': True, 'with_sub_docs': True,
"quyery": {}, "quyery": {},
'ignore_fields': ['password'], 'ignore_fields': ['password'],
'methods': [Methods.Get, Methods.List, Methods.Create], 'methods': [Methods.Get, Methods.List, Methods.Create, Methods.Update],
"indexes": [ "indexes": [
('union'), ('union'),
('username', 'union'), ('username', 'union'),
('accept_date') ('accept_date')
] ]
} }
deleted = BooleanField(default=False)
union = ReferenceField(Union) union = ReferenceField(Union)
member_no = LongField() member_no = LongField()
username = StringField() username = StringField(required=True)
photo = ImageField(thumbnail_size=(85, 120)) photo = ImageField(thumbnail_size=(85, 120))
password = StringField() password = StringField(required=True)
name = StringField() name = StringField(required=True)
middle_name = StringField() middle_name = StringField()
last_name = StringField() last_name = StringField(required=True)
gov_id = EncryptedStringField() gov_id = EncryptedStringField(required=True)
mother_name = EncryptedStringField() mother_name = EncryptedStringField()
father_name = EncryptedStringField() father_name = EncryptedStringField()
email = EncryptedStringField() email = EncryptedStringField()
place_of_birth = EncryptedStringField() place_of_birth = EncryptedStringField()
date_of_birth = EncryptedStringField() date_of_birth = EncryptedStringField(required=True)
telephone = EncryptedStringField() telephone = EncryptedStringField(required=True)
job = StringField() job = StringField()
address = EncryptedStringField() address = EncryptedStringField()
accept_date = DateTimeField() accept_date = DateTimeField()
@ -109,7 +111,7 @@ class User(Document):
'Transsexual Person', 'Transsexual Person',
'Transsexual Woman', 'Transsexual Woman',
'Two-Spirit' 'Two-Spirit'
)) ),required=True)
custom_fields = ListField(EmbeddedDocumentField(UserCustomFields)) custom_fields = ListField(EmbeddedDocumentField(UserCustomFields))
user_group = ReferenceField(Group) user_group = ReferenceField(Group)
payment_group = ReferenceField(PaymentGroup) payment_group = ReferenceField(PaymentGroup)
@ -121,7 +123,10 @@ class User(Document):
return str(self.id) return str(self.id)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if current_user: if self.union:
self.union = current_user.union
self.member_no = User.objects.filter(union=self.union).count() self.member_no = User.objects.filter(union=self.union).count()
self.password = generate_password_hash(self.password)
super(User, self).save(*args, **kwargs) super(User, self).save(*args, **kwargs)

@ -1 +1 @@
Subproject commit b4fb234e4781092e5d8765dae527a198ab0567aa Subproject commit 70be57ef3681f723271cc05edcbc055417a578d8
Loading…
Cancel
Save