Single Sign On

From OpenNMS
Jump to: navigation, search
Tested for Versions
The instructions in this article have been tested against the following versions of OpenNMS.
Tested Against:
Version 16.0.3 tested by Michele

Overview

As of OpenNMS 16.0.3-1 Single Sign On (SSO) using Spring Security and Kerberos is available and tested against freeIPA Kerberos server and Microsoft® Windows Domain Controllers.

Configuration for Microsoft® Windows; Domain Controllers

This example configuration was tested with opennms 16.0.3-1

On the DC
  • create service principal on DC for HTTP/opennms_server.internal.opennms.org@INTERNAL.OPENNMS.ORG with User opennmsSSOUser
  • create keytab file opennms_server.keytab for this service principal
  • create a user OpenNMSLdapUser for ldap access with a passwort which will not expire
On the opennms server (linux in this example)
  • download the jars for extended encryption support in java from oracle (read the license!), unpack and copy the jar's to your jre library directory, probably /usr/java/latest/jre/lib/security
  • You will need spring kerberos jar-files for version 1.0.1 or newer. If your installation has a lower version download spring kerberos jar-files for version 1.0.1 or newer and install them instead of the older files in $OPENNMS_HOME/lib (don't forget to remove the old files)
 $OPENNMS_HOME/lib/spring-security-kerberos-client-1.0.1.RELEASE.jar
 $OPENNMS_HOME/lib/spring-security-kerberos-core-1.0.1.RELEASE.jar
 $OPENNMS_HOME/lib/spring-security-kerberos-web-1.0.1.RELEASE.jar
  • create a directory </code>$OPENNMS_HOME/etc/credentials</code> for keytab files
  • copy the keytab file created above to $OPENNMS_HOME/etc/credentials
  • create a keytab file for the LDAP user OpenNMSLdapUser
  ktutil 
  ktutil:  addent -password -p OpenNMSLdapUser@INTERNAL.OPENNMS.ORG -k 1 -e aes256-cts-hmac-sha1-96
  Password for OpenNMSLdapUser@internal.opennms.org:
  ktutil:  wkt $OPENNMS_HOME/etc/certificates/OpenNMSLdapUser.keytab
  q
  • create /etc/krb5.ini with aes256-support, see example below

Test access to the kerberos server from the operating system level

  • create a temporary kerberos ticket for your kerberos service principal with kinit for test purposes
  opennms-server> kinit -k -t $OPENNMS_HOME/etc/certificates/opennms_server.keytab HTTP/opennms_server.internal.opennms.org@INTERNAL.OPENNMS.ORG
  opennms-server> klist
  Ticket cache: FILE:/tmp/krb5cc_8001
  Default principal: HTTP/opennms_server.internal.opennms.org@INTERNAL.OPENNMS.ORG
  • create a temporary kerberos ticket for your kerberos LDAP user with kinit for test purposes
  opennms-server> kinit -k -t $OPENNMS_HOME/etc/certificates/OpenNMSLdapUser.keytab OpenNMSLdapUser@INTERNAL.OPENNMS.ORG
  opennms-server> klist
  Ticket cache: FILE:/tmp/krb5cc_8003
  Default principal: OpenNMSLdapUser@INTERNAL.OPENNMS.ORG
  • rename $OPENNMS_HOME/jetty-webapps/opennms/WEB-INF/spring-security.d/sso_activeDirectory_kerb_ldap.xml.disable to $OPENNMS_HOME/jetty-webapps/opennms/WEB-INF/spring-security.d/sso_activeDirectory_kerb_ldap.xml and merge the config from the example below into this file
  • import the keytab file for LDAP access $OPENNMS_HOME/etc/certificates/OpenNMSLdapUser.keytab into this file at the appropriate place (see example)
  • create a keytab file for the LDAP user OpenNMSLdapUser and import it in sso_activeDirectory_kerb_ldap.xml in the ldap-part (see example)
  • create an entry to import /etc/krb5.ini (see example)
  • increase the maximum length of a request header allowed by Jetty, in opennms.properties:
# This sets the request header size for jetty.
# The default value is 4000 bytes.
org.opennms.netmgt.jetty.requestHeaderSize=8000
  • restart opennms
Testing/Debugging
  • you will get a blank page when the kerberos connection doesn't work
  • if it does not work, test access to the kerberos server from operating system level as described above
  • if access from operating system level works, turn on DEBUG for the web entry in log4j2.xml. Caution: look into both $OPENNMS_HOME/logs/web.log and $OPENNMS_HOME/logs/output.log for not missing any error message!
Example Configuration Files
  • Replace internal.opennms.org with your ip domain
  • Replace INTERNAL.OPENNMS.ORG with your ip domain
  • Replace opennmsSSOUser with the username your Windows Domain Admin decided to give you as username for your service principal
  • Replace yourWindowsDomain with the domain name of your Windows domain
  • Replace opennms_server with the hostname of your opennms server
  • Replace OpenNMSLdapUser with the username your Windows Domain Admin decided to give you for LDAP Access
Example krb5.ini File

/etc/krb5.ini

  [libdefaults]
        default_realm = INTERNAL.OPENNMS.ORG
        permitted_enctypes = aes256-cts-hmac-sha1-96 aes256-cts 
        default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes256-cts 
        default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes256-cts 
        dns_lookup_realm = false
        dns_lookup_kdc = false
        noaddresses = true
  [realms]
        INTERNAL.OPENNMS.ORG = {
                kdc = dcserver.internal.opennms.org
        }
  [domain_realm]
        .internal.opennms.org = INTERNAL.OPENNMS.ORG
        internal.opennms.org = INTERNAL.OPENNMS.ORG
  [logging]
    kdc = FILE:/var/log/krb5/krb5kdc.log
    admin_server = FILE:/var/log/krb5/kadmind.log
    default = SYSLOG:NOTICE:DAEMON


Apply the following changes to the $OPENNMS_HOME/jetty-webapps/opennms/WEB-INF/applicationContext-spring-security.xml File
diff --git a/jetty-webapps/opennms/WEB-INF/applicationContext-spring-security.xml b/jetty-webapps/opennms/WEB-INF/applicationContext-spring-security.xml

--- a/jetty-webapps/opennms/WEB-INF/applicationContext-spring-security.xml
+++ b/jetty-webapps/opennms/WEB-INF/applicationContext-spring-security.xml
@@ -55,7 +55,7 @@
   <http pattern="/webstart/**" security="none"/>

   <!-- Only one <http> section can match the implicit '/**' pattern -->
+  <http pattern="/**" access-denied-page="/accessDenied.jsp" realm="OpenNMS Realm" auto-config="false" entry-point-ref="spnegoEntryPoint">
-  <http pattern="/**" access-denied-page="/accessDenied.jsp" realm="OpenNMS Realm" auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint">
     <intercept-url pattern="/" access="ROLE_ANONYMOUS,ROLE_USER,ROLE_DASHBOARD" />
     <intercept-url pattern="/favicon.ico" access="ROLE_ANONYMOUS,ROLE_USER,ROLE_DASHBOARD" />
     <intercept-url pattern="/logoff.jsp" access="ROLE_ANONYMOUS,ROLE_USER,ROLE_DASHBOARD" />
@@ -91,7 +91,6 @@
     <!-- NrtCollection -->
     <intercept-url pattern="/amq/*" access="ROLE_ANONYMOUS,ROLE_USER,ROLE_DASHBOARD" />

+    <custom-filter ref="spnegoAuthenticationProcessingFilter" before="BASIC_AUTH_FILTER" />
     <!--Commented out for custom authentication filter<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1" />-->
     <http-basic />
     <logout logout-success-url="/" />
@@ -132,12 +131,10 @@
   <authentication-manager alias="authenticationManager">
     <!-- Use our custom authentication provider -->
     <authentication-provider ref="hybridAuthenticationProvider" />
+    <authentication-provider ref="kerberosAuthenticationProvider" />
+    <authentication-provider ref="kerberosServiceAuthenticationProvider" />
     <!-- To enable external (e.g. LDAP, RADIUS) authentication, uncomment the following.
          You must also rename and customize exactly ONE of the example files in the
          spring-security.d subdirectory. -->
+    <!-- <authentication-provider ref="externalAuthenticationProvider" /> -->
-    <authentication-provider ref="externalAuthenticationProvider" />
   </authentication-manager>

   <!-- ===================== USER DAO AUTHENTICATION ==================== -->


Example sso_activeDirectory_kerb_ldap.xml File

$OPENNMS_HOME/jetty-webapps/opennms/WEB-INF/spring-security.d/sso_activeDirectory_kerb_ldap.xml

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:sec="http://www.springframework.org/schema/security"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

<!--
     Example context for performing single sign-on (SSO) in an Active
     Directory environment, where Kerberos is the authentication source
     and LDAP group membership is used to grant roles to authenticated
     users.  Access to the LDAP directory is also Kerberized, so it is
     not necessary to store a plaintext password for a bind user.

     If the user's browser supports SPNEGO and is configured to accept
     it for the server, no interactive login should be required. As a
     fallback, form-based authentication with Kerberos credentials is
     used.

     Note that changes to the top-level applicationContext-spring-security.xml
     file are necessary when using this configuration. Specifically:

     * In the <http> element for the '/**' pattern, replace the reference to
       loginUrlAuthenticationEntryPoint with one to spnegoEntryPoint

     * In the same <http> element, add the following element before the
       <http-basic /> element:

       <custom-filter ref="spnegoAuthenticationProcessingFilter" before="BASIC_AUTH_FILTER" />

     * Instead of uncommenting the reference to externalAuthenticationProvider, add
       the following elements after the reference to hybridAuthenticationProvider:

       <authentication-provider ref="kerberosAuthenticationProvider" />
       <authentication-provider ref="kerberosServiceAuthenticationProvider" />
-->

  <bean id="kerberosAuthenticationProvider"
    class="org.opennms.web.springframework.security.KerberosLdapAuthenticationProvider">
    <property name="kerberosClient">
      <bean class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient">
        <property name="debug" value="true"/>
      </bean>
    </property>
    <property name="ldapUserSearch" ref="kerberosLdapUserSearch"/>
    <property name="ldapAuthoritiesPopulator" ref="kerberosUserGroupLdapAuthoritiesPopulator"/>
  </bean>

  <bean
    class="org.springframework.security.kerberos.authentication.sun.GlobalSunJaasKerberosConfig">
    <property name="debug" value="false" />
    <property name="krbConfLocation" value="/etc/krb5.conf"/>
  </bean>


  <bean id="kerberosServiceAuthenticationProvider"
    class="org.opennms.web.springframework.security.KerberosServiceLdapAuthenticationProvider">
    <property name="ticketValidator">
      <bean
        class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator">
        <!-- Name of the Kerberos service principal designated for the OpenNMS webapp -->
        <property name="servicePrincipal" value="HTTP/opennms-server.internal.opennms.org@INTERNAL.OPENNMS.ORG" />
        <!-- Location of the Kerberos keytab file. Must be of the form file:/path/to/keytab -->
        <property name="keyTabLocation" value="file:/opt/opennms/etc/credentials/opennms_server.keytab" />
        <property name="debug" value="true" />
      </bean>
    </property>
    <property name="ldapUserSearch" ref="kerberosLdapUserSearch"/>
    <property name="ldapAuthoritiesPopulator" ref="kerberosUserGroupLdapAuthoritiesPopulator"/>
  </bean>

  <bean id="spnegoEntryPoint"
    class="org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint" >
    <constructor-arg value="/login.jsp" />
  </bean>

  <bean id="spnegoAuthenticationProcessingFilter"
    class="org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter">
    <property name="authenticationManager" ref="authenticationManager" />
  </bean>

  <bean id="kerberosLdapContextSource"
    class="org.springframework.security.kerberos.client.ldap.KerberosLdapContextSource">
    <constructor-arg>
      <list>
        <!-- List one or more of your LDAP servers here -->
        <value>ldap://dcserver.internal.opennms.org:389/</value>
      </list>
    </constructor-arg>
    <!-- Base DN for LDAP searches. Every group below is relative to this. -->
    <constructor-arg value="dc=internal,dc=opennms,dc=org" />
    <property name="loginConfig" ref="ldapLoginConfig" />
  </bean>

  <bean id="ldapLoginConfig"
    class="org.springframework.security.kerberos.client.config.SunJaasKrb5LoginConfig">
    <!-- Name of the Kerberos user principal designated for querying the LDAP directory -->
    <property name="servicePrincipal" value="OpenNMSLdapUser@INTERNAL.OPENNMS.ORG" />
    <!-- Location of the Kerberos keytab file for the user principal above. Must be of the form file:/path/to/keytab -->
    <property name="keyTabLocation" value="file:/opt/opennms/etc/credentials/OpenNMSLdapUser.keytab" />
    <property name="debug" value="true" />
    <property name="isInitiator" value="true" />
  </bean>

  <bean id="kerberosLdapUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
    <!-- Search base for looking up users in the LDAP directory -->
    <constructor-arg index="0" value="ou=user" />
    <!-- Search filter for user lookups -->
    <constructor-arg index="1" value="(sAMAccountName={0})" />
    <constructor-arg index="2" ref="kerberosLdapContextSource" />
    <property name="searchSubtree" value="true" />
  </bean>

  <bean id="kerberosUserGroupLdapAuthoritiesPopulator" class="org.opennms.web.springframework.security.UserGroupLdapAuthoritiesPopulator">
    <constructor-arg ref="kerberosLdapContextSource" />
    <!-- Search base for looking up groups in the LDAP directory -->
    <constructor-arg value="ou=groups" />
    <property name="searchSubtree" value="true" />
    <property name="convertToUpperCase" value="true" />
    <property name="groupRoleAttribute" value="cn" />
    <!-- Search filter for groups -->
    <property name="groupSearchFilter" value="member={0}" />
    <property name="groupToRoleMap">
      <map>
        <entry>
          <!-- Name of the LDAP group for normal (non-admin) OpenNMS users -->
          <key><value>opennms_users</value></key>
          <list>
            <value>ROLE_USER</value>
            <value>ROLE_DASHBOARD</value>
          </list>
        </entry>
        <entry>
          <!-- Name of the LDAP group for OpenNMS administrators -->
          <key><value>opennms_admins</value></key>
          <list>
            <value>ROLE_USER</value>
            <value>ROLE_ADMIN</value>
            <value>ROLE_DASHBOARD</value>
          </list>
        </entry>
      </map>
    </property>
  </bean>

</beans>