浏览代码

HPCC-8627 Add new ESP HTPASSWD style MD5 authentication

Add new roadmap item "htpasswd" authentication method that does
not involve the complexities of LDAP. It was decided to authenticate
against an HTPASSWD generated password file, located through a config
setting.

Signed-off-by: William Whitehead <william.whitehead@lexisnexis.com>
William Whitehead 12 年之前
父节点
当前提交
0e0011c096

+ 109 - 0
cmake_modules/FindAPR.cmake

@@ -0,0 +1,109 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# - Find Apache Portable Runtime
+# Find the APR includes and libraries
+# This module defines
+#  APR_INCLUDE_DIR and APRUTIL_INCLUDE_DIR, where to find apr.h, etc.
+#  APR_LIBRARIES and APRUTIL_LIBRARIES, the libraries needed to use APR.
+#  APR_FOUND and APRUTIL_FOUND, If false, do not try to use APR.
+# also defined, but not for general use are
+#  APR_LIBRARY and APRUTIL_LIBRARY, where to find the APR library.
+
+# APR first.
+
+FIND_PATH(APR_INCLUDE_DIR apr.h
+/usr/local/include/apr-1
+/usr/local/include/apr-1.0
+/usr/include/apr-1
+/usr/include/apr-1.0
+)
+
+SET(APR_NAMES ${APR_NAMES} apr-1)
+FIND_LIBRARY(APR_LIBRARY
+  NAMES ${APR_NAMES}
+  PATHS /usr/lib /usr/local/lib
+  )
+
+IF (APR_LIBRARY AND APR_INCLUDE_DIR)
+    SET(APR_LIBRARIES ${APR_LIBRARY})
+    SET(APR_FOUND "YES")
+ELSE (APR_LIBRARY AND APR_INCLUDE_DIR)
+  SET(APR_FOUND "NO")
+ENDIF (APR_LIBRARY AND APR_INCLUDE_DIR)
+
+
+IF (APR_FOUND)
+   IF (NOT APR_FIND_QUIETLY)
+      MESSAGE(STATUS "Found APR: ${APR_LIBRARIES}")
+   ENDIF (NOT APR_FIND_QUIETLY)
+ELSE (APR_FOUND)
+   IF (APR_FIND_REQUIRED)
+      MESSAGE(FATAL_ERROR "Could not find APR library")
+   ENDIF (APR_FIND_REQUIRED)
+ENDIF (APR_FOUND)
+
+# Deprecated declarations.
+SET (NATIVE_APR_INCLUDE_PATH ${APR_INCLUDE_DIR} )
+GET_FILENAME_COMPONENT (NATIVE_APR_LIB_PATH ${APR_LIBRARY} PATH)
+
+MARK_AS_ADVANCED(
+  APR_LIBRARY
+  APR_INCLUDE_DIR
+  )
+
+# Next, APRUTIL.
+
+FIND_PATH(APRUTIL_INCLUDE_DIR apu.h
+/usr/local/include/apr-1
+/usr/local/include/apr-1.0
+/usr/include/apr-1
+/usr/include/apr-1.0
+)
+
+SET(APRUTIL_NAMES ${APRUTIL_NAMES} aprutil-1)
+FIND_LIBRARY(APRUTIL_LIBRARY
+  NAMES ${APRUTIL_NAMES}
+  PATHS /usr/lib /usr/local/lib
+  )
+
+IF (APRUTIL_LIBRARY AND APRUTIL_INCLUDE_DIR)
+    SET(APRUTIL_LIBRARIES ${APRUTIL_LIBRARY})
+    SET(APRUTIL_FOUND "YES")
+ELSE (APRUTIL_LIBRARY AND APRUTIL_INCLUDE_DIR)
+  SET(APRUTIL_FOUND "NO")
+ENDIF (APRUTIL_LIBRARY AND APRUTIL_INCLUDE_DIR)
+
+
+IF (APRUTIL_FOUND)
+   IF (NOT APRUTIL_FIND_QUIETLY)
+      MESSAGE(STATUS "Found APRUTIL: ${APRUTIL_LIBRARIES}")
+   ENDIF (NOT APRUTIL_FIND_QUIETLY)
+ELSE (APRUTIL_FOUND)
+   IF (APRUTIL_FIND_REQUIRED)
+      MESSAGE(FATAL_ERROR "Could not find APRUTIL library")
+   ENDIF (APRUTIL_FIND_REQUIRED)
+ENDIF (APRUTIL_FOUND)
+
+# Deprecated declarations.
+SET (NATIVE_APRUTIL_INCLUDE_PATH ${APRUTIL_INCLUDE_DIR} )
+GET_FILENAME_COMPONENT (NATIVE_APRUTIL_LIB_PATH ${APRUTIL_LIBRARY} PATH)
+
+MARK_AS_ADVANCED(
+  APRUTIL_LIBRARY
+  APRUTIL_INCLUDE_DIR
+  )

