213 lines
6.1 KiB
Python
213 lines
6.1 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
A simple class to manage an ACL.
|
|
"""
|
|
|
|
|
|
import os
|
|
import json
|
|
|
|
from fileCommands import DATA_PATH
|
|
from CommandException import CommandException
|
|
|
|
|
|
__author__ = "HorlogeSkynet"
|
|
__copyright__ = "Copyright 2017, ACMS"
|
|
__license__ = "GPLv3"
|
|
__status__ = "Development"
|
|
__date__ = "02/23/2017"
|
|
|
|
|
|
class AccessControlList():
|
|
|
|
"""
|
|
The only attribute (useful) in this class is the dictionary, and it is declared as a "private attribute".
|
|
|
|
The dictionary is constructed as a JSON file as below (a piece of advice: use a JSON editor):
|
|
{"groups": {"dentistes": ["Marie", "Xavier"], "chirurgien": ["Jules"], "pédiatres": ["Jules"]}, "files": {"filename_2": {"owner": "Marie", "write": ["dentistes"], "read": ["Xavier"], "execute": ["pédiatres"]}, "filename_1": {"owner": "Marie", "write": ["pédiatres", "dentistes"], "read": ["Xavier"], "execute": ["chirurgien"]}}}
|
|
|
|
During the class initialization, the dictionary is filled with data present in the backup file.
|
|
Each authorized and validated action implies the dumping of the new dictionary in the backup file (persistent data).
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.__FILE = 'Server/Data/passwd.json'
|
|
|
|
self.__data = {"groups": {}, "files": {}}
|
|
|
|
self.loadFromFile()
|
|
|
|
self.checkIntegrity()
|
|
|
|
def loadFromFile(self):
|
|
if os.path.exists(self.__FILE):
|
|
with open(self.__FILE, 'r') as file:
|
|
try:
|
|
self.__data = json.load(file)
|
|
|
|
except json.JSONDecodeError as e:
|
|
print("The backup file (\"" + self.__FILE + "\") looks corrupted (" + e.msg + ' [' + str(e.lineno) + '; ' + str(e.colno) + ']' + "). Contact an administrator.")
|
|
|
|
finally:
|
|
file.close()
|
|
|
|
def saveToFile(self):
|
|
with open(self.__FILE, 'w+') as file:
|
|
try:
|
|
json.dump(self.__data, file, ensure_ascii=False, indent='\t')
|
|
|
|
except (TypeError, json.JSONEncodeError):
|
|
print("An invalid object is present in the ACL dictionary, we\'d advise you to fix the backup in the \"" + self.__FILE + "\" file, and import it.")
|
|
|
|
finally:
|
|
file.close()
|
|
|
|
def checkIntegrity(self):
|
|
results = []
|
|
|
|
def browseFiles(path):
|
|
for file in os.listdir(path):
|
|
temp = path + file
|
|
if os.path.isdir(path + file):
|
|
results.append(temp + '/')
|
|
browseFiles(temp + '/')
|
|
|
|
else:
|
|
results.append(temp)
|
|
|
|
# Browses each file in the database and stores them into a list
|
|
browseFiles(DATA_PATH)
|
|
|
|
# Computes the symmetrical differences between the files browsed and the ones present in the ACL
|
|
differences = set(results).symmetric_difference(list(self.__data['files'].keys()))
|
|
if len(differences) != 0:
|
|
for difference in differences:
|
|
print("\nThe element \"" + difference + "\" is not present in the ACL or into the database. Please fix this difference.\n")
|
|
|
|
quit()
|
|
|
|
else:
|
|
print("\nYour database is clean ! Let\'s proceed.")
|
|
|
|
def isAllowedToOn(self, user, action, file):
|
|
try:
|
|
# This 'user' is allowed to perform this 'action' on this 'file' if: He's the owner, he has access, its group had access
|
|
if user == self.__data['files'][file]['owner'] or user in self.__data['files'][file][action] or [group in self.__data['files'][file][action] for group in getGroupsByUser(self.__data['groups'], user)].count(True) > 0:
|
|
return True
|
|
|
|
else:
|
|
return False
|
|
|
|
except:
|
|
return None
|
|
|
|
def addUserInGroup(self, user, group):
|
|
try:
|
|
if self.__data['groups'][group].count(user) == 0:
|
|
self.__data['groups'][group].append(user)
|
|
self.saveToFile()
|
|
|
|
else:
|
|
raise CommandException("This user is already in this group !")
|
|
|
|
except:
|
|
raise CommandException("Can\'t add this user into this group.")
|
|
|
|
def removeUserFromGroup(self, user, group):
|
|
try:
|
|
self.__data['groups'][group].remove(user)
|
|
self.saveToFile()
|
|
|
|
except:
|
|
raise CommandException("Can\'t remove this user from this group.")
|
|
|
|
def addFile(self, user, file, read=[], write=[], execute=[]):
|
|
if list(self.__data['files'].keys()).count(file) == 0:
|
|
# Only owner and its group (plus selected persons) can access this file
|
|
read.extend(getGroupsByUser(self.__data['groups'], user))
|
|
|
|
# Only owner (plus selected persons) can modify this file
|
|
# write.append(user) (Not mandatory, the own test is done)
|
|
|
|
# Only owner and its group (plus selected persons) can execute this file
|
|
execute.extend(getGroupsByUser(self.__data['groups'], user))
|
|
|
|
self.__data['files'][file] = {'owner': user, 'read': read, 'write': write, 'execute': execute}
|
|
|
|
self.saveToFile()
|
|
|
|
else:
|
|
raise CommandException("This file already exist !")
|
|
|
|
def deleteFile(self, user, file):
|
|
try:
|
|
del self.__data['files'][file]
|
|
self.saveToFile()
|
|
|
|
except:
|
|
raise CommandException("This file does not exist...")
|
|
|
|
def renameFile(self, user, file, newFileName):
|
|
try:
|
|
if list(self.__data['files'].keys()).count(newFileName) == 0:
|
|
self.__data['files'][newFileName] = self.__data['files'][file]
|
|
del self.__data['files'][file]
|
|
self.saveToFile()
|
|
|
|
else:
|
|
raise CommandException("A file with the new name specified already exist !")
|
|
|
|
except:
|
|
raise CommandException("An error occurred...")
|
|
|
|
def changeRightsOnFile(self, user, file, read=[], write=[], execute=[]):
|
|
try:
|
|
if user == self.__data['files'][file]['owner']:
|
|
self.__data['files'][file] = {'owner': user, 'read': read, 'write': write, 'execute': execute}
|
|
self.saveToFile()
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation !")
|
|
|
|
except:
|
|
raise CommandException("This file does not exist...")
|
|
|
|
def changeOwnOnFile(self, user, file, newUser):
|
|
try:
|
|
if user == self.__data['files'][file]['owner']:
|
|
self.__data['files'][file]['owner'] = newUser
|
|
self.saveToFile()
|
|
|
|
else:
|
|
raise CommandException("You\'re not allowed to perform this operation !")
|
|
|
|
except:
|
|
raise CommandException("This file does not exist...")
|
|
|
|
def isAdministrator(self, user):
|
|
if "administrator" in getGroupsByUser(self.__data['groups'], user):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
#################
|
|
# Miscellaneous #
|
|
#################
|
|
|
|
def getGroupsByUser(groups, user):
|
|
userGroups = []
|
|
|
|
try:
|
|
for group, members in groups.items():
|
|
if user in members:
|
|
userGroups.append(group)
|
|
|
|
except:
|
|
pass
|
|
|
|
finally:
|
|
return userGroups
|