How to: Integrate Waffle in XWiki using Tomcat on Windows

How to: Integrate Waffle in XWiki using Tomcat on Windows

  1. Make sure to install the LDAP Authenticator extension (https://extensions.xwiki.org/xwiki/bin/view/Extension/LDAP/Authenticator/).

  2. Run the Tomcat service using a domain service account. You will need to set the service principal name (SPN) for the service account as noted in the Waffle documentation (waffle/Docs/faq/NegotiateFailsWith401.md at master · Waffle/waffle · GitHub). Make sure that the domain service account has permission to write to the temp, logs, work, etc. in the Tomcat installation directory.

  3. Download Waffle - GitHub - Waffle/waffle: Enable drop-in Windows Single Sign On for popular Java web servers. (version 1.9.0 is the latest as I write this)

  4. Copy the following files from the Waffle distribution into the Tomcat lib directory:

    caffeine-2.6.2.jar
    jcl-over-slf4j-1.7.25.jar
    jna-4.5.1.jar
    jna-platform-4.5.1.jar
    slf4j-api-1.7.25.jar
    slf4j-simple-1.7.25.jar
    waffle-jna-1.9.0.jar
    waffle-tomcat9-1.9.0.jar
    

    (If you’re not using Tomcat 9, copy the correct waffle-tomcat*-1.9.0.jar file for your Tomcat version.)

  5. For XWiki 10.8, add Valve and Realm tags in META-INF\context.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <Context containerSciFilter="org.apache.tomcat.websocket.server.WsSci|org.apache.jasper.servlet.JasperInitializer">
      <Valve className="waffle.apache.NegotiateAuthenticator" principalFormat="fqn" roleFormat="both" protocols="Negotiate,NTLM" />
      <Realm className="waffle.apache.WindowsRealm" />
      <JarScanner>
        <JarScanFilter defaultTldScan="false"/>
      </JarScanner>
    </Context>
    

    For XWiki versions older than 10.8, you’ll need to create a new context.xml file containing only the Valve and Realm tags:

    <?xml version="1.0" encoding="UTF-8"?>
    <Context>
      <Valve className="waffle.apache.NegotiateAuthenticator" principalFormat="fqn" roleFormat="both" protocols="Negotiate,NTLM" />
      <Realm className="waffle.apache.WindowsRealm" />
    </Context>
    
  6. Modify WEB-INF\web.xml to add the <security-constraint> and <security-role> restrictions you want. Place these settings before the first <filter> tag in the file; e.g.:

    <security-constraint>
      <web-resource-collection>
        <web-resource-name>XWiki</web-resource-name>
        <url-pattern>/*</url-pattern>
      </web-resource-collection>
      <auth-constraint>
        <role-name>FABRIKAM\XWiki Users</role-name>
      </auth-constraint>
    </security-constraint>
    <security-role>
      <role-name>FABRIKAM\XWiki Users</role-name>
    </security-role>
    

    This example prevents authentication to the web server unless the connecting user is a member of the XWiki Users group in the FABRIKAM domain.

  7. Modify WEB-INF\xwiki.cfg to use the LDAP Authenticator settings you want to use; e.g.:

    xwiki.authentication.authclass=org.xwiki.contrib.ldap.XWikiLDAPAuthServiceImpl
    xwiki.authentication.ldap=1
    xwiki.authentication.ldap.remoteUserParser=(.+)\\\\(.+)
    xwiki.authentication.ldap.remoteUserMapping.2=uid
    xwiki.authentication.ldap.server=fabdc1.fabrikam.com
    xwiki.authentication.ldap.port=389
    xwiki.authentication.ldap.base_DN=DC=fabrikam,DC=com
    xwiki.authentication.ldap.bind_DN=FABRIKAM\\LDAPAuth
    xwiki.authentication.ldap.bind_pass=LDAPAuthAccountPassword
    xwiki.authentication.ldap.UID_attr=sAMAccountName
    xwiki.authentication.ldap.fields_mapping=name=sAMAccountName,last_name=sn,first_name=givenName,fullname=displayName,email=mail,ldap_dn=dn
    

    This example searches the fabrikam.com domain using the specified LDAP auth username and password. Unfortunately, we have to hard-code the LDAP auth account password in xwiki.cfg because the LDAP Authenticator extension requires it. I would recommend restricting access to the WEB-INF directory permissions because of this. (In the future if the LDAP Authenticator extension is updated to be able to perform an LDAP server binding using current credentials, the xwiki.authentication.ldap.bind_DN and xwiki.authentication.ldap.bind_pass settings will not be needed.)

I have successfully set up restricted access using Windows domain authentication using this configuration. I can update this post in case I’ve forgotten any details.

I’m maybe a bit picky about this, but the update is not about “binding without using credentials”, but binding with reusing the container’s user credentials. Binding anonymously (i.e. without credentials) is already supported by the extension, if I read the code correctly, but Active Directory does not allow it.

Correct, that’s what I meant. I updated my post. (You can delete your post now to avoid confusion.)

Binding anonymously (i.e. without credentials) is already supported by the extension, if I read the code correctly, but Active Directory does not allow it.

Since we don’t mind being pedantic (LOL), Actually Active Directory doesn’t allow it by default. It can be configured to allow anonymous binding, but it’s not the default.

I tried to help you getting your point across, because you clearly said “A” while I knew, from your other threads, that you meant “B”. Anybody joining the discussion just now may not have gotten your point.
If you think that is “pedantic”, I’m fine with that, although I may have described it slightly different.

Correct. But let me ask you a question: Why didn’t you configure your active directory to allow anonymous bind, although it would solve your problem (no hard coded passwords), created a feature request for the LDAP Authenticator and currently use a bind DN and a hardcoded password instead?

My guess: Maybe because changing the default and allow anonymous bind, while theoretically possible, is just not a good idea?

But to make our pedantic souls happy :wink: I revise my statement:

but Active Directory does not allow almost never allows it. [Assuming production installation, and not some dodgy lab installation].

Almost forgot the most important: I rest my case.

It’s always enjoyable to interact with someone in a forum who is always right and insists on the last word in every thread :wink:

Why didn’t you configure your active directory to allow anonymous bind, although it would solve your problem (no hard coded passwords)

Yes that would solve the problem and you’re right, it’s not a good idea security-wise.

but Active Directory almost never allows it

Again, I would reword this as “Active Directory doesn’t allow anonymous binding by default” or “most Active Directory instances are not going to allow anonymous bindings.”

I rest my case too. :smile:

Just wondered if I could get some help setting up SSO, I’ve followed your configuration steps above but it doesn’t seem to work for me. I’ve enabled debug logging for LDAP and i’m seeing these trace logs. Any ideas?

2018-10-04 10:34:57,568 [http://server/xwiki/bin/skin/resources/icons/xwiki/noavatar.png] TRACE x.c.l.XWikiLDAPAuthServiceImpl - Starting LDAP authentication
2018-10-04 10:34:57,568 [http://server/xwiki/bin/skin/resources/icons/xwiki/noavatar.png] DEBUG x.c.l.XWikiLDAPAuthServiceImpl - The provided user is null. We don’t try to authenticate, it probably means the user is in non logged mode.
2018-10-04 10:34:57,568 [http://server/xwiki/bin/skin/resources/icons/xwiki/noavatar.png] DEBUG x.c.l.XWikiLDAPAuthServiceImpl - XWikiUser: null
2018-10-04 10:34:57,575 [http://server/xwiki/bin/skin/skins/flamingo/print.css?skin=XWiki.DefaultSkin] TRACE x.c.l.XWikiLDAPAuthServiceImpl - Starting LDAP authentication
2018-10-04 10:34:57,575 [http://server/xwiki/bin/skin/skins/flamingo/print.css?skin=XWiki.DefaultSkin] DEBUG x.c.l.XWikiLDAPAuthServiceImpl - The provided user is null. We don’t try to authenticate, it probably means the user is in non logged mode.
2018-10-04 10:34:57,575 [http://server/xwiki/bin/skin/skins/flamingo/print.css?skin=XWiki.DefaultSkin] DEBUG x.c.l.XWikiLDAPAuthServiceImpl - XWikiUser: null

Sorry; can’t reproduce. It’s working for me here.

I would recommend testing Waffle in Tomcat using the demo web apps included in the Waffle download. They’re pretty helpful.

Thank you for posting this guide! Right now in our deployment we want our webserver logs to capture Active Directory account information in addition to IP address (but we do not want to have XWiki accounts pull from Active Directory). I spent a couple months trying to evaluate the numerous options of integrating Windows authentication. I was unsuccessful in setting up Waffle and all of the solutions which involved Tomcat integration. The only successful solution I was able to implement was to use IIS as a reverse proxy and handle Windows authentication in IIS.

@nha4601
How did you get this to work with reverse proxy?
We’re trying to do the same thing with IIS, but it isn’t passing through the credentials correctly into XWiki.

Tomcat / XWiki isn’t aware of the Active Directory user when using an http reverse proxy. Right now we have separate accounts within XWiki. The main goal behind us using IIS as a reverse proxy was to have the server logs (now in IIS) reflect the Active Directory account for each user request.

We did get a IIS reverse proxy using ISAPI redirector / AJP working which passed the Active Directory user information to Tomcat; however, users with a lot of credentials (OUs) experienced the “request entity too large error”. Increasing the packet size did not solve the issue. We therefore pivoted to using an http reverse proxy instead of ISAPI / AJP.

I am wondering why you need the AD account in the IIS server logs? (Just curious)

Our compliance office wanted to be able to log all activity by user. Without the AD account information we would only have IP addresses, which would have to be resolved to machines, then to users.

You could use the information in the audit logs and not have to worry about IIS. (Just a suggestion.)

@bstewart

This is working great, but I have a few questions.

  • Have you been able to get your photos from Active Directory to sync with XWiki when using this configuration? (I tried the

xwiki.authentication.ldap.update_user=1
xwiki.authentication.ldap.update_photo=1
xwiki.authentication.ldap.photo_attribute=thumbnailPhoto

) settings, but the photos don’t sync.

  • Is it possible to logon with a local account when we have waffle integration enabled?

Thanks!

This is working great, but I have a few questions.

Glad it’s working!

Have you been able to get your photos from Active Directory to sync with XWiki when using this configuration? (I tried the

xwiki.authentication.ldap.update_user=1
xwiki.authentication.ldap.update_photo=1
xwiki.authentication.ldap.photo_attribute=thumbnailPhoto

) settings, but the photos don’t sync.

I’ve never tried (we don’t use that attribute).

Is it possible to logon with a local account when we have waffle integration enabled?

The short/simple answer is no, but I don’t think you need to?

My recommendation is to sync an AD group to the XWiki.XWikiAdminGroup group in XWiki; e.g.:

xwiki.authentication.ldap.group_mapping=\
  XWiki.XWikiAdminGroup=CN=XWiki Admins,OU=XWiki,DC=fabrikam,DC=com|\
  ...

Start your browser as member of that group, and you are an administrator in XWiki.

HTH,

Bill

Thanks, @bstewart!
I’ll open a separate discussion for the LDAP Properties and add the LDAP Group Mapping that you recommended.

@nha4601 wrote:

Our compliance office wanted to be able to log all activity by user. Without the AD account information we would only have IP addresses, which would have to be resolved to machines, then to users.

I just wanted to mention something I forgot to mention before - when integrating Waffle into XWiki on Windows using Tomcat, the Tomcat access log lists the domain username that accesses each page.