Make it possible to configure plugins.

* Reworked configuration
This commit is contained in:
Ferdinand Thiessen 2020-08-23 23:58:26 +02:00
parent a000ccfb1c
commit 32066b1005
11 changed files with 249 additions and 215 deletions

View File

@ -29,56 +29,32 @@ def create_app():
CORS(app) CORS(app)
with app.app_context(): with app.app_context():
from .system.controller import dbConfig, ldapConfig
from .system.database import db from .system.database import db
app.config['SECRET_KEY'] = '0a657b97ef546da90b2db91862ad4e29' from .system.config import configure_app, config
configure_app(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://{user}:{passwd}@{host}/{database}'.format(
user=dbConfig['user'],
passwd=dbConfig['passwd'],
host=dbConfig['URL'],
database=dbConfig['database'])
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# app.config['MYSQL_CURSORCLASS'] = 'DictCursor'
app.config['LDAP_SERVER'] = ldapConfig['URL']
app.config['LDAP_PORT'] = ldapConfig['PORT']
if ldapConfig['BIND_DN']:
app.config['LDAP_BINDDN'] = ldapConfig['BIND_DN']
else:
app.config['LDAP_BINDDN'] = ldapConfig['DN']
if ldapConfig['BIND_SECRET']:
app.config['LDAP_SECRET'] = ldapConfig['BIND_SECRET']
app.config['LDAP_USE_TLS'] = False
app.config['LDAP_USE_SSL'] = ldapConfig['SSL']
app.config['LDAP_TLS_VERSION'] = ssl.PROTOCOL_TLSv1_2
app.config['LDAP_REQUIRE_CERT'] = ssl.CERT_NONE
app.config['FORCE_ATTRIBUTE_VALUE_AS_LIST'] = True
app.config['FG_AUTH_BACKENDS'] = [
entry_point.load() for entry_point in pkg_resources.iter_entry_points('flaschengeist.auth')
]
ldap = LDAPConn(app)
db.init_app(app) db.init_app(app)
for entry_point in pkg_resources.iter_entry_points('flaschengeist.auth'):
logger.debug('Found authentification plugin: %s', entry_point.name)
if entry_point.name == config['FLASCHENGEIST']['AUTH']:
app.config['FG_AUTH_BACKEND'] = entry_point.load()()
app.config['FG_AUTH_BACKEND'].configure(config[entry_point.name] if config.has_section(entry_point.name) else None)
logger.info('Loaded authentification plugin > %s <', entry_point.name)
break
if not app.config['FG_AUTH_BACKEND']:
logger.error('No authentification plugin configured or authentification plugin not found')
logger.info('Search for plugins')
discovered_plugins = { discovered_plugins = {
entry_point.name: entry_point.load() entry_point.name: entry_point.load()
for entry_point in pkg_resources.iter_entry_points('flaschengeist.plugin') for entry_point in pkg_resources.iter_entry_points('flaschengeist.plugin')
} }
#from geruecht import routes
#from geruecht.baruser.routes import baruser
#from geruecht.finanzer.routes import finanzer
#from geruecht.user.routes import user
#from geruecht.vorstand.routes import vorstand
#from geruecht.gastro.routes import gastrouser
#from geruecht.registration_route import registration
app.logger.info("Registrate bluebrints")
for name in discovered_plugins: for name in discovered_plugins:
app.logger.info("Register plugin: %s" % name) logger.debug("Found plugin: %s", name)
app.register_blueprint(discovered_plugins[name]()) if config.get(name, 'enabled', fallback=False):
logger.info('Loaded plugin > %s <', name)
app.register_blueprint(discovered_plugins[name]())
return app return app
#app.register_blueprint(baruser) #app.register_blueprint(baruser)

View File

@ -1,22 +0,0 @@
AccessTokenLifeTime: 1800
Database:
URL:
user:
passwd:
database:
LDAP:
URL:
DN:
BIND_DN:
BIND_SECRET:
SSL:
USER_DN:
ADMIN_DN:
ADMIN_SECRET:
Mail:
URL:
port:
user:
passwd:
email:
crypt: SSL/STARTLS

View File

@ -0,0 +1,37 @@
[FLASCHENGEIST]
# Set lifetime of session (idle time until you get logged out)
AccessTokenLifetime = 1800
# Select authentification provider
AUTH = auth_plain
[DATABASE]
USER =
HOST =
PASSWD =
DATABASE =
# [LDAP]
# URL =
# PORT =
# BINDDN =
# SECRET =
# USE_SSL =
## ADMIN_DN:
## ADMIN_SECRET:
[MAIL]
URL =
PORT =
USER =
PASSWD =
MAIL =
CRYPT = SSL/STARTLS
############################
# Configuration of plugins #
############################
[geruecht]
enable = true
[schubu]
enable = false

