mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-12-28 14:05:41 +00:00
Improve SAML support
Accept IdP EntityID to use when metadata contains more than one IdP. Allow specifying attribute names to get given name, surname, and email address. Allow specifying NameIDFormat to request. Allow specifying whether to get username from a named attribute, or NameID. Allow getting administrator state from attribute.
This commit is contained in:
parent
77f0deade8
commit
73d5215d3a
@ -19,7 +19,7 @@ if app.config['SAML_ENABLED']:
|
||||
from onelogin.saml2.idp_metadata_parser import OneLogin_Saml2_IdPMetadataParser
|
||||
idp_timestamp = datetime(1970, 1, 1)
|
||||
idp_data = None
|
||||
idp_data = OneLogin_Saml2_IdPMetadataParser.parse_remote(app.config['SAML_METADATA_URL'])
|
||||
idp_data = OneLogin_Saml2_IdPMetadataParser.parse_remote(app.config['SAML_METADATA_URL'], entity_id=app.config.get('SAML_IDP_ENTITY_ID', None))
|
||||
if idp_data is None:
|
||||
print('SAML: IDP Metadata initial load failed')
|
||||
exit(-1)
|
||||
@ -37,7 +37,7 @@ def get_idp_data():
|
||||
|
||||
def retreive_idp_data():
|
||||
global idp_data, idp_timestamp
|
||||
new_idp_data = OneLogin_Saml2_IdPMetadataParser.parse_remote(app.config['SAML_METADATA_URL'])
|
||||
new_idp_data = OneLogin_Saml2_IdPMetadataParser.parse_remote(app.config['SAML_METADATA_URL'], entity_id=app.config.get('SAML_IDP_ENTITY_ID', None))
|
||||
if new_idp_data is not None:
|
||||
idp_data = new_idp_data
|
||||
idp_timestamp = datetime.now()
|
||||
@ -205,7 +205,7 @@ def email_to_gravatar_url(email="", size=100):
|
||||
|
||||
def prepare_flask_request(request):
|
||||
# If server is behind proxys or balancers use the HTTP_X_FORWARDED fields
|
||||
url_data = urlparse.urlparse(request.url)
|
||||
url_data = urlparse(request.url)
|
||||
return {
|
||||
'https': 'on' if request.scheme == 'https' else 'off',
|
||||
'http_host': request.host,
|
||||
@ -229,7 +229,10 @@ def init_saml_auth(req):
|
||||
metadata = get_idp_data()
|
||||
settings = {}
|
||||
settings['sp'] = {}
|
||||
settings['sp']['NameIDFormat'] = idp_data['sp']['NameIDFormat']
|
||||
if 'SAML_NAMEID_FORMAT' in app.config:
|
||||
settings['sp']['NameIDFormat'] = app.config['SAML_NAMEID_FORMAT']
|
||||
else:
|
||||
settings['sp']['NameIDFormat'] = idp_data.get('sp', {}).get('NameIDFormat', 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified')
|
||||
settings['sp']['entityId'] = app.config['SAML_SP_ENTITY_ID']
|
||||
cert = open(CERT_FILE, "r").readlines()
|
||||
key = open(KEY_FILE, "r").readlines()
|
||||
@ -275,4 +278,4 @@ def init_saml_auth(req):
|
||||
settings['organization']['en-US']['name'] = 'PowerDNS-Admin'
|
||||
settings['organization']['en-US']['url'] = own_url
|
||||
auth = OneLogin_Saml2_Auth(req, settings)
|
||||
return auth
|
||||
return auth
|
||||
|
34
app/views.py
34
app/views.py
@ -17,7 +17,7 @@ from flask_login import login_user, logout_user, current_user, login_required
|
||||
from werkzeug import secure_filename
|
||||
from werkzeug.security import gen_salt
|
||||
|
||||
from .models import User, Domain, Record, Server, History, Anonymous, Setting, DomainSetting, DomainTemplate, DomainTemplateRecord
|
||||
from .models import User, Domain, Record, Server, History, Anonymous, Setting, DomainSetting, DomainTemplate, DomainTemplateRecord, Role
|
||||
from app import app, login_manager, github, google
|
||||
from app.lib import utils
|
||||
from app.decorators import admin_role_required, can_access_domain
|
||||
@ -230,20 +230,36 @@ def saml_authorized():
|
||||
self_url = self_url+req['script_name']
|
||||
if 'RelayState' in request.form and self_url != request.form['RelayState']:
|
||||
return redirect(auth.redirect_to(request.form['RelayState']))
|
||||
user = User.query.filter_by(username=session['samlNameId'].lower()).first()
|
||||
if app.config.get('SAML_ATTRIBUTE_USERNAME', False):
|
||||
username = session['samlUserdata'][app.config['SAML_ATTRIBUTE_USERNAME']][0].lower()
|
||||
else:
|
||||
username = session['samlNameId'].lower()
|
||||
user = User.query.filter_by(username=username).first()
|
||||
if not user:
|
||||
# create user
|
||||
user = User(username=session['samlNameId'],
|
||||
user = User(username=username,
|
||||
plain_text_password = None,
|
||||
email=session['samlNameId'])
|
||||
user.create_local_user()
|
||||
session['user_id'] = user.id
|
||||
if session['samlUserdata'].has_key("email"):
|
||||
user.email = session['samlUserdata']["email"][0].lower()
|
||||
if session['samlUserdata'].has_key("givenname"):
|
||||
user.firstname = session['samlUserdata']["givenname"][0]
|
||||
if session['samlUserdata'].has_key("surname"):
|
||||
user.lastname = session['samlUserdata']["surname"][0]
|
||||
logging.debug("Attributes are: {0}".format(repr(session['samlUserdata'])))
|
||||
email_attribute_name = app.config.get('SAML_ATTRIBUTE_EMAIL', 'email')
|
||||
givenname_attribute_name = app.config.get('SAML_ATTRIBUTE_GIVENNAME', 'givenname')
|
||||
surname_attribute_name = app.config.get('SAML_ATTRIBUTE_SURNAME', 'surname')
|
||||
admin_attribute_name = app.config.get('SAML_ATTRIBUTE_ADMIN', None)
|
||||
if email_attribute_name in session['samlUserdata']:
|
||||
user.email = session['samlUserdata'][email_attribute_name][0].lower()
|
||||
if givenname_attribute_name in session['samlUserdata']:
|
||||
user.firstname = session['samlUserdata'][givenname_attribute_name][0]
|
||||
if surname_attribute_name in session['samlUserdata']:
|
||||
user.lastname = session['samlUserdata'][surname_attribute_name][0]
|
||||
if admin_attribute_name:
|
||||
if 'true' in session['samlUserdata'].get(admin_attribute_name, []):
|
||||
logging.debug("User is an admin")
|
||||
user.role_id = Role.query.filter_by(name='Administrator').first().id
|
||||
else:
|
||||
logging.debug("User is NOT an admin")
|
||||
user.role_id = Role.query.filter_by(name='User').first().id
|
||||
user.plain_text_password = None
|
||||
user.update_profile()
|
||||
session['external_auth'] = True
|
||||
|
@ -97,6 +97,46 @@ SAML_PATH = os.path.join(os.path.dirname(__file__), 'saml')
|
||||
SAML_METADATA_URL = 'https://<hostname>/FederationMetadata/2007-06/FederationMetadata.xml'
|
||||
#Cache Lifetime in Seconds
|
||||
SAML_METADATA_CACHE_LIFETIME = 1
|
||||
|
||||
## EntityID of the IdP to use. Only needed if more than one IdP is
|
||||
## in the SAML_METADATA_URL
|
||||
### Default: First (only) IdP in the SAML_METADATA_URL
|
||||
### Example: https://idp.example.edu/idp
|
||||
#SAML_IDP_ENTITY_ID = 'https://idp.example.edu/idp'
|
||||
## NameID format to request
|
||||
### Default: The SAML NameID Format in the metadata if present,
|
||||
### otherwise urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
|
||||
### Example: urn:oid:0.9.2342.19200300.100.1.1
|
||||
#SAML_NAMEID_FORMAT = 'urn:oid:0.9.2342.19200300.100.1.1'
|
||||
|
||||
## Attribute to use for Email address
|
||||
### Default: email
|
||||
### Example: urn:oid:0.9.2342.19200300.100.1.3
|
||||
#SAML_ATTRIBUTE_EMAIL = 'urn:oid:0.9.2342.19200300.100.1.3'
|
||||
|
||||
## Attribute to use for Given name
|
||||
### Default: givenname
|
||||
### Example: urn:oid:2.5.4.42
|
||||
#SAML_ATTRIBUTE_GIVENNAME = 'urn:oid:2.5.4.42'
|
||||
|
||||
## Attribute to use for Surname
|
||||
### Default: surname
|
||||
### Example: urn:oid:2.5.4.4
|
||||
#SAML_ATTRIBUTE_SURNAME = 'urn:oid:2.5.4.4'
|
||||
|
||||
## Attribute to use for username
|
||||
### Default: Use NameID instead
|
||||
### Example: urn:oid:0.9.2342.19200300.100.1.1
|
||||
#SAML_ATTRIBUTE_USERNAME = 'urn:oid:0.9.2342.19200300.100.1.1'
|
||||
|
||||
## Attribute to get admin status from
|
||||
### Default: Don't control admin with SAML attribute
|
||||
### Example: https://example.edu/pdns-admin
|
||||
### If set, look for the value 'true' to set a user as an administrator
|
||||
### If not included in assertion, or set to something other than 'true',
|
||||
### the user is set as a non-administrator user.
|
||||
#SAML_ATTRIBUTE_ADMIN = 'https://example.edu/pdns-admin'
|
||||
|
||||
SAML_SP_ENTITY_ID = 'http://<SAML SP Entity ID>'
|
||||
SAML_SP_CONTACT_NAME = '<contact name>'
|
||||
SAML_SP_CONTACT_MAIL = '<contact mail>'
|
||||
|
Loading…
Reference in New Issue
Block a user