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("""
@@ -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('''
Zone: {{ domain }}
@@ -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 @@
-
+

Settings Editor

@@ -43,31 +43,43 @@
Associate: {{ history_assoc_account }}