forked from Github-Mirrors/canaille
Alternate login filters
This commit is contained in:
parent
9199ad8499
commit
de1d0a232d
7 changed files with 44 additions and 21 deletions
|
@ -11,5 +11,11 @@ ROOT_DN = "dc=mydomain,dc=tld"
|
|||
BIND_DN = "cn=admin,dc=mydomain,dc=tld"
|
||||
BIND_PW = "admin"
|
||||
|
||||
# Filter to match users on sign in. Supports a variable
|
||||
# {login}. For sigin against uid or mail use:
|
||||
# USER_FILTER = "(|(uid={login})(mail={login}))"
|
||||
USER_FILTER = "(|(uid={login})(cn={login}))"
|
||||
|
||||
# Filter to match admin users. If your server has memberof
|
||||
# you can filter against group membership
|
||||
ADMIN_FILTER = "cn=Jane Doe"
|
||||
|
|
|
@ -86,7 +86,7 @@ def app(slapd_server):
|
|||
"URI": slapd_server.ldap_uri,
|
||||
"BIND_DN": slapd_server.root_dn,
|
||||
"BIND_PW": slapd_server.root_pw,
|
||||
"USER_FILTER": "(|(uid={login})(mail={login}))",
|
||||
"USER_FILTER": "(|(uid={login})(cn={login}))",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -128,6 +128,11 @@ def client(app, slapd_connection):
|
|||
|
||||
@pytest.fixture
|
||||
def user(app, slapd_connection):
|
||||
u = User(cn="John Doe", sn="Doe", uid="user", userpassword="{SSHA}fw9DYeF/gHTHuVMepsQzVYAkffGcU8Fz")
|
||||
u = User(
|
||||
cn="John Doe",
|
||||
sn="Doe",
|
||||
uid="user",
|
||||
userpassword="{SSHA}fw9DYeF/gHTHuVMepsQzVYAkffGcU8Fz",
|
||||
)
|
||||
u.save(slapd_connection)
|
||||
return u
|
||||
|
|
|
@ -49,3 +49,17 @@ def test_login_no_password(testclient, slapd_connection, user, client):
|
|||
res = res.form.submit()
|
||||
assert 200 == res.status_code
|
||||
assert b"Login failed, please check your information" in res.body
|
||||
|
||||
|
||||
def test_login_with_alternate_attribute(testclient, slapd_connection, user, client):
|
||||
res = testclient.get("/login")
|
||||
assert 200 == res.status_code
|
||||
|
||||
res.form["login"] = "user"
|
||||
res.form["password"] = "correct horse battery staple"
|
||||
res = res.form.submit()
|
||||
res = res.follow()
|
||||
assert 200 == res.status_code
|
||||
|
||||
with testclient.session_transaction() as session:
|
||||
assert user.dn == session.get("user_dn")
|
||||
|
|
|
@ -133,10 +133,14 @@ class LDAPObjectHelper:
|
|||
conn.add_s(self.dn, attributes)
|
||||
|
||||
@classmethod
|
||||
def get(cls, dn, filter=None, conn=None):
|
||||
def get(cls, dn=None, filter=None, conn=None):
|
||||
conn = conn or cls.ldap()
|
||||
if "=" not in dn:
|
||||
|
||||
if dn is None:
|
||||
dn = f"{cls.base},{cls.root_dn}"
|
||||
elif "=" not in dn:
|
||||
dn = f"{cls.id}={dn},{cls.base},{cls.root_dn}"
|
||||
|
||||
result = conn.search_s(dn, ldap.SCOPE_SUBTREE, filter)
|
||||
|
||||
if not result:
|
||||
|
|
|
@ -18,7 +18,7 @@ class User(LDAPObjectHelper):
|
|||
admin = False
|
||||
|
||||
@classmethod
|
||||
def get(cls, dn, filter=None, conn=None):
|
||||
def get(cls, dn=None, filter=None, conn=None):
|
||||
conn = conn or cls.ldap()
|
||||
|
||||
user = super().get(dn, filter, conn)
|
||||
|
@ -32,12 +32,15 @@ class User(LDAPObjectHelper):
|
|||
user.admin = True
|
||||
return user
|
||||
|
||||
def login(self, password):
|
||||
if not self.check_password(password):
|
||||
return False
|
||||
@classmethod
|
||||
def login(cls, login, password):
|
||||
filter = current_app.config["LDAP"].get("USER_FILTER").format(login=login)
|
||||
user = User.get(filter=filter)
|
||||
if not user or not user.check_password(password):
|
||||
return None
|
||||
|
||||
session["user_dn"] = self.dn
|
||||
return True
|
||||
session["user_dn"] = user.dn
|
||||
return user
|
||||
|
||||
def check_password(self, password):
|
||||
conn = ldap.initialize(current_app.config["LDAP"]["URI"])
|
||||
|
|
|
@ -21,12 +21,7 @@ def authorize():
|
|||
if request.method == "GET":
|
||||
return render_template("login.html", form=form)
|
||||
|
||||
if not form.validate():
|
||||
flash(gettext("Login failed, please check your information"), "error")
|
||||
return render_template("login.html", form=form)
|
||||
|
||||
user = User.get(form.login.data)
|
||||
if not user or not user.login(form.password.data):
|
||||
if not form.validate() or not User.login(form.login.data, form.password.data):
|
||||
flash(gettext("Login failed, please check your information"), "error")
|
||||
return render_template("login.html", form=form)
|
||||
|
||||
|
|
|
@ -24,14 +24,10 @@ def login():
|
|||
form = LoginForm(request.form or None)
|
||||
|
||||
if request.form:
|
||||
if not form.validate():
|
||||
if not form.validate() or not User.login(form.login.data, form.password.data):
|
||||
flash(gettext("Login failed, please check your information"), "error")
|
||||
return render_template("login.html", form=form)
|
||||
|
||||
user = User.get(form.login.data)
|
||||
if not user or not user.login(form.password.data):
|
||||
flash(gettext("Login failed, please check your information"), "error")
|
||||
return render_template("login.html", form=form)
|
||||
return redirect(url_for("web.routes.index"))
|
||||
|
||||
return render_template("login.html", form=form)
|
||||
|
|
Loading…
Reference in a new issue