Merge pull request #612 from Unrud/auth
Allow auth backends to provide login and password
This commit is contained in:
commit
824835bcd4
2
config
2
config
@ -66,7 +66,7 @@
|
||||
[auth]
|
||||
|
||||
# Authentication method
|
||||
# Value: None | htpasswd
|
||||
# Value: None | htpasswd | remote_user | http_x_remote_user
|
||||
#type = None
|
||||
|
||||
# Htpasswd filename
|
||||
|
@ -371,15 +371,19 @@ class Application:
|
||||
function = getattr(self, "do_%s" % environ["REQUEST_METHOD"].upper())
|
||||
|
||||
# Ask authentication backend to check rights
|
||||
authorization = environ.get("HTTP_AUTHORIZATION", None)
|
||||
if authorization and authorization.startswith("Basic"):
|
||||
external_login = self.Auth.get_external_login(environ)
|
||||
authorization = environ.get("HTTP_AUTHORIZATION", "")
|
||||
if external_login:
|
||||
login, password = external_login
|
||||
elif authorization.startswith("Basic"):
|
||||
authorization = authorization[len("Basic"):].strip()
|
||||
login, password = self.decode(base64.b64decode(
|
||||
authorization.encode("ascii")), environ).split(":", 1)
|
||||
user = self.Auth.map_login_to_user(login)
|
||||
else:
|
||||
user = self.Auth.map_login_to_user(environ.get("REMOTE_USER", ""))
|
||||
# DEPRECATED: use remote_user backend instead
|
||||
login = environ.get("REMOTE_USER", "")
|
||||
password = ""
|
||||
user = self.Auth.map_login_to_user(login)
|
||||
|
||||
# If "/.well-known" is not available, clients query "/"
|
||||
if path == "/.well-known" or path.startswith("/.well-known/"):
|
||||
@ -437,7 +441,7 @@ class Application:
|
||||
status, headers, answer = NOT_ALLOWED
|
||||
|
||||
if (status, headers, answer) == NOT_ALLOWED and not (
|
||||
user and is_authenticated):
|
||||
user and is_authenticated) and not external_login:
|
||||
# Unknown or unauthorized user
|
||||
self.logger.debug("Asking client for authentication")
|
||||
status = client.UNAUTHORIZED
|
||||
|
@ -67,6 +67,10 @@ def load(configuration, logger):
|
||||
logger.debug("Authentication type is %s", auth_type)
|
||||
if auth_type == "None":
|
||||
class_ = NoneAuth
|
||||
elif auth_type == "remote_user":
|
||||
class_ = RemoteUserAuth
|
||||
elif auth_type == "http_x_remote_user":
|
||||
class_ = HttpXRemoteUserAuth
|
||||
elif auth_type == "htpasswd":
|
||||
class_ = Auth
|
||||
else:
|
||||
@ -79,6 +83,14 @@ class BaseAuth:
|
||||
self.configuration = configuration
|
||||
self.logger = logger
|
||||
|
||||
def get_external_login(self, environ):
|
||||
"""Optionally provide the login and password externally.
|
||||
|
||||
Returns a tuple (login, password) or ().
|
||||
|
||||
"""
|
||||
return ()
|
||||
|
||||
def is_authenticated(self, user, password):
|
||||
"""Validate credentials.
|
||||
|
||||
@ -201,3 +213,13 @@ class Auth(BaseAuth):
|
||||
if login_ok & password_ok:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class RemoteUserAuth(NoneAuth):
|
||||
def get_external_login(self, environ):
|
||||
return environ.get("REMOTE_USER", ""), ""
|
||||
|
||||
|
||||
class HttpXRemoteUserAuth(NoneAuth):
|
||||
def get_external_login(self, environ):
|
||||
return environ.get("HTTP_X_REMOTE_USER", ""), ""
|
||||
|
@ -109,6 +109,34 @@ class TestBaseAuthRequests(BaseTest):
|
||||
"bcrypt",
|
||||
"tmp:$2y$05$oD7hbiQFQlvCM7zoalo/T.MssV3VNTRI3w5KDnj8NTUKJNWfVpvRq")
|
||||
|
||||
def test_remote_user(self):
|
||||
self.configuration.set("auth", "type", "remote_user")
|
||||
self.application = Application(self.configuration, self.logger)
|
||||
status, _, answer = self.request(
|
||||
"PROPFIND", "/",
|
||||
"""<?xml version="1.0" encoding="utf-8"?>
|
||||
<propfind xmlns="DAV:">
|
||||
<prop>
|
||||
<current-user-principal />
|
||||
</prop>
|
||||
</propfind>""", REMOTE_USER="test")
|
||||
assert status == 207
|
||||
assert ">/test/<" in answer
|
||||
|
||||
def test_http_x_remote_user(self):
|
||||
self.configuration.set("auth", "type", "http_x_remote_user")
|
||||
self.application = Application(self.configuration, self.logger)
|
||||
status, _, answer = self.request(
|
||||
"PROPFIND", "/",
|
||||
"""<?xml version="1.0" encoding="utf-8"?>
|
||||
<propfind xmlns="DAV:">
|
||||
<prop>
|
||||
<current-user-principal />
|
||||
</prop>
|
||||
</propfind>""", HTTP_X_REMOTE_USER="test")
|
||||
assert status == 207
|
||||
assert ">/test/<" in answer
|
||||
|
||||
def test_custom(self):
|
||||
"""Custom authentication."""
|
||||
self.configuration.set("auth", "type", "tests.custom.auth")
|
||||
|
Loading…
x
Reference in New Issue
Block a user