This repository has been archived on 2023-11-03. You can view files and clone it, but cannot push or open issues or pull requests.
ACMS/src/Server/ACL.py

245 lines
7.5 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
A simple class to manage an ACL.
"""
import os
import json
from colorama import Fore
from .fileCommands import DATA_PATH
from .CommandException import CommandException
__author__ = "HorlogeSkynet"
__copyright__ = "Copyright 2017, ACMS"
__license__ = "GPLv3"
__status__ = "Production"
__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 = DATA_PATH + '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(Fore.RED + "The backup file (\"" + self.__FILE + "\") looks corrupted (" + e.msg + ' [' + str(e.lineno) + '; ' + str(e.colno) + ']' + "). Contact an administrator." + Fore.RESET)
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(Fore.RED + "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." + Fore.RESET)
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(Fore.RED + "\nThe element \"" + difference + "\" is not present in the ACL or into the database. Please fix this difference.\n" + Fore.RESET)
quit()
else:
print(Fore.GREEN + "\nYour database is clean ! Let\'s proceed.\n" + Fore.RESET)
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 self.getGroupsByUser(user)].count(True) > 0:
return True
else:
return False
except:
return None
def createGroup(self, group):
if list(self.__data['groups'].keys()).count(group) == 0:
self.__data['groups'][group] = []
self.saveToFile()
else:
raise CommandException("This group already exists !")
def removeGroup(self, group):
if list(self.__data['groups'].keys()).count(group) != 0:
if group != "administrator":
if len(self.__data['groups'][group]) == 0:
del self.__data['groups'][group]
self.saveToFile()
else:
raise CommandException("This group is not empty, you can\'t remove it.")
else:
raise CommandException("You can\'t remove this special group.")
else:
raise CommandException("This group does not exist...")
def addUserInGroup(self, user, group):
try:
if list(self.__data['groups'].keys()).count(group) != 0:
if self.__data['groups'][group].count(user) != 0:
raise CommandException("This user is already in this group !")
else:
self.__data['groups'][group].append(user)
else:
self.__data['groups'][group] = [user]
self.saveToFile()
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):
if list(self.__data['files'].keys()).count(file) == 0:
read = []
execute = []
write = []
# Only owner and its group (plus selected persons) can access this file
read.extend(self.getGroupsByUser(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(self.getGroupsByUser(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 setRightsOnFile(self, user, file, read, write, execute):
try:
if user == self.__data['files'][file]['owner'] or self.isAdministrator(user):
self.__data['files'][file] = {'owner': self.__data['files'][file]['owner'], '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 getOwnerOnFile(self, file):
if list(self.__data['files'].keys()).count(file):
return str(self.__data['files'][file]['owner'])
else:
raise CommandException("This file does not exist...")
def getRightsOnFile(self, file):
if list(self.__data['files'].keys()).count(file):
return self.__data['files'][file]['read'], self.__data['files'][file]['write'], self.__data['files'][file]['execute']
else:
raise CommandException("This file does not exist...")
def changeOwnOnFile(self, user, file, newUser):
try:
if user == self.__data['files'][file]['owner'] or self.isAdministrator(user):
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 user in self.__data['groups']['administrator']:
return True
else:
return False
# A simple function in order to gather the groups where an user is present
def getGroupsByUser(self, user):
userGroups = []
try:
for group, members in self.__data['groups'].items():
if user in members:
userGroups.append(group)
except:
pass
finally:
return userGroups