+ 21 - 0
cmake_modules/commonSetup.cmake

@@ -62,6 +62,7 @@ IF ("${COMMONSETUP_DONE}" STREQUAL "")
   option(USE_GIT_DESCRIBE "Use git describe to generate build tag" ON)
   option(CHECK_GIT_TAG "Require git tag to match the generated build tag" OFF)
   option(USE_XALAN "Configure use of xalan" ON)
+  option(USE_APR "Configure use of Apache Software Foundation (ASF) Portable Runtime (APR) libraries" ON)
   option(USE_LIBXSLT "Configure use of libxslt" OFF)
   option(MAKE_DOCS "Create documentation at build time." OFF)
   option(MAKE_DOCS_ONLY "Create a base build with only docs." OFF)
@@ -507,6 +508,26 @@ IF ("${COMMONSETUP_DONE}" STREQUAL "")
       else()
         add_definitions (-D_NO_MYSQL)
       endif(USE_MYSQL)
+
+      if(USE_APR)
+        find_package(APR)
+        if (APR_FOUND)
+          add_definitions (-D_USE_APR)
+          include_directories(${APR_INCLUDE_DIR})
+          link_directories(${APR_LIBRARIES})
+        else()
+          message(FATAL_ERROR "APR requested but package not found")
+        endif()
+        if (APRUTIL_FOUND)
+          include_directories(${APRUTIL_INCLUDE_DIR})
+          link_directories(${APRUTIL_LIBRARIES})
+        else()
+          message(FATAL_ERROR "APRUTIL requested but package not found")
+        endif()
+      else()
+        add_definitions (-D_NO_APR)
+      endif(USE_APR)
+
   ENDIF()
   ###########################################################################
   ###

+ 14 - 0
esp/bindings/http/platform/httpbinding.cpp

@@ -326,7 +326,21 @@ EspHttpBinding::EspHttpBinding(IPropertyTree* tree, const char *bindname, const
                 m_secmgr.setown(SecLoader::loadSecManager("Local", "EspHttpBinding", NULL));
                 m_authmap.setown(m_secmgr->createAuthMap(authcfg));
             }
