From 765eab999a3b16ebbd45cc49405e2ad641666043 Mon Sep 17 00:00:00 2001 From: Steve Shipway Date: Fri, 3 Jan 2020 15:36:38 +1300 Subject: [PATCH 1/2] Azure OAuth - add Group mappings to Roles --- powerdnsadmin/models/setting.py | 4 ++ powerdnsadmin/routes/admin.py | 4 ++ powerdnsadmin/routes/index.py | 34 +++++++++++++- .../admin_setting_authentication.html | 45 ++++++++++++++++++- 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/powerdnsadmin/models/setting.py b/powerdnsadmin/models/setting.py index 991c2ae..fba9a26 100644 --- a/powerdnsadmin/models/setting.py +++ b/powerdnsadmin/models/setting.py @@ -73,6 +73,10 @@ class Setting(db.Model): 'https://login.microsoftonline.com/[tenancy]/oauth2/v2.0/token', 'azure_oauth_authorize_url': 'https://login.microsoftonline.com/[tenancy]/oauth2/v2.0/authorize', + 'azure_sg_enabled': False, + 'azure_admin_group': '', + 'azure_operator_group': '', + 'azure_user_group': '', 'oidc_oauth_enabled': False, 'oidc_oauth_key': '', 'oidc_oauth_secret': '', diff --git a/powerdnsadmin/routes/admin.py b/powerdnsadmin/routes/admin.py index cd3cbe8..d892a29 100644 --- a/powerdnsadmin/routes/admin.py +++ b/powerdnsadmin/routes/admin.py @@ -720,6 +720,10 @@ def setting_authentication(): request.form.get('azure_oauth_token_url')) Setting().set('azure_oauth_authorize_url', request.form.get('azure_oauth_authorize_url')) + Setting().set('azure_sg_enabled', True if request.form.get('azure_sg_enabled')=='ON' else False) + Setting().set('azure_admin_group', request.form.get('azure_admin_group')) + Setting().set('azure_operator_group', request.form.get('azure_operator_group')) + Setting().set('azure_user_group', request.form.get('azure_user_group')) result = { 'status': True, 'msg': 'Saved successfully. Please reload PDA to take effect.' diff --git a/powerdnsadmin/routes/index.py b/powerdnsadmin/routes/index.py index 08bf111..e476e0d 100644 --- a/powerdnsadmin/routes/index.py +++ b/powerdnsadmin/routes/index.py @@ -201,7 +201,19 @@ def login(): return redirect(url_for('index.index')) if 'azure_token' in session: - me = json.loads(azure.get('me').text) + azure_info = azure.get('me?$select=displayName,givenName,id,mail,surname,userPrincipalName,preferredName,memberOf').text + current_app.logger.info('Azure loginreturned: '+azure_info) + me = json.loads(azure_info) + + azure_info = azure.post('me/getMemberGroups',json={'securityEnabledOnly': False}).text + current_app.logger.info('Azure groups returned: '+azure_info) + grouplookup = json.loads(azure_info) + # Groups are in mygroups['value'] which is an array + if "value" in grouplookup: + mygroups = grouplookup["value"] + else: + mygroups = [] + azure_username = me["userPrincipalName"] azure_givenname = me["givenName"] azure_familyname = me["surname"] @@ -211,6 +223,7 @@ def login(): azure_email = "" if not azure_email: azure_email = me["userPrincipalName"] + # Handle foreign principals such as guest users azure_email = re.sub(r"#.*$", "", azure_email) azure_username = re.sub(r"#.*$", "", azure_username) @@ -235,6 +248,25 @@ def login(): session['user_id'] = user.id session['authentication_type'] = 'OAuth' + + # Handle group memberships, if defined + if Setting().get('azure_sg_enabled'): + if Setting().get('azure_admin_group') in mygroups: + current_app.logger.info('Setting role for user '+azure_username+' to Administrator due to group membership') + user.set_role("Administrator") + else: + if Setting().get('azure_operator_group') in mygroups: + current_app.logger.info('Setting role for user '+azure_username+' to Operator due to group membership') + user.set_role("Operator") + else: + if Setting().get('azure_user_group') in mygroups: + current_app.logger.info('Setting role for user '+azure_username+' to User due to group membership') + user.set_role("User") + else: + current_app.logger.warning('User '+azure_username+' has no relevant group memberships') + session.pop('azure_token', None) + return render_template('login.html', saml_enabled=SAML_ENABLED, error=('User '+azure_username+' is not in any authorised groups.')) + login_user(user, remember=False) signin_history(user.username, 'Azure OAuth', True) return redirect(url_for('index.index')) diff --git a/powerdnsadmin/templates/admin_setting_authentication.html b/powerdnsadmin/templates/admin_setting_authentication.html index 7cd55d7..53a9798 100644 --- a/powerdnsadmin/templates/admin_setting_authentication.html +++ b/powerdnsadmin/templates/admin_setting_authentication.html @@ -384,7 +384,7 @@
- ADVANCE + ADVANCED
@@ -406,6 +406,36 @@
+
+ GROUP SECURITY +
+ +
+ +     + +
+
+
+ + + +
+
+ + + +
+
+ + + +
+
@@ -414,6 +444,19 @@
Help

Fill in all the fields in the left form.

+

You first need to define an Application Registration in your Azure Active Directory, with the appropriate HTTPS URL for this endpoint, and with the appropriate rights, as explained in the documentation.

+

+
From cff4d0af533d1493d167804b6754c996508ea792 Mon Sep 17 00:00:00 2001 From: Steve Shipway Date: Fri, 3 Jan 2020 15:57:07 +1300 Subject: [PATCH 2/2] Fix some formatting issues --- powerdnsadmin/routes/index.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/powerdnsadmin/routes/index.py b/powerdnsadmin/routes/index.py index e476e0d..61e4bac 100644 --- a/powerdnsadmin/routes/index.py +++ b/powerdnsadmin/routes/index.py @@ -201,12 +201,13 @@ def login(): return redirect(url_for('index.index')) if 'azure_token' in session: - azure_info = azure.get('me?$select=displayName,givenName,id,mail,surname,userPrincipalName,preferredName,memberOf').text - current_app.logger.info('Azure loginreturned: '+azure_info) + azure_info = azure.get('me?$select=displayName,givenName,id,mail,surname,userPrincipalName,preferredName').text + current_app.logger.info('Azure login returned: '+azure_info) me = json.loads(azure_info) - azure_info = azure.post('me/getMemberGroups',json={'securityEnabledOnly': False}).text - current_app.logger.info('Azure groups returned: '+azure_info) + azure_info = azure.post('me/getMemberGroups', + json={'securityEnabledOnly': False}).text + current_app.logger.info('Azure groups returned: ' + azure_info) grouplookup = json.loads(azure_info) # Groups are in mygroups['value'] which is an array if "value" in grouplookup: @@ -252,20 +253,31 @@ def login(): # Handle group memberships, if defined if Setting().get('azure_sg_enabled'): if Setting().get('azure_admin_group') in mygroups: - current_app.logger.info('Setting role for user '+azure_username+' to Administrator due to group membership') + current_app.logger.info('Setting role for user ' + + azure_username + + ' to Administrator due to group membership') user.set_role("Administrator") else: if Setting().get('azure_operator_group') in mygroups: - current_app.logger.info('Setting role for user '+azure_username+' to Operator due to group membership') + current_app.logger.info('Setting role for user ' + + azure_username + + ' to Operator due to group membership') user.set_role("Operator") else: if Setting().get('azure_user_group') in mygroups: - current_app.logger.info('Setting role for user '+azure_username+' to User due to group membership') + current_app.logger.info('Setting role for user ' + + azure_username + + ' to User due to group membership') user.set_role("User") else: - current_app.logger.warning('User '+azure_username+' has no relevant group memberships') + current_app.logger.warning('User ' + + azure_username + + ' has no relevant group memberships') session.pop('azure_token', None) - return render_template('login.html', saml_enabled=SAML_ENABLED, error=('User '+azure_username+' is not in any authorised groups.')) + return render_template('login.html', + saml_enabled=SAML_ENABLED, + error=('User ' + azure_username + + ' is not in any authorised groups.')) login_user(user, remember=False) signin_history(user.username, 'Azure OAuth', True)