ajout gestion token et basic auth sur apikaz

This commit is contained in:
HPL 2024-08-19 23:36:49 +02:00
parent 7c52d4844b
commit 94cbbc1006
2 changed files with 331 additions and 99 deletions

View File

@ -14,6 +14,8 @@ from flask import Flask, jsonify, send_from_directory, request, abort, json, Res
from flask_mail import Mail, Message from flask_mail import Mail, Message
from flasgger import Swagger from flasgger import Swagger
from flask_restful import Api, Resource from flask_restful import Api, Resource
from flask_jwt_extended import JWTManager, create_access_token, jwt_required
from passlib.hash import sha512_crypt from passlib.hash import sha512_crypt
from unidecode import unidecode from unidecode import unidecode
from email_validator import validate_email, EmailNotValidError from email_validator import validate_email, EmailNotValidError
@ -23,6 +25,7 @@ from bs4 import BeautifulSoup
from datetime import datetime from datetime import datetime
app = Flask(__name__) app = Flask(__name__)
jwt = JWTManager(app)
api = Api(app) api = Api(app)
app.logger.setLevel(logging.DEBUG) app.logger.setLevel(logging.DEBUG)
@ -33,8 +36,41 @@ swagger = Swagger(app, template={
"title": "L'API Kaz de la mort qui tue", "title": "L'API Kaz de la mort qui tue",
"version": "0.2.0", "version": "0.2.0",
"description": "Permettre des opérations de gestion des services kaz avec des écrans Ouaib" "description": "Permettre des opérations de gestion des services kaz avec des écrans Ouaib"
} },
"tags": [
{"name": "Authentication", "description": "Auth related operations"},
{"name": "Test", "description": "pour tester des conneries"},
{"name": "Password", "description": "Gestion Mdp"},
{"name": "Paheko", "description": "Gestion Paheko"},
{"name": "Mattermost", "description": "Gestion Mattermost Authent"},
{"name": "Mattermost User", "description": "Gestion Mattermost User"},
{"name": "Mattermost Team", "description": "Gestion Mattermost Team"},
{"name": "Ldap", "description": "Gestion Ldap"},
{"name": "Cloud", "description": "Gestion Cloud Général"},
{"name": "Sympa", "description": "Gestion Sympa"},
{"name": "Quota", "description": "Gestion Quota"},
{"name": "Dns", "description": "Gestion Dns"},
{"name": "Kaz User", "description": "Gestion Kaz User"}
],
"securityDefinitions": {
"basicAuth": {
"type": "basic",
"description": "Basic Authentication with username and password"
},
"Bearer": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
"description": "JWT Authorization header using the Bearer scheme. Example: 'Bearer {token}'"
}
}
}) })
#TODO:
# check variables
# fail2ban (ou alors sur traefik)
# découper app.py en service
# quels scripts bash garder ?
#************************************************* #*************************************************
@ -47,7 +83,7 @@ swagger = Swagger(app, template={
#TODO: au lieu d'avoir les IP en dur, prendre le fichier allow_ip' #TODO: au lieu d'avoir les IP en dur, prendre le fichier allow_ip'
trusted_ips = [ trusted_ips = [
"82.64.20.246", "82.64.20.246",
"31.39.14.228", "31.39.14.228",
"51.75.112.172", "51.75.112.172",
"80.11.47.59", "80.11.47.59",
@ -58,44 +94,17 @@ trusted_ips = [
"80.67.176.91", "80.67.176.91",
"89.234.177.119", "89.234.177.119",
"78.127.1.19", "78.127.1.19",
"80.215.236.243", "80.215.236.243"
"78.117.86.68",
"80.215.236.168"
] ]
@app.before_request
def limit_remote_addr():
if request.environ['HTTP_X_FORWARDED_FOR'] not in trusted_ips:
abort(jsonify(message="Et pis quoi encore "+request.environ['HTTP_X_FORWARDED_FOR']), 400)
#************************************************* #*************************************************
@app.route('/print_env')
def print_environment():
# Crée une chaîne de caractères pour stocker les variables d'environnement
env_string = ""
# Itère sur les variables d'environnement et les ajoute à la chaîne de caractères
for key, value in os.environ.items():
env_string += f"{key}: {value}\n" + "<br>"
# Retourne la chaîne de caractères contenant les variables d'environnement
return env_string
#*************************************************
#***** DEBUT Quelques fonctions utiles ***********
#*************************************************
#pour injecter la date dans dans le contexte des template
@app.context_processor
def inject_now():
return {'now': datetime.now}
#*************************************************
#***** FIN Quelques fonctions utiles ***********
#*************************************************
#variables globales #variables globales
#*************************************************
#le secret pour générer les tokens
#app.config['JWT_SECRET_KEY'] = os.environ.get('JWT_SECRET_KEY')
app.config['JWT_SECRET_KEY'] = os.environ.get('JWT_SECRET_KEY', 'your_jwt_secret_key')
#le paheko de kaz #le paheko de kaz
paheko_ident=os.environ.get('paheko_API_USER') paheko_ident=os.environ.get('paheko_API_USER')
@ -148,12 +157,64 @@ MAIL_USERNAME=app.config['MAIL_USERNAME']
serveur_imap = os.environ.get('serveur_imap') serveur_imap = os.environ.get('serveur_imap')
mot_de_passe_mail=os.environ.get('mot_de_passe_mail') mot_de_passe_mail=os.environ.get('mot_de_passe_mail')
#*************************************************
@app.before_request
def limit_remote_addr():
if request.environ['HTTP_X_FORWARDED_FOR'] not in trusted_ips:
abort(jsonify(message="Et pis quoi encore ?"), 400)
#*************************************************
#authent mdp/pass basique
def check_auth(username, password):
return username == os.environ.get('apikaz_doc_user') and password == os.environ.get('apikaz_doc_password')
def authenticate():
return Response('tssssss.\n', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
@app.before_request
def require_basic_auth():
if request.path.startswith('/apidocs') or request.path.startswith('/print_env'):
#if request.path.startswith('/'):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
return authenticate()
#*************************************************
#DANGER: ne jamais mettre print_env en PROD
@app.route('/print_env')
def print_environment():
# Crée une chaîne de caractères pour stocker les variables d'environnement
env_string = ""
# Itère sur les variables d'environnement et les ajoute à la chaîne de caractères
for key, value in os.environ.items():
env_string += f"{key}: {value}\n" + "<br>"
# Retourne la chaîne de caractères contenant les variables d'environnement
return env_string
#*************************************************
#***** DEBUT Quelques fonctions utiles ***********
#*************************************************
#pour injecter la date dans dans le contexte des template
@app.context_processor
def inject_now():
return {'now': datetime.now}
#*************************************************
#***** FIN Quelques fonctions utiles ***********
#*************************************************
#************************************************* #*************************************************
@app.route('/favicon.ico') @app.route('/favicon.ico')
def favicon(): def favicon():
# return send_from_directory(os.path.join(app.root_path, 'static'),'favicon.ico') # return send_from_directory(os.path.join(app.root_path, 'static'),'favicon.ico')
return '', 204 return '', 204
#************************************************* #*************************************************
#la page d'accueil est vide #la page d'accueil est vide
@ -161,16 +222,51 @@ def favicon():
def silence(): def silence():
return "" return ""
#*************************************************
# obtenir un token
@app.route('/get_token', methods=['GET'])
def get_token():
"""
Get JWT token with basic auth
---
tags:
- Authentication
security:
- basicAuth: []
responses:
200:
description: Token generated successfully
schema:
type: object
properties:
access_token:
type: string
description: JWT access token
401:
description: Unauthorized
"""
auth = request.authorization
if auth and check_auth(auth.username, auth.password):
# Créez un token JWT après une authentification réussie
access_token = create_access_token(identity=auth.username)
return jsonify(access_token=access_token)
else:
return authenticate()
#************************************************* #*************************************************
#*******MDP*************************************** #*******MDP***************************************
#************************************************* #*************************************************
class Password_create(Resource): class Password_create(Resource):
@jwt_required()
def get(self): def get(self):
""" """
créer un password qui colle avec les appli kaz créer un password qui colle avec les appli kaz
--- ---
tags: tags:
- Password - Password
security:
- Bearer: []
parameters: [] parameters: []
responses: responses:
200: 200:
@ -184,7 +280,7 @@ class Password_create(Resource):
try: try:
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
new_password="_"+output.decode("utf-8")+"_" new_password="_"+output.decode("utf-8")+"_"
return new_password,200 return new_password,200
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
return e.output.decode("utf-8"), 400 return e.output.decode("utf-8"), 400
@ -196,12 +292,16 @@ api.add_resource(Password_create, '/password/create')
#************************************************* #*************************************************
class Paheko_categories(Resource): class Paheko_categories(Resource):
@jwt_required()
def get(self): def get(self):
""" """
Récupérer les catégories Paheko avec le compteur associé Récupérer les catégories Paheko avec le compteur associé
--- ---
tags: tags:
- Paheko - Paheko
security:
- Bearer: []
parameters: [] parameters: []
responses: responses:
200: 200:
@ -227,12 +327,16 @@ api.add_resource(Paheko_categories, '/paheko/user/categories')
#************************************************* #*************************************************
class Paheko_users(Resource): class Paheko_users(Resource):
@jwt_required()
def get(self,categorie): def get(self,categorie):
""" """
Afficher les membres d'une catégorie Paheko Afficher les membres d'une catégorie Paheko
--- ---
tags: tags:
- Paheko - Paheko
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: categorie name: categorie
@ -248,6 +352,9 @@ class Paheko_users(Resource):
global paheko_ident, paheko_pass, paheko_url global paheko_ident, paheko_pass, paheko_url
auth = (paheko_ident, paheko_pass) auth = (paheko_ident, paheko_pass)
if not categorie.isdigit():
return 'Id de category non valide', 400
api_url = paheko_url + '/api/user/category/'+categorie+'.json' api_url = paheko_url + '/api/user/category/'+categorie+'.json'
response = requests.get(api_url, auth=auth) response = requests.get(api_url, auth=auth)
@ -263,19 +370,23 @@ api.add_resource(Paheko_users, '/paheko/user/category/<categorie>')
#************************************************* #*************************************************
class Paheko_user(Resource): class Paheko_user(Resource):
def __init__(self): def __init__(self):
global paheko_ident, paheko_pass, paheko_url global paheko_ident, paheko_pass, paheko_url
self.paheko_ident = paheko_ident self.paheko_ident = paheko_ident
self.paheko_pass = paheko_pass self.paheko_pass = paheko_pass
self.paheko_url = paheko_url self.paheko_url = paheko_url
self.auth = (self.paheko_ident, self.paheko_pass) self.auth = (self.paheko_ident, self.paheko_pass)
@jwt_required()
def get(self,ident): def get(self,ident):
""" """
Afficher un membre de Paheko par son email kaz ou son numéro ou le non court de l'orga Afficher un membre de Paheko par son email kaz ou son numéro ou le non court de l'orga
--- ---
tags: tags:
- Paheko - Paheko
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: ident name: ident
@ -289,8 +400,10 @@ class Paheko_user(Resource):
description: N'existe pas description: N'existe pas
""" """
if '@' in ident: emailmatchregexp = re.compile(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
data = { "sql": f"select * from users where email='{ident}'" }
if emailmatchregexp.match(ident):
data = { "sql": f"select * from users where email='{ident}' or alias = '{ident}'" }
api_url = self.paheko_url + '/api/sql/' api_url = self.paheko_url + '/api/sql/'
response = requests.post(api_url, auth=self.auth, data=data) response = requests.post(api_url, auth=self.auth, data=data)
#TODO: if faut Rechercher count et vérifier que = 1 et supprimer le count=1 dans la réponse #TODO: if faut Rechercher count et vérifier que = 1 et supprimer le count=1 dans la réponse
@ -298,26 +411,35 @@ class Paheko_user(Resource):
api_url = self.paheko_url + '/api/user/'+ident api_url = self.paheko_url + '/api/user/'+ident
response = requests.get(api_url, auth=self.auth) response = requests.get(api_url, auth=self.auth)
else: else:
data = { "sql": f"select * from users where admin_orga=1 and nom_orga='{ident}'" } nomorga = re.sub(r'\W+', '', ident) # on vire les caractères non alphanumérique
data = { "sql": f"select * from users where admin_orga=1 and nom_orga='{nomorga}'" }
api_url = self.paheko_url + '/api/sql/' api_url = self.paheko_url + '/api/sql/'
response = requests.post(api_url, auth=self.auth, data=data) response = requests.post(api_url, auth=self.auth, data=data)
#TODO:if faut Rechercher count et vérifier que = 1 et supprimer le count=1 dans la réponse #TODO:if faut Rechercher count et vérifier que = 1 et supprimer le count=1 dans la réponse
if response.status_code == 200: if response.status_code == 200:
data = response.json() data = response.json()
return jsonify(data) if data["count"] == 1:
return jsonify(data["results"][0])
elif data["count"] == 0:
return "pas de résultat", 400
else:
return "Plusieurs utilisateurs correspondent ?!", 400
else: else:
#return jsonify({'error': 'La requête a échoué'}), response.status_code #return jsonify({'error': 'La requête a échoué'}), response.status_code
return "pas de résultat", response.status_code return "pas de résultat", response.status_code
#************************************************* #*************************************************
@jwt_required()
def put(self,ident,field,new_value): def put(self,ident,field,new_value):
""" """
Modifie la valeur d'un champ d'un membre paheko (ident= numéro paheko ou email kaz) Modifie la valeur d'un champ d'un membre paheko (ident= numéro paheko ou email kaz)
--- ---
tags: tags:
- Paheko - Paheko
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: ident name: ident
@ -345,7 +467,8 @@ class Paheko_user(Resource):
""" """
#récupérer le numero paheko si on fournit un email kaz #récupérer le numero paheko si on fournit un email kaz
if '@' in ident: emailmatchregexp = re.compile(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
if emailmatchregexp.match(ident):
data = { "sql": f"select id from users where email='{ident}'" } data = { "sql": f"select id from users where email='{ident}'" }
api_url = self.paheko_url + '/api/sql/' api_url = self.paheko_url + '/api/sql/'
response = requests.post(api_url, auth=self.auth, data=data) response = requests.post(api_url, auth=self.auth, data=data)
@ -361,16 +484,23 @@ class Paheko_user(Resource):
ident = data['results'][0]['id'] ident = data['results'][0]['id']
else: else:
return "pas de résultat", response.status_code return "pas de résultat", response.status_code
elif not ident.isdigit():
return "Identifiant utilisateur invalide", response.status_code
regexp = re.compile("[^a-zA-Z0-9 \\r\\n\\t" + re.escape(string.punctuation) + "]")
valeur = regexp.sub('',new_value) # mouais, il faudrait être beaucoup plus précis ici en fonction des champs qu'on accepte...
champ = re.sub(r'\W+','',field) # pas de caractères non alphanumériques ici, dans l'idéal, c'est à choisir dans une liste plutot
api_url = self.paheko_url + '/api/user/'+str(ident) api_url = self.paheko_url + '/api/user/'+str(ident)
payload = {field: new_value} payload = {champ: valeur}
response = requests.post(api_url, auth=self.auth, data=payload) response = requests.post(api_url, auth=self.auth, data=payload)
return response.json(),response.status_code return response.json(),response.status_code
#************************************************* #*************************************************
api.add_resource(Paheko_user, '/paheko/user/<ident>', endpoint='paheko_get_user', methods=['GET']) api.add_resource(Paheko_user, '/paheko/user/<ident>', endpoint='paheko_get_user', methods=['GET'])
api.add_resource(Paheko_user, '/paheko/user/<ident>/<field>/<new_value>', endpoint='paheko_maj_user', methods=['PUT']) api.add_resource(Paheko_user, '/paheko/user/<ident>/<string:field>/<string:new_value>', endpoint='paheko_maj_user', methods=['PUT'])
#************************************************* #*************************************************
@ -382,12 +512,15 @@ class Paheko_users_action(Resource):
self.paheko_pass = paheko_pass self.paheko_pass = paheko_pass
self.paheko_url = paheko_url self.paheko_url = paheko_url
@jwt_required()
def get(self, action): def get(self, action):
""" """
retourne tous les membres de paheko avec une action à mener (création du compte kaz / modification...) retourne tous les membres de paheko avec une action à mener (création du compte kaz / modification...)
--- ---
tags: tags:
- Paheko - Paheko
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: action name: action
@ -411,7 +544,7 @@ class Paheko_users_action(Resource):
else: else:
return "pas de résultat", response.status_code return "pas de résultat", response.status_code
api.add_resource(Paheko_users_action, '/paheko/users/<string:action>') api.add_resource(Paheko_users_action, '/paheko/users/<string:action>')
#************************************************* #*************************************************
#*******MATTERMOST******************************** #*******MATTERMOST********************************
@ -431,12 +564,16 @@ def Mattermost_authenticate():
#************************************************* #*************************************************
class Mattermost_message(Resource): class Mattermost_message(Resource):
@jwt_required()
def post(self,message,equipe="kaz",canal="creation-comptes"): def post(self,message,equipe="kaz",canal="creation-comptes"):
""" """
Envoyer un message dans une Equipe/Canal de MM Envoyer un message dans une Equipe/Canal de MM
--- ---
tags: tags:
- Mattermost - Mattermost
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: equipe name: equipe
@ -476,12 +613,15 @@ class Mattermost_user(Resource):
Mattermost_authenticate() Mattermost_authenticate()
#************************************************* #*************************************************
@jwt_required()
def get(self,user): def get(self,user):
""" """
Le user existe t-il sur MM ? Le user existe t-il sur MM ?
--- ---
tags: tags:
- Mattermost User - Mattermost User
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: user name: user
@ -503,13 +643,15 @@ class Mattermost_user(Resource):
return 404 # Le nom d'utilisateur n'existe pas return 404 # Le nom d'utilisateur n'existe pas
#************************************************* #*************************************************
@jwt_required()
def post(self,user,email,password): def post(self,user,email,password):
""" """
Créer un utilisateur sur MM Créer un utilisateur sur MM
--- ---
tags: tags:
- Mattermost User - Mattermost User
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: user name: user
@ -541,12 +683,15 @@ class Mattermost_user(Resource):
#************************************************* #*************************************************
@jwt_required()
def delete(self,email): def delete(self,email):
""" """
Supprimer un utilisateur sur MM Supprimer un utilisateur sur MM
--- ---
tags: tags:
- Mattermost User - Mattermost User
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -568,12 +713,16 @@ class Mattermost_user(Resource):
return e.output.decode("utf-8"), 400 return e.output.decode("utf-8"), 400
#************************************************* #*************************************************
@jwt_required()
def put(self,email,new_password): def put(self,email,new_password):
""" """
Changer un password pour un utilisateur de MM Changer un password pour un utilisateur de MM
--- ---
tags: tags:
- Mattermost User - Mattermost User
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -607,12 +756,16 @@ api.add_resource(Mattermost_user, '/mattermost/user/change/password/<string:emai
#************************************************* #*************************************************
class Mattermost_user_team(Resource): class Mattermost_user_team(Resource):
@jwt_required()
def post(self,email,equipe): def post(self,email,equipe):
""" """
Affecte un utilisateur à une équipe MM Affecte un utilisateur à une équipe MM
--- ---
tags: tags:
- Mattermost Team - Mattermost Team
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -643,12 +796,15 @@ api.add_resource(Mattermost_user_team, '/mattermost/user/team/<string:email>/<st
#************************************************* #*************************************************
class Mattermost_user_channel(Resource): class Mattermost_user_channel(Resource):
@jwt_required()
def post(self,email,equipe,canal): def post(self,email,equipe,canal):
""" """
Affecte un utilisateur à un canal MM Affecte un utilisateur à un canal MM
--- ---
tags: tags:
- Mattermost - Mattermost
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -688,12 +844,16 @@ class Mattermost_team(Resource):
Mattermost_authenticate() Mattermost_authenticate()
#************************************************* #*************************************************
@jwt_required()
def get(self): def get(self):
""" """
Lister les équipes sur MM Lister les équipes sur MM
--- ---
tags: tags:
- Mattermost Team - Mattermost Team
security:
- Bearer: []
parameters: [] parameters: []
responses: responses:
200: 200:
@ -715,12 +875,15 @@ class Mattermost_team(Resource):
return e.output.decode("utf-8"), 400 return e.output.decode("utf-8"), 400
#************************************************* #*************************************************
@jwt_required()
def post(self,equipe,email): def post(self,equipe,email):
""" """
Créer une équipe sur MM et affecter un admin si email est renseigné (set admin marche ) Créer une équipe sur MM et affecter un admin si email est renseigné (set admin marche )
--- ---
tags: tags:
- Mattermost Team - Mattermost Team
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: equipe name: equipe
@ -752,12 +915,15 @@ class Mattermost_team(Resource):
return e.output.decode("utf-8"), 400 return e.output.decode("utf-8"), 400
#************************************************* #*************************************************
@jwt_required()
def delete(self,equipe): def delete(self,equipe):
""" """
Supprimer une équipe sur MM Supprimer une équipe sur MM
--- ---
tags: tags:
- Mattermost Team - Mattermost Team
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: equipe name: equipe
@ -807,12 +973,15 @@ class Ldap_user(Resource):
allowed_fields = ['mailDeSecours', 'mailEnabled', 'nextcloudEnabled', 'mobilizonEnabled', 'agoraEnabled', 'userPassword', 'identifiantKaz', 'mailAlias', 'quota'] allowed_fields = ['mailDeSecours', 'mailEnabled', 'nextcloudEnabled', 'mobilizonEnabled', 'agoraEnabled', 'userPassword', 'identifiantKaz', 'mailAlias', 'quota']
return field in allowed_fields return field in allowed_fields
@jwt_required()
def get(self, email): def get(self, email):
""" """
Vérifier si un utilisateur avec cet email existe dans le LDAP soit comme mail principal soit comme alias Vérifier si un utilisateur avec cet email existe dans le LDAP soit comme mail principal soit comme alias
--- ---
tags: tags:
- Ldap - Ldap
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -857,13 +1026,15 @@ class Ldap_user(Resource):
#************************************************* #*************************************************
@jwt_required()
def delete(self, email): def delete(self, email):
""" """
Supprimer un utilisateur du LDAP par son adresse e-mail Supprimer un utilisateur du LDAP par son adresse e-mail
--- ---
tags: tags:
- Ldap - Ldap
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -907,13 +1078,15 @@ class Ldap_user(Resource):
#************************************************* #*************************************************
@jwt_required()
def post(self, email): def post(self, email):
""" """
Ajouter, supprimer ou modifier un champ pour l'utilisateur LDAP Ajouter, supprimer ou modifier un champ pour l'utilisateur LDAP
--- ---
tags: tags:
- Ldap - Ldap
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -1007,13 +1180,15 @@ class Ldap_user(Resource):
return str(e), 400 return str(e), 400
#************************************************* #*************************************************
@jwt_required()
def put(self, email, **kwargs): def put(self, email, **kwargs):
""" """
Créer une nouvelle entrée dans le LDAP pour un nouvel utilisateur. QUESTION: A QUOI SERVENT PRENOM/NOM/IDENT_KAZ DANS LE LDAP ? POURQUOI 3 QUOTA ? Créer une nouvelle entrée dans le LDAP pour un nouvel utilisateur. QUESTION: A QUOI SERVENT PRENOM/NOM/IDENT_KAZ DANS LE LDAP ? POURQUOI 3 QUOTA ?
--- ---
tags: tags:
- Ldap - Ldap
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -1126,12 +1301,16 @@ api.add_resource(Ldap_user, '/ldap/user/add/<string:email>', endpoint='ldap_user
#TODO: pas réussi à faire une seule classe Cloud_user avec 2 méthodes get/delete #TODO: pas réussi à faire une seule classe Cloud_user avec 2 méthodes get/delete
class Cloud_user(Resource): class Cloud_user(Resource):
@jwt_required()
def get(self, email): def get(self, email):
""" """
Existe dans le cloud général ? Existe dans le cloud général ?
--- ---
tags: tags:
- Cloud - Cloud
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -1167,6 +1346,8 @@ api.add_resource(Cloud_user, '/cloud/user/<string:email>')
#************************************************* #*************************************************
class Cloud_user_delete(Resource): class Cloud_user_delete(Resource):
@jwt_required()
def delete(self, email): def delete(self, email):
""" """
Supprime le compte dans le cloud général Supprime le compte dans le cloud général
@ -1174,6 +1355,8 @@ class Cloud_user_delete(Resource):
--- ---
tags: tags:
- Cloud - Cloud
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -1209,12 +1392,15 @@ api.add_resource(Cloud_user_delete, '/cloud/user/delete/<string:email>')
#************************************************* #*************************************************
# class Cloud_user_change(Resource): # class Cloud_user_change(Resource):
# @jwt_required()
# def put(self, email, new_password): # def put(self, email, new_password):
# """ # """
# Modifie le mot de passe d'un Utilisateur dans le cloud général: QUESTION: A PRIORI INUTILE CAR LIE AU LDAP # Modifie le mot de passe d'un Utilisateur dans le cloud général: QUESTION: A PRIORI INUTILE CAR LIE AU LDAP
# --- # ---
# tags: # tags:
# - Cloud # - Cloud
# security:
# - Bearer: []
# parameters: # parameters:
# - in: path # - in: path
# name: email # name: email
@ -1278,12 +1464,15 @@ class Sympa_user(Resource):
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
return e.output.decode("utf-8"), 400 # Retourne la sortie de la commande et un code d'erreur 400 return e.output.decode("utf-8"), 400 # Retourne la sortie de la commande et un code d'erreur 400
@jwt_required()
def post(self, email, liste): def post(self, email, liste):
""" """
Ajouter un email dans une liste sympa Ajouter un email dans une liste sympa
--- ---
tags: tags:
- Sympa - Sympa
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -1302,12 +1491,15 @@ class Sympa_user(Resource):
output, status_code = self._execute_sympa_command(email, liste, 'add') output, status_code = self._execute_sympa_command(email, liste, 'add')
return output, status_code return output, status_code
@jwt_required()
def delete(self, email, liste): def delete(self, email, liste):
""" """
Supprimer un email dans une liste sympa Supprimer un email dans une liste sympa
--- ---
tags: tags:
- Sympa - Sympa
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -1340,13 +1532,15 @@ class Quota(Resource):
# sur kazkouil.fr, j'ai modifié /etc/dovecot/conf.d/20-lmtp.conf # sur kazkouil.fr, j'ai modifié /etc/dovecot/conf.d/20-lmtp.conf
#mail_plugins = $mail_plugins sieve quota #mail_plugins = $mail_plugins sieve quota
@jwt_required()
def get(self, email): def get(self, email):
""" """
Récupérer la place prise par une BAL Récupérer la place prise par une BAL (EN COURS)
--- ---
tags: tags:
- Quota (EN COURS) - Quota
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: email name: email
@ -1402,12 +1596,15 @@ class Dns_serveurs(Resource):
self.gandi_key = gandi_key self.gandi_key = gandi_key
self.gandi_url_api = gandi_url_api self.gandi_url_api = gandi_url_api
@jwt_required()
def get(self): def get(self):
""" """
Renvoie tous les serveurs kaz de la zone dns Renvoie tous les serveurs kaz de la zone dns
--- ---
tags: tags:
- Dns - Dns
security:
- Bearer: []
responses: responses:
200: 200:
description: Succès, liste des serveurs description: Succès, liste des serveurs
@ -1440,13 +1637,15 @@ class Dns(Resource):
self.dns_serveurs_resource = Dns_serveurs() self.dns_serveurs_resource = Dns_serveurs()
#************************************************* #*************************************************
@jwt_required()
def get(self,sdomaine): def get(self,sdomaine):
""" """
Le sous-domaine existe t-il dans la zone dns avec un enreg CNAME ? Le sous-domaine existe t-il dans la zone dns avec un enreg CNAME ?
--- ---
tags: tags:
- Dns - Dns
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: sdomaine name: sdomaine
@ -1466,12 +1665,15 @@ class Dns(Resource):
#************************************************* #*************************************************
@jwt_required()
def delete(self,sdomaine): def delete(self,sdomaine):
""" """
suppression du sdomaine suppression du sdomaine
--- ---
tags: tags:
- Dns - Dns
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: sdomaine name: sdomaine
@ -1490,12 +1692,15 @@ class Dns(Resource):
#************************************************* #*************************************************
@jwt_required()
def post(self,sdomaine,serveur): def post(self,sdomaine,serveur):
""" """
Créé le sous-domaine de type CNAME qui pointe sur serveur Créé le sous-domaine de type CNAME qui pointe sur serveur
--- ---
tags: tags:
- Dns - Dns
security:
- Bearer: []
parameters: parameters:
- in: path - in: path
name: sdomaine name: sdomaine
@ -1564,12 +1769,15 @@ class Kaz_user(Resource):
#******************************************************************************************** #********************************************************************************************
@jwt_required()
def delete(self): def delete(self):
""" """
Utile pour les tests de createUser. Avant le POST de /kaz/create/users. Ça permet de supprimer/maj les comptes. Utile pour les tests de createUser. Avant le POST de /kaz/create/users. Ça permet de supprimer/maj les comptes.
--- ---
tags: tags:
- Kaz - Kaz User
security:
- Bearer: []
parameters: [] parameters: []
responses: responses:
201: 201:
@ -1608,12 +1816,15 @@ class Kaz_user(Resource):
#******************************************************************************************** #********************************************************************************************
@jwt_required()
def post(self): def post(self):
""" """
Créé un nouveau kaznaute: inscription sur MM / Cloud / email + msg sur MM + email à partir de action="a créer" sur paheko Créé un nouveau kaznaute: inscription sur MM / Cloud / email + msg sur MM + email à partir de action="a créer" sur paheko
--- ---
tags: tags:
- Kaz - Kaz User
security:
- Bearer: []
parameters: [] parameters: []
responses: responses:
201: 201:
@ -1770,12 +1981,15 @@ class Test(Resource):
#global mattermost_url, sympa_url, webmail_url, mdp_url, site_url, nc_url #global mattermost_url, sympa_url, webmail_url, mdp_url, site_url, nc_url
#******************************************************************************************** #********************************************************************************************
@jwt_required()
def get(self): def get(self):
""" """
Pour tester des conneries Pour tester des conneries: # test lançement de cmde ssh sur des serveurs distants:
--- ---
tags: tags:
- a simple test - Test
security:
- Bearer: []
parameters: [] parameters: []
responses: responses:
201: 201:
@ -1784,6 +1998,23 @@ class Test(Resource):
description: KO description: KO
""" """
#******************************************************************************************** #********************************************************************************************
# test lançcement de cmde ssh sur des serveurs distants:
# il faut au préalable que la clé publique de root du conteneur apikaz soit dans authorized key du user fabricer de la machine 163.172.94.54
# clé à créer dans le Dockerfile
# risque sécu ?
cmd="ssh -p 2201 fabricer@163.172.94.54 mkdir -p /tmp/toto"
try:
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
return "ok",200
except subprocess.CalledProcessError as e:
return e.output.decode("utf-8"), 400
#********************************************************************************************
# #***** test suppression de toutes les équipes de MM sauf KAZ # #***** test suppression de toutes les équipes de MM sauf KAZ
# res,status=self.mattermost_team_resource=Mattermost_team().get() # res,status=self.mattermost_team_resource=Mattermost_team().get()
# for equipe in res: # for equipe in res:
@ -1794,39 +2025,39 @@ class Test(Resource):
#**** test messagerie #**** test messagerie
NOM="toto" # NOM="toto"
EMAIL_SOUHAITE='f@kaz.bzh' # EMAIL_SOUHAITE='f@kaz.bzh'
PASSWORD="toto" # PASSWORD="toto"
QUOTA="1" # QUOTA="1"
ADMIN_ORGA="0" # ADMIN_ORGA="0"
#
context = { # context = {
'ADMIN_ORGA': ADMIN_ORGA, # 'ADMIN_ORGA': ADMIN_ORGA,
'NOM': NOM, # 'NOM': NOM,
'EMAIL_SOUHAITE': EMAIL_SOUHAITE, # 'EMAIL_SOUHAITE': EMAIL_SOUHAITE,
'PASSWORD': PASSWORD, # 'PASSWORD': PASSWORD,
'QUOTA': QUOTA, # 'QUOTA': QUOTA,
'URL_WEBMAIL': webmail_url, # 'URL_WEBMAIL': webmail_url,
'URL_AGORA': mattermost_url, # 'URL_AGORA': mattermost_url,
'URL_MDP': mdp_url, # 'URL_MDP': mdp_url,
'URL_LISTE': sympa_url, # 'URL_LISTE': sympa_url,
'URL_SITE': site_url, # 'URL_SITE': site_url,
'URL_CLOUD': cloud_url # 'URL_CLOUD': cloud_url
} # }
#
subject = "KAZ: confirmation d'inscription !" # subject = "KAZ: confirmation d'inscription !"
sender=app.config['MAIL_USERNAME'] # sender=app.config['MAIL_USERNAME']
reply_to = app.config['MAIL_REPLY_TO'] # reply_to = app.config['MAIL_REPLY_TO']
#
msg = Message(subject=subject, sender=sender, reply_to=reply_to, recipients=[EMAIL_SOUHAITE]) # msg = Message(subject=subject, sender=sender, reply_to=reply_to, recipients=[EMAIL_SOUHAITE])
msg.html = render_template('email_inscription.html', **context) # msg.html = render_template('email_inscription.html', **context)
#
# Parsez le contenu HTML avec BeautifulSoup # # Parsez le contenu HTML avec BeautifulSoup
soup = BeautifulSoup(msg.html, 'html.parser') # soup = BeautifulSoup(msg.html, 'html.parser')
msg.body = soup.get_text() # msg.body = soup.get_text()
#
mail.send(msg) # mail.send(msg)
return "Message envoyé!" # return "Message envoyé!"
#******************************************************************************************** #********************************************************************************************
# #**** test ms erreur # #**** test ms erreur
@ -1847,8 +2078,7 @@ class Test(Resource):
# sleep(20) # sleep(20)
# return str(lock_file), 201 # return str(lock_file), 201
api.add_resource(Test, '/atest', endpoint='atest', methods=['GET']) api.add_resource(Test, '/test', endpoint='test', methods=['GET'])
#************************************************* #*************************************************
#************************************************* #*************************************************

View File

@ -7,3 +7,5 @@ passlib
unidecode unidecode
email-validator email-validator
python-ldap python-ldap
flask-jwt-extended
BeautifulSoup4