Spring Security and LDAP

From OpenNMS

Contents

Sample Configuration "LDAP only"

OpenNMS Version

OpenNMS version 1.7.5

Spring Security Version

Spring Security 2.04

Spring Security

Version 1.7.5 of openNMS never included the spring security framework so you will need to download it from the following URL spring-security-2.0.4.zip.

Notes about provided configs

I developed these configurations for my company but have tried to sanitize them for public consumption there are fields of note that will be required to be changed in addition to the following you may enable TLS/SSL for your LDAP server if you install root ca's which is beyond the scope of this document.

You will need to configure the following values.

LDAP host and its port : ldap://foo.com:389 LDAP search base : ou=mydepartment,o=mycompany,dc=com

      • Note this account only needs search privileges and should be acl limited

User that will do binds to perform lookups : uid=myUser,ou=Users,ou=mydepartment,o=mycompany,dc=ca Password for the above user : myPassword

The group section for the bind is based off the ldif I have provided, customize as you see fit.


Configuring applicationContext-spring-security.xml

Spring security is configured in $OPENNMS_HOME/jetty-webapps/opennms/WEB-INF/applicationContext-spring-security.xml. You have to add the following definitions there.

  <beans:bean id="upperCaseMd5PasswordEncoder" class="org.opennms.web.springframework.security.UpperCaseMd5PasswordEncoder"/>

<!-- LDAP Start -->
  <beans:bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">

    <!-- Enter your LDAP server address, dc, o and ou  here -->
    <beans:constructor-arg value="<bold>ldap://foo.com:389/ou=mydepartment,o=mycompany,dc=com</bold>" />

    <!-- Enter User parameters for accessing your LDAP server here -->
    <beans:property name="userDn" value="uid=myUser,ou=Users,ou=mydepartment,o=mycompany,dc=ca"/>
    <beans:property name="password" value="myPassword"/>

  </beans:bean>
    <beans:bean id="ldapAuthProvider" class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
      <custom-authentication-provider />
        <beans:constructor-arg>
           <beans:bean class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
             <beans:constructor-arg ref="contextSource"/>
             <beans:property name="userSearch" ref="userSearch">
             </beans:property>
           </beans:bean>
        </beans:constructor-arg>
        <beans:constructor-arg>
           <beans:bean class="org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator">
             <beans:constructor-arg ref="contextSource"/>
             <beans:constructor-arg value="ou=ONMS,ou=Groups"/>
             <beans:property name="groupRoleAttribute" value="cn"/>
             <beans:property name="searchSubtree" value="false" />
             <beans:property name="convertToUpperCase" value="true" />
             <beans:property name="rolePrefix" value="ROLE_" />
             <beans:property name="groupSearchFilter" value="memberUid={1}" />
           </beans:bean>
        </beans:constructor-arg>
  </beans:bean>

  <beans:bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
    <beans:constructor-arg index="0" value="ou=Users" />
    <beans:constructor-arg index="1" value="(uid={0})" />
    <beans:constructor-arg index="2" ref="contextSource" />
    <beans:property name="searchSubtree" value="true" />
  </beans:bean>


<!-- LDAP End -->

  <!-- ====================== RADIUS AUTHENTICATION ===================== -->

Modify the magic-users.properties

###########################################################################
## U S E R S
###########################################################################

# A comma-separated list of user keys.  A user.{KEY}.username and
# user.{KEY}.password property must be set for each key in this property.
users=rtc

# The RTC View Control Manager daemon uses this user to authenticate itself
# while sending RTC data posts.
user.rtc.username=rtc
user.rtc.password=rtc

###########################################################################
## R O L E S
###########################################################################

# A comma-separated list of role keys.  A role.{KEY}.name and
# role.{KEY}.users property must be set for each key in this property.
#roles=rtc, admin, rouser, dashboard, provision
roles=rtc

