diff --git a/README.md b/README.md index 88d8ae4..fde76d0 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,14 @@ Web application configuration is stored in `config.py` file. Let's clone it from (flask)$ vim config.py ``` +You can configure group based security by tweaking the below parameters in `config.py`. Groups membership comes from LDAP. +Setting `LDAP_GROUP_SECURITY` to True enables group-based security. With this enabled only members of the two groups listed below are allowed to login. Members of `LDAP_ADMIN_GROUP` will get the Administrator role and members of `LDAP_USER_GROUP` will get the User role. Sample config below: +``` +LDAP_GROUP_SECURITY = True +LDAP_ADMIN_GROUP = 'CN=PowerDNS-Admin Admin,OU=Custom,DC=ivan,DC=local' +LDAP_USER_GROUP = 'CN=PowerDNS-Admin User,OU=Custom,DC=ivan,DC=local' +``` + Create database after having proper configs ``` (flask)% ./create_db.py diff --git a/app/models.py b/app/models.py index fc88c7e..a7f9872 100644 --- a/app/models.py +++ b/app/models.py @@ -20,12 +20,21 @@ from lib import utils from lib.log import logger logging = logger('MODEL', app.config['LOG_LEVEL'], app.config['LOG_FILE']).config() +LDAP_URI = app.config['LDAP_URI'] +LDAP_USERNAME = app.config['LDAP_USERNAME'] +LDAP_PASSWORD = app.config['LDAP_PASSWORD'] +LDAP_SEARCH_BASE = app.config['LDAP_SEARCH_BASE'] +LDAP_TYPE = app.config['LDAP_TYPE'] if 'LDAP_TYPE' in app.config.keys(): LDAP_URI = app.config['LDAP_URI'] LDAP_USERNAME = app.config['LDAP_USERNAME'] LDAP_PASSWORD = app.config['LDAP_PASSWORD'] LDAP_SEARCH_BASE = app.config['LDAP_SEARCH_BASE'] LDAP_TYPE = app.config['LDAP_TYPE'] + LDAP_GROUP_SECURITY = app.config['LDAP_GROUP_SECURITY'] + if LDAP_GROUP_SECURITY == True: + LDAP_ADMIN_GROUP = app.config['LDAP_ADMIN_GROUP'] + LDAP_USER_GROUP = app.config['LDAP_USER_GROUP'] LDAP_FILTER = app.config['LDAP_FILTER'] LDAP_USERNAMEFIELD = app.config['LDAP_USERNAMEFIELD'] else: @@ -216,27 +225,69 @@ class User(db.Model): # create user if not exist in the db if not User.query.filter(User.username == self.username).first(): try: - # try to get user's firstname & lastname from LDAP - # this might be changed in the future - self.firstname = result[0][0][1]['givenName'][0] - self.lastname = result[0][0][1]['sn'][0] - self.email = result[0][0][1]['mail'][0] - except Exception: - self.firstname = self.username - self.lastname = '' + ldap_username = result[0][0][0] + l.simple_bind_s(ldap_username, self.password) + if LDAP_GROUP_SECURITY: + try: + if LDAP_TYPE == 'ldap': + uid = result[0][0][1]['uid'][0] + groupSearchFilter = "(&(objectClass=posixGroup)(memberUid=%s))" % uid + else: + groupSearchFilter = "(&(objectcategory=group)(member=%s))" % ldap_username + groups = self.ldap_search(groupSearchFilter, LDAP_SEARCH_BASE) + allowedlogin = False + isadmin = False + for group in groups: + logging.debug(group) + if (group[0][0] == LDAP_ADMIN_GROUP): + allowedlogin = True + isadmin = True + logging.info('User %s is part of the "%s" group that allows admin access to PowerDNS-Admin' % (self.username,LDAP_ADMIN_GROUP)) + if (group[0][0] == LDAP_USER_GROUP): + allowedlogin = True + logging.info('User %s is part of the "%s" group that allows user access to PowerDNS-Admin' % (self.username,LDAP_USER_GROUP)) + if allowedlogin == False: + logging.error('User %s is not part of the "%s" or "%s" groups that allow access to PowerDNS-Admin' % (self.username,LDAP_ADMIN_GROUP,LDAP_USER_GROUP)) + return False + except: + logging.error('LDAP group lookup for user "%s" has failed' % self.username) + logging.info('User "%s" logged in successfully' % self.username) + + # create user if not exist in the db + if User.query.filter(User.username == self.username).first() == None: + try: + # try to get user's firstname & lastname from LDAP + # this might be changed in the future + self.firstname = result[0][0][1]['givenName'][0] + self.lastname = result[0][0][1]['sn'][0] + except: + self.firstname = self.username + self.lastname = '' - # first register user will be in Administrator role - self.role_id = Role.query.filter_by(name='User').first().id - if User.query.count() == 0: - self.role_id = Role.query.filter_by(name='Administrator').first().id + # first registered user will be in Administrator role or if part of LDAP Admin group + if (User.query.count() == 0): + self.role_id = Role.query.filter_by(name='Administrator').first().id + else: + self.role_id = Role.query.filter_by(name='User').first().id + + # + if LDAP_GROUP_SECURITY: + if isadmin == True: + self.role_id = Role.query.filter_by(name='Administrator').first().id - self.create_user() - logging.info('Created user "%s" in the DB' % self.username) - - return True - - logging.error('Unsupported authentication method') - return False + self.create_user() + logging.info('Created user "%s" in the DB' % self.username) + else: + # user already exists in database, set their admin status based on group membership (if enabled) + if LDAP_GROUP_SECURITY: + self.set_admin(isadmin) + return True + except: + logging.error('User "%s" input a wrong password' % self.username) + return False + else: + logging.error('Unsupported authentication method') + return False def create_user(self): """ diff --git a/config_template.py b/config_template.py index cdde7b4..01ef241 100644 --- a/config_template.py +++ b/config_template.py @@ -41,6 +41,9 @@ LDAP_URI = 'ldaps://your-ldap-server:636' LDAP_USERNAME = 'cn=dnsuser,ou=users,ou=services,dc=duykhanh,dc=me' LDAP_PASSWORD = 'dnsuser' LDAP_SEARCH_BASE = 'ou=System Admins,ou=People,dc=duykhanh,dc=me' +LDAP_GROUP_SECURITY = False +LDAP_ADMIN_GROUP = 'CN=PowerDNS-Admin Admin,OU=Custom,DC=ivan,DC=local' +LDAP_USER_GROUP = 'CN=PowerDNS-Admin User,OU=Custom,DC=ivan,DC=local' # Additional options only if LDAP_TYPE=ldap LDAP_USERNAMEFIELD = 'uid' LDAP_FILTER = '(objectClass=inetorgperson)'