google-code-export / webpasswordsafe

Automatically exported from code.google.com/p/webpasswordsafe
0 stars 3 forks source link

Configuration walk through / example config for ldap / MS Active Directory authentication #106

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Please describe desired steps of proposed new feature/enhancement:
1. The existing administrator guide at 
http://webpasswordsafe.googlecode.com/svn/trunk/docs/AdministratorGuide.html is 
relatively sparse in relation to describing authentication plugin configuration
2. Some other issues have been submitted where people appear to have had 
trouble configuring ldap integration (Issues 84, 93, 100)
3. It took me significantly longer than I would have liked to configure this, 
but I did succeed 
4. Regardless of the above, very nice project & thanks for sharing.

What version of the product are you using? On what operating system?
Product versions 1.3 & 1.4 svn rev 203. The operating system should not be 
important to this feature request, but for completeness the submission below 
was compiled using Windows Server 2008 R2

Since these actions took longer than I would have liked, I've attempted to 
document them. The documentation will likely be used elsewhere, but since it 
was completed in personal time, I'm happy to have GPL v2 applied to it, should 
you decide to incorporate it into your existing docs. Regardless, having it 
available in the issues tracker hopefully saves someone else some time :)

This text attempts to consolidate existing documentation, that describe 
configuration steps to deliver a working integration between WebPasswordSafe 
and Microsoft  Active Directory.

Prerequisites:
This guide does not assist with the completion of these steps:

    • WebPasswordSafe installed and functional using the default / LocalAuthenticator authentication (1). This integration guide was written and tested against WebPasswordSafe-1.3 with debug logging enabled, and WebPasswordsafe-1.4 (svn revision 203; default logging)
    • Microsoft Active Directory installed and functional. This integration guide was written and tested against an active directory at forest & domain functional level of Windows Server 2012. It is anticipated it would work regardless of functional level.
    • The ability to create a user account in the Active Directory with Domain Users membership. WebPasswordSafe will use this account for the purpose of Distinguished Name lookup of users that attempt to login to WebPasswordSafe
    • A Public Key Infrastructure installed and functional. (2) It is necessary that the PKI be able to sign certificates for the purpose of Server Authentication
    • All Active Directory Domain Controllers must have a Server Authentication certificate installed, (2) along with the associated CA / Intermediate CA('s)  

(1) See: 
http://webpasswordsafe.googlecode.com/svn/trunk/docs/AdministratorGuide.html 
for the pre-existing Administrator Guide.

(2) In the context of Active Directory, the simplest configuration from the 
perspective of this implementation is that Active Directory Certificate 
Services already be installed:
http://technet.microsoft.com/en-au/library/hh831740.aspx
In the case that AD-CS is not already existing in the environment,  one 
approach is the use of OpenSSL to create a private CA, generate and install 
certificates.
Microsoft documentation for the creation of the Certificate Signing Request, 
installation of the resulting certificate:
http://support.microsoft.com/kb/321051
3rd party documentation for the creation of the Certificate Signing Request, 
signing of the CSR using an OpenSSL generated CA, installation of the resulting 
certificate:
http://www.javaxt.com/Tutorials/Windows/How_to_Enable_LDAPS_in_Active_Directory
OpenSSL binaries for Windows hosts: (note: this guide was written using OpenSSL 
on Centos 6.5, not these binaries)
http://www.openssl.org/related/binaries.html

Integration steps:

Note: Where a domain name is required in the examples, this document assumes 
the domain name is contoso.com. These values should be modified to match your 
environment.

From the WebPasswordSafe host, confirm that ldaps is configured, working and 
accessible on each of your domain controllers:
Telnet domain.controller.fully.qualified.name 636
The test should be regarded successful if you are able to establish a 
connection; meaningful communication with the server is not important for this 
test.

Install your CA certificate, along with any intermediary certificates,  into 
the CA keystore of the Java installation that Tomcat is using:
https://code.google.com/p/webpasswordsafe/wiki/AdminGuide (Comment 
by da...@darins.net, Jun 3, 2011)