View File

@ -1,4 +1,10 @@
class Auth(): class Auth():
def defaultConfig(self):
return None
def configure(self, config):
pass
def login(self, user, pw): def login(self, user, pw):
""" """
user User class containing at least the uid user User class containing at least the uid

View File

@ -0,0 +1,20 @@
import flaschengeist.modules as modules
from flask import current_app as app
class AuthPlain(modules.Auth):
def configure(self, config):
app.config.update(
'LDAP_SERVER' = config['URL'],
'LDAP_PORT' = config['PORT'],
'LDAP_BINDDN' = config['BINDDN'],
'LDAP_SECRET' = config['SECRET']
'LDAP_USE_SSL' = config['USE_SSL'],
'LDAP_TLS_VERSION' = ssl.PROTOCOL_TLSv1_2,
'LDAP_REQUIRE_CERT' = ssl.CERT_NONE,
'FORCE_ATTRIBUTE_VALUE_AS_LIST' = True
)
def login(self, user, password):
if not user:
return False
return False

View File

@ -0,0 +1,162 @@
import configparser
import os
from pathlib import Path
from .. import _modpath, logger
default = {
'FLASCHENGEIST': {
'AccessTokenLifeTime': 1800
},
'MAIL': {
'CRYPT': 'SSL/STARTLS'
}
}
config = configparser.ConfigParser()
config.read_dict(default)
pathes = [_modpath, Path.home()/".config"]
if 'FLASCHENGEIST_CONF' in os.environ:
pathes.append(Path(os.environ.get("FLASCHENGEIST_CONF")))
for loc in pathes:
try:
with (loc/"flaschengeist.cfg").open() as source:
config.read_file(source)
except IOError:
pass
# Always enable this buildin plugins!
config.read_dict({
'auth': {
'enabled': True
}
})
def configure_app(app):
if not config.has_option('FLASCHENGEIST', 'SECRET_KEY'):
logger.warn('No secret key was configured, please configure one for production systems!')
app.config['SECRET_KEY'] = config.get('FLASCHENGEIST', 'SECRET_KEY', fallback='0a657b97ef546da90b2db91862ad4e29')
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://{user}:{passwd}@{host}/{database}'.format(
user=config['DATABASE']['user'],
passwd=config['DATABASE']['passwd'],
host=config['DATABASE']['host'],
database=config['DATABASE']['database']
)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
#class ConifgParser():
# def __init__(self, file='config.yml'):
# self.file = file
# with open(file, 'r') as f:
# self.config = yaml.safe_load(f)
#
# if 'Database' not in self.config:
# self.__error__(
# 'Wrong Configuration for Database. You should configure databaseconfig with "URL", "user", "passwd", "database"')
# if 'URL' not in self.config['Database'] or 'user' not in self.config['Database'] or 'passwd' not in self.config['Database'] or 'database' not in self.config['Database']:
# self.__error__(
# 'Wrong Configuration for Database. You should configure databaseconfig with "URL", "user", "passwd", "database"')
#
# self.db = self.config['Database']
# logger.debug("Set Databaseconfig: {}".format(self.db))
#
# if 'LDAP' not in self.config:
# self.__error__(
# 'Wrong Configuration for LDAP. You should configure ldapconfig with "URL" and "BIND_DN"')
# if 'URL' not in self.config['LDAP'] or 'DN' not in self.config['LDAP']:
# self.__error__(
# 'Wrong Configuration for LDAP. You should configure ldapconfig with "URL" and "BIND_DN"')
# if 'PORT' not in self.config['LDAP']:
# logger.info(
# 'No Config for port in LDAP found. Set it to default: {}'.format(389))
# self.config['LDAP']['PORT'] = 389
# if 'ADMIN_DN' not in self.config['LDAP']:
# logger.info(
# 'No Config for ADMIN_DN in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(None)
# )
# self.config['LDAP']['ADMIN_DN'] = None
# if 'ADMIN_SECRET' not in self.config['LDAP']:
# logger.info(
# 'No Config for ADMIN_SECRET in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(None)
# )
# self.config['LDAP']['ADMIN_SECRET'] = None
# if 'USER_DN' not in self.config['LDAP']:
# logger.info(
# 'No Config for USER_DN in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(None)
# )
# self.config['LDAP']['USER_DN'] = None
# if 'BIND_DN' not in self.config['LDAP']:
# logger.info(
# 'No Config for BIND_DN in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(None)
# )
# self.config['LDAP']['BIND_DN'] = None
# if 'BIND_SECRET' not in self.config['LDAP']:
# logger.info(
# 'No Config for BIND_SECRET in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(None)
# )
# self.config['LDAP']['BIND_SECRET'] = None
# if 'SSL' not in self.config['LDAP']:
# logger.info(
# 'No Config for SSL in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(False)
# )
# self.config['LDAP']['SSL'] = False
# else:
# self.config['LDAP']['SSL'] = bool(self.config['LDAP']['SSL'])
# self.ldap = self.config['LDAP']
# logger.debug("Set LDAPconfig: {}".format(self.ldap))
# if 'AccessTokenLifeTime' in self.config:
# self.accessTokenLifeTime = int(self.config['AccessTokenLifeTime'])
# logger.info("Set AccessTokenLifeTime: {}".format(
# self.accessTokenLifeTime))
# else:
# self.accessTokenLifeTime = default['AccessTokenLifeTime']
# logger.info("No Config for AccessTokenLifetime found. Set it to default: {}".format(
# self.accessTokenLifeTime))
#
# if 'Mail' not in self.config:
# self.config['Mail'] = default['Mail']
# logger.info('No Conifg for Mail found. Set it to defaul: {}'.format(
# self.config['Mail']))
# if 'URL' not in self.config['Mail']:
# self.config['Mail']['URL'] = default['Mail']['URL']
# logger.info("No Config for URL in Mail found. Set it to default")
# if 'port' not in self.config['Mail']:
# self.config['Mail']['port'] = default['Mail']['port']
# logger.info("No Config for port in Mail found. Set it to default")
# else:
# self.config['Mail']['port'] = int(self.config['Mail']['port'])
# logger.info("No Conifg for port in Mail found. Set it to default")
# if 'user' not in self.config['Mail']:
# self.config['Mail']['user'] = default['Mail']['user']
# logger.info("No Config for user in Mail found. Set it to default")
# if 'passwd' not in self.config['Mail']:
# self.config['Mail']['passwd'] = default['Mail']['passwd']
# logger.info("No Config for passwd in Mail found. Set it to default")
# if 'email' not in self.config['Mail']:
# self.config['Mail']['email'] = default['Mail']['email']
# logger.info("No Config for email in Mail found. Set it to default")
# if 'crypt' not in self.config['Mail']:
# self.config['Mail']['crypt'] = default['Mail']['crypt']
# logger.info("No Config for crypt in Mail found. Set it to default")
# self.mail = self.config['Mail']
# logger.debug('Set Mailconfig: {}'.format(self.mail))
#
# def getLDAP(self):
# return self.ldap
#
# def getDatabase(self):
# return self.db
#
# def getAccessToken(self):
# return self.accessTokenLifeTime
#
# def getMail(self):
# return self.mail
#
# def __error__(self, msg):
# logger.error(msg, exc_info=True)
# sys.exit(-1)
#
#
#if __name__ == '__main__':
# ConifgParser()

