10 Replies Latest reply on Jul 21, 2014 4:06 PM by jessholle

    Migration from Tomcat Combined/JNDIRealm to Wildfly?

    jessholle

      Can someone point me to simple how-to guidance on moving from simple usage of Tomcat's CombinedRealm with multiple JNDIRealm children (to query multiple LDAPs) as a basis for web application authentication to best accomplish the same thing in Wildfly?

        • 1. Re: Migration from Tomcat Combined/JNDIRealm to Wildfly?
          sfcoy
          • 2. Re: Migration from Tomcat Combined/JNDIRealm to Wildfly?
            jessholle

            The article you site is helpful on many other fronts but shows no ability to reference multiple LDAP URLs in a non-failover fashion, e.g. to have 1 set of users defined by LDAP URL A and another disjoint set of users defined by LDAP URL B.  This capability has been in both Apache HTTP Server and Tomcat for many years.  Yet doing the obvious thing in Wildfly to achieve this, adding 2 <ldap> elements to the <authentication> element in the JBoss configuration, produces errors in Wildfly 8.0.  Apparently only 1 <ldap> element is allowed here.

             

            How can this requirement be addressed currently with Wildfly 8.0?  With 8.1?

             

            If this cannot be addressed currently how should Wildfly be extended to handle this?  With a <combinedrealm> sort of notion that can be used to enclose multiple <ldap> elements here?  Or....?

             

            This isn't a hypothetical need -- and I'm actually shocked that JBoss doesn't address this (at least not in any obvious fashion).

            • 3. Re: Migration from Tomcat Combined/JNDIRealm to Wildfly?
              scrublet

              Is there any way for you to use security-domains to achieve your goals? For a number of reasons, the <ldap> security realm couldn't do what I wanted to do. Instead, I configured a <security-domain> with the AdvancedLdap <login-module> to achieve my goals. My application then pointed at the security-domain, as well as other subsystems.

               

              You could define a <security-domain> with a <login-module> for each LDAP connection. In your A/B example you would thus have:

               

              <subsystem xmlns="urn:jboss:domain:security:1.2">
                   <security-domains>
                        <security-domain name="chainedLdap" cache-type="default">
                             <authentication>
                                  <login-module code="AdvancedLdap" flag="sufficient">
                                       <!-- A bunch of <module-option> entries for your LDAP A -->
                                  </login-module>
                                  <login-module code="AdvancedLdap" flag="sufficient">
                                       <!-- A bunch of <module-option> entries for your LDAP B -->
                                  </login-module>
                             </authentication>
                        </security-domain>
                   </security-domains>
              </subsystem>
              

               

              In that code, the "sufficient" flag means that if the LDAP A succeeds, you're done. If it doesn't, go to LDAP B. If that doesn't succeed, reject the user.

               

              Then, if you still required the use of the actual Realm to be referenced, instead of the <ldap> tag, you use <jaas name="chainedLdap"/>, which of course points to this new chained security domain.

              • 4. Re: Migration from Tomcat Combined/JNDIRealm to Wildfly?
                jessholle

                Thanks, that is helpful.

                 

                Initially I thought you meant that the best available approach was to write a custom login module.

                 

                Now, however, I notice PicketBox Authentication, which provides 2 different LDAP modules already.

                 

                It still seems odd that one can't just have multiple <ldap> elements, but this seems workable.

                • 5. Re: Migration from Tomcat Combined/JNDIRealm to Wildfly?
                  scrublet

                  To be clear: Picketbox actually provides four LDAP modules. I am definitely not the best person to ask as to each's purpose, but my impressions when using them have been:

                   

                  LdapLoginModule - basic login module, best when you have a simple LDAP server to connect to (e.g., one with minimal to no authentication to get in, simple LDAP structure inside).

                  LdapExtLoginModule - extends the basic login module with some more options for searching for users and roles

                  AdvancedLdapLoginModule - my favorite, this is almost like a reboot of LDAP functionality for AS7/Wildfly. In my personal opinion the options are easier to figure out, and this was the first module I got to work with Active Directory (in conjunction with the KerberosLoginModule)

                  AdvancedLdapADLogin - directly extends AdvancedLdapLoginModule and adds two options. I have no idea what this is used for, my LDAP/AD understanding is minimal.

                   

                  As far as having multiple <ldap> elements, I'm not sure there's a standard for security realms to chain together authentication systems (Tomcat may have just made their own system up, I don't know). Versus the security subsystem whose functionality is defined by JAAS.

                  • 6. Re: Migration from Tomcat Combined/JNDIRealm to Wildfly?
                    jessholle

                    It took me quite some time to understand where to place <login-module> elements -- since JBoss has <authentication> multiple elements in standalone-full.xml, which have completely different schemas based on namespaces.  This could hardly be more confusing -- especially since my original intent was to modify the ApplicationRealm.

                     

                    Since modification of the ApplicationRealm clearly isn't possible, this way, I created my own domain ala:

                     

                    <security-domain name="MyDomain" cache-type="default">

                      <authentication>

                        <!-- Note that org.jboss.security.negotiation.AdvancedLdapLoginModule isn't found at all, so I can't use that, nor do I see anything to suggest what the full classname might be now, if this has changed. -->

                        <login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="sufficient">

                          <module-option name="java.naming.provider.url" value="ldap://localhost:389"/>

                          <module-option name="bindDN" value="cn=Manager"/>

                          <module-option name="bindCredential" value="manager"/>

                          <module-option name="baseCtxDN" value="ou=people,cn=EnterpriseLdap,cn=SomeCN,o=someOrg"/>

                          <module-option name="baseFilter" value="(uid={0})"/>

                          <module-option name="password-stacking" value="useFirstPass"/>  <!-- Appropriate? -->               

                          <module-option name="defaultRole" value="valid-user"/>                   

                        </login-module>

                        <login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="sufficient">

                          <module-option name="java.naming.provider.url" value="ldap://localhost:389"/>

                          <module-option name="bindDN" value="cn=Manager"/>

                          <module-option name="bindCredential" value="manager"/>

                          <module-option name="baseCtxDN" value="ou=people,cn=AdministrativeLdap,cn=SomeCN,o=someOrg"/>

                          <module-option name="baseFilter" value="(uid={0})"/>

                          <module-option name="password-stacking" value="useFirstPass"/>  <!-- Appropriate? -->

                          <module-option name="defaultRole" value="valid-user"/>                   

                        </login-module>

                      </authentication>

                    </security-domain>

                     

                    I reference this via jboss-web.xml and was all set to celebrate.

                     

                    Unfortunately, this fails miserably with:

                     

                    2014-07-21 12:31:54,789 TRACE [org.jboss.security] (default task-2) PBOX000236: Begin initialize method

                    2014-07-21 12:31:54,789 TRACE [org.jboss.security] (default task-2) PBOX000240: Begin login method

                    2014-07-21 12:31:54,795 DEBUG [org.jboss.security] (default task-2) PBOX000269: Failed to parse roleRecursion as number, using default value 0

                    2014-07-21 12:31:54,796 TRACE [org.jboss.security] (default task-2) PBOX000220: Logging into LDAP server with env {java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.security.principal=cn=Manager, defaultRole=valid-user, password-stacking=useFirstPass, baseCtxDN=ou=people,cn=EnterpriseLdap,cn=SomeCN,o=someOrg, baseFilter=(uid={0}), jboss.security.security_domain=MyDomain, java.naming.provider.url=ldap://localhost:389, bindDN=cn=Manager, bindCredential=******, java.naming.security.authentication=simple, java.naming.security.credentials=******}

                    2014-07-21 12:31:54,801 DEBUG [org.jboss.security] (default task-2) PBOX000283: Bad password for username wcadmin

                    2014-07-21 12:31:54,802 TRACE [org.jboss.security] (default task-2) PBOX000236: Begin initialize method

                    2014-07-21 12:31:54,802 TRACE [org.jboss.security] (default task-2) PBOX000240: Begin login method

                    2014-07-21 12:31:54,802 DEBUG [org.jboss.security] (default task-2) PBOX000269: Failed to parse roleRecursion as number, using default value 0

                    2014-07-21 12:31:54,802 TRACE [org.jboss.security] (default task-2) PBOX000220: Logging into LDAP server with env {java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.security.principal=cn=Manager, defaultRole=valid-user, password-stacking=useFirstPass, baseCtxDN=ou=people,cn=AdministrativeLdap,cn=SomeCN,o=someOrg, baseFilter=(uid={0}), jboss.security.security_domain=MyDomain, java.naming.provider.url=ldap://localhost:389, bindDN=cn=Manager, bindCredential=******, java.naming.security.authentication=simple, java.naming.security.credentials=******}

                    2014-07-21 12:31:54,804 TRACE [org.jboss.security] (default task-2) PBOX000220: Logging into LDAP server with env {java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.security.principal=uid=wcadmin,ou=people,cn=AdministrativeLdap,cn=SomeCN,o=someOrg, defaultRole=valid-user, password-stacking=useFirstPass, baseCtxDN=ou=people,cn=AdministrativeLdap,cn=SomeCN,o=someOrg, baseFilter=(uid={0}), jboss.security.security_domain=MyDomain, java.naming.provider.url=ldap://localhost:389, bindDN=cn=Manager, bindCredential=******, java.naming.security.authentication=simple, java.naming.security.credentials=******}

                    2014-07-21 12:31:54,806 DEBUG [org.jboss.security] (default task-2) PBOX000283: Bad password for username wcadmin

                    2014-07-21 12:31:54,806 TRACE [org.jboss.security] (default task-2) PBOX000244: Begin abort method

                    2014-07-21 12:31:54,806 TRACE [org.jboss.security] (default task-2) PBOX000244: Begin abort method

                    2014-07-21 12:31:54,806 DEBUG [org.jboss.security] (default task-2) PBOX000206: Login failure: javax.security.auth.login.FailedLoginException: PBOX000070: Password invalid/Password required

                        at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:284) [picketbox-4.0.20.Final.jar:4.0.20.Final]

                     

                    Yet this logging is clearly inaccurate as:

                    1. The "EnterpriseLdap" URL doesn't even contain a wcadmin entry -- so it should note the lack of an entry, not a bad password!
                    2. The "AdministrativeLdap" URL contains a wcadmin *and* the LDAP logs show a successful bind having occurred on the user entry for wcadmin.

                     

                    So what is *really* wrong here?  There's no indication.

                     

                    Any suggestion as to what logging to enable beyond setting org.jboss.security and org.jboss.as.web.security to TRACE would be appreciated!

                    • 7. Re: Re: Migration from Tomcat Combined/JNDIRealm to Wildfly?
                      scrublet

                      You are confusing the <authentication> element of a <security-realm> with the <authentication> element of a <security-domain>. I believe you also may be confusing how web applications interact with domains and realms in general (more on that at the bottom).

                       

                      A <security-realm> element defines a child <authentication> element. This auth element may have a <local> child element and ONE AND ONLY ONE of <ldap>, <properties>, <users>, <jaas>, or <plug-in>. You can find the documentation for this in ${jboss.home.dir}/docs/schema/jboss-as-config_2_1.xsd.  Each of those elements provides relatively little configuration compared to <security-domain>, which is why the <jaas> element exists. The <jaas> element is used to define a <security-realm> that uses a configured <security-domain> for authentication. Refer to my earlier XML example, where I showed you a <security-domain> with two <login-module> elements. You want to point your <security-realm> to that <security-domain>:

                       

                      <security-realm>
                           <authentication>
                                <jaas name="chainedLdap"/>
                           </authentication>
                      </security-realm>
                      

                      Now, when your security realm is queried for a user, it will immediately forward processing to the JAAS <security-domain>. As I described there, web application requests that reach this security-domain will try the first <login-module> (which you have ostensibly configured to point to your first LDAP server) and if that fails they will try the second <login-module> (which you have pointed to your second LDAP server). Note that the schema for security domains is ${jboss.home.dir}/docs/schema/jboss-as-security_1_2.xsd. This documentation is of limited use however, since the schema won't help you learn the available options for the login-module "code" attribute and the <module-option> elements that go with each individual code.

                       

                      On Realms versus Domains

                      I'm less certain I completely understand the design decisions and frameworks behind this distinction, but I'll do my best. As far as I can tell, <security-realm> is more intended for server infrastructure than web application development. The thing is, AFAIK you can't point a web application directly to a security REALM...only a security DOMAIN. That <realm-name> element in web.xml? That's only used for DIGEST hashing (I think). With Wildfly, you pair a web application with a <security-domain> by creating a jboss-web.xml file with a <security-domain> element. If you don't do that, Wildfly will automatically use the "other" <security-domain> that is defined in the default standalone.xml.

                       

                      I think you may be getting hung up on the "Realm" idea because it's how Tomcat functioned. My suspicion is that what you really want is the security domain I defined in the earlier post, a jboss-web.xml pointing to that security-domain, and optionally the realm with a <jaas> element that I defined above.

                      1 of 1 people found this helpful
                      • 8. Re: Migration from Tomcat Combined/JNDIRealm to Wildfly?
                        jessholle

                        As noted, this is again helpful.

                         

                        Now, however, I'm stuck with clearly incorrect log output from LdapExtLoginModule and no full classname for AdvancedLdapLoginModule.

                         

                        LdapExtLoginModule would seem to suffice for my needs -- if I can get it working.  My main interest in trying AdvancedLdapLoginModule at this point is that perhaps it actually provides correct and meaningful log output.

                        • 9. Re: Migration from Tomcat Combined/JNDIRealm to Wildfly?
                          scrublet

                          Something's weird, I didn't see all of your earlier post (or maybe you sent me a message and I didn't see it.) Anyways, obnoxious issue #1 - you can't find AdvancedLdap. AdvancedLdap is actually part of the jboss-negotiation project. It has to be added to your project's dependencies in order to be used. (Side note: I need to read the JAAS spec or something, my guess is that while the server defines the JAAS security-domains, they are instantiated and accessed within the scope of the application, not the server, so that's why you need this? Just a guess.)

                           

                          Try adding the following to your pom file:

                           

                          <dependencyManagement>
                               <dependencies>
                                   <dependency>
                                      <groupId>org.wildfly.bom</groupId>
                                      <artifactId>jboss-javaee-7.0-with-security</artifactId>
                                      <version>8.0.0.Final</version>
                                      <type>pom</type>
                                      <scope>import</scope>
                                   </dependency>
                               </dependencies>
                          </dependencyManagement>
                          
                          <dependencies>
                               <dependency>
                                   <groupId>org.jboss.security</groupId>
                                   <artifactId>jboss-negotiation-common</artifactId>
                                   <scope>provided</scope>
                               </dependency>
                               <dependency>
                                   <groupId>org.jboss.security</groupId>
                                   <artifactId>jboss-negotiation-extras</artifactId>
                                   <scope>provided</scope>
                               </dependency>
                          </dependencies>
                          
                          <build>
                               <plugins>
                                    <plugin>
                                         <artifactId>maven-war-plugin</artifactId>
                                         <version>2.4</version>
                                         <configuration>
                                              <archive>
                                                   <manifestEntries>
                                                        <Dependencies>org.jboss.security.negotiation</Dependencies>
                                                   </manifestEntries>
                                              </archive>
                                         </configuration>
                                    </plugin>
                               </plugins>
                          </build>
                          
                          

                          Adding all that should enable you to use AdvancedLdap as a "code" entry. After that, here's an example I've used:

                           

                          <login-module code="AdvancedLdap">
                               <module-option name="password-stacking" value="useFirstPass"/>
                               <module-option name="java.naming.provider.url" value="ldap://localhost:389"/>
                               <module-option name="bindAuthentication" value="simple"/>
                               <module-option name="allowEmptyPasswords" value="false"/>
                               <module-option name="bindDN" value="cn=manager"/>          <!-- I think this is wrong...you need the full path -->
                               <module-option name="bindCredential" value="manager"/>
                               <module-option name="baseCtxDN" value="ou=people,cn=AdministrativeLdap,cn=SomeCN,o=someOrg"/>
                               <module-option name="baseFilter" value="(CN={0})"/>
                               <module-option name="defaultRole" value="valid-user"/>     <!-- Edit: I just noticed this isn't a valid AdvancedLdap option. Probably will need to configure the roles, but let's get the authentication working first -->
                          </login-module>
                          
                          

                          Note that I think (but am not sure) that your bindDN is wrong. If your manager is in the same place as baseCtxDN, I think it will have to be the full thing (cn=manager,out=people,cn=Admin...). Of course, it looks like you DID succeed in binding "manager" on the second login-module so maybe I'm dead wrong. Your first login-module didn't fail because it didn't find wcadmin, for the record. It failed because it didn't find MANAGER...so maybe bindDN is allowed to be combined with baseCtxDN? The second login-module does succeed in binding manager, leading me to believe manager exists in AdministrativeLdap but not in EnterpriseLdap.

                           

                          Also note that my example uses CN instead of uid. Might be worth a shot.

                           

                          I've also gotten LdapExt to work in the past but I do prefer AdvancedLdap. Your logging is enabled as good as it gets. Also, you don't see a lack-of-an-entry type of error message so that someone couldn't fish for usernames by looking for that error message.

                          • 10. Re: Migration from Tomcat Combined/JNDIRealm to Wildfly?
                            jessholle

                            My issue turned out to be:

                            1. The logging and error reporting in LdapExtLoginModule is abysmal.
                            2. LdapExtLoginModule goes ahead and does a search for roles even if you don't provide it any of the configuration options it needs to do such a search, resulting in the entire authentication failing due to passing null parameters to the role search!

                             

                            Combining these 2 leads to a real headache.  I don't really want to do a role search.  I just want to specify a defaultRole and be done.

                             

                            In contrast, Tomcat JNDIRealm simply doesn't do a role search if the roleSearch criteria property isn't specified.  Much more sensible behavior.

                             

                            At any rate I have this working now -- but it's doing a pointless role search.