The next section builds on the existing documentation available at:
http://webpasswordsafe.googlecode.com/svn/trunk/docs/AdministratorGuide.html

In case you have no other backup, make a copy of your existing 
webpasswordsafe-service.xml from:
<webpasswordsafe-app-name>\WEB-INF

Open webpasswordsafe -service.xml in your editor of choice. First we will step 
through each of the required changes, culminating in a complete working example 
config at the end:

Change chaining of authenticator beans to include ldapAuthenticator. Original 
setting:
<bean id="userLockoutAuthenticator"
        class="net.webpasswordsafe.server.plugin.authentication.UserLockoutAuthenticator">
        <property name="authenticator" ref="localAuthenticator" />

In the default configuration the line:
<property name="authenticator" ref="localAuthenticator" />
Causes all authentication requests to be evaluated against the built in user 
database. Alternate options for this entry are:

Ref="ldapAuthenticator" 
Populating ldapAuthenticator would cause all authentication attempts to be 
validated only by ldap / Active Directory. 

Ref="multiAuthenticator"
Populating multiAuthenticator allows per-user rules to be configured regarding 
the authentication scheme used. We will choose this option. 

Proposed setting:
<property name="authenticator" ref="multiAuthenticator" />

The bean ids "multiAuthenticator" , "authnContextSource" & "authnLdapTemplate" 
need to be moved from the xml comment into the main part of the xml document.

The bean id "multiAuthenticator" contains the default text:
                    <entry key="users">
                        <list>
                            <value>admin</value>
                        </list>
                    </entry>
                    <entry key="authenticator" value-ref="localAuthenticator"></entry>

This setting causes the default user admin to be able to authenticate against 
the built in authentication database. In a properly designed and implemented 
Active Directory environment, it should never be necessary to attempt to login 
using the built in authentication database. Since any need for this 
functionality is likely to occur in a disaster, we make that action as easy as 
possible. NOTE: it is still necessary to know the password for the account that 
is stored in the local authentication database. Preserving knowledge  of that 
password is left as an exercise for the reader

Proposed setting:
<value>SomeRandomString-admin</value>

The beain id "authnContextSource" contains a number of settings that must be 
customized for your Active Directory environment:

Add a property not already existing:
<property name="referral" value="follow" />
This setting should mitigate the risk of authentication failures due to 
"javax.naming.PartialResultException: Unprocessed Continuation Reference(s). 
More information is available:
http://pe-kay.blogspot.com.au/2013/01/webpasswordsafe-ldap-authentication.html
http://technet.microsoft.com/en-us/library/cc978014.aspx

<property name="url" value="ldap://localhost:389" />
Using ldap (as opposed to ldaps) introduces the risk that the password of every 
user logging in to WebPasswordSafe will be transmitted in clear text across 
your network. As this situation is so undesirable, clear text ldap 
configurations will not be discussed further. 
Proposed setting: ldaps://

Specifying a port number when connecting to Active Directory ldaps can have 
unexpected results. If you intend to connect to the ldap directory over ssl, no 
port number should be specified
If you intend to connect to the Global Catalog ldap directory over ssl, ":3269" 
should be specified
In a configuration where certificates are being manually deployed, using a 
Global Catalog can help to minimise the number of directory severs that will be 
queried. This in turn can minimise the risk of requesting a response from a 
server that does not have the appropriate certificates installed. More 
information about Global Catalog search: 
http://technet.microsoft.com/en-us/library/cc978012.aspx.
Proposed setting: <none - no port setting proposed>

Assuming you are not deploying WebPasswordSafe on a domain controller, 
localhost could be replaced using one of two options:
Fully Qualified Domain Name (FQDN) of a domain controller in your directory, eg:
Dc1.contoso.com
FQDN of your directory, eg:
Contoso.com
Proposed setting: contoso.com