# This role allows a user to make RTC data posts.
role.rtc.name=OpenNMS RTC Daemon
role.rtc.users=rtc
role.rtc.notInDefaultGroup=true

# This role allows users access to configuration and
# administrative web pages.
#role.admin.name=OpenNMS Administrator
#role.admin.users=admin

# This role disallows user write access
#role.rouser.name=OpenNMS Read-Only User
#role.rouser.users=

# This role allows access to the dashboard only
#role.dashboard.name=OpenNMS Dashboard User
#role.dashboard.users=
#role.dashboard.notInDefaultGroup=true

# This role was added for WIND
#role.provision.name=OpenNMS Provision User
#role.provision.users=

Sample LDIF For group structure

dn: ou=ONMS, ou=Groups,ou=mydepartment,o=mycompany,dc=com
ou: ONMS
description: Open NMS groups
objectClass: top
objectClass: organizationalUnit

dn: cn=ADMIN, ou=ONMS, ou=Groups,ou=mydepartment,o=mycompany,dc=com
gidNumber: 7010
userPassword:: e2NyeXB0fXg=
memberUid: myAdminUser
objectClass: posixGroup
objectClass: top
cn: ADMIN

dn: cn=ANONYMOUS, ou=ONMS, ou=Groups,ou=mydepartment,o=mycompany,dc=com
gidNumber: 7011
userPassword:: e2NyeXB0fXg=
memberUid: myAnonymousUser
objectClass: posixGroup
objectClass: top
cn: ANONYMOUS

dn: cn=USER, ou=ONMS, ou=Groups,ou=mydepartment,o=mycompany,dc=com
gidNumber: 7012
userPassword:: e2NyeXB0fXg=
memberUid: myRegUser
objectClass: posixGroup
objectClass: top
cn: USER

dn: cn=DASHBOARD, ou=ONMS, ou=Groups,ou=mydepartment,o=mycompany,dc=com
gidNumber: 7013
userPassword:: e2NyeXB0fXg=
memberUid: myDashboardUser
objectClass: posixGroup
objectClass: top
cn: DASHBOARD

dn: cn=PROVISION, ou=ONMS, ou=Groups,ou=mydepartment,o=mycompany,dc=com
gidNumber: 7014
userPassword:: e2NyeXB0fXg=
memberUid: myProvisionUser
objectClass: posixGroup
objectClass: top
cn: PROVISION

dn: cn=RTC, ou=ONMS, ou=Groups,ou=mydepartment,o=mycompany,dc=com
gidNumber: 7015
userPassword:: e2NyeXB0fXg=
memberUid: myRTCUser
objectClass: posixGroup
objectClass: top
cn: RTC

Sample Configuration "local Authentication and LDAP"

OpenNMS Version

OpenNMS version 1.7.8 and later

Spring Security Version

Spring Security 2.04 as integrated in OpenNMS 1.7.8

Design

  • OpenNMS Administration is done for some (internal or external) customer
  • OpenNMS Admin Responsability should never be gained by the customer
  • LDAP administration is done by the customer (internal or external)
  • OpenNMS internal users shouldn't be authenticated by LDAP
    • to prevent OpenNMS outages when someone by error changes OpenNMS LDAP users
    • for having availability of OpenNMS even when LDAP is down/unreachable

Technics

  • OpenNMS-provided authentication is used for Admin and internal users
  • LDAP is provided from Active Directory (AD)
    • only LDAP users from a specific department (OU=...) are allowed
    • only users belonging to one of the groups g_operating or g_helpdesk are allowed
    • saMAccountName is used to identify the UserID within LDAP/AD

Solution

  • use DAO authentication (OpenNMS local authentication) for Admin Users
  • use DAO authentication for opennms internal users like RTC, MAP etc.
  • use LDAP authentication for all (internal or external) customers
  • assign ROLE_USER to all LDAP authenticated users

Values from AD

Values from LDAP/AD (some lines from LDIF of a sample-user):

