mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-12-04 19:15:30 +00:00
Allow all application settings to be configured by environment variables (#1535)
This commit is contained in:
commit
9193317d00
@ -1,151 +1,2 @@
|
||||
# import everything from environment variables
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
# Defaults for Docker image
|
||||
BIND_ADDRESS = '0.0.0.0'
|
||||
PORT = 80
|
||||
SERVER_EXTERNAL_SSL = os.getenv('SERVER_EXTERNAL_SSL', True)
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:////data/powerdns-admin.db'
|
||||
SESSION_COOKIE_SAMESITE = 'Lax'
|
||||
CSRF_COOKIE_HTTPONLY = True
|
||||
SESSION_TYPE = 'sqlalchemy'
|
||||
|
||||
legal_envvars = (
|
||||
'SECRET_KEY',
|
||||
'OIDC_OAUTH_ENABLED',
|
||||
'OIDC_OAUTH_KEY',
|
||||
'OIDC_OAUTH_SECRET',
|
||||
'OIDC_OAUTH_API_URL',
|
||||
'OIDC_OAUTH_TOKEN_URL',
|
||||
'OIDC_OAUTH_AUTHORIZE_URL',
|
||||
'OIDC_OAUTH_METADATA_URL',
|
||||
'OIDC_OAUTH_LOGOUT_URL',
|
||||
'OIDC_OAUTH_SCOPE',
|
||||
'OIDC_OAUTH_USERNAME',
|
||||
'OIDC_OAUTH_FIRSTNAME',
|
||||
'OIDC_OAUTH_LAST_NAME',
|
||||
'OIDC_OAUTH_EMAIL',
|
||||
'BIND_ADDRESS',
|
||||
'PORT',
|
||||
'SERVER_EXTERNAL_SSL',
|
||||
'LOG_LEVEL',
|
||||
'SALT',
|
||||
'SQLALCHEMY_TRACK_MODIFICATIONS',
|
||||
'SQLALCHEMY_DATABASE_URI',
|
||||
'SQLALCHEMY_ENGINE_OPTIONS',
|
||||
'MAIL_SERVER',
|
||||
'MAIL_PORT',
|
||||
'MAIL_DEBUG',
|
||||
'MAIL_USE_TLS',
|
||||
'MAIL_USE_SSL',
|
||||
'MAIL_USERNAME',
|
||||
'MAIL_PASSWORD',
|
||||
'MAIL_DEFAULT_SENDER',
|
||||
'SAML_ENABLED',
|
||||
'SAML_DEBUG',
|
||||
'SAML_PATH',
|
||||
'SAML_METADATA_URL',
|
||||
'SAML_METADATA_CACHE_LIFETIME',
|
||||
'SAML_IDP_SSO_BINDING',
|
||||
'SAML_IDP_ENTITY_ID',
|
||||
'SAML_NAMEID_FORMAT',
|
||||
'SAML_ATTRIBUTE_EMAIL',
|
||||
'SAML_ATTRIBUTE_GIVENNAME',
|
||||
'SAML_ATTRIBUTE_SURNAME',
|
||||
'SAML_ATTRIBUTE_NAME',
|
||||
'SAML_ATTRIBUTE_USERNAME',
|
||||
'SAML_ATTRIBUTE_ADMIN',
|
||||
'SAML_ATTRIBUTE_GROUP',
|
||||
'SAML_GROUP_ADMIN_NAME',
|
||||
'SAML_GROUP_TO_ACCOUNT_MAPPING',
|
||||
'SAML_ATTRIBUTE_ACCOUNT',
|
||||
'SAML_SP_ENTITY_ID',
|
||||
'SAML_SP_CONTACT_NAME',
|
||||
'SAML_SP_CONTACT_MAIL',
|
||||
'SAML_SIGN_REQUEST',
|
||||
'SAML_WANT_MESSAGE_SIGNED',
|
||||
'SAML_LOGOUT',
|
||||
'SAML_LOGOUT_URL',
|
||||
'SAML_ASSERTION_ENCRYPTED',
|
||||
'REMOTE_USER_LOGOUT_URL',
|
||||
'REMOTE_USER_COOKIES',
|
||||
'SIGNUP_ENABLED',
|
||||
'LOCAL_DB_ENABLED',
|
||||
'LDAP_ENABLED',
|
||||
'SAML_CERT',
|
||||
'SAML_KEY',
|
||||
'SESSION_TYPE',
|
||||
'SESSION_COOKIE_SECURE',
|
||||
'CSRF_COOKIE_SECURE',
|
||||
'CAPTCHA_ENABLE',
|
||||
)
|
||||
|
||||
legal_envvars_int = ('PORT', 'MAIL_PORT', 'SAML_METADATA_CACHE_LIFETIME')
|
||||
|
||||
legal_envvars_bool = (
|
||||
'SQLALCHEMY_TRACK_MODIFICATIONS',
|
||||
'HSTS_ENABLED',
|
||||
'MAIL_DEBUG',
|
||||
'MAIL_USE_TLS',
|
||||
'MAIL_USE_SSL',
|
||||
'OIDC_OAUTH_ENABLED',
|
||||
'SAML_ENABLED',
|
||||
'SAML_DEBUG',
|
||||
'SAML_SIGN_REQUEST',
|
||||
'SAML_WANT_MESSAGE_SIGNED',
|
||||
'SAML_LOGOUT',
|
||||
'SAML_ASSERTION_ENCRYPTED',
|
||||
'REMOTE_USER_ENABLED',
|
||||
'SIGNUP_ENABLED',
|
||||
'LOCAL_DB_ENABLED',
|
||||
'LDAP_ENABLED',
|
||||
'SESSION_COOKIE_SECURE',
|
||||
'CSRF_COOKIE_SECURE',
|
||||
'CAPTCHA_ENABLE',
|
||||
'SERVER_EXTERNAL_SSL',
|
||||
)
|
||||
|
||||
legal_envvars_dict = (
|
||||
'SQLALCHEMY_ENGINE_OPTIONS',
|
||||
)
|
||||
|
||||
def str2bool(v):
|
||||
return v.lower() in ("true", "yes", "1")
|
||||
|
||||
|
||||
def dictfromstr(v, ret):
|
||||
try:
|
||||
return json.loads(ret)
|
||||
except Exception as e:
|
||||
print('Cannot parse json {} for variable {}'.format(ret, v))
|
||||
print(e)
|
||||
raise ValueError
|
||||
|
||||
|
||||
for v in legal_envvars:
|
||||
|
||||
ret = None
|
||||
# _FILE suffix will allow to read value from file, useful for Docker containers.
|
||||
# secrets feature
|
||||
if v + '_FILE' in os.environ:
|
||||
if v in os.environ:
|
||||
raise AttributeError(
|
||||
"Both {} and {} are set but are exclusive.".format(
|
||||
v, v + '_FILE'))
|
||||
with open(os.environ[v + '_FILE']) as f:
|
||||
ret = f.read()
|
||||
f.close()
|
||||
|
||||
elif v in os.environ:
|
||||
ret = os.environ[v]
|
||||
|
||||
if ret is not None:
|
||||
if v in legal_envvars_bool:
|
||||
ret = str2bool(ret)
|
||||
if v in legal_envvars_int:
|
||||
ret = int(ret)
|
||||
if v in legal_envvars_dict:
|
||||
ret = dictfromstr(v, ret)
|
||||
sys.modules[__name__].__dict__[v] = ret
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:////data/powerdns-admin.db'
|
@ -4,11 +4,11 @@ from flask import Flask
|
||||
from flask_mail import Mail
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
from flask_session import Session
|
||||
|
||||
from .lib import utils
|
||||
|
||||
|
||||
def create_app(config=None):
|
||||
from powerdnsadmin.lib.settings import AppSettings
|
||||
from . import models, routes, services
|
||||
from .assets import assets
|
||||
app = Flask(__name__)
|
||||
@ -50,6 +50,9 @@ def create_app(config=None):
|
||||
elif config.endswith('.py'):
|
||||
app.config.from_pyfile(config)
|
||||
|
||||
# Load any settings defined with environment variables
|
||||
AppSettings.load_environment(app)
|
||||
|
||||
# HSTS
|
||||
if app.config.get('HSTS_ENABLED'):
|
||||
from flask_sslify import SSLify
|
||||
@ -84,7 +87,7 @@ def create_app(config=None):
|
||||
app.jinja_env.filters['format_datetime_local'] = utils.format_datetime
|
||||
app.jinja_env.filters['format_zone_type'] = utils.format_zone_type
|
||||
|
||||
# Register context proccessors
|
||||
# Register context processors
|
||||
from .models.setting import Setting
|
||||
|
||||
@app.context_processor
|
||||
|
@ -13,6 +13,7 @@ def admin_role_required(f):
|
||||
"""
|
||||
Grant access if user is in Administrator role
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if current_user.role.name != 'Administrator':
|
||||
@ -26,6 +27,7 @@ def operator_role_required(f):
|
||||
"""
|
||||
Grant access if user is in Operator role or higher
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if current_user.role.name not in ['Administrator', 'Operator']:
|
||||
@ -39,6 +41,7 @@ def history_access_required(f):
|
||||
"""
|
||||
Grant access if user is in Operator role or higher, or Users can view history
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if current_user.role.name not in [
|
||||
@ -57,6 +60,7 @@ def can_access_domain(f):
|
||||
- user is in granted Account, or
|
||||
- user is in granted Domain
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if current_user.role.name not in ['Administrator', 'Operator']:
|
||||
@ -83,10 +87,11 @@ def can_configure_dnssec(f):
|
||||
- user is in Operator role or higher, or
|
||||
- dnssec_admins_only is off
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if current_user.role.name not in [
|
||||
'Administrator', 'Operator'
|
||||
'Administrator', 'Operator'
|
||||
] and Setting().get('dnssec_admins_only'):
|
||||
abort(403)
|
||||
|
||||
@ -94,16 +99,18 @@ def can_configure_dnssec(f):
|
||||
|
||||
return decorated_function
|
||||
|
||||
|
||||
def can_remove_domain(f):
|
||||
"""
|
||||
Grant access if:
|
||||
- user is in Operator role or higher, or
|
||||
- allow_user_remove_domain is on
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if current_user.role.name not in [
|
||||
'Administrator', 'Operator'
|
||||
'Administrator', 'Operator'
|
||||
] and not Setting().get('allow_user_remove_domain'):
|
||||
abort(403)
|
||||
return f(*args, **kwargs)
|
||||
@ -111,17 +118,17 @@ def can_remove_domain(f):
|
||||
return decorated_function
|
||||
|
||||
|
||||
|
||||
def can_create_domain(f):
|
||||
"""
|
||||
Grant access if:
|
||||
- user is in Operator role or higher, or
|
||||
- allow_user_create_domain is on
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if current_user.role.name not in [
|
||||
'Administrator', 'Operator'
|
||||
'Administrator', 'Operator'
|
||||
] and not Setting().get('allow_user_create_domain'):
|
||||
abort(403)
|
||||
return f(*args, **kwargs)
|
||||
@ -144,11 +151,12 @@ def api_basic_auth(f):
|
||||
|
||||
# Remove "Basic " from the header value
|
||||
auth_header = auth_header[6:]
|
||||
auth_components = []
|
||||
|
||||
try:
|
||||
auth_header = str(base64.b64decode(auth_header), 'utf-8')
|
||||
# NK: We use auth_components here as we don't know if we'll have a :, we split it maximum 1 times to grab the
|
||||
# username, the rest of the string would be the password.
|
||||
# NK: We use auth_components here as we don't know if we'll have a colon,
|
||||
# we split it maximum 1 times to grab the username, the rest of the string would be the password.
|
||||
auth_components = auth_header.split(':', maxsplit=1)
|
||||
except (binascii.Error, UnicodeDecodeError) as e:
|
||||
current_app.logger.error(
|
||||
@ -211,16 +219,19 @@ def callback_if_request_body_contains_key(callback, http_methods=[], keys=[]):
|
||||
If request body contains one or more of specified keys, call
|
||||
:param callback
|
||||
"""
|
||||
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
check_current_http_method = not http_methods or request.method in http_methods
|
||||
if (check_current_http_method and
|
||||
set(request.get_json(force=True).keys()).intersection(set(keys))
|
||||
set(request.get_json(force=True).keys()).intersection(set(keys))
|
||||
):
|
||||
callback(*args, **kwargs)
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return decorated_function
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
@ -246,16 +257,18 @@ def api_role_can(action, roles=None, allow_self=False):
|
||||
except:
|
||||
username = None
|
||||
if (
|
||||
(current_user.role.name in roles) or
|
||||
(allow_self and user_id and current_user.id == user_id) or
|
||||
(allow_self and username and current_user.username == username)
|
||||
(current_user.role.name in roles) or
|
||||
(allow_self and user_id and current_user.id == user_id) or
|
||||
(allow_self and username and current_user.username == username)
|
||||
):
|
||||
return f(*args, **kwargs)
|
||||
msg = (
|
||||
"User {} with role {} does not have enough privileges to {}"
|
||||
).format(current_user.username, current_user.role.name, action)
|
||||
raise NotEnoughPrivileges(message=msg)
|
||||
|
||||
return decorated_function
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
@ -265,15 +278,16 @@ def api_can_create_domain(f):
|
||||
- user is in Operator role or higher, or
|
||||
- allow_user_create_domain is on
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if current_user.role.name not in [
|
||||
'Administrator', 'Operator'
|
||||
'Administrator', 'Operator'
|
||||
] and not Setting().get('allow_user_create_domain'):
|
||||
msg = "User {0} does not have enough privileges to create zone"
|
||||
current_app.logger.error(msg.format(current_user.username))
|
||||
raise NotEnoughPrivileges()
|
||||
|
||||
|
||||
if Setting().get('deny_domain_override'):
|
||||
req = request.get_json(force=True)
|
||||
domain = Domain()
|
||||
@ -294,10 +308,11 @@ def apikey_can_create_domain(f):
|
||||
- deny_domain_override is off or
|
||||
- override_domain is true (from request)
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if g.apikey.role.name not in [
|
||||
'Administrator', 'Operator'
|
||||
'Administrator', 'Operator'
|
||||
] and not Setting().get('allow_user_create_domain'):
|
||||
msg = "ApiKey #{0} does not have enough privileges to create zone"
|
||||
current_app.logger.error(msg.format(g.apikey.id))
|
||||
@ -320,20 +335,23 @@ def apikey_can_remove_domain(http_methods=[]):
|
||||
- user is in Operator role or higher, or
|
||||
- allow_user_remove_domain is on
|
||||
"""
|
||||
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
check_current_http_method = not http_methods or request.method in http_methods
|
||||
|
||||
if (check_current_http_method and
|
||||
g.apikey.role.name not in ['Administrator', 'Operator'] and
|
||||
not Setting().get('allow_user_remove_domain')
|
||||
g.apikey.role.name not in ['Administrator', 'Operator'] and
|
||||
not Setting().get('allow_user_remove_domain')
|
||||
):
|
||||
msg = "ApiKey #{0} does not have enough privileges to remove zone"
|
||||
current_app.logger.error(msg.format(g.apikey.id))
|
||||
raise NotEnoughPrivileges()
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return decorated_function
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
@ -341,6 +359,7 @@ def apikey_is_admin(f):
|
||||
"""
|
||||
Grant access if user is in Administrator role
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if g.apikey.role.name != 'Administrator':
|
||||
@ -358,6 +377,7 @@ def apikey_can_access_domain(f):
|
||||
- user has Operator role or higher, or
|
||||
- user has explicitly been granted access to domain
|
||||
"""
|
||||
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if g.apikey.role.name not in ['Administrator', 'Operator']:
|
||||
@ -382,22 +402,26 @@ def apikey_can_configure_dnssec(http_methods=[]):
|
||||
- user is in Operator role or higher, or
|
||||
- dnssec_admins_only is off
|
||||
"""
|
||||
|
||||
def decorator(f=None):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
check_current_http_method = not http_methods or request.method in http_methods
|
||||
|
||||
if (check_current_http_method and
|
||||
g.apikey.role.name not in ['Administrator', 'Operator'] and
|
||||
Setting().get('dnssec_admins_only')
|
||||
g.apikey.role.name not in ['Administrator', 'Operator'] and
|
||||
Setting().get('dnssec_admins_only')
|
||||
):
|
||||
msg = "ApiKey #{0} does not have enough privileges to configure dnssec"
|
||||
current_app.logger.error(msg.format(g.apikey.id))
|
||||
raise DomainAccessForbidden(message=msg)
|
||||
return f(*args, **kwargs) if f else None
|
||||
|
||||
return decorated_function
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def allowed_record_types(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
@ -423,6 +447,7 @@ def allowed_record_types(f):
|
||||
|
||||
return decorated_function
|
||||
|
||||
|
||||
def allowed_record_ttl(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
@ -431,12 +456,12 @@ def allowed_record_ttl(f):
|
||||
|
||||
if request.method == 'GET':
|
||||
return f(*args, **kwargs)
|
||||
|
||||
|
||||
if g.apikey.role.name in ['Administrator', 'Operator']:
|
||||
return f(*args, **kwargs)
|
||||
|
||||
allowed_ttls = Setting().get_ttl_options()
|
||||
allowed_numeric_ttls = [ ttl[0] for ttl in allowed_ttls ]
|
||||
allowed_numeric_ttls = [ttl[0] for ttl in allowed_ttls]
|
||||
content = request.get_json()
|
||||
try:
|
||||
for record in content['rrsets']:
|
||||
@ -497,6 +522,7 @@ def dyndns_login_required(f):
|
||||
|
||||
return decorated_function
|
||||
|
||||
|
||||
def apikey_or_basic_auth(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
@ -505,4 +531,5 @@ def apikey_or_basic_auth(f):
|
||||
return apikey_auth(f)(*args, **kwargs)
|
||||
else:
|
||||
return api_basic_auth(f)(*args, **kwargs)
|
||||
|
||||
return decorated_function
|
||||
|
@ -1,44 +1,32 @@
|
||||
import os
|
||||
import urllib.parse
|
||||
|
||||
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
### BASIC APP CONFIG
|
||||
SALT = '$2b$12$yLUMTIfl21FKJQpTkRQXCu'
|
||||
SECRET_KEY = 'e951e5a1f4b94151b360f47edf596dd2'
|
||||
BIND_ADDRESS = '0.0.0.0'
|
||||
PORT = 9191
|
||||
HSTS_ENABLED = False
|
||||
SERVER_EXTERNAL_SSL = os.getenv('SERVER_EXTERNAL_SSL', True)
|
||||
|
||||
SESSION_TYPE = 'sqlalchemy'
|
||||
SESSION_COOKIE_SAMESITE = 'Lax'
|
||||
CSRF_COOKIE_HTTPONLY = True
|
||||
|
||||
#CAPTCHA Config
|
||||
CAPTCHA_ENABLE = True
|
||||
CAPTCHA_LENGTH = 6
|
||||
CAPTCHA_WIDTH = 160
|
||||
CAPTCHA_HEIGHT = 60
|
||||
CAPTCHA_LENGTH = 6
|
||||
CAPTCHA_SESSION_KEY = 'captcha_image'
|
||||
|
||||
### DATABASE CONFIG
|
||||
SQLA_DB_USER = 'pda'
|
||||
SQLA_DB_PASSWORD = 'changeme'
|
||||
SQLA_DB_HOST = '127.0.0.1'
|
||||
SQLA_DB_NAME = 'pda'
|
||||
CAPTCHA_WIDTH = 160
|
||||
CSRF_COOKIE_HTTPONLY = True
|
||||
HSTS_ENABLED = False
|
||||
PORT = 9191
|
||||
SALT = '$2b$12$yLUMTIfl21FKJQpTkRQXCu'
|
||||
SAML_ASSERTION_ENCRYPTED = True
|
||||
SAML_ENABLED = False
|
||||
SECRET_KEY = 'e951e5a1f4b94151b360f47edf596dd2'
|
||||
SERVER_EXTERNAL_SSL = os.getenv('SERVER_EXTERNAL_SSL', True)
|
||||
SESSION_COOKIE_SAMESITE = 'Lax'
|
||||
SESSION_TYPE = 'sqlalchemy'
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'pdns.db')
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = True
|
||||
|
||||
### DATABASE - MySQL
|
||||
# SQLA_DB_USER = 'pda'
|
||||
# SQLA_DB_PASSWORD = 'changeme'
|
||||
# SQLA_DB_HOST = '127.0.0.1'
|
||||
# SQLA_DB_NAME = 'pda'
|
||||
# SQLALCHEMY_DATABASE_URI = 'mysql://{}:{}@{}/{}'.format(
|
||||
# urllib.parse.quote_plus(SQLA_DB_USER),
|
||||
# urllib.parse.quote_plus(SQLA_DB_PASSWORD),
|
||||
# SQLA_DB_HOST,
|
||||
# SQLA_DB_NAME
|
||||
# )
|
||||
|
||||
### DATABASE - SQLite
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'pdns.db')
|
||||
|
||||
# SAML Authnetication
|
||||
SAML_ENABLED = False
|
||||
SAML_ASSERTION_ENCRYPTED = True
|
||||
|
638
powerdnsadmin/lib/settings.py
Normal file
638
powerdnsadmin/lib/settings.py
Normal file
@ -0,0 +1,638 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
basedir = os.path.abspath(Path(os.path.dirname(__file__)).parent)
|
||||
|
||||
class AppSettings(object):
|
||||
|
||||
defaults = {
|
||||
# Flask Settings
|
||||
'bind_address': '0.0.0.0',
|
||||
'csrf_cookie_secure': False,
|
||||
'log_level': 'WARNING',
|
||||
'port': 9191,
|
||||
'salt': '$2b$12$yLUMTIfl21FKJQpTkRQXCu',
|
||||
'secret_key': 'e951e5a1f4b94151b360f47edf596dd2',
|
||||
'session_cookie_secure': False,
|
||||
'session_type': 'sqlalchemy',
|
||||
'sqlalchemy_track_modifications': True,
|
||||
'sqlalchemy_database_uri': 'sqlite:///' + os.path.join(basedir, 'pdns.db'),
|
||||
'sqlalchemy_engine_options': {},
|
||||
|
||||
# General Settings
|
||||
'captcha_enable': True,
|
||||
'captcha_height': 60,
|
||||
'captcha_length': 6,
|
||||
'captcha_session_key': 'captcha_image',
|
||||
'captcha_width': 160,
|
||||
'mail_server': 'localhost',
|
||||
'mail_port': 25,
|
||||
'mail_debug': False,
|
||||
'mail_use_ssl': False,
|
||||
'mail_use_tls': False,
|
||||
'mail_username': '',
|
||||
'mail_password': '',
|
||||
'mail_default_sender': '',
|
||||
'remote_user_enabled': False,
|
||||
'remote_user_cookies': [],
|
||||
'remote_user_logout_url': '',
|
||||
'hsts_enabled': False,
|
||||
'server_external_ssl': True,
|
||||
'maintenance': False,
|
||||
'fullscreen_layout': True,
|
||||
'record_helper': True,
|
||||
'login_ldap_first': True,
|
||||
'default_record_table_size': 15,
|
||||
'default_domain_table_size': 10,
|
||||
'auto_ptr': False,
|
||||
'record_quick_edit': True,
|
||||
'pretty_ipv6_ptr': False,
|
||||
'dnssec_admins_only': False,
|
||||
'allow_user_create_domain': False,
|
||||
'allow_user_remove_domain': False,
|
||||
'allow_user_view_history': False,
|
||||
'custom_history_header': '',
|
||||
'delete_sso_accounts': False,
|
||||
'bg_domain_updates': False,
|
||||
'enable_api_rr_history': True,
|
||||
'preserve_history': False,
|
||||
'site_name': 'PowerDNS-Admin',
|
||||
'site_url': 'http://localhost:9191',
|
||||
'session_timeout': 10,
|
||||
'warn_session_timeout': True,
|
||||
'pdns_api_url': '',
|
||||
'pdns_api_key': '',
|
||||
'pdns_api_timeout': 30,
|
||||
'pdns_version': '4.1.1',
|
||||
'verify_ssl_connections': True,
|
||||
'verify_user_email': False,
|
||||
'enforce_api_ttl': False,
|
||||
'ttl_options': '1 minute,5 minutes,30 minutes,60 minutes,24 hours',
|
||||
'otp_field_enabled': True,
|
||||
'custom_css': '',
|
||||
'otp_force': False,
|
||||
'max_history_records': 1000,
|
||||
'deny_domain_override': False,
|
||||
'account_name_extra_chars': False,
|
||||
'gravatar_enabled': False,
|
||||
'pdns_admin_log_level': 'WARNING',
|
||||
|
||||
# Local Authentication Settings
|
||||
'local_db_enabled': True,
|
||||
'signup_enabled': True,
|
||||
'pwd_enforce_characters': False,
|
||||
'pwd_min_len': 10,
|
||||
'pwd_min_lowercase': 3,
|
||||
'pwd_min_uppercase': 2,
|
||||
'pwd_min_digits': 2,
|
||||
'pwd_min_special': 1,
|
||||
'pwd_enforce_complexity': False,
|
||||
'pwd_min_complexity': 11,
|
||||
|
||||
# LDAP Authentication Settings
|
||||
'ldap_enabled': False,
|
||||
'ldap_type': 'ldap',
|
||||
'ldap_uri': '',
|
||||
'ldap_base_dn': '',
|
||||
'ldap_admin_username': '',
|
||||
'ldap_admin_password': '',
|
||||
'ldap_domain': '',
|
||||
'ldap_filter_basic': '',
|
||||
'ldap_filter_username': '',
|
||||
'ldap_filter_group': '',
|
||||
'ldap_filter_groupname': '',
|
||||
'ldap_sg_enabled': False,
|
||||
'ldap_admin_group': '',
|
||||
'ldap_operator_group': '',
|
||||
'ldap_user_group': '',
|
||||
'autoprovisioning': False,
|
||||
'autoprovisioning_attribute': '',
|
||||
'urn_value': '',
|
||||
'purge': False,
|
||||
|
||||
# Google OAuth Settings
|
||||
'google_oauth_enabled': False,
|
||||
'google_oauth_client_id': '',
|
||||
'google_oauth_client_secret': '',
|
||||
'google_oauth_scope': 'openid email profile',
|
||||
'google_base_url': 'https://www.googleapis.com/oauth2/v3/',
|
||||
'google_oauth_auto_configure': True,
|
||||
'google_oauth_metadata_url': 'https://accounts.google.com/.well-known/openid-configuration',
|
||||
'google_token_url': 'https://oauth2.googleapis.com/token',
|
||||
'google_authorize_url': 'https://accounts.google.com/o/oauth2/v2/auth',
|
||||
|
||||
# GitHub OAuth Settings
|
||||
'github_oauth_enabled': False,
|
||||
'github_oauth_key': '',
|
||||
'github_oauth_secret': '',
|
||||
'github_oauth_scope': 'email',
|
||||
'github_oauth_api_url': 'https://api.github.com/user',
|
||||
'github_oauth_auto_configure': False,
|
||||
'github_oauth_metadata_url': '',
|
||||
'github_oauth_token_url': 'https://github.com/login/oauth/access_token',
|
||||
'github_oauth_authorize_url': 'https://github.com/login/oauth/authorize',
|
||||
|
||||
# Azure OAuth Settings
|
||||
'azure_oauth_enabled': False,
|
||||
'azure_oauth_key': '',
|
||||
'azure_oauth_secret': '',
|
||||
'azure_oauth_scope': 'User.Read openid email profile',
|
||||
'azure_oauth_api_url': 'https://graph.microsoft.com/v1.0/',
|
||||
'azure_oauth_auto_configure': True,
|
||||
'azure_oauth_metadata_url': '',
|
||||
'azure_oauth_token_url': '',
|
||||
'azure_oauth_authorize_url': '',
|
||||
'azure_sg_enabled': False,
|
||||
'azure_admin_group': '',
|
||||
'azure_operator_group': '',
|
||||
'azure_user_group': '',
|
||||
'azure_group_accounts_enabled': False,
|
||||
'azure_group_accounts_name': 'displayName',
|
||||
'azure_group_accounts_name_re': '',
|
||||
'azure_group_accounts_description': 'description',
|
||||
'azure_group_accounts_description_re': '',
|
||||
|
||||
# OIDC OAuth Settings
|
||||
'oidc_oauth_enabled': False,
|
||||
'oidc_oauth_key': '',
|
||||
'oidc_oauth_secret': '',
|
||||
'oidc_oauth_scope': 'email',
|
||||
'oidc_oauth_api_url': '',
|
||||
'oidc_oauth_auto_configure': True,
|
||||
'oidc_oauth_metadata_url': '',
|
||||
'oidc_oauth_token_url': '',
|
||||
'oidc_oauth_authorize_url': '',
|
||||
'oidc_oauth_logout_url': '',
|
||||
'oidc_oauth_username': 'preferred_username',
|
||||
'oidc_oauth_email': 'email',
|
||||
'oidc_oauth_firstname': 'given_name',
|
||||
'oidc_oauth_last_name': 'family_name',
|
||||
'oidc_oauth_account_name_property': '',
|
||||
'oidc_oauth_account_description_property': '',
|
||||
|
||||
# SAML Authentication Settings
|
||||
'saml_enabled': False,
|
||||
'saml_debug': False,
|
||||
'saml_path': os.path.join(basedir, 'saml'),
|
||||
'saml_metadata_url': None,
|
||||
'saml_metadata_cache_lifetime': 1,
|
||||
'saml_idp_sso_binding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
||||
'saml_idp_entity_id': None,
|
||||
'saml_nameid_format': None,
|
||||
'saml_attribute_account': None,
|
||||
'saml_attribute_email': 'email',
|
||||
'saml_attribute_givenname': 'givenname',
|
||||
'saml_attribute_surname': 'surname',
|
||||
'saml_attribute_name': None,
|
||||
'saml_attribute_username': None,
|
||||
'saml_attribute_admin': None,
|
||||
'saml_attribute_group': None,
|
||||
'saml_group_admin_name': None,
|
||||
'saml_group_operator_name': None,
|
||||
'saml_group_to_account_mapping': None,
|
||||
'saml_sp_entity_id': None,
|
||||
'saml_sp_contact_name': None,
|
||||
'saml_sp_contact_mail': None,
|
||||
'saml_sign_request': False,
|
||||
'saml_want_message_signed': True,
|
||||
'saml_logout': True,
|
||||
'saml_logout_url': None,
|
||||
'saml_assertion_encrypted': True,
|
||||
'saml_cert': None,
|
||||
'saml_key': None,
|
||||
|
||||
# Zone Record Settings
|
||||
'forward_records_allow_edit': {
|
||||
'A': True,
|
||||
'AAAA': True,
|
||||
'AFSDB': False,
|
||||
'ALIAS': False,
|
||||
'CAA': True,
|
||||
'CERT': False,
|
||||
'CDNSKEY': False,
|
||||
'CDS': False,
|
||||
'CNAME': True,
|
||||
'DNSKEY': False,
|
||||
'DNAME': False,
|
||||
'DS': False,
|
||||
'HINFO': False,
|
||||
'KEY': False,
|
||||
'LOC': True,
|
||||
'LUA': False,
|
||||
'MX': True,
|
||||
'NAPTR': False,
|
||||
'NS': True,
|
||||
'NSEC': False,
|
||||
'NSEC3': False,
|
||||
'NSEC3PARAM': False,
|
||||
'OPENPGPKEY': False,
|
||||
'PTR': True,
|
||||
'RP': False,
|
||||
'RRSIG': False,
|
||||
'SOA': False,
|
||||
'SPF': True,
|
||||
'SSHFP': False,
|
||||
'SRV': True,
|
||||
'TKEY': False,
|
||||
'TSIG': False,
|
||||
'TLSA': False,
|
||||
'SMIMEA': False,
|
||||
'TXT': True,
|
||||
'URI': False
|
||||
},
|
||||
'reverse_records_allow_edit': {
|
||||
'A': False,
|
||||
'AAAA': False,
|
||||
'AFSDB': False,
|
||||
'ALIAS': False,
|
||||
'CAA': False,
|
||||
'CERT': False,
|
||||
'CDNSKEY': False,
|
||||
'CDS': False,
|
||||
'CNAME': False,
|
||||
'DNSKEY': False,
|
||||
'DNAME': False,
|
||||
'DS': False,
|
||||
'HINFO': False,
|
||||
'KEY': False,
|
||||
'LOC': True,
|
||||
'LUA': False,
|
||||
'MX': False,
|
||||
'NAPTR': False,
|
||||
'NS': True,
|
||||
'NSEC': False,
|
||||
'NSEC3': False,
|
||||
'NSEC3PARAM': False,
|
||||
'OPENPGPKEY': False,
|
||||
'PTR': True,
|
||||
'RP': False,
|
||||
'RRSIG': False,
|
||||
'SOA': False,
|
||||
'SPF': False,
|
||||
'SSHFP': False,
|
||||
'SRV': False,
|
||||
'TKEY': False,
|
||||
'TSIG': False,
|
||||
'TLSA': False,
|
||||
'SMIMEA': False,
|
||||
'TXT': True,
|
||||
'URI': False
|
||||
},
|
||||
}
|
||||
|
||||
types = {
|
||||
# Flask Settings
|
||||
'bind_address': str,
|
||||
'csrf_cookie_secure': bool,
|
||||
'log_level': str,
|
||||
'port': int,
|
||||
'salt': str,
|
||||
'secret_key': str,
|
||||
'session_cookie_secure': bool,
|
||||
'session_type': str,
|
||||
'sqlalchemy_track_modifications': bool,
|
||||
'sqlalchemy_database_uri': str,
|
||||
'sqlalchemy_engine_options': dict,
|
||||
|
||||
# General Settings
|
||||
'captcha_enable': bool,
|
||||
'captcha_height': int,
|
||||
'captcha_length': int,
|
||||
'captcha_session_key': str,
|
||||
'captcha_width': int,
|
||||
'mail_server': str,
|
||||
'mail_port': int,
|
||||
'mail_debug': bool,
|
||||
'mail_use_ssl': bool,
|
||||
'mail_use_tls': bool,
|
||||
'mail_username': str,
|
||||
'mail_password': str,
|
||||
'mail_default_sender': str,
|
||||
'hsts_enabled': bool,
|
||||
'remote_user_enabled': bool,
|
||||
'remote_user_cookies': list,
|
||||
'remote_user_logout_url': str,
|
||||
'maintenance': bool,
|
||||
'fullscreen_layout': bool,
|
||||
'record_helper': bool,
|
||||
'login_ldap_first': bool,
|
||||
'default_record_table_size': int,
|
||||
'default_domain_table_size': int,
|
||||
'auto_ptr': bool,
|
||||
'record_quick_edit': bool,
|
||||
'pretty_ipv6_ptr': bool,
|
||||
'dnssec_admins_only': bool,
|
||||
'allow_user_create_domain': bool,
|
||||
'allow_user_remove_domain': bool,
|
||||
'allow_user_view_history': bool,
|
||||
'custom_history_header': str,
|
||||
'delete_sso_accounts': bool,
|
||||
'bg_domain_updates': bool,
|
||||
'enable_api_rr_history': bool,
|
||||
'preserve_history': bool,
|
||||
'site_name': str,
|
||||
'site_url': str,
|
||||
'session_timeout': int,
|
||||
'warn_session_timeout': bool,
|
||||
'pdns_api_url': str,
|
||||
'pdns_api_key': str,
|
||||
'pdns_api_timeout': int,
|
||||
'pdns_version': str,
|
||||
'verify_ssl_connections': bool,
|
||||
'verify_user_email': bool,
|
||||
'enforce_api_ttl': bool,
|
||||
'ttl_options': str,
|
||||
'otp_field_enabled': bool,
|
||||
'custom_css': str,
|
||||
'otp_force': bool,
|
||||
'max_history_records': int,
|
||||
'deny_domain_override': bool,
|
||||
'account_name_extra_chars': bool,
|
||||
'gravatar_enabled': bool,
|
||||
'pdns_admin_log_level': str,
|
||||
'forward_records_allow_edit': dict,
|
||||
'reverse_records_allow_edit': dict,
|
||||
|
||||
# Local Authentication Settings
|
||||
'local_db_enabled': bool,
|
||||
'signup_enabled': bool,
|
||||
'pwd_enforce_characters': bool,
|
||||
'pwd_min_len': int,
|
||||
'pwd_min_lowercase': int,
|
||||
'pwd_min_uppercase': int,
|
||||
'pwd_min_digits': int,
|
||||
'pwd_min_special': int,
|
||||
'pwd_enforce_complexity': bool,
|
||||
'pwd_min_complexity': int,
|
||||
|
||||
# LDAP Authentication Settings
|
||||
'ldap_enabled': bool,
|
||||
'ldap_type': str,
|
||||
'ldap_uri': str,
|
||||
'ldap_base_dn': str,
|
||||
'ldap_admin_username': str,
|
||||
'ldap_admin_password': str,
|
||||
'ldap_domain': str,
|
||||
'ldap_filter_basic': str,
|
||||
'ldap_filter_username': str,
|
||||
'ldap_filter_group': str,
|
||||
'ldap_filter_groupname': str,
|
||||
'ldap_sg_enabled': bool,
|
||||
'ldap_admin_group': str,
|
||||
'ldap_operator_group': str,
|
||||
'ldap_user_group': str,
|
||||
'autoprovisioning': bool,
|
||||
'autoprovisioning_attribute': str,
|
||||
'urn_value': str,
|
||||
'purge': bool,
|
||||
|
||||
# Google OAuth Settings
|
||||
'google_oauth_enabled': bool,
|
||||
'google_oauth_client_id': str,
|
||||
'google_oauth_client_secret': str,
|
||||
'google_oauth_scope': str,
|
||||
'google_base_url': str,
|
||||
'google_oauth_auto_configure': bool,
|
||||
'google_oauth_metadata_url': str,
|
||||
'google_token_url': str,
|
||||
'google_authorize_url': str,
|
||||
|
||||
# GitHub OAuth Settings
|
||||
'github_oauth_enabled': bool,
|
||||
'github_oauth_key': str,
|
||||
'github_oauth_secret': str,
|
||||
'github_oauth_scope': str,
|
||||
'github_oauth_api_url': str,
|
||||
'github_oauth_auto_configure': bool,
|
||||
'github_oauth_metadata_url': str,
|
||||
'github_oauth_token_url': str,
|
||||
'github_oauth_authorize_url': str,
|
||||
|
||||
# Azure OAuth Settings
|
||||
'azure_oauth_enabled': bool,
|
||||
'azure_oauth_key': str,
|
||||
'azure_oauth_secret': str,
|
||||
'azure_oauth_scope': str,
|
||||
'azure_oauth_api_url': str,
|
||||
'azure_oauth_auto_configure': bool,
|
||||
'azure_oauth_metadata_url': str,
|
||||
'azure_oauth_token_url': str,
|
||||
'azure_oauth_authorize_url': str,
|
||||
'azure_sg_enabled': bool,
|
||||
'azure_admin_group': str,
|
||||
'azure_operator_group': str,
|
||||
'azure_user_group': str,
|
||||
'azure_group_accounts_enabled': bool,
|
||||
'azure_group_accounts_name': str,
|
||||
'azure_group_accounts_name_re': str,
|
||||
'azure_group_accounts_description': str,
|
||||
'azure_group_accounts_description_re': str,
|
||||
|
||||
# OIDC OAuth Settings
|
||||
'oidc_oauth_enabled': bool,
|
||||
'oidc_oauth_key': str,
|
||||
'oidc_oauth_secret': str,
|
||||
'oidc_oauth_scope': str,
|
||||
'oidc_oauth_api_url': str,
|
||||
'oidc_oauth_auto_configure': bool,
|
||||
'oidc_oauth_metadata_url': str,
|
||||
'oidc_oauth_token_url': str,
|
||||
'oidc_oauth_authorize_url': str,
|
||||
'oidc_oauth_logout_url': str,
|
||||
'oidc_oauth_username': str,
|
||||
'oidc_oauth_email': str,
|
||||
'oidc_oauth_firstname': str,
|
||||
'oidc_oauth_last_name': str,
|
||||
'oidc_oauth_account_name_property': str,
|
||||
'oidc_oauth_account_description_property': str,
|
||||
|
||||
# SAML Authentication Settings
|
||||
'saml_enabled': bool,
|
||||
'saml_debug': bool,
|
||||
'saml_path': str,
|
||||
'saml_metadata_url': str,
|
||||
'saml_metadata_cache_lifetime': int,
|
||||
'saml_idp_sso_binding': str,
|
||||
'saml_idp_entity_id': str,
|
||||
'saml_nameid_format': str,
|
||||
'saml_attribute_account': str,
|
||||
'saml_attribute_email': str,
|
||||
'saml_attribute_givenname': str,
|
||||
'saml_attribute_surname': str,
|
||||
'saml_attribute_name': str,
|
||||
'saml_attribute_username': str,
|
||||
'saml_attribute_admin': str,
|
||||
'saml_attribute_group': str,
|
||||
'saml_group_admin_name': str,
|
||||
'saml_group_operator_name': str,
|
||||
'saml_group_to_account_mapping': str,
|
||||
'saml_sp_entity_id': str,
|
||||
'saml_sp_contact_name': str,
|
||||
'saml_sp_contact_mail': str,
|
||||
'saml_sign_request': bool,
|
||||
'saml_want_message_signed': bool,
|
||||
'saml_logout': bool,
|
||||
'saml_logout_url': str,
|
||||
'saml_assertion_encrypted': bool,
|
||||
'saml_cert': str,
|
||||
'saml_key': str,
|
||||
}
|
||||
|
||||
groups = {
|
||||
'authentication': [
|
||||
# Local Authentication Settings
|
||||
'local_db_enabled',
|
||||
'signup_enabled',
|
||||
'pwd_enforce_characters',
|
||||
'pwd_min_len',
|
||||
'pwd_min_lowercase',
|
||||
'pwd_min_uppercase',
|
||||
'pwd_min_digits',
|
||||
'pwd_min_special',
|
||||
'pwd_enforce_complexity',
|
||||
'pwd_min_complexity',
|
||||
|
||||
# LDAP Authentication Settings
|
||||
'ldap_enabled',
|
||||
'ldap_type',
|
||||
'ldap_uri',
|
||||
'ldap_base_dn',
|
||||
'ldap_admin_username',
|
||||
'ldap_admin_password',
|
||||
'ldap_domain',
|
||||
'ldap_filter_basic',
|
||||
'ldap_filter_username',
|
||||
'ldap_filter_group',
|
||||
'ldap_filter_groupname',
|
||||
'ldap_sg_enabled',
|
||||
'ldap_admin_group',
|
||||
'ldap_operator_group',
|
||||
'ldap_user_group',
|
||||
'autoprovisioning',
|
||||
'autoprovisioning_attribute',
|
||||
'urn_value',
|
||||
'purge',
|
||||
|
||||
# Google OAuth Settings
|
||||
'google_oauth_enabled',
|
||||
'google_oauth_client_id',
|
||||
'google_oauth_client_secret',
|
||||
'google_oauth_scope',
|
||||
'google_base_url',
|
||||
'google_oauth_auto_configure',
|
||||
'google_oauth_metadata_url',
|
||||
'google_token_url',
|
||||
'google_authorize_url',
|
||||
|
||||
# GitHub OAuth Settings
|
||||
'github_oauth_enabled',
|
||||
'github_oauth_key',
|
||||
'github_oauth_secret',
|
||||
'github_oauth_scope',
|
||||
'github_oauth_api_url',
|
||||
'github_oauth_auto_configure',
|
||||
'github_oauth_metadata_url',
|
||||
'github_oauth_token_url',
|
||||
'github_oauth_authorize_url',
|
||||
|
||||
# Azure OAuth Settings
|
||||
'azure_oauth_enabled',
|
||||
'azure_oauth_key',
|
||||
'azure_oauth_secret',
|
||||
'azure_oauth_scope',
|
||||
'azure_oauth_api_url',
|
||||
'azure_oauth_auto_configure',
|
||||
'azure_oauth_metadata_url',
|
||||
'azure_oauth_token_url',
|
||||
'azure_oauth_authorize_url',
|
||||
'azure_sg_enabled',
|
||||
'azure_admin_group',
|
||||
'azure_operator_group',
|
||||
'azure_user_group',
|
||||
'azure_group_accounts_enabled',
|
||||
'azure_group_accounts_name',
|
||||
'azure_group_accounts_name_re',
|
||||
'azure_group_accounts_description',
|
||||
'azure_group_accounts_description_re',
|
||||
|
||||
# OIDC OAuth Settings
|
||||
'oidc_oauth_enabled',
|
||||
'oidc_oauth_key',
|
||||
'oidc_oauth_secret',
|
||||
'oidc_oauth_scope',
|
||||
'oidc_oauth_api_url',
|
||||
'oidc_oauth_auto_configure',
|
||||
'oidc_oauth_metadata_url',
|
||||
'oidc_oauth_token_url',
|
||||
'oidc_oauth_authorize_url',
|
||||
'oidc_oauth_logout_url',
|
||||
'oidc_oauth_username',
|
||||
'oidc_oauth_email',
|
||||
'oidc_oauth_firstname',
|
||||
'oidc_oauth_last_name',
|
||||
'oidc_oauth_account_name_property',
|
||||
'oidc_oauth_account_description_property',
|
||||
]
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def convert_type(name, value):
|
||||
import json
|
||||
from json import JSONDecodeError
|
||||
if name in AppSettings.types:
|
||||
var_type = AppSettings.types[name]
|
||||
|
||||
# Handle boolean values
|
||||
if var_type == bool and isinstance(value, str):
|
||||
if value.lower() in ['True', 'true', '1'] or value is True:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# Handle float values
|
||||
if var_type == float:
|
||||
return float(value)
|
||||
|
||||
# Handle integer values
|
||||
if var_type == int:
|
||||
return int(value)
|
||||
|
||||
if (var_type == dict or var_type == list) and isinstance(value, str) and len(value) > 0:
|
||||
try:
|
||||
return json.loads(value)
|
||||
except JSONDecodeError as e:
|
||||
# Provide backwards compatibility for legacy non-JSON format
|
||||
value = value.replace("'", '"').replace('True', 'true').replace('False', 'false')
|
||||
try:
|
||||
return json.loads(value)
|
||||
except JSONDecodeError as e:
|
||||
raise ValueError('Cannot parse json {} for variable {}'.format(value, name))
|
||||
|
||||
if var_type == str:
|
||||
return str(value)
|
||||
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def load_environment(app):
|
||||
""" Load app settings from environment variables when defined. """
|
||||
import os
|
||||
|
||||
for var_name, default_value in AppSettings.defaults.items():
|
||||
env_name = var_name.upper()
|
||||
current_value = None
|
||||
|
||||
if env_name + '_FILE' in os.environ:
|
||||
if env_name in os.environ:
|
||||
raise AttributeError(
|
||||
"Both {} and {} are set but are exclusive.".format(
|
||||
env_name, env_name + '_FILE'))
|
||||
with open(os.environ[env_name + '_FILE']) as f:
|
||||
current_value = f.read()
|
||||
f.close()
|
||||
|
||||
elif env_name in os.environ:
|
||||
current_value = os.environ[env_name]
|
||||
|
||||
if current_value is not None:
|
||||
app.config[env_name] = AppSettings.convert_type(var_name, current_value)
|
@ -1,450 +1,19 @@
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
import pytimeparse
|
||||
from ast import literal_eval
|
||||
from distutils.util import strtobool
|
||||
from flask import current_app
|
||||
|
||||
from .base import db
|
||||
from powerdnsadmin.lib.settings import AppSettings
|
||||
|
||||
|
||||
class Setting(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(64), unique=True, index=True)
|
||||
value = db.Column(db.Text())
|
||||
|
||||
types = {
|
||||
'maintenance': bool,
|
||||
'fullscreen_layout': bool,
|
||||
'record_helper': bool,
|
||||
'login_ldap_first': bool,
|
||||
'default_record_table_size': int,
|
||||
'default_domain_table_size': int,
|
||||
'auto_ptr': bool,
|
||||
'record_quick_edit': bool,
|
||||
'pretty_ipv6_ptr': bool,
|
||||
'dnssec_admins_only': bool,
|
||||
'allow_user_create_domain': bool,
|
||||
'allow_user_remove_domain': bool,
|
||||
'allow_user_view_history': bool,
|
||||
'custom_history_header': str,
|
||||
'delete_sso_accounts': bool,
|
||||
'bg_domain_updates': bool,
|
||||
'enable_api_rr_history': bool,
|
||||
'preserve_history': bool,
|
||||
'site_name': str,
|
||||
'site_url': str,
|
||||
'session_timeout': int,
|
||||
'warn_session_timeout': bool,
|
||||
'pdns_api_url': str,
|
||||
'pdns_api_key': str,
|
||||
'pdns_api_timeout': int,
|
||||
'pdns_version': str,
|
||||
'verify_ssl_connections': bool,
|
||||
'verify_user_email': bool,
|
||||
'enforce_api_ttl': bool,
|
||||
'ttl_options': str,
|
||||
'otp_field_enabled': bool,
|
||||
'custom_css': str,
|
||||
'otp_force': bool,
|
||||
'max_history_records': int,
|
||||
'deny_domain_override': bool,
|
||||
'account_name_extra_chars': bool,
|
||||
'gravatar_enabled': bool,
|
||||
'forward_records_allow_edit': dict,
|
||||
'reverse_records_allow_edit': dict,
|
||||
'local_db_enabled': bool,
|
||||
'signup_enabled': bool,
|
||||
'pwd_enforce_characters': bool,
|
||||
'pwd_min_len': int,
|
||||
'pwd_min_lowercase': int,
|
||||
'pwd_min_uppercase': int,
|
||||
'pwd_min_digits': int,
|
||||
'pwd_min_special': int,
|
||||
'pwd_enforce_complexity': bool,
|
||||
'pwd_min_complexity': int,
|
||||
'ldap_enabled': bool,
|
||||
'ldap_type': str,
|
||||
'ldap_uri': str,
|
||||
'ldap_base_dn': str,
|
||||
'ldap_admin_username': str,
|
||||
'ldap_admin_password': str,
|
||||
'ldap_domain': str,
|
||||
'ldap_filter_basic': str,
|
||||
'ldap_filter_username': str,
|
||||
'ldap_filter_group': str,
|
||||
'ldap_filter_groupname': str,
|
||||
'ldap_sg_enabled': bool,
|
||||
'ldap_admin_group': str,
|
||||
'ldap_operator_group': str,
|
||||
'ldap_user_group': str,
|
||||
'autoprovisioning': bool,
|
||||
'autoprovisioning_attribute': str,
|
||||
'urn_value': str,
|
||||
'purge': bool,
|
||||
'google_oauth_enabled': bool,
|
||||
'google_oauth_client_id': str,
|
||||
'google_oauth_client_secret': str,
|
||||
'google_oauth_scope': str,
|
||||
'google_base_url': str,
|
||||
'google_oauth_auto_configure': bool,
|
||||
'google_oauth_metadata_url': str,
|
||||
'google_token_url': str,
|
||||
'google_authorize_url': str,
|
||||
'github_oauth_enabled': bool,
|
||||
'github_oauth_key': str,
|
||||
'github_oauth_secret': str,
|
||||
'github_oauth_scope': str,
|
||||
'github_oauth_api_url': str,
|
||||
'github_oauth_auto_configure': bool,
|
||||
'github_oauth_metadata_url': str,
|
||||
'github_oauth_token_url': str,
|
||||
'github_oauth_authorize_url': str,
|
||||
'azure_oauth_enabled': bool,
|
||||
'azure_oauth_key': str,
|
||||
'azure_oauth_secret': str,
|
||||
'azure_oauth_scope': str,
|
||||
'azure_oauth_api_url': str,
|
||||
'azure_oauth_auto_configure': bool,
|
||||
'azure_oauth_metadata_url': str,
|
||||
'azure_oauth_token_url': str,
|
||||
'azure_oauth_authorize_url': str,
|
||||
'azure_sg_enabled': bool,
|
||||
'azure_admin_group': str,
|
||||
'azure_operator_group': str,
|
||||
'azure_user_group': str,
|
||||
'azure_group_accounts_enabled': bool,
|
||||
'azure_group_accounts_name': str,
|
||||
'azure_group_accounts_name_re': str,
|
||||
'azure_group_accounts_description': str,
|
||||
'azure_group_accounts_description_re': str,
|
||||
'oidc_oauth_enabled': bool,
|
||||
'oidc_oauth_key': str,
|
||||
'oidc_oauth_secret': str,
|
||||
'oidc_oauth_scope': str,
|
||||
'oidc_oauth_api_url': str,
|
||||
'oidc_oauth_auto_configure': bool,
|
||||
'oidc_oauth_metadata_url': str,
|
||||
'oidc_oauth_token_url': str,
|
||||
'oidc_oauth_authorize_url': str,
|
||||
'oidc_oauth_logout_url': str,
|
||||
'oidc_oauth_username': str,
|
||||
'oidc_oauth_email': str,
|
||||
'oidc_oauth_firstname': str,
|
||||
'oidc_oauth_last_name': str,
|
||||
'oidc_oauth_account_name_property': str,
|
||||
'oidc_oauth_account_description_property': str,
|
||||
}
|
||||
|
||||
defaults = {
|
||||
# General Settings
|
||||
'maintenance': False,
|
||||
'fullscreen_layout': True,
|
||||
'record_helper': True,
|
||||
'login_ldap_first': True,
|
||||
'default_record_table_size': 15,
|
||||
'default_domain_table_size': 10,
|
||||
'auto_ptr': False,
|
||||
'record_quick_edit': True,
|
||||
'pretty_ipv6_ptr': False,
|
||||
'dnssec_admins_only': False,
|
||||
'allow_user_create_domain': False,
|
||||
'allow_user_remove_domain': False,
|
||||
'allow_user_view_history': False,
|
||||
'custom_history_header': '',
|
||||
'delete_sso_accounts': False,
|
||||
'bg_domain_updates': False,
|
||||
'enable_api_rr_history': True,
|
||||
'preserve_history': False,
|
||||
'site_name': 'PowerDNS-Admin',
|
||||
'site_url': 'http://localhost:9191',
|
||||
'session_timeout': 10,
|
||||
'warn_session_timeout': True,
|
||||
'pdns_api_url': '',
|
||||
'pdns_api_key': '',
|
||||
'pdns_api_timeout': 30,
|
||||
'pdns_version': '4.1.1',
|
||||
'verify_ssl_connections': True,
|
||||
'verify_user_email': False,
|
||||
'enforce_api_ttl': False,
|
||||
'ttl_options': '1 minute,5 minutes,30 minutes,60 minutes,24 hours',
|
||||
'otp_field_enabled': True,
|
||||
'custom_css': '',
|
||||
'otp_force': False,
|
||||
'max_history_records': 1000,
|
||||
'deny_domain_override': False,
|
||||
'account_name_extra_chars': False,
|
||||
'gravatar_enabled': False,
|
||||
|
||||
# Local Authentication Settings
|
||||
'local_db_enabled': True,
|
||||
'signup_enabled': True,
|
||||
'pwd_enforce_characters': False,
|
||||
'pwd_min_len': 10,
|
||||
'pwd_min_lowercase': 3,
|
||||
'pwd_min_uppercase': 2,
|
||||
'pwd_min_digits': 2,
|
||||
'pwd_min_special': 1,
|
||||
'pwd_enforce_complexity': False,
|
||||
'pwd_min_complexity': 11,
|
||||
|
||||
# LDAP Authentication Settings
|
||||
'ldap_enabled': False,
|
||||
'ldap_type': 'ldap',
|
||||
'ldap_uri': '',
|
||||
'ldap_base_dn': '',
|
||||
'ldap_admin_username': '',
|
||||
'ldap_admin_password': '',
|
||||
'ldap_domain': '',
|
||||
'ldap_filter_basic': '',
|
||||
'ldap_filter_username': '',
|
||||
'ldap_filter_group': '',
|
||||
'ldap_filter_groupname': '',
|
||||
'ldap_sg_enabled': False,
|
||||
'ldap_admin_group': '',
|
||||
'ldap_operator_group': '',
|
||||
'ldap_user_group': '',
|
||||
'autoprovisioning': False,
|
||||
'autoprovisioning_attribute': '',
|
||||
'urn_value': '',
|
||||
'purge': False,
|
||||
|
||||
# Google OAuth2 Settings
|
||||
'google_oauth_enabled': False,
|
||||
'google_oauth_client_id': '',
|
||||
'google_oauth_client_secret': '',
|
||||
'google_oauth_scope': 'openid email profile',
|
||||
'google_base_url': 'https://www.googleapis.com/oauth2/v3/',
|
||||
'google_oauth_auto_configure': True,
|
||||
'google_oauth_metadata_url': 'https://accounts.google.com/.well-known/openid-configuration',
|
||||
'google_token_url': 'https://oauth2.googleapis.com/token',
|
||||
'google_authorize_url': 'https://accounts.google.com/o/oauth2/v2/auth',
|
||||
|
||||
# GitHub OAuth2 Settings
|
||||
'github_oauth_enabled': False,
|
||||
'github_oauth_key': '',
|
||||
'github_oauth_secret': '',
|
||||
'github_oauth_scope': 'email',
|
||||
'github_oauth_api_url': 'https://api.github.com/user',
|
||||
'github_oauth_auto_configure': False,
|
||||
'github_oauth_metadata_url': '',
|
||||
'github_oauth_token_url': 'https://github.com/login/oauth/access_token',
|
||||
'github_oauth_authorize_url': 'https://github.com/login/oauth/authorize',
|
||||
|
||||
# Azure OAuth2 Settings
|
||||
'azure_oauth_enabled': False,
|
||||
'azure_oauth_key': '',
|
||||
'azure_oauth_secret': '',
|
||||
'azure_oauth_scope': 'User.Read openid email profile',
|
||||
'azure_oauth_api_url': 'https://graph.microsoft.com/v1.0/',
|
||||
'azure_oauth_auto_configure': True,
|
||||
'azure_oauth_metadata_url': '',
|
||||
'azure_oauth_token_url': '',
|
||||
'azure_oauth_authorize_url': '',
|
||||
'azure_sg_enabled': False,
|
||||
'azure_admin_group': '',
|
||||
'azure_operator_group': '',
|
||||
'azure_user_group': '',
|
||||
'azure_group_accounts_enabled': False,
|
||||
'azure_group_accounts_name': 'displayName',
|
||||
'azure_group_accounts_name_re': '',
|
||||
'azure_group_accounts_description': 'description',
|
||||
'azure_group_accounts_description_re': '',
|
||||
|
||||
# OIDC OAuth2 Settings
|
||||
'oidc_oauth_enabled': False,
|
||||
'oidc_oauth_key': '',
|
||||
'oidc_oauth_secret': '',
|
||||
'oidc_oauth_scope': 'email',
|
||||
'oidc_oauth_api_url': '',
|
||||
'oidc_oauth_auto_configure': True,
|
||||
'oidc_oauth_metadata_url': '',
|
||||
'oidc_oauth_token_url': '',
|
||||
'oidc_oauth_authorize_url': '',
|
||||
'oidc_oauth_logout_url': '',
|
||||
'oidc_oauth_username': 'preferred_username',
|
||||
'oidc_oauth_email': 'email',
|
||||
'oidc_oauth_firstname': 'given_name',
|
||||
'oidc_oauth_last_name': 'family_name',
|
||||
'oidc_oauth_account_name_property': '',
|
||||
'oidc_oauth_account_description_property': '',
|
||||
|
||||
# Zone Record Settings
|
||||
'forward_records_allow_edit': {
|
||||
'A': True,
|
||||
'AAAA': True,
|
||||
'AFSDB': False,
|
||||
'ALIAS': False,
|
||||
'CAA': True,
|
||||
'CERT': False,
|
||||
'CDNSKEY': False,
|
||||
'CDS': False,
|
||||
'CNAME': True,
|
||||
'DNSKEY': False,
|
||||
'DNAME': False,
|
||||
'DS': False,
|
||||
'HINFO': False,
|
||||
'KEY': False,
|
||||
'LOC': True,
|
||||
'LUA': False,
|
||||
'MX': True,
|
||||
'NAPTR': False,
|
||||
'NS': True,
|
||||
'NSEC': False,
|
||||
'NSEC3': False,
|
||||
'NSEC3PARAM': False,
|
||||
'OPENPGPKEY': False,
|
||||
'PTR': True,
|
||||
'RP': False,
|
||||
'RRSIG': False,
|
||||
'SOA': False,
|
||||
'SPF': True,
|
||||
'SSHFP': False,
|
||||
'SRV': True,
|
||||
'TKEY': False,
|
||||
'TSIG': False,
|
||||
'TLSA': False,
|
||||
'SMIMEA': False,
|
||||
'TXT': True,
|
||||
'URI': False
|
||||
},
|
||||
'reverse_records_allow_edit': {
|
||||
'A': False,
|
||||
'AAAA': False,
|
||||
'AFSDB': False,
|
||||
'ALIAS': False,
|
||||
'CAA': False,
|
||||
'CERT': False,
|
||||
'CDNSKEY': False,
|
||||
'CDS': False,
|
||||
'CNAME': False,
|
||||
'DNSKEY': False,
|
||||
'DNAME': False,
|
||||
'DS': False,
|
||||
'HINFO': False,
|
||||
'KEY': False,
|
||||
'LOC': True,
|
||||
'LUA': False,
|
||||
'MX': False,
|
||||
'NAPTR': False,
|
||||
'NS': True,
|
||||
'NSEC': False,
|
||||
'NSEC3': False,
|
||||
'NSEC3PARAM': False,
|
||||
'OPENPGPKEY': False,
|
||||
'PTR': True,
|
||||
'RP': False,
|
||||
'RRSIG': False,
|
||||
'SOA': False,
|
||||
'SPF': False,
|
||||
'SSHFP': False,
|
||||
'SRV': False,
|
||||
'TKEY': False,
|
||||
'TSIG': False,
|
||||
'TLSA': False,
|
||||
'SMIMEA': False,
|
||||
'TXT': True,
|
||||
'URI': False
|
||||
},
|
||||
}
|
||||
|
||||
groups = {
|
||||
'authentication': [
|
||||
# Local Authentication Settings
|
||||
'local_db_enabled',
|
||||
'signup_enabled',
|
||||
'pwd_enforce_characters',
|
||||
'pwd_min_len',
|
||||
'pwd_min_lowercase',
|
||||
'pwd_min_uppercase',
|
||||
'pwd_min_digits',
|
||||
'pwd_min_special',
|
||||
'pwd_enforce_complexity',
|
||||
'pwd_min_complexity',
|
||||
|
||||
# LDAP Authentication Settings
|
||||
'ldap_enabled',
|
||||
'ldap_type',
|
||||
'ldap_uri',
|
||||
'ldap_base_dn',
|
||||
'ldap_admin_username',
|
||||
'ldap_admin_password',
|
||||
'ldap_domain',
|
||||
'ldap_filter_basic',
|
||||
'ldap_filter_username',
|
||||
'ldap_filter_group',
|
||||
'ldap_filter_groupname',
|
||||
'ldap_sg_enabled',
|
||||
'ldap_admin_group',
|
||||
'ldap_operator_group',
|
||||
'ldap_user_group',
|
||||
'autoprovisioning',
|
||||
'autoprovisioning_attribute',
|
||||
'urn_value',
|
||||
'purge',
|
||||
|
||||
# Google OAuth2 Settings
|
||||
'google_oauth_enabled',
|
||||
'google_oauth_client_id',
|
||||
'google_oauth_client_secret',
|
||||
'google_oauth_scope',
|
||||
'google_base_url',
|
||||
'google_oauth_auto_configure',
|
||||
'google_oauth_metadata_url',
|
||||
'google_token_url',
|
||||
'google_authorize_url',
|
||||
|
||||
# GitHub OAuth2 Settings
|
||||
'github_oauth_enabled',
|
||||
'github_oauth_key',
|
||||
'github_oauth_secret',
|
||||
'github_oauth_scope',
|
||||
'github_oauth_api_url',
|
||||
'github_oauth_auto_configure',
|
||||
'github_oauth_metadata_url',
|
||||
'github_oauth_token_url',
|
||||
'github_oauth_authorize_url',
|
||||
|
||||
# Azure OAuth2 Settings
|
||||
'azure_oauth_enabled',
|
||||
'azure_oauth_key',
|
||||
'azure_oauth_secret',
|
||||
'azure_oauth_scope',
|
||||
'azure_oauth_api_url',
|
||||
'azure_oauth_auto_configure',
|
||||
'azure_oauth_metadata_url',
|
||||
'azure_oauth_token_url',
|
||||
'azure_oauth_authorize_url',
|
||||
'azure_sg_enabled',
|
||||
'azure_admin_group',
|
||||
'azure_operator_group',
|
||||
'azure_user_group',
|
||||
'azure_group_accounts_enabled',
|
||||
'azure_group_accounts_name',
|
||||
'azure_group_accounts_name_re',
|
||||
'azure_group_accounts_description',
|
||||
'azure_group_accounts_description_re',
|
||||
|
||||
# OIDC OAuth2 Settings
|
||||
'oidc_oauth_enabled',
|
||||
'oidc_oauth_key',
|
||||
'oidc_oauth_secret',
|
||||
'oidc_oauth_scope',
|
||||
'oidc_oauth_api_url',
|
||||
'oidc_oauth_auto_configure',
|
||||
'oidc_oauth_metadata_url',
|
||||
'oidc_oauth_token_url',
|
||||
'oidc_oauth_authorize_url',
|
||||
'oidc_oauth_logout_url',
|
||||
'oidc_oauth_username',
|
||||
'oidc_oauth_email',
|
||||
'oidc_oauth_firstname',
|
||||
'oidc_oauth_last_name',
|
||||
'oidc_oauth_account_name_property',
|
||||
'oidc_oauth_account_description_property',
|
||||
]
|
||||
}
|
||||
ZONE_TYPE_FORWARD = 'forward'
|
||||
ZONE_TYPE_REVERSE = 'reverse'
|
||||
|
||||
def __init__(self, id=None, name=None, value=None):
|
||||
self.id = id
|
||||
@ -457,44 +26,12 @@ class Setting(db.Model):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
def convert_type(self, name, value):
|
||||
import json
|
||||
from json import JSONDecodeError
|
||||
if name in self.types:
|
||||
var_type = self.types[name]
|
||||
|
||||
# Handle boolean values
|
||||
if var_type == bool:
|
||||
if value == 'True' or value == 'true' or value == '1' or value is True:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# Handle float values
|
||||
if var_type == float:
|
||||
return float(value)
|
||||
|
||||
# Handle integer values
|
||||
if var_type == int:
|
||||
return int(value)
|
||||
|
||||
if (var_type == dict or var_type == list) and isinstance(value, str) and len(value) > 0:
|
||||
try:
|
||||
return json.loads(value)
|
||||
except JSONDecodeError as e:
|
||||
pass
|
||||
|
||||
if var_type == str:
|
||||
return str(value)
|
||||
|
||||
return value
|
||||
|
||||
def set_maintenance(self, mode):
|
||||
maintenance = Setting.query.filter(
|
||||
Setting.name == 'maintenance').first()
|
||||
|
||||
if maintenance is None:
|
||||
value = self.defaults['maintenance']
|
||||
value = AppSettings.defaults['maintenance']
|
||||
maintenance = Setting(name='maintenance', value=str(value))
|
||||
db.session.add(maintenance)
|
||||
|
||||
@ -516,7 +53,7 @@ class Setting(db.Model):
|
||||
current_setting = Setting.query.filter(Setting.name == setting).first()
|
||||
|
||||
if current_setting is None:
|
||||
value = self.defaults[setting]
|
||||
value = AppSettings.defaults[setting]
|
||||
current_setting = Setting(name=setting, value=str(value))
|
||||
db.session.add(current_setting)
|
||||
|
||||
@ -535,27 +72,30 @@ class Setting(db.Model):
|
||||
return False
|
||||
|
||||
def set(self, setting, value):
|
||||
import json
|
||||
current_setting = Setting.query.filter(Setting.name == setting).first()
|
||||
|
||||
if current_setting is None:
|
||||
current_setting = Setting(name=setting, value=None)
|
||||
db.session.add(current_setting)
|
||||
|
||||
value = str(self.convert_type(setting, value))
|
||||
value = AppSettings.convert_type(setting, value)
|
||||
|
||||
if isinstance(value, dict) or isinstance(value, list):
|
||||
value = json.dumps(value)
|
||||
|
||||
try:
|
||||
current_setting.value = value
|
||||
db.session.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
current_app.logger.error('Cannot edit setting {0}. DETAIL: {1}'.format(
|
||||
setting, e))
|
||||
current_app.logger.error('Cannot edit setting {0}. DETAIL: {1}'.format(setting, e))
|
||||
current_app.logger.debug(traceback.format_exec())
|
||||
db.session.rollback()
|
||||
return False
|
||||
|
||||
def get(self, setting):
|
||||
if setting in self.defaults:
|
||||
if setting in AppSettings.defaults:
|
||||
|
||||
if setting.upper() in current_app.config:
|
||||
result = current_app.config[setting.upper()]
|
||||
@ -566,51 +106,45 @@ class Setting(db.Model):
|
||||
if hasattr(result, 'value'):
|
||||
result = result.value
|
||||
|
||||
return self.convert_type(setting, result)
|
||||
return AppSettings.convert_type(setting, result)
|
||||
else:
|
||||
return self.defaults[setting]
|
||||
return AppSettings.defaults[setting]
|
||||
else:
|
||||
current_app.logger.error('Unknown setting queried: {0}'.format(setting))
|
||||
|
||||
def get_group(self, group):
|
||||
if not isinstance(group, list):
|
||||
group = self.groups[group]
|
||||
group = AppSettings.groups[group]
|
||||
|
||||
result = {}
|
||||
records = self.query.all()
|
||||
|
||||
for record in records:
|
||||
if record.name in group:
|
||||
result[record.name] = self.convert_type(record.name, record.value)
|
||||
for var_name, default_value in AppSettings.defaults.items():
|
||||
if var_name in group:
|
||||
result[var_name] = self.get(var_name)
|
||||
|
||||
return result
|
||||
|
||||
def get_records_allow_to_edit(self):
|
||||
return list(
|
||||
set(self.get_forward_records_allow_to_edit() +
|
||||
self.get_reverse_records_allow_to_edit()))
|
||||
set(self.get_supported_record_types(self.ZONE_TYPE_FORWARD) +
|
||||
self.get_supported_record_types(self.ZONE_TYPE_REVERSE)))
|
||||
|
||||
def get_forward_records_allow_to_edit(self):
|
||||
records = self.get('forward_records_allow_edit')
|
||||
f_records = literal_eval(records) if isinstance(records,
|
||||
str) else records
|
||||
r_name = [r for r in f_records if f_records[r]]
|
||||
# Sort alphabetically if python version is smaller than 3.6
|
||||
if sys.version_info[0] < 3 or (sys.version_info[0] == 3
|
||||
and sys.version_info[1] < 6):
|
||||
r_name.sort()
|
||||
return r_name
|
||||
def get_supported_record_types(self, zone_type):
|
||||
setting_value = []
|
||||
|
||||
if zone_type == self.ZONE_TYPE_FORWARD:
|
||||
setting_value = self.get('forward_records_allow_edit')
|
||||
elif zone_type == self.ZONE_TYPE_REVERSE:
|
||||
setting_value = self.get('reverse_records_allow_edit')
|
||||
|
||||
records = literal_eval(setting_value) if isinstance(setting_value, str) else setting_value
|
||||
types = [r for r in records if records[r]]
|
||||
|
||||
def get_reverse_records_allow_to_edit(self):
|
||||
records = self.get('reverse_records_allow_edit')
|
||||
r_records = literal_eval(records) if isinstance(records,
|
||||
str) else records
|
||||
r_name = [r for r in r_records if r_records[r]]
|
||||
# Sort alphabetically if python version is smaller than 3.6
|
||||
if sys.version_info[0] < 3 or (sys.version_info[0] == 3
|
||||
and sys.version_info[1] < 6):
|
||||
r_name.sort()
|
||||
return r_name
|
||||
if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 6):
|
||||
types.sort()
|
||||
|
||||
return types
|
||||
|
||||
def get_ttl_options(self):
|
||||
return [(pytimeparse.parse(ttl), ttl)
|
||||
|
@ -128,14 +128,17 @@ def extract_changelogs_from_history(histories, record_name=None, record_type=Non
|
||||
|
||||
# filter only the records with the specific record_name, record_type
|
||||
if record_name != None and record_type != None:
|
||||
details['add_rrsets'] = list(filter_rr_list_by_name_and_type(details['add_rrsets'], record_name, record_type))
|
||||
details['del_rrsets'] = list(filter_rr_list_by_name_and_type(details['del_rrsets'], record_name, record_type))
|
||||
details['add_rrsets'] = list(
|
||||
filter_rr_list_by_name_and_type(details['add_rrsets'], record_name, record_type))
|
||||
details['del_rrsets'] = list(
|
||||
filter_rr_list_by_name_and_type(details['del_rrsets'], record_name, record_type))
|
||||
|
||||
if not details['add_rrsets'] and not details['del_rrsets']:
|
||||
continue
|
||||
|
||||
# same record name and type RR are being deleted and created in same entry.
|
||||
del_add_changes = set([(r['name'], r['type']) for r in details['add_rrsets']]).intersection([(r['name'], r['type']) for r in details['del_rrsets']])
|
||||
del_add_changes = set([(r['name'], r['type']) for r in details['add_rrsets']]).intersection(
|
||||
[(r['name'], r['type']) for r in details['del_rrsets']])
|
||||
for del_add_change in del_add_changes:
|
||||
changes.append(HistoryRecordEntry(
|
||||
entry,
|
||||
@ -155,8 +158,8 @@ def extract_changelogs_from_history(histories, record_name=None, record_type=Non
|
||||
# sort changes by the record name
|
||||
if changes:
|
||||
changes.sort(key=lambda change:
|
||||
change.del_rrset['name'] if change.del_rrset else change.add_rrset['name']
|
||||
)
|
||||
change.del_rrset['name'] if change.del_rrset else change.add_rrset['name']
|
||||
)
|
||||
out_changes.extend(changes)
|
||||
return out_changes
|
||||
|
||||
@ -1149,10 +1152,10 @@ def history_table(): # ajax call data
|
||||
.outerjoin(Account, Domain.account_id == Account.id) \
|
||||
.outerjoin(AccountUser, Account.id == AccountUser.account_id) \
|
||||
.filter(db.or_(
|
||||
DomainUser.user_id == current_user.id,
|
||||
AccountUser.user_id == current_user.id
|
||||
)) \
|
||||
.subquery()
|
||||
DomainUser.user_id == current_user.id,
|
||||
AccountUser.user_id == current_user.id
|
||||
)) \
|
||||
.subquery()
|
||||
base_query = base_query.filter(History.domain_id.in_(allowed_domain_id_subquery))
|
||||
|
||||
domain_name = request.args.get('domain_name_filter') if request.args.get('domain_name_filter') != None \
|
||||
@ -1271,7 +1274,8 @@ def history_table(): # ajax call data
|
||||
)
|
||||
).order_by(History.created_on.desc()) \
|
||||
.limit(lim).all()
|
||||
elif user_name != None and current_user.role.name in ['Administrator', 'Operator']: # only admins can see the user login-logouts
|
||||
elif user_name != None and current_user.role.name in ['Administrator',
|
||||
'Operator']: # only admins can see the user login-logouts
|
||||
|
||||
histories = base_query.filter(
|
||||
db.and_(
|
||||
@ -1296,7 +1300,8 @@ def history_table(): # ajax call data
|
||||
temp.append(h)
|
||||
break
|
||||
histories = temp
|
||||
elif (changed_by != None or max_date != None) and current_user.role.name in ['Administrator', 'Operator']: # select changed by and date filters only
|
||||
elif (changed_by != None or max_date != None) and current_user.role.name in ['Administrator',
|
||||
'Operator']: # select changed by and date filters only
|
||||
histories = base_query.filter(
|
||||
db.and_(
|
||||
History.created_on <= max_date if max_date != None else True,
|
||||
@ -1305,7 +1310,8 @@ def history_table(): # ajax call data
|
||||
)
|
||||
) \
|
||||
.order_by(History.created_on.desc()).limit(lim).all()
|
||||
elif (changed_by != None or max_date != None): # special filtering for user because one user does not have access to log-ins logs
|
||||
elif (
|
||||
changed_by != None or max_date != None): # special filtering for user because one user does not have access to log-ins logs
|
||||
histories = base_query.filter(
|
||||
db.and_(
|
||||
History.created_on <= max_date if max_date != None else True,
|
||||
@ -1396,7 +1402,7 @@ def setting_basic_edit(setting):
|
||||
new_value = jdata['value']
|
||||
result = Setting().set(setting, new_value)
|
||||
|
||||
if (result):
|
||||
if result:
|
||||
return make_response(
|
||||
jsonify({
|
||||
'status': 'ok',
|
||||
@ -1460,52 +1466,29 @@ def setting_pdns():
|
||||
@login_required
|
||||
@operator_role_required
|
||||
def setting_records():
|
||||
from powerdnsadmin.lib.settings import AppSettings
|
||||
if request.method == 'GET':
|
||||
_fr = Setting().get('forward_records_allow_edit')
|
||||
_rr = Setting().get('reverse_records_allow_edit')
|
||||
f_records = literal_eval(_fr) if isinstance(_fr, str) else _fr
|
||||
r_records = literal_eval(_rr) if isinstance(_rr, str) else _rr
|
||||
|
||||
forward_records = Setting().get('forward_records_allow_edit')
|
||||
reverse_records = Setting().get('reverse_records_allow_edit')
|
||||
return render_template('admin_setting_records.html',
|
||||
f_records=f_records,
|
||||
r_records=r_records)
|
||||
f_records=forward_records,
|
||||
r_records=reverse_records)
|
||||
elif request.method == 'POST':
|
||||
fr = {}
|
||||
rr = {}
|
||||
records = Setting().defaults['forward_records_allow_edit']
|
||||
records = AppSettings.defaults['forward_records_allow_edit']
|
||||
for r in records:
|
||||
fr[r] = True if request.form.get('fr_{0}'.format(
|
||||
r.lower())) else False
|
||||
rr[r] = True if request.form.get('rr_{0}'.format(
|
||||
r.lower())) else False
|
||||
|
||||
Setting().set('forward_records_allow_edit', str(fr))
|
||||
Setting().set('reverse_records_allow_edit', str(rr))
|
||||
Setting().set('forward_records_allow_edit', json.dumps(fr))
|
||||
Setting().set('reverse_records_allow_edit', json.dumps(rr))
|
||||
|
||||
return redirect(url_for('admin.setting_records'))
|
||||
|
||||
|
||||
def has_an_auth_method(local_db_enabled=None,
|
||||
ldap_enabled=None,
|
||||
google_oauth_enabled=None,
|
||||
github_oauth_enabled=None,
|
||||
oidc_oauth_enabled=None,
|
||||
azure_oauth_enabled=None):
|
||||
if local_db_enabled is None:
|
||||
local_db_enabled = Setting().get('local_db_enabled')
|
||||
if ldap_enabled is None:
|
||||
ldap_enabled = Setting().get('ldap_enabled')
|
||||
if google_oauth_enabled is None:
|
||||
google_oauth_enabled = Setting().get('google_oauth_enabled')
|
||||
if github_oauth_enabled is None:
|
||||
github_oauth_enabled = Setting().get('github_oauth_enabled')
|
||||
if oidc_oauth_enabled is None:
|
||||
oidc_oauth_enabled = Setting().get('oidc_oauth_enabled')
|
||||
if azure_oauth_enabled is None:
|
||||
azure_oauth_enabled = Setting().get('azure_oauth_enabled')
|
||||
return local_db_enabled or ldap_enabled or google_oauth_enabled or github_oauth_enabled or oidc_oauth_enabled \
|
||||
or azure_oauth_enabled
|
||||
|
||||
|
||||
@admin_bp.route('/setting/authentication', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@admin_role_required
|
||||
@ -1517,6 +1500,7 @@ def setting_authentication():
|
||||
@login_required
|
||||
@admin_role_required
|
||||
def setting_authentication_api():
|
||||
from powerdnsadmin.lib.settings import AppSettings
|
||||
result = {'status': 1, 'messages': [], 'data': {}}
|
||||
|
||||
if request.form.get('commit') == '1':
|
||||
@ -1524,7 +1508,7 @@ def setting_authentication_api():
|
||||
data = json.loads(request.form.get('data'))
|
||||
|
||||
for key, value in data.items():
|
||||
if key in model.groups['authentication']:
|
||||
if key in AppSettings.groups['authentication']:
|
||||
model.set(key, value)
|
||||
|
||||
result['data'] = Setting().get_group('authentication')
|
||||
|
@ -72,9 +72,9 @@ def domain(domain_name):
|
||||
quick_edit = Setting().get('record_quick_edit')
|
||||
records_allow_to_edit = Setting().get_records_allow_to_edit()
|
||||
forward_records_allow_to_edit = Setting(
|
||||
).get_forward_records_allow_to_edit()
|
||||
).get_supported_record_types(Setting().ZONE_TYPE_FORWARD)
|
||||
reverse_records_allow_to_edit = Setting(
|
||||
).get_reverse_records_allow_to_edit()
|
||||
).get_supported_record_types(Setting().ZONE_TYPE_REVERSE)
|
||||
ttl_options = Setting().get_ttl_options()
|
||||
records = []
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user