Complete proposed setting:
"ldaps://contoso.com"

Ldap bind & user lookup account
<property name="userDn" value="cn=Manager,dc=webpasswordsafe,dc=com" />
<property name="password" value="" />
For each directory user that attempts to authenticate WebPasswordSafe uses the 
account defined above to lookup the Distinguished Name of that user. Assuming 
default AD permissions are in place, this account needs nothing more than 
membership of "Domain Users". Assuming you created a "WebPasswordSafe" user in 
the default "Users" folder.

The proposed configuration is:
<property name="userDn" value="CN=WebPasswordSafe,CN=Users,DC=contoso,DC=com" />
<property name="password" value="WebPasswordSafe-account-password" />

It is worth remembering that some characters need special handling in xml. For 
example, if the lookup account is defined in an OU in the root of the directory 
called "Service & Special Accounts", the proposed configuration would need to 
be modified to:

<property name="userDn" value="CN=WebPasswordSafe,CN=Service &amp; Special 
Accounts,DC=contoso,DC=com" />
<property name="password" value="WebPasswordSafe-account-password" />

<bean id="ldapAuthenticator"
Contains the properties:
Filter - If you configure this property with:
<property name="filter" value="(&amp;(objectclass=person)(sAMAccountName=$1))" 
/>
Your users would need to be defined in WebPasswordSafe using their 
sAMAccountName. sAMAccountName is the value displayed in Active Directory Users 
& Computers on the Account tab. Other potential properties to use for 
authentication can be explored using LDP:
http://technet.microsoft.com/en-us/library/cc772839(v=ws.10).aspx

Base
Assuming you want all users in the domain to be potential WebPasswordSafe 
users, the proposed setting is:
 <property name="base" value="dc=corpneta,dc=com" />

It is worth remembering that all users of WebPasswordsafe need to be created / 
defined there - it is not sufficient to have an Active Directory account to be 
able to login. 

At this point, you should be able to start your java servlet container, and 
have WebPasswordSafe attempt ldaps authentication. If user contoso\Alice 
(Alice@Contoso.com) exists in the domain, and should be granted access to 
WebPasswordSafe, then a user with UserName "Alice" should exist in 
WebPasswordSafe.

If it still fails to work:
As per: 
http://webpasswordsafe.googlecode.com/svn-history/r174/trunk/docs/AdministratorG
uide.html
/webpasswordsafe/src/main/resources/log4j.xml
can be edited to increase log file verbosity:

This means you will have to build WebPasswordSafe from source (this change is 
not possible using the webpasswordsafe-sample-1.3.war - but you weren't going 
to use that anyway, right?)

DEBUG is likely the log level you wish to configure

Be aware that DEBUG logging can cause passwords to be logged; be sure not to 
run this configuration in production, and to delete log files before reverting 
to a production configuration.

Example log entries, and possible causes:

2014-05-24 08:09:20,011 DEBUG [http-nio-443-exec-5]: ldap error authenticating: 
simple bind failed: localhost:636; nested exception is 
javax.naming.CommunicationException: simple bind failed: contoso.com:636 [Root 
exception is javax.net.ssl.SSLHandshakeException: 
sun.security.validator.ValidatorException: PKIX path building failed: 
sun.security.provider.certpath.SunCertPathBuilderException: unable to find 
valid certification path to requested target]