dn: CN=SampleUserId,OU=SomeDept,OU=SomeOrgUnit,dc=SomeCompany,dc=SomeCountry
...
memberOf: CN=g_operating,OU=SomeDept,OU=SomeOrgUnit,dc=SomeCompany,dc=SomeCountry
...
sAMAccountName: SampleUserID
...

Spring Security Configuration

Spring security is configured in $OPENNMS_HOME/jetty-webapps/opennms/WEB-INF/applicationContext-spring-security.xml. You have to add the following definitions there. You don't have to alter other configuration files for this LDAP integration. Admin-Users are configured in OpenNMS as described in Docu-overview#Users.

Just add the following lines below the Dao Authentication in applicationContext-spring-security.xml and change the fields like IP-address / Root-DN / Userid / Password for the LDAP-server, UserSearch path and groups the users must belong to.

Take a look at the filters for the groups - they contain the complete path, obviously in this notation neither the root-DN nor the SearchBase part of the path is added to the filter! (Took me some time to figure this out...).



 <beans:bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
   <beans:constructor-arg value="ldap://11.12.13.14:389/dc=SomeCompany,dc=SomeCountry"</bold> />
   <beans:property name="userDn" value="userIDforLDAP-Queries"/>
   <beans:property name="password" value="password"/>
 </beans:bean>


 <beans:bean id="ldapAuthProvider" class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
   <custom-authentication-provider />      
   <beans:constructor-arg ref="ldapAuthenticator"/>
   <beans:constructor-arg ref="ldapAuthoritiesPopulator"/>
 </beans:bean>


 <beans:bean id="ldapAuthenticator" class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
   <beans:constructor-arg ref="contextSource"/>
   <beans:property name="userSearch" ref="userSearch">
   </beans:property>
 </beans:bean>


   <beans:bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
     <beans:constructor-arg index="0" value="OU=SomeDept,OU=SomeOrgUnit" />

     <beans:constructor-arg index="1" value="(&amp;(sAMAccountName={0})
                (|(memberOf=cn=g_operating,OU=SomeDept,OU=SomeOrgUnit,dc=SomeCompany,dc=SomeCountry)
                  (memberOf=cn=g_helpdesk, OU=SomeDept,OU=SomeOrgUnit,dc=SomeCompany,dc=SomeCountry)))" />
     <beans:constructor-arg index="2" ref="contextSource" />
     <beans:property name="searchSubtree" value="true" />
   </beans:bean>



 <beans:bean id="ldapAuthoritiesPopulator" class="org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator">
   <beans:constructor-arg ref="contextSource"/>

   <beans:constructor-arg value="OU=SomeDept,OU=SomeOrgUnit"/>

   <beans:property name="groupRoleAttribute" value=""/>
   <beans:property name="rolePrefix" value="" />

   <beans:property name="defaultRole" value="ROLE_USER" />

 </beans:bean>

Troubleshooting

Enable DEBUG in log4j.properties for

log4j.category.org.springframework.security=DEBUG, MISC
log4j.category.OpenNMS.Spring=DEBUG, SPRING
log4j.category.org.springframework=DEBUG, SPRING

Don't forget to disable DEBUG after you finished your tests!

Search for LDAP server IP, userid's / groups or IP address of authenticating clients in spring.log and misc.log.

Look out for Granted Authorities: ROLE_USER. If there are other roles too there is a possibility to gain admin rights for your OpenNMS system by providing the roles in LDAP / AD.

Personal tools
DevJam 2008 Sponsors
DevJam 2008 Sponsor: Google
DevJam 2008 Sponsor: Netregistry
DevJam 2008 Sponsor: Papa John's
NewEdge Networks
OpenNMS takes home the gold award!
Join the Free Software Foundation
Support This Project Commercial OpenNMS Support OpenNMS Italia Get OpenNMS at SourceForge.net. Fast, secure and Free Open Source software downloads Our Network Simulator Our Java Profiler