Doc sphinx-like serveur
This commit is contained in:
parent
44e7b1a635
commit
167e988782
4 changed files with 43 additions and 41 deletions
|
@ -1,8 +1,12 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Configuration du client cranspasswords"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
#: Serveurs distants utilisables,
|
||||||
|
#: avec la commande distante à exécuter et l'username sur le serveur
|
||||||
servers = {
|
servers = {
|
||||||
'default': {
|
'default': {
|
||||||
'server_cmd': ['/usr/bin/ssh', 'vert.adm.crans.org',\
|
'server_cmd': ['/usr/bin/ssh', 'vert.adm.crans.org',\
|
||||||
|
@ -17,4 +21,3 @@ servers = {
|
||||||
# n'ayant pas le même login sur leur pc
|
# n'ayant pas le même login sur leur pc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
server
1
server
|
@ -1,2 +1,3 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# sudo-wrapper pour exécuter cranspasswords côté serveur
|
||||||
sudo /root/cranspasswords/server.py $*
|
sudo /root/cranspasswords/server.py $*
|
||||||
|
|
58
server.py
58
server.py
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
"""cranspasswords-server.py: Serveur pour cranspasswords"""
|
|
||||||
|
"""Serveur pour cranspasswords"""
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
|
@ -18,22 +19,23 @@ MYUID = pwd.getpwuid(os.getuid())[0]
|
||||||
if MYUID == 'root':
|
if MYUID == 'root':
|
||||||
MYUID = os.environ['SUDO_USER']
|
MYUID = os.environ['SUDO_USER']
|
||||||
|
|
||||||
def validate(roles,mode='r'):
|
def validate(roles, mode='r'):
|
||||||
"""Valide que l'appelant appartient bien aux roles précisés
|
"""Vérifie que l'appelant appartient bien aux roles précisés
|
||||||
Si mode mode='w', recherche un rôle en écriture
|
Si mode mode='w', recherche un rôle en écriture
|
||||||
"""
|
"""
|
||||||
for role in roles:
|
for role in roles:
|
||||||
if mode == 'w': role+='-w'
|
if mode == 'w':
|
||||||
|
role += '-w'
|
||||||
if ROLES.has_key(role) and MYUID in ROLES[role]:
|
if ROLES.has_key(role) and MYUID in ROLES[role]:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def getpath(filename,backup=False):
|
def getpath(filename, backup=False):
|
||||||
"""Récupère le chemin du fichier `filename'"""
|
"""Récupère le chemin du fichier ``filename``"""
|
||||||
return os.path.join(STORE, '%s.%s' % (filename,'bak' if backup else 'json'))
|
return os.path.join(STORE, '%s.%s' % (filename, 'bak' if backup else 'json'))
|
||||||
|
|
||||||
def writefile(filename, contents):
|
def writefile(filename, contents):
|
||||||
"""Écrit le fichier de manière sécure"""
|
"""Écrit le fichier avec les bons droits UNIX"""
|
||||||
os.umask(0077)
|
os.umask(0077)
|
||||||
f = open(filename, 'w')
|
f = open(filename, 'w')
|
||||||
f.write(contents)
|
f.write(contents)
|
||||||
|
@ -44,26 +46,22 @@ def listroles():
|
||||||
return ROLES
|
return ROLES
|
||||||
|
|
||||||
def listkeys():
|
def listkeys():
|
||||||
"""Liste les uid et les clés correspondantes"""
|
"""Liste les usernames et les (mail, fingerprint) correspondants"""
|
||||||
return KEYS
|
return KEYS
|
||||||
|
|
||||||
def listfiles():
|
def listfiles():
|
||||||
"""Liste les fichiers dans l'espace de stockage, et les roles qui peuvent y accéder"""
|
"""Liste les fichiers dans l'espace de stockage, et les roles qui peuvent y accéder"""
|
||||||
os.chdir(STORE)
|
os.chdir(STORE)
|
||||||
|
|
||||||
filenames = glob.glob('*.json')
|
|
||||||
|
|
||||||
files = {}
|
|
||||||
|
|
||||||
|
filenames = glob.glob('*.json')
|
||||||
|
files = {}
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
file_dict = json.loads(open(filename).read())
|
file_dict = json.loads(open(filename).read())
|
||||||
files[filename[:-5]] = file_dict["roles"]
|
files[filename[:-5]] = file_dict["roles"]
|
||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
def getfile(filename):
|
def getfile(filename):
|
||||||
"""Récupère le fichier `filename'"""
|
"""Récupère le fichier ``filename``"""
|
||||||
|
|
||||||
filepath = getpath(filename)
|
filepath = getpath(filename)
|
||||||
try:
|
try:
|
||||||
obj = json.loads(open(filepath).read())
|
obj = json.loads(open(filepath).read())
|
||||||
|
@ -75,19 +73,16 @@ def getfile(filename):
|
||||||
|
|
||||||
|
|
||||||
def putfile(filename):
|
def putfile(filename):
|
||||||
"""Écrit le fichier `filename' avec les données reçues sur stdin."""
|
"""Écrit le fichier ``filename`` avec les données reçues sur stdin."""
|
||||||
|
|
||||||
filepath = getpath(filename)
|
filepath = getpath(filename)
|
||||||
|
|
||||||
stdin = sys.stdin.read()
|
stdin = sys.stdin.read()
|
||||||
parsed_stdin = json.loads(stdin)
|
parsed_stdin = json.loads(stdin)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
roles = parsed_stdin['roles']
|
roles = parsed_stdin['roles']
|
||||||
contents = parsed_stdin['contents']
|
contents = parsed_stdin['contents']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
old = getfile(filename)
|
old = getfile(filename)
|
||||||
oldroles = old['roles']
|
oldroles = old['roles']
|
||||||
|
@ -98,9 +93,9 @@ def putfile(filename):
|
||||||
if not validate(oldroles,'w'):
|
if not validate(oldroles,'w'):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
notification("Modification de %s" % filename,\
|
notification("Modification de %s" % filename,
|
||||||
"Le fichier %s a été modifié par %s." %\
|
"Le fichier %s a été modifié par %s." % (filename, MYUID),
|
||||||
(filename,MYUID),filename,old)
|
filename, old)
|
||||||
|
|
||||||
|
|
||||||
writefile(filepath, json.dumps({'roles': roles, 'contents': contents}))
|
writefile(filepath, json.dumps({'roles': roles, 'contents': contents}))
|
||||||
|
@ -123,22 +118,22 @@ def rmfile(filename):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def notification(subject,corps,fname,old):
|
def backup(fname, old):
|
||||||
back = open(getpath(fname,True),'a')
|
"""Backupe l'ancienne version du fichier"""
|
||||||
|
back = open(getpath(fname, backup=True), 'a')
|
||||||
back.write(json.dumps(old))
|
back.write(json.dumps(old))
|
||||||
back.write('\n')
|
back.write('\n')
|
||||||
back.write('* %s: %s\n' % (str(datetime.datetime.now()),corps))
|
back.write('* %s: %s\n' % (str(datetime.datetime.now()),corps))
|
||||||
back.close()
|
back.close()
|
||||||
|
|
||||||
# Puis envoi du message
|
def notification(subject, corps, fname, old):
|
||||||
|
"""Envoie par mail une notification de changement de fichier"""
|
||||||
conn = smtplib.SMTP('localhost')
|
conn = smtplib.SMTP('localhost')
|
||||||
frommail = CRANSP_MAIL
|
frommail = CRANSP_MAIL
|
||||||
tomail = DEST_MAIL
|
tomail = DEST_MAIL
|
||||||
msg = MIMEMultipart(_charset="utf-8")
|
msg = MIMEMultipart(_charset="utf-8")
|
||||||
msg['Subject'] = subject
|
msg['Subject'] = subject
|
||||||
msg['X-Mailer'] = "cranspasswords"
|
msg['X-Mailer'] = "cranspasswords"
|
||||||
# me == the sender's email address
|
|
||||||
# family = the list of all recipients' email addresses
|
|
||||||
msg['From'] = CRANSP_MAIL
|
msg['From'] = CRANSP_MAIL
|
||||||
msg['To'] = DEST_MAIL
|
msg['To'] = DEST_MAIL
|
||||||
msg.preamble = "cranspasswords report"
|
msg.preamble = "cranspasswords report"
|
||||||
|
@ -167,7 +162,7 @@ if __name__ == "__main__":
|
||||||
filename = argv[1]
|
filename = argv[1]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if command == "listroles":
|
if command == "listroles":
|
||||||
print json.dumps(listroles())
|
print json.dumps(listroles())
|
||||||
elif command == "listkeys":
|
elif command == "listkeys":
|
||||||
|
@ -185,4 +180,3 @@ if __name__ == "__main__":
|
||||||
print json.dumps(rmfile(filename))
|
print json.dumps(rmfile(filename))
|
||||||
else:
|
else:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
""" Configuration Serveur de cranspasswords.
|
""" Configuration Serveur de cranspasswords.
|
||||||
Sont définis ici les utilisateurs et les rôles associés.
|
Sont définis ici les utilisateurs et les rôles associés.
|
||||||
Ce fichier est donné à titre d'exemple, mais n'est PAS
|
Ce fichier est donné à titre d'exemple, mais n'est PAS
|
||||||
|
@ -7,19 +8,19 @@ utilisé lorsque fonctionnement en mode client.
|
||||||
Dans le futur, sera remplacé par une connexion ldap.
|
Dans le futur, sera remplacé par une connexion ldap.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
#: Répertoire de stockage des mots de passe
|
||||||
STORE = '/root/cranspasswords/db/'
|
STORE = '/root/cranspasswords/db/'
|
||||||
""" Répertoire de stockage """
|
|
||||||
|
|
||||||
|
#: Ce serveur est-il read-only (on ne peut pas y modifier les mots de passe)
|
||||||
READONLY = False
|
READONLY = False
|
||||||
""" Ce serveur est-il read-only (on ne peut pas y modifier les mots de passe) """
|
|
||||||
|
|
||||||
|
#: Expéditeur du mail de notification
|
||||||
CRANSP_MAIL = "cranspasswords <root@crans.org>"
|
CRANSP_MAIL = "cranspasswords <root@crans.org>"
|
||||||
""" Expéditeur du mail de notification """
|
|
||||||
|
|
||||||
|
#: Destinataire du mail de notification
|
||||||
DEST_MAIL = "root@crans.org"
|
DEST_MAIL = "root@crans.org"
|
||||||
""" Destinataire du mail de notification """
|
|
||||||
|
|
||||||
|
|
||||||
|
#: Mapping des utilisateurs et de leurs (mail, fingerprint GPG)
|
||||||
KEYS = {
|
KEYS = {
|
||||||
'aza-vallina': ('Damien.Aza-Vallina@crans.org', None),
|
'aza-vallina': ('Damien.Aza-Vallina@crans.org', None),
|
||||||
'becue': ('becue@crans.org', '9AE04D986400E3B67528F4930D442664194974E2'),
|
'becue': ('becue@crans.org', '9AE04D986400E3B67528F4930D442664194974E2'),
|
||||||
|
@ -62,11 +63,12 @@ KEYS = {
|
||||||
'kviard': ('kviard@crans.org', None)
|
'kviard': ('kviard@crans.org', None)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Les variables suivantes sont utilisées pour définir le dictionnaire des
|
#: Les variables suivantes sont utilisées pour définir le dictionnaire des
|
||||||
# rôles.
|
#: rôles.
|
||||||
RTC=[
|
RTC=[
|
||||||
"iffrig"
|
"iffrig"
|
||||||
]
|
]
|
||||||
|
#: Liste des usernames des nounous
|
||||||
NOUNOUS=RTC+[
|
NOUNOUS=RTC+[
|
||||||
"blockelet",
|
"blockelet",
|
||||||
"becue",
|
"becue",
|
||||||
|
@ -86,12 +88,14 @@ NOUNOUS=RTC+[
|
||||||
]
|
]
|
||||||
|
|
||||||
# Autogen:
|
# Autogen:
|
||||||
|
#: Liste des usernames des apprentis
|
||||||
APPRENTIS=['grande', 'bonaque', 'moisy-mabille', 'baste', 'duplouy', 'besson', 'pvincent', 'quelennec', 'pommeret', 'guiraud', 'serrano', 'kherouf', 'randazzo', 'tilquin', 'lasseri', 'epalle', 'soret', 'gstalter', 'kviard']
|
APPRENTIS=['grande', 'bonaque', 'moisy-mabille', 'baste', 'duplouy', 'besson', 'pvincent', 'quelennec', 'pommeret', 'guiraud', 'serrano', 'kherouf', 'randazzo', 'tilquin', 'lasseri', 'epalle', 'soret', 'gstalter', 'kviard']
|
||||||
|
|
||||||
|
#: Liste des usernames des membres du CA
|
||||||
CA=[
|
CA=[
|
||||||
]
|
]
|
||||||
|
|
||||||
## Les vrais rôles !
|
#: Les roles utilisés pour savoir qui a le droit le lire/écrire quoi
|
||||||
ROLES = {
|
ROLES = {
|
||||||
"ca": CA,
|
"ca": CA,
|
||||||
"ca-w": CA,
|
"ca-w": CA,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue