diff --git a/README.md b/README.md index eb93a05cdf437115a8901ab80897e54a53177850..d36f6f25d572d01a22116a0f31b51ac210f40c16 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,45 @@ example using Flask's and [blueprints](http://flask.pocoo.org/docs/blueprints/). +OpenLDAP +---------- + +Add the ``LDAP`` instance to your code and depending on your OpenLDAP +configuration, add the following at least LDAP_USER_OBJECT_FILTER and +LDAP_USER_OBJECT_FILTER. + +```python +from flask import Flask +from flask.ext.simpleldap import LDAP + +app = Flask(__name__) +ldap = LDAP(app) + +# Base +app.config['LDAP_REALM_NAME'] = 'OpenLDAP Authentication' +app.config['LDAP_HOST'] = 'openldap.example.org' +app.config['LDAP_BASE_DN'] = 'dc=users,dc=openldap,dc=org' +app.config['LDAP_USERNAME'] = 'cn=user,ou=servauth-users,dc=users,dc=openldap,dc=org' +app.config['LDAP_PASSWORD'] = 'password' + +# OpenLDAP +app.config['LDAP_OBJECTS_DN'] = 'dn' +app.config['LDAP_OPENLDAP'] = True +app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=inetOrgPerson)(uid=%s))' + +# Groups +app.config['LDAP_GROUP_MEMBERS_FIELD'] = "uniquemember" +app.config['LDAP_GROUP_OBJECT_FILTER'] = "(&(objectclass=groupOfUniqueNames)(uniquemember=%s))" +app.config['LDAP_GROUP_MEMBER_FILTER'] = "(&(cn=*)(objectclass=groupOfUniqueNames)(uniquemember=%s))" +app.config['LDAP_GROUP_MEMBER_FILTER_FIELD'] = "cn" + +@app.route('/ldap') +@ldap.login_required +def ldap_protected(): + return 'Success!' +``` + + Resources --------- diff --git a/examples/basic_auth/app_oldap.py b/examples/basic_auth/app_oldap.py new file mode 100644 index 0000000000000000000000000000000000000000..06880f518bd80641e6a19cd870638bed246b87cf --- /dev/null +++ b/examples/basic_auth/app_oldap.py @@ -0,0 +1,25 @@ +from flask import Flask, g, request, session, redirect, url_for +from flask.ext.simpleldap import LDAP + +app = Flask(__name__) +app.secret_key = 'dev key' +app.debug = True + +app.config['LDAP_OPENLDAP'] = True +app.config['LDAP_OBJECTS_DN'] = 'dn' +app.config['LDAP_REALM_NAME'] = 'OpenLDAP Authentication' +app.config['LDAP_HOST'] = 'openldap.example.org' +app.config['LDAP_BASE_DN'] = 'dc=users,dc=openldap,dc=org' +app.config['LDAP_USERNAME'] = 'cn=user,ou=servauth-users,dc=users,dc=openldap,dc=org' +app.config['LDAP_PASSWORD'] = 'password' +app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=inetOrgPerson)(uid=%s))' + +ldap = LDAP(app) + +@app.route('/') +@ldap.basic_auth_required +def index(): + return 'Welcome, {0}!'.format(g.ldap_username) + +if __name__ == '__main__': + app.run() diff --git a/examples/groups/app.py b/examples/groups/app.py index b074e6093cd6ba1e2e6e64346afff7cf54a3b4c6..88b697c14d802cb8e77cab679492b14e9425bafe 100644 --- a/examples/groups/app.py +++ b/examples/groups/app.py @@ -12,6 +12,7 @@ app.config['LDAP_PASSWORD'] = 'password' ldap = LDAP(app) + @app.before_request def before_request(): g.user = None diff --git a/examples/groups/app_oldap.py b/examples/groups/app_oldap.py new file mode 100644 index 0000000000000000000000000000000000000000..98af66e956381a902f16d23b37a0c7b98ef2ccbe --- /dev/null +++ b/examples/groups/app_oldap.py @@ -0,0 +1,74 @@ +from flask import Flask, g, request, session, redirect, url_for +from flask.ext.simpleldap import LDAP + +app = Flask(__name__) +app.secret_key = 'dev key' +app.debug = True + +app.config['LDAP_OPENLDAP'] = True +app.config['LDAP_OBJECTS_DN'] = 'dn' +app.config['LDAP_REALM_NAME'] = 'OpenLDAP Authentication' +app.config['LDAP_HOST'] = 'openldap.example.org' +app.config['LDAP_BASE_DN'] = 'dc=users,dc=openldap,dc=org' +app.config['LDAP_USERNAME'] = 'cn=user,ou=servauth-users,dc=users,dc=openldap,dc=org' +app.config['LDAP_PASSWORD'] = 'password' +app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=inetOrgPerson)(uid=%s))' + +# Group configuration +app.config['LDAP_GROUP_MEMBERS_FIELD'] = "uniquemember" +app.config['LDAP_GROUP_OBJECT_FILTER'] = "(&(objectclass=groupOfUniqueNames)(uniquemember=%s))" +app.config['LDAP_GROUP_MEMBER_FILTER'] = "(&(cn=*)(objectclass=groupOfUniqueNames)(uniquemember=%s))" +app.config['LDAP_GROUP_MEMBER_FILTER_FIELD'] = "cn" + +ldap = LDAP(app) + + +@app.before_request +def before_request(): + g.user = None + if 'user_id' in session: + # This is where you'd query your database to get the user info. + g.user = {} + # Create a global with the LDAP groups the user is a member of. + g.ldap_groups = ldap.get_user_groups(user=session['user_id']) + + +@app.route('/') +@ldap.login_required +def index(): + return 'Successfully logged in!' + + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if g.user: + return redirect(url_for('index')) + if request.method == 'POST': + user = request.form['user'] + passwd = request.form['passwd'] + test = ldap.bind_user(user, passwd) + if test is None or passwd == '': + return 'Invalid credentials' + else: + session['user_id'] = request.form['user'] + return redirect('/') + return """<form action="" method="post"> + user: <input name="user"><br> + password:<input type="password" name="passwd"><br> + <input type="submit" value="Submit"></form>""" + + +@app.route('/group') +@ldap.group_required(groups=['web-developers']) +def group(): + return 'Group restricted page' + + +@app.route('/logout') +def logout(): + session.pop('user_id', None) + return redirect(url_for('index')) + + +if __name__ == '__main__': + app.run() diff --git a/flask_simpleldap/__init__.py b/flask_simpleldap/__init__.py index 3c84e8242be40267d6de7f8f2cd24aa138bf0c1a..0c8b26460cebdb19bbeab32dbfc11a966def9bf6 100644 --- a/flask_simpleldap/__init__.py +++ b/flask_simpleldap/__init__.py @@ -1,14 +1,13 @@ # -*- coding: utf-8 -*- -__all__ = ['LDAP'] - import re from functools import wraps - import ldap import ldap.filter from flask import abort, current_app, g, make_response, redirect, url_for, \ request +__all__ = ['LDAP'] + try: from flask import _app_ctx_stack as stack except ImportError: @@ -65,6 +64,9 @@ class LDAP(object): app.config.setdefault('LDAP_GROUP_MEMBERS_FIELD', 'member') app.config.setdefault('LDAP_LOGIN_VIEW', 'login') app.config.setdefault('LDAP_REALM_NAME', 'LDAP authentication') + app.config.setdefault('LDAP_OPENLDAP', False) + app.config.setdefault('LDAP_GROUP_MEMBER_FILTER', '*') + app.config.setdefault('LDAP_GROUP_MEMBER_FILTER_FIELD', '*') if app.config['LDAP_USE_SSL'] or app.config['LDAP_USE_TLS']: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, @@ -140,6 +142,7 @@ class LDAP(object): """ user_dn = self.get_object_details(user=username, dn_only=True) + if user_dn is None: return try: @@ -174,14 +177,20 @@ class LDAP(object): try: records = conn.search_s(current_app.config['LDAP_BASE_DN'], ldap.SCOPE_SUBTREE, query, fields) + conn.unbind_s() result = {} if records: if dn_only: - if current_app.config['LDAP_OBJECTS_DN'] in records[0][1]: - dn = records[0][1][ - current_app.config['LDAP_OBJECTS_DN']] - return dn[0] + if current_app.config['LDAP_OPENLDAP']: + if records: + return records[0][0] + else: + if current_app.config['LDAP_OBJECTS_DN'] \ + in records[0][1]: + dn = records[0][1][ + current_app.config['LDAP_OBJECTS_DN']] + return dn[0] for k, v in records[0][1].items(): result[k] = v return result @@ -197,20 +206,39 @@ class LDAP(object): conn = self.bind try: - records = conn.search_s( - current_app.config['LDAP_BASE_DN'], ldap.SCOPE_SUBTREE, - ldap.filter.filter_format( - current_app.config['LDAP_USER_OBJECT_FILTER'], (user,)), - [current_app.config['LDAP_USER_GROUPS_FIELD']]) + if current_app.config['LDAP_OPENLDAP']: + fields = \ + [str(current_app.config['LDAP_GROUP_MEMBER_FILTER_FIELD'])] + records = conn.search_s( + current_app.config['LDAP_BASE_DN'], ldap.SCOPE_SUBTREE, + ldap.filter.filter_format( + current_app.config['LDAP_GROUP_MEMBER_FILTER'], + (self.get_object_details(user, dn_only=True),)), + fields) + else: + records = conn.search_s( + current_app.config['LDAP_BASE_DN'], ldap.SCOPE_SUBTREE, + ldap.filter.filter_format( + current_app.config['LDAP_USER_OBJECT_FILTER'], + (user,)), + [current_app.config['LDAP_USER_GROUPS_FIELD']]) + conn.unbind_s() if records: - if current_app.config['LDAP_USER_GROUPS_FIELD'] in \ - records[0][1]: - groups = records[0][1][ - current_app.config['LDAP_USER_GROUPS_FIELD']] - result = [re.findall('(?:cn=|CN=)(.*?),', group)[0] for - group in groups] - return result + if current_app.config['LDAP_OPENLDAP']: + group_member_filter = \ + current_app.config['LDAP_GROUP_MEMBER_FILTER_FIELD'] + groups = [record[1][group_member_filter][0] for + record in records] + return groups + else: + if current_app.config['LDAP_USER_GROUPS_FIELD'] in \ + records[0][1]: + groups = records[0][1][ + current_app.config['LDAP_USER_GROUPS_FIELD']] + result = [re.findall('(?:cn=|CN=)(.*?),', group)[0] for + group in groups] + return result except ldap.LDAPError as e: raise LDAPException(self.error(e)) @@ -289,7 +317,6 @@ class LDAP(object): return redirect( url_for(current_app.config['LDAP_LOGIN_VIEW'], next=request.path)) - match = [group for group in groups if group in g.ldap_groups] if not match: abort(401)