View File

@ -1,135 +0,0 @@
import yaml
import sys
from flask import current_app
from werkzeug.local import LocalProxy
logger = LocalProxy(lambda: current_app.logger)
default = {
'AccessTokenLifeTime': 1800,
'Mail': {
'URL': '',
'port': 0,
'user': '',
'passwd': '',
'email': '',
'crypt': 'STARTTLS'
}
}
class ConifgParser():
def __init__(self, file='config.yml'):
self.file = file
with open(file, 'r') as f:
self.config = yaml.safe_load(f)
if 'Database' not in self.config:
self.__error__(
'Wrong Configuration for Database. You should configure databaseconfig with "URL", "user", "passwd", "database"')
if 'URL' not in self.config['Database'] or 'user' not in self.config['Database'] or 'passwd' not in self.config['Database'] or 'database' not in self.config['Database']:
self.__error__(
'Wrong Configuration for Database. You should configure databaseconfig with "URL", "user", "passwd", "database"')
self.db = self.config['Database']
logger.debug("Set Databaseconfig: {}".format(self.db))
if 'LDAP' not in self.config:
self.__error__(
'Wrong Configuration for LDAP. You should configure ldapconfig with "URL" and "BIND_DN"')
if 'URL' not in self.config['LDAP'] or 'DN' not in self.config['LDAP']:
self.__error__(
'Wrong Configuration for LDAP. You should configure ldapconfig with "URL" and "BIND_DN"')
if 'PORT' not in self.config['LDAP']:
logger.info(
'No Config for port in LDAP found. Set it to default: {}'.format(389))
self.config['LDAP']['PORT'] = 389
if 'ADMIN_DN' not in self.config['LDAP']:
logger.info(
'No Config for ADMIN_DN in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(None)
)
self.config['LDAP']['ADMIN_DN'] = None
if 'ADMIN_SECRET' not in self.config['LDAP']:
logger.info(
'No Config for ADMIN_SECRET in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(None)
)
self.config['LDAP']['ADMIN_SECRET'] = None
if 'USER_DN' not in self.config['LDAP']:
logger.info(
'No Config for USER_DN in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(None)
)
self.config['LDAP']['USER_DN'] = None
if 'BIND_DN' not in self.config['LDAP']:
logger.info(
'No Config for BIND_DN in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(None)
)
self.config['LDAP']['BIND_DN'] = None
if 'BIND_SECRET' not in self.config['LDAP']:
logger.info(
'No Config for BIND_SECRET in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(None)
)
self.config['LDAP']['BIND_SECRET'] = None
if 'SSL' not in self.config['LDAP']:
logger.info(
'No Config for SSL in LDAP found. Set it to default {}. (Maybe Password reset not working)'.format(False)
)
self.config['LDAP']['SSL'] = False
else:
self.config['LDAP']['SSL'] = bool(self.config['LDAP']['SSL'])
self.ldap = self.config['LDAP']
logger.debug("Set LDAPconfig: {}".format(self.ldap))
if 'AccessTokenLifeTime' in self.config:
self.accessTokenLifeTime = int(self.config['AccessTokenLifeTime'])
logger.info("Set AccessTokenLifeTime: {}".format(
self.accessTokenLifeTime))
else:
self.accessTokenLifeTime = default['AccessTokenLifeTime']
logger.info("No Config for AccessTokenLifetime found. Set it to default: {}".format(
self.accessTokenLifeTime))
if 'Mail' not in self.config:
self.config['Mail'] = default['Mail']
logger.info('No Conifg for Mail found. Set it to defaul: {}'.format(
self.config['Mail']))
if 'URL' not in self.config['Mail']:
self.config['Mail']['URL'] = default['Mail']['URL']
logger.info("No Config for URL in Mail found. Set it to default")
if 'port' not in self.config['Mail']:
self.config['Mail']['port'] = default['Mail']['port']
logger.info("No Config for port in Mail found. Set it to default")
else:
self.config['Mail']['port'] = int(self.config['Mail']['port'])
logger.info("No Conifg for port in Mail found. Set it to default")
if 'user' not in self.config['Mail']:
self.config['Mail']['user'] = default['Mail']['user']
logger.info("No Config for user in Mail found. Set it to default")
if 'passwd' not in self.config['Mail']:
self.config['Mail']['passwd'] = default['Mail']['passwd']
logger.info("No Config for passwd in Mail found. Set it to default")
if 'email' not in self.config['Mail']:
self.config['Mail']['email'] = default['Mail']['email']
logger.info("No Config for email in Mail found. Set it to default")
if 'crypt' not in self.config['Mail']:
self.config['Mail']['crypt'] = default['Mail']['crypt']
logger.info("No Config for crypt in Mail found. Set it to default")
self.mail = self.config['Mail']
logger.debug('Set Mailconfig: {}'.format(self.mail))
def getLDAP(self):
return self.ldap
def getDatabase(self):
return self.db
def getAccessToken(self):
return self.accessTokenLifeTime
def getMail(self):
return self.mail
def __error__(self, msg):
logger.error(msg, exc_info=True)
sys.exit(-1)
if __name__ == '__main__':
ConifgParser()

