diff --git a/config b/config index 2845169..621093e 100644 --- a/config +++ b/config @@ -47,9 +47,12 @@ stock = utf-8 [auth] # Authentication method -# Value: None | htpasswd | IMAP | LDAP | PAM | courier | http +# Value: None | htpasswd | IMAP | LDAP | PAM | courier | http | custom type = None +# custom auth handler +custom_handler = + # Htpasswd filename htpasswd_filename = /etc/radicale/users # Htpasswd encryption method diff --git a/radicale/auth/__init__.py b/radicale/auth/__init__.py index 5e7c01b..5dbdde4 100644 --- a/radicale/auth/__init__.py +++ b/radicale/auth/__init__.py @@ -34,13 +34,17 @@ def load(): log.LOGGER.debug("Authentication type is %s" % auth_type) if auth_type == "None": return None + elif auth_type == 'custom': + auth_module = config.get("auth", "custom_handler") + __import__(auth_module) + module = sys.modules[auth_module] else: root_module = __import__( "auth.%s" % auth_type, globals=globals(), level=2) module = getattr(root_module, auth_type) - # Override auth.is_authenticated - sys.modules[__name__].is_authenticated = module.is_authenticated - return module + # Override auth.is_authenticated + sys.modules[__name__].is_authenticated = module.is_authenticated + return module def is_authenticated(user, password): diff --git a/radicale/config.py b/radicale/config.py index 36dbb76..b905c60 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -55,6 +55,7 @@ INITIAL_CONFIG = { "stock": "utf-8"}, "auth": { "type": "None", + "custom_handler": "", "htpasswd_filename": "/etc/radicale/users", "htpasswd_encryption": "crypt", "imap_hostname": "localhost", diff --git a/tests/__init__.py b/tests/__init__.py index 0d5678c..3878cfe 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -21,8 +21,6 @@ Tests for Radicale. """ -import base64 -import hashlib import os import shutil import sys @@ -38,7 +36,6 @@ os.environ["RADICALE_CONFIG"] = os.path.join(os.path.dirname( os.path.dirname(__file__)), "config") from radicale import config -from radicale.auth import htpasswd from .helpers import get_file_content from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine @@ -126,19 +123,10 @@ class GitMultiFileSystem(GitFileSystem, MultiFileSystem): """Base class for multifilesystem tests using Git""" -class HtpasswdAuthSystem(BaseTest): +class AuthSystem(BaseTest): """Base class to test Radicale with Htpasswd authentication""" def setup(self): - self.colpath = tempfile.mkdtemp() - htpasswd_file_path = os.path.join(self.colpath, ".htpasswd") - with open(htpasswd_file_path, "wb") as fd: - fd.write(b"tmp:{SHA}" + base64.b64encode( - hashlib.sha1(b"bepo").digest())) - config.set("auth", "type", "htpasswd") self.userpass = "dG1wOmJlcG8=" - self.application = radicale.Application() - htpasswd.FILENAME = htpasswd_file_path - htpasswd.ENCRYPTION = "sha1" def teardown(self): config.set("auth", "type", "None") diff --git a/tests/custom/__init__.py b/tests/custom/__init__.py new file mode 100644 index 0000000..bf893c0 --- /dev/null +++ b/tests/custom/__init__.py @@ -0,0 +1 @@ +# coding=utf-8 \ No newline at end of file diff --git a/tests/custom/auth.py b/tests/custom/auth.py new file mode 100644 index 0000000..6fc1352 --- /dev/null +++ b/tests/custom/auth.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# +# This file is part of Radicale Server - Calendar Server +# Copyright © 2008 Nicolas Kandel +# Copyright © 2008 Pascal Halter +# Copyright © 2008-2013 Guillaume Ayoub +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Radicale. If not, see . + +""" +Custom authentication. + +Just check username for testing + +""" + + +def is_authenticated(user, password): + return user == 'tmp' diff --git a/tests/test_auth.py b/tests/test_auth.py index a6de517..fb31464 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -22,22 +22,45 @@ Radicale tests with simple requests and authentication. """ -from nose import with_setup -from . import HtpasswdAuthSystem +import base64 +import hashlib +import os +import radicale +import tempfile +from tests import AuthSystem +from radicale import config +from radicale.auth import htpasswd -class TestBaseAuthRequests(HtpasswdAuthSystem): +class TestBaseAuthRequests(AuthSystem): """ Tests basic requests with auth. - ..note Only htpasswd works at the moment since - it requires to spawn processes running servers for - others auth methods (ldap). + We should setup auth for each type before create Application object """ - @with_setup(HtpasswdAuthSystem.setup, HtpasswdAuthSystem.teardown) def test_root(self): - """Tests a GET request at "/".""" + self.colpath = tempfile.mkdtemp() + htpasswd_file_path = os.path.join(self.colpath, ".htpasswd") + with open(htpasswd_file_path, "wb") as fd: + fd.write(b"tmp:{SHA}" + base64.b64encode( + hashlib.sha1(b"bepo").digest())) + config.set("auth", "type", "htpasswd") + + htpasswd.FILENAME = htpasswd_file_path + htpasswd.ENCRYPTION = "sha1" + + self.application = radicale.Application() + + status, headers, answer = self.request( + "GET", "/", HTTP_AUTHORIZATION=self.userpass) + assert status == 200 + assert "Radicale works!" in answer + + def test_custom(self): + config.set("auth", "type", "custom") + config.set("auth", "custom_handler", "tests.custom.auth") + self.application = radicale.Application() status, headers, answer = self.request( "GET", "/", HTTP_AUTHORIZATION=self.userpass) assert status == 200