(copied & adapted from  
https://code.google.com/p/webpasswordsafe/wiki/AdminGuide)
As per the referenced page, the above error suggests your java cacerts file 
does not contain your CA certificate, or possibly an intermediary CA 
certificate is missing

2014-05-24 08:49:29,089 DEBUG [http-nio-443-exec-5]: Got Ldap context on server 
'ldaps://dc1.contoso.com:636'
2014-05-24 08:49:29,245 DEBUG [http-nio-443-exec-5]: ldap error authenticating: 
nested exception is javax.naming.PartialResultException [Root exception is 
javax.naming.CommunicationException: simple bind failed: contoso.com:636 [Root 
exception is java.net.SocketException: Connection reset]]

In the above case, dc1.contoso.com had a certificate installed for ldaps, but 
another domain controller did not. Ensuring all domain controllers had a 
certificate in place for ldaps resolved the issue. Another workaround that 
solved the issue in the test environment was to connect to 
"ldaps://dc1.contoso.com:3269" - (GC ldap)

2014-05-25 19:40:08,246 DEBUG [http-nio-443-exec-4]: ldap error authenticating: 
Uncategorized exception occured during LDAP processing; nested exception is 
javax.naming.NamingException: [LDAP: error code 1 - 000004DC: LdapErr: 
DSID-0C090724, comment: In order to perform this operation a successful bind 
must be completed on the connection., data 0, v23f0 ]; remaining name 
'dc=contoso,dc=com'

In the above case, the password property in authnContextSource was missing

Webpasswordsafe-service.xml file created by following the steps in this guide:

<?xml version="1.0" encoding="UTF-8"?>
<!--
    Copyright 2008-2013 Josh Drummond

    This file is part of WebPasswordSafe.

    WebPasswordSafe 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 2 of the License, or
    (at your option) any later version.

    WebPasswordSafe 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 WebPasswordSafe; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-->
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:context="http://www.springframework.org/schema/context"
     xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- core services -->

    <context:component-scan base-package="net.webpasswordsafe.server.service" />

    <!-- pluggable services -->

    <bean id="passwordGenerator"
        class="net.webpasswordsafe.server.plugin.generator.SimpleRandomPasswordGenerator" >
        <property name="passwordLength" value="20" />
        <property name="allowLowercase" value="true" />
        <property name="allowUppercase" value="true" />
        <property name="allowNumeric" value="true" />
        <property name="specialChars" value="!@#$%^*" />
        <property name="excludeChars" value="O0l1" />
    </bean>

    <bean id="authenticator"
        class="net.webpasswordsafe.server.plugin.authentication.IPLockoutAuthenticator">
        <property name="authenticator" ref="userLockoutAuthenticator" />
        <property name="failedLoginThreshold" value="10" />
        <property name="lockoutLength" value="1440" />
        <property name="whitelist">
            <set>
                <value>127.0.0.1</value>
            </set>
        </property>
    </bean>

    <bean id="userLockoutAuthenticator"
        class="net.webpasswordsafe.server.plugin.authentication.UserLockoutAuthenticator">
        <property name="authenticator" ref="multiAuthenticator" />
        <property name="failedLoginThreshold" value="5" />
        <property name="whitelist">
            <set>
                <value>admin</value>
            </set>
        </property>
    </bean>

    <bean id="localAuthenticator"
        class="net.webpasswordsafe.server.plugin.authentication.LocalAuthenticator">
    </bean>

    <bean id="multiAuthenticator"
        class="net.webpasswordsafe.server.plugin.authentication.CompositeAuthenticator">
        <property name="authenticators">
            <list>
                <map>
                    <entry key="users">
                        <list>
                            <value>SomeRandomString-admin</value>
                        </list>
                    </entry>
                    <entry key="authenticator" value-ref="localAuthenticator"></entry>
                </map>
                <map>
                    <entry key="anyUser" value="true" />
                    <entry key="authenticator" value-ref="ldapAuthenticator"></entry>
                </map>
            </list>
        </property>
    </bean>

    <bean id="authnContextSource" class="org.springframework.ldap.core.support.LdapContextSource">
    <property name="referral" value="follow" />
        <property name="url" value="ldaps://contoso.com" />
        <property name="userDn" value="CN=WebPasswordSafe,CN=Users,DC=contoso,DC=com" />
<property name="password" value="WebPasswordSafe-account-password" />
    </bean>
    <bean id="authnLdapTemplate" class="org.springframework.ldap.core.LdapTemplate">
        <constructor-arg ref="authnContextSource" />
    </bean>
    <bean id="ldapAuthenticator" class="net.webpasswordsafe.server.plugin.authentication.LdapAuthenticator">
        <property name="ldapTemplate" ref="authnLdapTemplate" />
        <property name="filter" value="(&amp;(objectclass=person)(sAMAccountName=$1))" />
       <property name="base" value="dc=corpneta,dc=com" />
    </bean>

    <!-- ## Uncomment to use a different authenticator implementation

    <bean id="demoAuthenticator"
        class="net.webpasswordsafe.server.plugin.authentication.DemoAuthenticator">
        <property name="demoPassword" value="demo" />
    </bean>

    <bean id="rsaAuthenticator"
        class="net.webpasswordsafe.server.plugin.authentication.RsaSecurIdAuthenticator">
        <property name="configPath" value="/usr/local/rsa/rsa_api.properties" />
    </bean>
    -->

    <bean id="roleRetriever"
        class="net.webpasswordsafe.server.plugin.authentication.LocalRoleRetriever">
        <property name="adminUsers">
            <set>
                <value>admin</value>
            </set>
        </property>
    </bean>

    <bean id="authorizer"
        class="net.webpasswordsafe.server.plugin.authorization.DefaultAuthorizer">
        <property name="allowAdminBypassPasswordPermissions" value="true" />
    </bean>

    <bean id="auditLoggerLog4j"
        class="net.webpasswordsafe.server.plugin.audit.Log4jAuditLogger">
        <property name="delimiter" value=" || " />
    </bean>

    <bean id="auditLoggerDatabase"
        class="net.webpasswordsafe.server.plugin.audit.DatabaseAuditLogger" />

    <bean id="auditLogger" 
        class="net.webpasswordsafe.server.plugin.audit.CompositeAuditLogger">
        <property name="auditLoggers">
            <list>
                <ref bean="auditLoggerLog4j" />
                <ref bean="auditLoggerDatabase" />
            </list>
        </property>
    </bean>

    <!--  Encryption related settings, these should not be changed after initial deployment otherwise
          data may be corrupted or unreadable -->

    <!-- ## Uncomment for Jasypt Encryption -->
    <bean id="digester" class="net.webpasswordsafe.server.plugin.encryption.JasyptDigester">
        <property name="passwordEncryptor" ref="passwordEncryptor" />
    </bean>
    <bean id="passwordEncryptor" class="org.jasypt.util.password.StrongPasswordEncryptor" />
    <bean id="encryptor" class="net.webpasswordsafe.server.plugin.encryption.JasyptEncryptor">
        <property name="stringEncryptor" ref="strongEncryptor" />
    </bean>
    <bean id="bcProvider" class="org.bouncycastle.jce.provider.BouncyCastleProvider" />
    <bean id="strongEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
        <property name="algorithm" value="${encryptor.jasypt.algorithm}" />
        <property name="provider" ref="bcProvider" />
        <property name="password" value="${encryptor.jasypt.password}" />
        <property name="keyObtentionIterations" value="${encryptor.jasypt.keyObtentionIterations}" />
    </bean>

    <!-- ## Uncomment for OWASP-ESAPI Encryption -->
    <!-- 
    <bean id="digester" class="net.webpasswordsafe.server.plugin.encryption.EsapiDigester">
        <constructor-arg index="0" value="${encryptor.esapi.useClasspath}" />
        <constructor-arg index="1" value="${encryptor.esapi.resourceDir}" />
    </bean>
    <bean id="encryptor" class="net.webpasswordsafe.server.plugin.encryption.EsapiEncryptor">
        <constructor-arg index="0" value="${encryptor.esapi.useClasspath}" />
        <constructor-arg index="1" value="${encryptor.esapi.resourceDir}" />
    </bean>
    -->

</beans>

Original issue reported on code.google.com by e...@tunedglobal.com on 25 May 2014 at 11:17