diff --git a/package.json b/package.json
index 42f866d..3aaac1d 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"jquery-ui-dist": "^1.13.2",
"jquery.quicksearch": "^2.4.0",
"jtimeout": "^3.2.0",
+ "knockout": "^3.5.1",
"multiselect": "^0.9.12"
},
"resolutions": {
diff --git a/powerdnsadmin/assets.py b/powerdnsadmin/assets.py
index 5e17d7f..8f9192f 100644
--- a/powerdnsadmin/assets.py
+++ b/powerdnsadmin/assets.py
@@ -20,6 +20,7 @@ js_login = Bundle(
'node_modules/jquery/dist/jquery.js',
'node_modules/bootstrap/dist/js/bootstrap.js',
'node_modules/icheck/icheck.js',
+ 'node_modules/knockout/build/output/knockout-latest.js',
'custom/js/custom.js',
filters=(ConcatFilter, 'rjsmin'),
output='generated/login.js')
@@ -55,6 +56,7 @@ js_main = Bundle(
'node_modules/datatables.net-plugins/sorting/natural.js',
'node_modules/jtimeout/src/jTimeout.js',
'node_modules/jquery.quicksearch/src/jquery.quicksearch.js',
+ 'node_modules/knockout/build/output/knockout-latest.js',
'custom/js/custom.js',
'node_modules/bootstrap-datepicker/dist/js/bootstrap-datepicker.js',
filters=(ConcatFilter, 'rjsmin'),
diff --git a/powerdnsadmin/models/setting.py b/powerdnsadmin/models/setting.py
index dedaaab..1ef3166 100644
--- a/powerdnsadmin/models/setting.py
+++ b/powerdnsadmin/models/setting.py
@@ -15,6 +15,7 @@ class Setting(db.Model):
value = db.Column(db.Text())
defaults = {
+ # General Settings
'maintenance': False,
'fullscreen_layout': True,
'record_helper': True,
@@ -42,56 +43,79 @@ class Setting(db.Model):
'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,
- 'autoprovisioning': False,
- 'urn_value': '',
- 'autoprovisioning_attribute': '',
- 'purge': False,
- 'verify_user_email': False,
+ '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_group': '',
'ldap_filter_username': '',
+ 'ldap_filter_group': '',
'ldap_filter_groupname': '',
'ldap_sg_enabled': False,
'ldap_admin_group': '',
'ldap_operator_group': '',
'ldap_user_group': '',
- 'ldap_domain': '',
+ '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_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_token_url':
- 'https://github.com/login/oauth/access_token',
- 'github_oauth_authorize_url':
- 'https://github.com/login/oauth/authorize',
'github_oauth_metadata_url': '',
- 'google_oauth_enabled': False,
- 'google_oauth_client_id': '',
- 'google_oauth_client_secret': '',
- 'google_token_url': 'https://oauth2.googleapis.com/token',
- 'google_oauth_scope': 'openid email profile',
- 'google_authorize_url': 'https://accounts.google.com/o/oauth2/v2/auth',
- 'google_oauth_metadata_url': '',
- 'google_base_url': 'https://www.googleapis.com/oauth2/v3/',
+ '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_token_url':
- 'https://login.microsoftonline.com/[tenancy]/oauth2/v2.0/token',
- 'azure_oauth_authorize_url':
- 'https://login.microsoftonline.com/[tenancy]/oauth2/v2.0/authorize',
'azure_oauth_metadata_url': '',
+ 'azure_oauth_token_url': '',
+ 'azure_oauth_authorize_url': '',
'azure_sg_enabled': False,
'azure_admin_group': '',
'azure_operator_group': '',
@@ -101,22 +125,25 @@ class Setting(db.Model):
'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_metadata_url': '',
'oidc_oauth_token_url': '',
'oidc_oauth_authorize_url': '',
- 'oidc_oauth_metadata_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_email': 'email',
'oidc_oauth_account_name_property': '',
'oidc_oauth_account_description_property': '',
- 'enforce_api_ttl': False,
+
+ # Zone Record Settings
'forward_records_allow_edit': {
'A': True,
'AAAA': True,
@@ -193,22 +220,6 @@ class Setting(db.Model):
'TXT': True,
'URI': 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,
- '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
}
def __init__(self, id=None, name=None, value=None):
diff --git a/powerdnsadmin/routes/admin.py b/powerdnsadmin/routes/admin.py
index eedabdc..7ec669d 100644
--- a/powerdnsadmin/routes/admin.py
+++ b/powerdnsadmin/routes/admin.py
@@ -72,8 +72,8 @@ def get_record_changes(del_rrset, add_rrset):
"""For the given record, return the state dict."""
return {
"disabled": record['disabled'],
- "content": record['content'],
- "comment": record.get('comment', ''),
+ "content": record['content'],
+ "comment": record.get('comment', ''),
}
add_records = get_records(add_rrset)
@@ -149,8 +149,8 @@ def extract_changelogs_from_a_history_entry(out_changes, history_entry, change_n
# Sort them by the record name
if change_num in out_changes:
out_changes[change_num].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']
+ )
# only used for changelog per record
if record_name != None and record_type != None: # then get only the records with the specific (record_name, record_type) tuple
@@ -897,7 +897,8 @@ class DetailedHistory():
description=DetailedHistory.get_key_val(detail_dict,
"description"))
- elif any(msg in history.msg for msg in ['Change zone','Change domain']) and 'access control' in history.msg: # added or removed a user from a zone
+ elif any(msg in history.msg for msg in ['Change zone',
+ 'Change domain']) and 'access control' in history.msg: # added or removed a user from a zone
users_with_access = DetailedHistory.get_key_val(detail_dict, "user_has_access")
self.detailed_msg = render_template_string("""
@@ -942,7 +943,7 @@ class DetailedHistory():
linked_domains=DetailedHistory.get_key_val(detail_dict,
"domains"))
- elif any(msg in history.msg for msg in ['Update type for zone','Update type for domain']):
+ elif any(msg in history.msg for msg in ['Update type for zone', 'Update type for domain']):
self.detailed_msg = render_template_string("""
Zone: {{ domain }}
@@ -977,7 +978,8 @@ class DetailedHistory():
'status'),
history_msg=DetailedHistory.get_key_val(detail_dict, 'msg'))
- elif any(msg in history.msg for msg in ['Update zone','Update domain']) and 'associate account' in history.msg: # When an account gets associated or dissociate with zones
+ elif any(msg in history.msg for msg in ['Update zone',
+ 'Update domain']) and 'associate account' in history.msg: # When an account gets associated or dissociate with zones
self.detailed_msg = render_template_string('''
Associate: {{ history_assoc_account }}
@@ -1231,8 +1233,10 @@ def history_table(): # ajax call data
.filter(
db.and_(
db.or_(
- History.msg.like("%domain " + domain_name) if domain_name != "*" else History.msg.like("%domain%"),
- History.msg.like("%zone " + domain_name) if domain_name != "*" else History.msg.like("%zone%"),
+ History.msg.like("%domain " + domain_name) if domain_name != "*" else History.msg.like(
+ "%domain%"),
+ History.msg.like("%zone " + domain_name) if domain_name != "*" else History.msg.like(
+ "%zone%"),
History.msg.like(
"%domain " + domain_name + " access control") if domain_name != "*" else History.msg.like(
"%domain%access control"),
@@ -1540,7 +1544,8 @@ def has_an_auth_method(local_db_enabled=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
+ 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'])
@@ -1562,17 +1567,20 @@ def setting_authentication():
pwd_enforce_characters = True if request.form.get('pwd_enforce_characters') else False
pwd_min_len = safe_cast(request.form.get('pwd_min_len', Setting().defaults["pwd_min_len"]), int,
Setting().defaults["pwd_min_len"])
- pwd_min_lowercase = safe_cast(request.form.get('pwd_min_lowercase', Setting().defaults["pwd_min_lowercase"]), int,
- Setting().defaults["pwd_min_lowercase"])
- pwd_min_uppercase = safe_cast(request.form.get('pwd_min_uppercase', Setting().defaults["pwd_min_uppercase"]), int,
- Setting().defaults["pwd_min_uppercase"])
+ pwd_min_lowercase = safe_cast(
+ request.form.get('pwd_min_lowercase', Setting().defaults["pwd_min_lowercase"]), int,
+ Setting().defaults["pwd_min_lowercase"])
+ pwd_min_uppercase = safe_cast(
+ request.form.get('pwd_min_uppercase', Setting().defaults["pwd_min_uppercase"]), int,
+ Setting().defaults["pwd_min_uppercase"])
pwd_min_digits = safe_cast(request.form.get('pwd_min_digits', Setting().defaults["pwd_min_digits"]), int,
Setting().defaults["pwd_min_digits"])
pwd_min_special = safe_cast(request.form.get('pwd_min_special', Setting().defaults["pwd_min_special"]), int,
Setting().defaults["pwd_min_special"])
pwd_enforce_complexity = True if request.form.get('pwd_enforce_complexity') else False
- pwd_min_complexity = safe_cast(request.form.get('pwd_min_complexity', Setting().defaults["pwd_min_complexity"]), int,
+ pwd_min_complexity = safe_cast(request.form.get('pwd_min_complexity',
+ Setting().defaults["pwd_min_complexity"]), int,
Setting().defaults["pwd_min_complexity"])
if not has_an_auth_method(local_db_enabled=local_db_enabled):
@@ -1585,14 +1593,12 @@ def setting_authentication():
else:
Setting().set('local_db_enabled', local_db_enabled)
Setting().set('signup_enabled', signup_enabled)
-
Setting().set('pwd_enforce_characters', pwd_enforce_characters)
Setting().set('pwd_min_len', pwd_min_len)
Setting().set('pwd_min_lowercase', pwd_min_lowercase)
Setting().set('pwd_min_uppercase', pwd_min_uppercase)
Setting().set('pwd_min_digits', pwd_min_digits)
Setting().set('pwd_min_special', pwd_min_special)
-
Setting().set('pwd_enforce_complexity', pwd_enforce_complexity)
Setting().set('pwd_min_complexity', pwd_min_complexity)
@@ -2097,16 +2103,16 @@ def global_search():
results = server.global_search(object_type='all', query=query)
# Filter results to domains to which the user has access permission
- if current_user.role.name not in [ 'Administrator', 'Operator' ]:
+ if current_user.role.name not in ['Administrator', 'Operator']:
allowed_domains = db.session.query(Domain) \
.outerjoin(DomainUser, Domain.id == DomainUser.domain_id) \
.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
- )) \
+ db.or_(
+ DomainUser.user_id == current_user.id,
+ AccountUser.user_id == current_user.id
+ )) \
.with_entities(Domain.name) \
.all()
allowed_domains = [value for value, in allowed_domains]
diff --git a/powerdnsadmin/static/custom/js/app-authentication-settings-editor.js b/powerdnsadmin/static/custom/js/app-authentication-settings-editor.js
new file mode 100644
index 0000000..104b3e9
--- /dev/null
+++ b/powerdnsadmin/static/custom/js/app-authentication-settings-editor.js
@@ -0,0 +1,273 @@
+let model;
+
+let AuthenticationSettingsModel = function (user_data, csrf_token, selector) {
+ let self = this;
+
+ let defaults = {
+ tab_active: '',
+ tab_default: 'local',
+
+ // 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: '',
+ google_base_url: '',
+ google_oauth_auto_configure: false,
+ google_oauth_metadata_url: '',
+ google_token_url: '',
+ google_authorize_url: '',
+
+ // GitHub OAuth2 Settings
+ github_oauth_enabled: false,
+ github_oauth_key: '',
+ github_oauth_secret: '',
+ github_oauth_scope: '',
+ github_oauth_api_url: '',
+ github_oauth_auto_configure: false,
+ github_oauth_metadata_url: '',
+ github_oauth_token_url: '',
+ github_oauth_authorize_url: '',
+
+ // Azure AD OAuth2 Settings
+ azure_oauth_enabled: false,
+ azure_oauth_key: '',
+ azure_oauth_secret: '',
+ azure_oauth_scope: '',
+ azure_oauth_api_url: '',
+ azure_oauth_auto_configure: false,
+ 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: '',
+ azure_group_accounts_name_re: '',
+ azure_group_accounts_description: '',
+ azure_group_accounts_description_re: '',
+
+ // OIDC OAuth2 Settings
+ oidc_oauth_enabled: false,
+ oidc_oauth_key: '',
+ oidc_oauth_secret: '',
+ oidc_oauth_scope: '',
+ oidc_oauth_api_url: '',
+ oidc_oauth_auto_configure: false,
+ 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: '',
+ }
+
+ self.data = {};
+
+ self.setupObservables = function () {
+ self.tab_active = ko.observable(self.data.tab_active);
+ self.tab_default = ko.observable(self.data.tab_default);
+
+ // Local Authentication Settings
+ self.local_db_enabled = ko.observable(self.data.local_db_enabled);
+ self.signup_enabled = ko.observable(self.data.signup_enabled);
+ self.pwd_enforce_characters = ko.observable(self.data.pwd_enforce_characters);
+ self.pwd_min_len = ko.observable(self.data.pwd_min_len);
+ self.pwd_min_lowercase = ko.observable(self.data.pwd_min_lowercase);
+ self.pwd_min_uppercase = ko.observable(self.data.pwd_min_uppercase);
+ self.pwd_min_digits = ko.observable(self.data.pwd_min_digits);
+ self.pwd_min_special = ko.observable(self.data.pwd_min_special);
+ self.pwd_enforce_complexity = ko.observable(self.data.pwd_enforce_complexity);
+ self.pwd_min_complexity = ko.observable(self.data.pwd_min_complexity);
+
+ // LDAP Authentication Settings
+ self.ldap_enabled = ko.observable(self.data.ldap_enabled);
+ self.ldap_type = ko.observable(self.data.ldap_type);
+ self.ldap_uri = ko.observable(self.data.ldap_uri);
+ self.ldap_base_dn = ko.observable(self.data.ldap_base_dn);
+ self.ldap_admin_username = ko.observable(self.data.ldap_admin_username);
+ self.ldap_admin_password = ko.observable(self.data.ldap_admin_password);
+ self.ldap_domain = ko.observable(self.data.ldap_domain);
+ self.ldap_filter_basic = ko.observable(self.data.ldap_filter_basic);
+ self.ldap_filter_username = ko.observable(self.data.ldap_filter_username);
+ self.ldap_filter_group = ko.observable(self.data.ldap_filter_group);
+ self.ldap_filter_groupname = ko.observable(self.data.ldap_filter_groupname);
+ self.ldap_sg_enabled = ko.observable(self.data.ldap_sg_enabled);
+ self.ldap_admin_group = ko.observable(self.data.ldap_admin_group);
+ self.ldap_operator_group = ko.observable(self.data.ldap_operator_group);
+ self.ldap_user_group = ko.observable(self.data.ldap_user_group);
+ self.autoprovisioning = ko.observable(self.data.autoprovisioning);
+ self.autoprovisioning_attribute = ko.observable(self.data.autoprovisioning_attribute);
+ self.urn_value = ko.observable(self.data.urn_value);
+ self.purge = ko.observable(self.data.purge);
+
+ // Google OAuth2 Settings
+ self.google_oauth_enabled = ko.observable(self.data.google_oauth_enabled);
+ self.google_oauth_client_id = ko.observable(self.data.google_oauth_client_id);
+ self.google_oauth_client_secret = ko.observable(self.data.google_oauth_client_secret);
+ self.google_oauth_scope = ko.observable(self.data.google_oauth_scope);
+ self.google_base_url = ko.observable(self.data.google_base_url);
+ self.google_oauth_auto_configure = ko.observable(self.data.google_oauth_auto_configure);
+ self.google_oauth_metadata_url = ko.observable(self.data.google_oauth_metadata_url);
+ self.google_token_url = ko.observable(self.data.google_token_url);
+ self.google_authorize_url = ko.observable(self.data.google_authorize_url);
+
+ // GitHub OAuth2 Settings
+ self.github_oauth_enabled = ko.observable(self.data.github_oauth_enabled);
+ self.github_oauth_key = ko.observable(self.data.github_oauth_key);
+ self.github_oauth_secret = ko.observable(self.data.github_oauth_secret);
+ self.github_oauth_scope = ko.observable(self.data.github_oauth_scope);
+ self.github_oauth_api_url = ko.observable(self.data.github_oauth_api_url);
+ self.github_oauth_auto_configure = ko.observable(self.data.github_oauth_auto_configure);
+ self.github_oauth_metadata_url = ko.observable(self.data.github_oauth_metadata_url);
+ self.github_oauth_token_url = ko.observable(self.data.github_oauth_token_url);
+ self.github_oauth_authorize_url = ko.observable(self.data.github_oauth_authorize_url);
+
+ // Azure AD OAuth2 Settings
+ self.azure_oauth_enabled = ko.observable(self.data.azure_oauth_enabled);
+ self.azure_oauth_key = ko.observable(self.data.azure_oauth_key);
+ self.azure_oauth_secret = ko.observable(self.data.azure_oauth_secret);
+ self.azure_oauth_scope = ko.observable(self.data.azure_oauth_scope);
+ self.azure_oauth_api_url = ko.observable(self.data.azure_oauth_api_url);
+ self.azure_oauth_auto_configure = ko.observable(self.data.azure_oauth_auto_configure);
+ self.azure_oauth_metadata_url = ko.observable(self.data.azure_oauth_metadata_url);
+ self.azure_oauth_token_url = ko.observable(self.data.azure_oauth_token_url);
+ self.azure_oauth_authorize_url = ko.observable(self.data.azure_oauth_authorize_url);
+ self.azure_sg_enabled = ko.observable(self.data.azure_sg_enabled);
+ self.azure_admin_group = ko.observable(self.data.azure_admin_group);
+ self.azure_operator_group = ko.observable(self.data.azure_operator_group);
+ self.azure_user_group = ko.observable(self.data.azure_user_group);
+ self.azure_group_accounts_enabled = ko.observable(self.data.azure_group_accounts_enabled);
+ self.azure_group_accounts_name = ko.observable(self.data.azure_group_accounts_name);
+ self.azure_group_accounts_name_re = ko.observable(self.data.azure_group_accounts_name_re);
+ self.azure_group_accounts_description = ko.observable(self.data.azure_group_accounts_description);
+ self.azure_group_accounts_description_re = ko.observable(self.data.azure_group_accounts_description_re);
+
+ // OIDC OAuth2 Settings
+ self.oidc_oauth_enabled = ko.observable(self.data.oidc_oauth_enabled);
+ self.oidc_oauth_key = ko.observable(self.data.oidc_oauth_key);
+ self.oidc_oauth_secret = ko.observable(self.data.oidc_oauth_secret);
+ self.oidc_oauth_scope = ko.observable(self.data.oidc_oauth_scope);
+ self.oidc_oauth_api_url = ko.observable(self.data.oidc_oauth_api_url);
+ self.oidc_oauth_auto_configure = ko.observable(self.data.oidc_oauth_auto_configure);
+ self.oidc_oauth_metadata_url = ko.observable(self.data.oidc_oauth_metadata_url);
+ self.oidc_oauth_token_url = ko.observable(self.data.oidc_oauth_token_url);
+ self.oidc_oauth_authorize_url = ko.observable(self.data.oidc_oauth_authorize_url);
+ self.oidc_oauth_logout_url = ko.observable(self.data.oidc_oauth_logout_url);
+ self.oidc_oauth_username = ko.observable(self.data.oidc_oauth_username);
+ self.oidc_oauth_email = ko.observable(self.data.oidc_oauth_email);
+ self.oidc_oauth_firstname = ko.observable(self.data.oidc_oauth_firstname);
+ self.oidc_oauth_last_name = ko.observable(self.data.oidc_oauth_last_name);
+ self.oidc_oauth_account_name_property = ko.observable(self.data.oidc_oauth_account_name_property);
+ self.oidc_oauth_account_description_property = ko.observable(self.data.oidc_oauth_account_description_property);
+ }
+
+ self.updateWithDefaults = function (instance) {
+ self.data = $.extend(defaults, instance)
+ }
+
+ self.activateTab = function (tab) {
+ $('[role="tablist"] a.nav-link').blur();
+ self.tab_active(tab);
+ window.location.hash = tab;
+ }
+
+ self.activateDefaultTab = function () {
+ self.activateTab(self.tab_default());
+ }
+
+ self.initTabs = function() {
+ if (self.hasHash()) {
+ self.activateTab(self.getHash());
+ } else {
+ self.activateDefaultTab();
+ }
+ }
+
+ self.getHash = function () {
+ return window.location.hash.substring(1);
+ }
+
+ self.hasHash = function () {
+ return window.location.hash.length > 1;
+ }
+
+ self.setupListeners = function () {
+ if ('onhashchange' in window) {
+ $(window).bind('hashchange', self.onHashChange);
+ }
+ }
+
+ self.destroyListeners = function () {
+ if ('onhashchange' in window) {
+ $(window).unbind('hashchange', self.onHashChange);
+ }
+ }
+
+ self.onTabClick = function (model, event) {
+ self.activateTab($(event.target).data('tab'));
+ return false;
+ }
+
+ self.onHashChange = function (event) {
+ let hash = window.location.hash.trim();
+ if (hash.length > 1) {
+ self.activateTab(hash.substring(1));
+ } else {
+ self.activateDefaultTab();
+ }
+ }
+
+ self.updateWithDefaults(user_data);
+ self.setupObservables();
+
+ ko.applyBindings(self);
+
+ self.initTabs();
+ self.setupListeners();
+}
+
+$(function () {
+ // TODO: Load the data from the server and pass it to the model instantiation
+ loaded_data = {};
+ model = new AuthenticationSettingsModel(loaded_data, CSRF_TOKEN, '#settings-editor');
+})
\ No newline at end of file
diff --git a/powerdnsadmin/templates/admin_setting_authentication.html b/powerdnsadmin/templates/admin_setting_authentication.html
index ca8baa5..73d305d 100644
--- a/powerdnsadmin/templates/admin_setting_authentication.html
+++ b/powerdnsadmin/templates/admin_setting_authentication.html
@@ -25,7 +25,7 @@
-
+
@@ -43,31 +43,43 @@
-
+
@@ -201,13 +210,18 @@
to be enabled.
Password Requirements
-
This section allows you to customize your local DB password
- requirements
- and ensure that when users change their password or signup
- they are
- picking strong passwords.
-
Setting any entry field to a blank value will revert it back
- to default.
+
This section allows you to customize your local DB
+ password
+ requirements
+ and ensure that when users change their password or
+ signup
+ they are
+ picking strong passwords.
+
+
Setting any entry field to a blank value will revert it
+ back
+ to default.
+
Enforce Character Requirements
This option will enforce the character type requirements
for
@@ -247,7 +261,7 @@
log factor
is 11 as it is considered secure. More
information about
- the this can be found at
+ this can be found at
here
@@ -264,7 +278,7 @@
-
+
{% if error %}
@@ -281,7 +295,7 @@
@@ -290,7 +304,7 @@
+ data-bind="checked: ldap_enabled">
Enable LDAP
Authentication
@@ -299,18 +313,17 @@
+ data-bind="enable: ldap_enabled, checked: ldap_type">
OpenLDAP
-
+ data-bind="enable: ldap_enabled, checked: ldap_type">
Active Directory
@@ -325,7 +338,7 @@
id="ldap_uri"
placeholder="e.g. ldaps://your-ldap-server:636"
data-error="Please input LDAP URI"
- value="{{ SETTING.get('ldap_uri') }}">
+ data-bind="enable: ldap_enabled, value: ldap_uri, valueUpdate: 'afterkeydown'">
LDAP Base DN
@@ -334,11 +347,11 @@
id="ldap_base_dn"
placeholder="e.g. dc=mydomain,dc=com"
data-error="Please input LDAP Base DN"
- value="{{ SETTING.get('ldap_base_dn') }}">
+ data-bind="enable: ldap_enabled, value: ldap_base_dn, valueUpdate: 'afterkeydown'">
-
@@ -429,15 +442,15 @@
+ id="ldap_sg_off" value="0"
+ data-bind="enable: ldap_enabled, checked: ldap_sg_enabled, checkedValue: false">
OFF
+ id="ldap_sg_on" value="1"
+ data-bind="enable: ldap_enabled, checked: ldap_sg_enabled, checkedValue: true">
ON
@@ -448,7 +461,7 @@
name="ldap_admin_group" id="ldap_admin_group"
placeholder="e.g. cn=sysops,dc=mydomain,dc=com"
data-error="Please input LDAP DN for Admin group"
- value="{{ SETTING.get('ldap_admin_group') }}">
+ data-bind="enable: ldap_enabled() && ldap_sg_enabled(), value: ldap_admin_group, valueUpdate: 'afterkeydown'">
@@ -459,7 +472,7 @@
id="ldap_operator_group"
placeholder="e.g. cn=operators,dc=mydomain,dc=com"
data-error="Please input LDAP DN for Operator group"
- value="{{ SETTING.get('ldap_operator_group') }}">
+ data-bind="enable: ldap_enabled() && ldap_sg_enabled(), value: ldap_operator_group, valueUpdate: 'afterkeydown'">
@@ -468,7 +481,7 @@
name="ldap_user_group" id="ldap_user_group"
placeholder="e.g. cn=users,dc=mydomain,dc=com"
data-error="Please input LDAP DN for User group"
- value="{{ SETTING.get('ldap_user_group') }}">
+ data-bind="enable: ldap_enabled() && ldap_sg_enabled(), value: ldap_user_group, valueUpdate: 'afterkeydown'">
@@ -479,17 +492,17 @@
+ id="autoprovisioning_off" value="0"
+ data-bind="enable: ldap_enabled, checked: autoprovisioning, checkedValue: false">
OFF
+ id="autoprovisioning_on" value="1"
+ data-bind="enable: ldap_enabled, checked: autoprovisioning, checkedValue: true">
ON
+
@@ -501,7 +514,7 @@
id="autoprovisioning_attribute"
placeholder="e.g. eduPersonEntitlement"
data-error=" Please input field responsible for autoprovisioning"
- value="{{ SETTING.get('autoprovisioning_attribute') }}">
+ data-bind="enable: ldap_enabled() && autoprovisioning(), value: autoprovisioning_attribute, valueUpdate: 'afterkeydown'">
@@ -513,7 +526,7 @@
id="urn_value"
placeholder="e.g. urn:mace:
"
data-error="Please fill this field"
- value="{{ SETTING.get('urn_value') }}">
+ data-bind="enable: ldap_enabled() && autoprovisioning(), value: urn_value, valueUpdate: 'afterkeydown'">
{% if error %}
Please input the correct prefix for your urn value
{% endif %}
@@ -524,16 +537,16 @@
+ value="0"
+ data-bind="enable: ldap_enabled() && autoprovisioning(), checked: purge, checkedValue: false">
OFF
+ value="1"
+ data-bind="enable: ldap_enabled() && autoprovisioning(), checked: purge, checkedValue: true">
ON
@@ -722,7 +735,7 @@
-
+
@@ -762,7 +775,7 @@
id="google_oauth_client_secret"
placeholder="Google OAuth Client Secret"
data-error="Please input Client Secret"
- value="{{ SETTING.get('google_oauth_client_secret') }}">
+ data-bind="enable: google_oauth_enabled, value: google_oauth_client_secret, valueUpdate: 'afterkeydown'">
@@ -772,16 +785,16 @@
id="google_oauth_scope"
placeholder="e.g. email profile"
data-error="Please input scope"
- value="{{ SETTING.get('google_oauth_scope') }}">
+ data-bind="enable: google_oauth_enabled, value: google_oauth_scope, valueUpdate: 'afterkeydown'">
API URL
+ data-bind="enable: google_oauth_enabled, value: google_base_url, valueUpdate: 'afterkeydown'">
@@ -790,18 +803,18 @@
+ data-bind="enable: google_oauth_enabled, value: google_oauth_metadata_url, valueUpdate: 'afterkeydown'">
Token URL
+ data-bind="enable: google_oauth_enabled, value: google_token_url, valueUpdate: 'afterkeydown'">
@@ -810,9 +823,9 @@
+ data-bind="enable: google_oauth_enabled, value: google_authorize_url, valueUpdate: 'afterkeydown'">
@@ -853,7 +866,7 @@
-
+
@@ -890,7 +903,7 @@
id="github_oauth_secret"
placeholder="Github OAuth Client Secret"
data-error="Please input Client Secret"
- value="{{ SETTING.get('github_oauth_secret') }}">
+ data-bind="enable: github_oauth_enabled, value: github_oauth_secret, valueUpdate: 'afterkeydown'">
@@ -900,7 +913,7 @@
id="github_oauth_scope"
placeholder="e.g. email"
data-error="Please input scope"
- value="{{ SETTING.get('github_oauth_scope') }}">
+ data-bind="enable: github_oauth_enabled, value: github_oauth_scope, valueUpdate: 'afterkeydown'">
@@ -910,7 +923,7 @@
id="github_oauth_api_url"
placeholder="e.g. https://api.github.com/user"
data-error="Please input API URL"
- value="{{ SETTING.get('github_oauth_api_url') }}">
+ data-bind="enable: github_oauth_enabled, value: github_oauth_api_url, valueUpdate: 'afterkeydown'">
@@ -921,7 +934,7 @@
id="github_oauth_metadata_url"
placeholder="e.g. https://{yourDomain}/.well-known/oauth-metadata.json"
data-error="Please input Metadata URL"
- value="{{ SETTING.get('github_oauth_metadata_url') }}">
+ data-bind="enable: github_oauth_enabled, value: github_oauth_metadata_url, valueUpdate: 'afterkeydown'">
@@ -932,7 +945,7 @@
id="github_oauth_token_url"
placeholder="e.g. https://github.com/login/oauth/access_token"
data-error="Please input Token URL"
- value="{{ SETTING.get('github_oauth_token_url') }}">
+ data-bind="enable: github_oauth_enabled, value: github_oauth_token_url, valueUpdate: 'afterkeydown'">
@@ -943,7 +956,7 @@
id="github_oauth_authorize_url"
placeholder="e.g. https://github.com/login/oauth/authorize"
data-error="Please input Authorize URL"
- value="{{ SETTING.get('github_oauth_authorize_url') }}">
+ data-bind="enable: github_oauth_enabled, value: github_oauth_authorize_url, valueUpdate: 'afterkeydown'">
@@ -981,7 +994,7 @@
-
+
@@ -1172,7 +1185,7 @@
id="azure_group_accounts_name_re"
placeholder="e.g. (.*)"
data-error="Please input the regex for Azure group name"
- value="{{ SETTING.get('azure_group_accounts_name_re') }}">
+ data-bind="enable: azure_oauth_enabled() && azure_group_accounts_enabled(), value: azure_group_accounts_name_re, valueUpdate: 'afterkeydown'">
@@ -1184,7 +1197,7 @@
id="azure_group_accounts_description"
placeholder="e.g. description. If empty uses whole string"
data-error="Please input the Claim for Azure group description"
- value="{{ SETTING.get('azure_group_accounts_description') }}">
+ data-bind="enable: azure_oauth_enabled() && azure_group_accounts_enabled(), value: azure_group_accounts_description, valueUpdate: 'afterkeydown'">
@@ -1196,7 +1209,7 @@
id="azure_group_accounts_description_re"
placeholder="e.g. (.*). If empty uses whole string"
data-error="Please input the regex for Azure group description"
- value="{{ SETTING.get('azure_group_accounts_description_re') }}">
+ data-bind="enable: azure_oauth_enabled() && azure_group_accounts_enabled(), value: azure_group_accounts_description_re, valueUpdate: 'afterkeydown'">
@@ -1289,7 +1302,7 @@
-
+
+
+ Email
+
@@ -1411,7 +1433,7 @@
id="oidc_oauth_firstname"
placeholder="e.g. given_name"
data-error="Please input First Name claim"
- value="{{ SETTING.get('oidc_oauth_firstname') }}">
+ data-bind="enable: oidc_oauth_enabled, value: oidc_oauth_firstname, valueUpdate: 'afterkeydown'">
@@ -1421,16 +1443,7 @@
id="oidc_oauth_last_name"
placeholder="e.g. family_name"
data-error="Please input Last Name claim"
- value="{{ SETTING.get('oidc_oauth_last_name') }}">
-
-
-
- Email
-
+ data-bind="enable: oidc_oauth_enabled, value: oidc_oauth_last_name, valueUpdate: 'afterkeydown'">
@@ -1444,7 +1457,7 @@
id="oidc_oauth_account_name_property"
placeholder="e.g. account_name"
data-error="Please input property containing account_name"
- value="{{ SETTING.get('oidc_oauth_account_name_property') }}">
+ data-bind="enable: oidc_oauth_enabled, value: oidc_oauth_account_name_property, valueUpdate: 'afterkeydown'">
@@ -1456,7 +1469,7 @@
id="oidc_oauth_account_description_property"
placeholder="e.g. account_description"
data-error="Please input property containing account_description"
- value="{{ SETTING.get('oidc_oauth_account_description_property') }}">
+ data-bind="enable: oidc_oauth_enabled, value: oidc_oauth_account_description_property, valueUpdate: 'afterkeydown'">
@@ -1516,8 +1529,18 @@
{%- endassets %}
+
+
+
+