View File

@ -1,8 +1,3 @@
from ..configparser import ConifgParser
from flaschengeist import _modpath
config = ConifgParser(_modpath/'config.yml')
class Singleton(type): class Singleton(type):
_instances = {} _instances = {}
def __call__(cls, *args, **kwargs): def __call__(cls, *args, **kwargs):
@ -10,7 +5,3 @@ class Singleton(type):
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls] return cls._instances[cls]
dbConfig = config.getDatabase()
ldapConfig = config.getLDAP()
accConfig = config.getAccessToken()
mailConfig = config.getMail()

View File

@ -1,4 +1,4 @@
from .. import Singleton, mailConfig from .. import Singleton
from ...models.user import User from ...models.user import User
from datetime import datetime, timedelta from datetime import datetime, timedelta
from . import mainUserController from . import mainUserController

View File

@ -167,10 +167,8 @@ class Base:
user = User.query.filter_by(uid=username).first() user = User.query.filter_by(uid=username).first()
if user is None: if user is None:
user = User(uid=username) user = User(uid=username)
for backend in current_app.config['FG_AUTH_BACKENDS']: if current_app.config['FG_AUTH_BACKEND'].login(user, password):
b = backend() db.session.add(user)
if b.login(user, password): db.session.commit()
db.session.add(user) return user
db.session.commit()
return user
raise PermissionDenied() raise PermissionDenied()

View File

@ -16,7 +16,8 @@ setup(
'auth = flaschengeist.modules.auth:register' 'auth = flaschengeist.modules.auth:register'
], ],
'flaschengeist.auth': [ 'flaschengeist.auth': [
'plain_auth = flaschengeist.modules.auth_plain:AuthPlain' 'auth_plain = flaschengeist.modules.auth_plain:AuthPlain',
'auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP'
] ]
} }
) )