+            else if(stricmp(m_authmethod.str(), "htpasswd") == 0)
+            {
+                Owned<IPropertyTree> cfg;
+                Owned<IPropertyTree> process_config = getProcessConfig(tree, procname);
+                if(process_config.get() != NULL)
+                    cfg.setown(process_config->getPropTree("htpasswdSecurity"));
+                if(cfg == NULL)
+                {
+                    ERRLOG("can't find htpasswdSecurity in configuration");
+                    throw MakeStringException(-1, "can't find htpasswdSecurity in configuration");
+                }
 
+                m_secmgr.setown(SecLoader::loadSecManager("htpasswd", "EspHttpBinding", LINK(cfg)));
+                m_authmap.setown(m_secmgr->createAuthMap(authcfg));
+            }
             IRestartManager* restartManager = dynamic_cast<IRestartManager*>(m_secmgr.get());
             if(restartManager!=NULL)
             {

+ 4 - 0
system/security/CMakeLists.txt

@@ -21,3 +21,7 @@ HPCC_ADD_SUBDIRECTORY (test "PLATFORM")
 if (USE_ZLIB)
   HPCC_ADD_SUBDIRECTORY (zcrypt "PLATFORM")
 endif()
+
+IF (USE_APR)
+  HPCC_ADD_SUBDIRECTORY (htpasswdSecurity)
+ENDIF(USE_APR)

+ 56 - 0
system/security/htpasswdSecurity/CMakeLists.txt

@@ -0,0 +1,56 @@
+################################################################################
+#    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+################################################################################
+
+
+# Component: LdapSecurity
+#####################################################
+# Description:
+# ------------
+#    Cmake Input File for htpasswdSecurity
+#####################################################
+
+project( htpasswdSecurity )
+
+set (    SRCS
+         ../shared/authmap.cpp
+         ../shared/caching.cpp
+         ../shared/basesecurity.cpp
+         ../shared/defaultsecuritymanager.cpp
+         ./htpasswdSecurity.cpp
+    )
+
+include_directories (
+         ./../../include
+         ./../shared
+         ./../../jlib
+         ./../../../esp/platform
+         ./../../../dali/base
+         ${APR_INCLUDE_DIR}
+         ${APRUTIL_INCLUDE_DIR}
+    )
+
+ADD_DEFINITIONS( -DHTPASSWDSECURITY_EXPORTS -D_USRDLL )
+
+HPCC_ADD_LIBRARY( htpasswdSecurity SHARED ${SRCS} )
+install ( TARGETS htpasswdSecurity RUNTIME DESTINATION ${EXEC_DIR} LIBRARY DESTINATION ${LIB_DIR} )
+target_link_libraries ( htpasswdSecurity
+         jlib
+         dalibase
+         ${APR_LIBRARIES}
+         ${APRUTIL_LIBRARIES}
+    )
+
+

+ 205 - 0
system/security/htpasswdSecurity/htpasswdSecurity.cpp

@@ -0,0 +1,205 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#pragma warning( disable : 4786 )
+
+#include "defaultsecuritymanager.hpp"
+#include "authmap.ipp"
+#include <apr_md5.h>
+#include "htpasswdSecurity.hpp"
+
+class CHtpasswdSecurityManager : public CDefaultSecurityManager
+{
+public:
+	CHtpasswdSecurityManager(const char *serviceName, IPropertyTree *authconfig) : CDefaultSecurityManager(serviceName, (IPropertyTree *)NULL)
+	{
+		if (authconfig)
+			authconfig->getProp("@htpasswdFile", pwFile);
+		apr_initialized = false;
+	}
+
+	~CHtpasswdSecurityManager()
+	{
+		userMap.kill();
+	}
+
+	IAuthMap * createAuthMap(IPropertyTree * authconfig)
+	{
+		CAuthMap* authmap = new CAuthMap(this);
+
+		Owned<IPropertyTreeIterator> loc_iter;
+		loc_iter.setown(authconfig->getElements(".//Location"));
+		if (loc_iter)
+		{
+			IPropertyTree *location = NULL;
+			loc_iter->first();
+			while(loc_iter->isValid())
+			{
+				location = &loc_iter->query();
+				if (location)
+				{
+					StringBuffer pathstr, rstr, required, description;
+					location->getProp("@path", pathstr);
+					location->getProp("@resource", rstr);
+					location->getProp("@required", required);
+					location->getProp("@description", description);
+
+					if(pathstr.length() == 0)
+						throw MakeStringException(-1, "path empty in Authenticate/Location");
+					if(rstr.length() == 0)
+						throw MakeStringException(-1, "resource empty in Authenticate/Location");
+
+					ISecResourceList* rlist = authmap->queryResourceList(pathstr.str());
+					if(rlist == NULL)
+					{
+						rlist = createResourceList("localsecurity");
+						authmap->add(pathstr.str(), rlist);
+					}
+					ISecResource* rs = rlist->addResource(rstr.str());
+					unsigned requiredaccess = str2perm(required.str());
+					rs->setRequiredAccessFlags(requiredaccess);
+					rs->setDescription(description.str());
+				}
+				loc_iter->next();
+			}
+		}
+
+		return authmap;
+	}
+
+protected:
+
+	bool IsPasswordValid(ISecUser& sec_user)
+	{
+		StringBuffer user;
+		user.append(sec_user.getName());
+		if (0 == user.length())
+			throw MakeStringException(-1, "htpasswd User name is NULL");
+
+		CriticalBlock block(crit);
+		if (!apr_initialized)
+			initAPR();
+		loadPwds();//reload password file if modified
+		StringBuffer *encPW = userMap.getValue(user.str());
+		if (encPW && encPW->length())
+		{
+			apr_status_t rc = apr_password_validate(sec_user.credentials().getPassword(), encPW->str());
+			if (rc != APR_SUCCESS)
+				DBGLOG("htpasswd authentication for user %s failed - APR RC %d", user.str(), rc );
+			return rc == APR_SUCCESS;
+		}
+		DBGLOG("User %s not in htpasswd file", user.str());
+		return false;
+	}
+
+private:
+
+	void initAPR()
+	{
+		try
+		{
+			apr_status_t rc = apr_md5_init(&md5_ctx);
+			if (rc != APR_SUCCESS)
+				throw MakeStringException(-1, "htpasswd apr_md5_init returns error %d", rc );
+			apr_initialized = true;
+		}
+		catch (...)
+		{
+			throw MakeStringException(-1, "htpasswd exception calling apr_md5_init");
+		}
+	}
+
+	bool loadPwds()
+	{
+		try
+		{
+			if (!pwFile.length())
+				throw MakeStringException(-1, "htpasswd Password file not specified");
+
+			Owned<IFile> file = createIFile(pwFile.str());
+			if (!file->exists())
+			{
+				userMap.kill();
+				throw MakeStringException(-1, "htpasswd Password file does not exist");
+			}
+
+			bool isDir;
+			offset_t size;
+			CDateTime whenChanged;
+			file->getInfo(isDir,size,whenChanged);
+			if (isDir)
+			{
+				userMap.kill();
+				throw MakeStringException(-1, "htpasswd Password file specifies a directory");
+			}
+			if (0 == whenChanged.compare(pwFileLastMod))
+				return true;//Don't reload if file unchanged
+			userMap.kill();
+			OwnedIFileIO io = file->open(IFOread);
+			if (!io)
+				throw MakeStringException(-1, "htpasswd Unable to open Password file");
+
+			MemoryBuffer mb;
+			size32_t count = read(io, 0, (size32_t)-1, mb);
+			if (0 == count)
+				throw MakeStringException(-1, "htpasswd Password file is empty");
+
+			mb.append((char)NULL);
+			char * p = (char*)mb.toByteArray();
+			char *saveptr;
+			const char * seps = "\f\r\n";
+			char * next = strtok_r(p, seps, &saveptr);
+			if (next)
+			{
+				do
+				{
+					char * colon = strchr(next,':');
+					if (NULL == colon)
+						throw MakeStringException(-1, "htpasswd Password file appears malformed");
+					*colon = (char)NULL;
+					userMap.setValue(next, colon+1);//username, enctypted password
+				} while (next = strtok_r(NULL, seps, &saveptr));
+			}
+
+			io->close();
+			pwFileLastMod = whenChanged;//remember when last changed
+		}
+		catch(IException*)
+		{
+			throw MakeStringException(-1, "htpasswd Exception accessing Password file");
+		}
+		return true;
+	}
+
+
+private:
+	mutable CriticalSection crit;
+	StringBuffer    pwFile;
+	CDateTime       pwFileLastMod;
+	bool            apr_initialized;
+	MapStringTo<StringBuffer> userMap;
+	apr_md5_ctx_t 	md5_ctx;
+};
+
+extern "C"
+{
+    HTPASSWDSECURITY_API ISecManager * newHtpasswdSecManager(const char *serviceName, IPropertyTree &config)
+    {
+        return new CHtpasswdSecurityManager(serviceName, &config);
+    }
+}
+

+ 42 - 0
system/security/htpasswdSecurity/htpasswdSecurity.hpp

@@ -0,0 +1,42 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#ifndef HTPASSWDSECURITY_HPP_
+#define HTPASSWDSECURITY_HPP_
+
+#ifndef HTPASSWDSECURITY_API
+
+#ifdef _WIN32
+    #ifndef HTPASSWDSECURITY_EXPORTS
+        #define HTPASSWDSECURITY_API __declspec(dllimport)
+    #else
+        #define HTPASSWDSECURITY_API __declspec(dllexport)
+    #endif //HTPASSWDSECURITY_EXPORTS
+#else
+    #define HTPASSWDSECURITY_API
+#endif //_WIN32
+
+#endif 
+
+#include "basesecurity.hpp"
+
+extern "C" 
+{
+    HTPASSWDSECURITY_API ISecManager * newHtpasswdSecManager(const char *serviceName, IPropertyTree &config);
+}
+
+#endif // HTPASSWDSECURITY_HPP_

+ 33 - 13
system/security/shared/seclib.hpp

@@ -34,13 +34,9 @@
 #endif //_WIN32
 #endif 
 
-#ifdef _WIN32
-#define SECLIB "seclib.dll"
-#define LDAPSECLIB "LdapSecurity.dll"
-#else
-#define SECLIB "libseclib.so"
-#define LDAPSECLIB "libLdapSecurity.so"
-#endif
+#define SECLIB "seclib"
+#define LDAPSECLIB "LdapSecurity"
+#define HTPASSWDSECLIB "htpasswdSecurity"
 
 enum NewSecAccessFlags
 {
@@ -325,6 +321,7 @@ const char* const sec_CompanyZip        = "sec_company_zip";
 typedef ISecManager* (*createSecManager_t)(const char *model_name, const char *serviceName, IPropertyTree &config);
 typedef IAuthMap* (*createDefaultAuthMap_t)(IPropertyTree* config);
 typedef ISecManager* (*newLdapSecManager_t)(const char *serviceName, IPropertyTree &config);
+typedef ISecManager* (*newHtpasswdSecManager_t)(const char *serviceName, IPropertyTree &config);
 
 extern "C" SECLIB_API ISecManager *createSecManager(const char *model_name, const char *serviceName, IPropertyTree &config);
 extern "C" SECLIB_API IAuthMap *createDefaultAuthMap(IPropertyTree* config);
@@ -336,9 +333,12 @@ public:
     {
         if(model_name && stricmp(model_name, "LdapSecurity") == 0)
         {
-            HINSTANCE ldapseclib = LoadSharedObject(LDAPSECLIB, true, false);
+            StringBuffer realName;
+            realName.append(SharedObjectPrefix).append(LDAPSECLIB).append(SharedObjectExtension);
+
+            HINSTANCE ldapseclib = LoadSharedObject(realName.str(), true, false);
             if(ldapseclib == NULL)
-                throw MakeStringException(-1, "can't load library %s", LDAPSECLIB);
+                throw MakeStringException(-1, "can't load library %s", realName.str());
             
             newLdapSecManager_t xproc = NULL;
             xproc = (newLdapSecManager_t)GetSharedProcedure(ldapseclib, "newLdapSecManager");
@@ -346,13 +346,33 @@ public:
             if (xproc)
                 return xproc(servicename, *cfg);
             else
-                throw MakeStringException(-1, "procedure newLdapSecManager of %s can't be loaded", LDAPSECLIB);
+                throw MakeStringException(-1, "procedure newLdapSecManager of %s can't be loaded", realName.str());
+        }
+        else if(model_name && stricmp(model_name, "htpasswdSecurity") == 0)
+        {
+            StringBuffer realName;
+            realName.append(SharedObjectPrefix).append(HTPASSWDSECLIB).append(SharedObjectExtension);
+
+            HINSTANCE htpasswdseclib = LoadSharedObject(realName.str(), true, false);
+            if(htpasswdseclib == NULL)
+                throw MakeStringException(-1, "can't load library %s", realName.str());
+
+            newHtpasswdSecManager_t xproc = NULL;
+            xproc = (newHtpasswdSecManager_t)GetSharedProcedure(htpasswdseclib, "newHtpasswdSecManager");
+
+            if (xproc)
+                return xproc(servicename, *cfg);
+            else
+                throw MakeStringException(-1, "procedure newHtpasswdSecManager of %s can't be loaded", realName.str());
         }
         else
         {
-            HINSTANCE seclib = LoadSharedObject(SECLIB, true, false);       // ,false,true may actually be more helpful, could delete next two lines.
+            StringBuffer realName;
+            realName.append(SharedObjectPrefix).append(SECLIB).append(SharedObjectExtension);
+
+            HINSTANCE seclib = LoadSharedObject(realName.str(), true, false);       // ,false,true may actually be more helpful, could delete next two lines.
             if(seclib == NULL)
-                throw MakeStringException(-1, "can't load library %s", SECLIB);
+                throw MakeStringException(-1, "can't load library %s", realName.str());
 
             createSecManager_t xproc = NULL;
             xproc = (createSecManager_t)GetSharedProcedure(seclib, "createSecManager");
@@ -360,7 +380,7 @@ public:
             if (xproc)
                 return xproc(model_name, servicename, *cfg);
             else
-                throw MakeStringException(-1, "procedure createSecManager of %s can't be loaded", SECLIB);
+                throw MakeStringException(-1, "procedure createSecManager of %s can't be loaded", realName.str());
         }
     }   
     static IAuthMap* loadDefaultAuthMap(IPropertyTree* cfg)

+ 39 - 22
system/security/shared/secloader.hpp

@@ -19,12 +19,6 @@
 #define _SECLOADER_HPP__
 #include "seclib.hpp"
 
-#ifdef _WIN32
-#define LDAPSECLIB "LdapSecurity.dll"
-#else
-#define LDAPSECLIB "libLdapSecurity.so"
-#endif
-
 typedef IAuthMap* (*createDefaultAuthMap_t_)(IPropertyTree* config);
 typedef ISecManager* (*newSecManager_t_)(const char *serviceName, IPropertyTree &config);
 
@@ -33,50 +27,73 @@ class SecLoader
 public:
     static ISecManager* loadSecManager(const char* model_name, const char* servicename, IPropertyTree* cfg)
     {
-        if(model_name && stricmp(model_name, "LdapSecurity") == 0)
+        if (!model_name || !*model_name)
+            throw MakeStringExceptionDirect(-1, "Security model not specified");
+
+        StringBuffer realName;
+
+        if(stricmp(model_name, "LdapSecurity") == 0)
         {
-            HINSTANCE ldapseclib = LoadSharedObject(LDAPSECLIB, true, false);
+            realName.append(SharedObjectPrefix).append(LDAPSECLIB).append(SharedObjectExtension);
+            HINSTANCE ldapseclib = LoadSharedObject(realName.str(), true, false);
             if(ldapseclib == NULL)
-                throw MakeStringException(-1, "can't load library %s", LDAPSECLIB);
-            
+                throw MakeStringException(-1, "can't load library %s", realName.str());
+
             newSecManager_t_ xproc = NULL;
             xproc = (newSecManager_t_)GetSharedProcedure(ldapseclib, "newLdapSecManager");
 
             if (xproc)
                 return xproc(servicename, *cfg);
             else
-                throw MakeStringException(-1, "procedure newLdapSecManager of %s can't be loaded", LDAPSECLIB);
+                throw MakeStringException(-1, "procedure newLdapSecManager of %s can't be loaded", realName.str());
         }
-        else if(model_name && stricmp(model_name, "Local") == 0)
+        else if(stricmp(model_name, "Local") == 0)
         {
-            HINSTANCE ldapseclib = LoadSharedObject(LDAPSECLIB, true, false);
+            realName.append(SharedObjectPrefix).append(LDAPSECLIB).append(SharedObjectExtension);
+            HINSTANCE ldapseclib = LoadSharedObject(realName.str(), true, false);
             if(ldapseclib == NULL)
-                throw MakeStringException(-1, "can't load library %s", LDAPSECLIB);
-            
+                throw MakeStringException(-1, "can't load library %s", realName.str());
+
             newSecManager_t_ xproc = NULL;
             xproc = (newSecManager_t_)GetSharedProcedure(ldapseclib, "newLocalSecManager");
 
             if (xproc)
                 return xproc(servicename, *cfg);
             else
-                throw MakeStringException(-1, "procedure newLocalSecManager of %s can't be loaded", LDAPSECLIB);
+                throw MakeStringException(-1, "procedure newLocalSecManager of %s can't be loaded", realName.str());
         }
-        else if(model_name && stricmp(model_name, "Default") == 0)
+        else if(stricmp(model_name, "Default") == 0)
         {
-            HINSTANCE ldapseclib = LoadSharedObject(LDAPSECLIB, true, false);
+            realName.append(SharedObjectPrefix).append(LDAPSECLIB).append(SharedObjectExtension);
+            HINSTANCE ldapseclib = LoadSharedObject(realName.str(), true, false);
             if(ldapseclib == NULL)
-                throw MakeStringException(-1, "can't load library %s", LDAPSECLIB);
-            
+                throw MakeStringException(-1, "can't load library %s", realName.str());
+
             newSecManager_t_ xproc = NULL;
             xproc = (newSecManager_t_)GetSharedProcedure(ldapseclib, "newDefaultSecManager");
 
             if (xproc)
                 return xproc(servicename, *cfg);
             else
-                throw MakeStringException(-1, "procedure newDefaultSecManager of %s can't be loaded", LDAPSECLIB);
+                throw MakeStringException(-1, "procedure newDefaultSecManager of %s can't be loaded", realName.str());
+        }
+        else if(stricmp(model_name, "htpasswd") == 0)
+        {
+            realName.append(SharedObjectPrefix).append(HTPASSWDSECLIB).append(SharedObjectExtension);
+            HINSTANCE htpasswdseclib = LoadSharedObject(realName.str(), true, false);
+            if(htpasswdseclib == NULL)
+                throw MakeStringException(-1, "can't load library %s", realName.str());
+
+            newSecManager_t_ xproc = NULL;
+            xproc = (newSecManager_t_)GetSharedProcedure(htpasswdseclib, "newHtpasswdSecManager");
+
+            if (xproc)
+                return xproc(servicename, *cfg);
+            else
+                throw MakeStringException(-1, "procedure newHtpasswdSecManager of %s can't be loaded", realName.str());
         }
         else
-            throw MakeStringException(-1, "Security model %s not supported", model_name?model_name:"UNKNOWN");
+            throw MakeStringException(-1, "Security model %s not supported", model_name);
     }   
 
     static IAuthMap* loadTheDefaultAuthMap(IPropertyTree* cfg)