How to setup Hudson with Subversion and mod_auth_sspi (NTLM)

This mini HOW-TO is for those who are in the urge of using a Subversion server behind a windows based Apache secured by mod_auth_sspi.

Since it this authentication scheme causes some trouble with Hudson (see hereand here) and I ran into the same trouble too here is my setup and solution to get mod_auth_sspi working with Hudson.

Setup

Suppose you have a similar environment for your Subversion. The Hudson part is irrelevant in this context.

  • Apache 2.2.9 running on a Windows 2008 Server (DAV/2 mod_ssl/2.2.9 OpenSSL0.9.8h SVN/1.5.5 mod_auth_sspi/1.0.4)
  • Subversion mounted to Apache 2.2.9 with webdav
  • Apache Authentication Module: mod_auth_sspi
  • Hudson (Release 1.300) on a different machine (Linux or Windows does not matter), served by Tomcat6 and Sun Java6

Synopsis

When you try to setup your project with Subversion then Hudson refuses to connect to the svn repository declared in your hudson job when the access to the repository is protected by mod_auth_sspi. You get this kind of exception from Hudson (lines wrapped for better readability):

org.tmatesoft.svn.core.SVNAuthenticationException: svn: Authentication failed
for http://geonosis/repos/projects/helloWorld/trunk/printHelloWorld
        at
org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:67)
[...]
Caused by: org.tmatesoft.svn.core.SVNAuthenticationException: svn: Authentication failed
for http://geonosis/repos/projects/helloWorld/trunk/printHelloWorld
        at
org.tmatesoft.svn.core.internal.wc.SVNErrorManager.authenticationFailed(SVNErrorManager.java:36)

Cause

My guess is that the mod_auth_sspi (NTLM) does not understand what the svnkit (Basic Authentication) of Hudson says to authenticate. (It is my assumption because I am not a Microsoft-Techie - I prefer open standards and sources.) The credentials you enter in Hudson do not make their way into the mod_auth_sspi. Side note: They get send from Hudson: you will see them when you disable ssl and sniff the packets on the wire.

In your Apache error.log you will see an empty user, even when you provided a user name in Hudson. Note the "user unknown" text in the end of the log entry:

[Thu May 29 09:13:33 2008] [error] [client 192.168.0.15] (OS 1326)Logon failure: unknown user name or
bad password.  : authentication failure for "/repos/projects/helloWorld/trunk/printHelloWorld": user unknown

Lets solve this...

Workaround/Solution

The idea is to enforce the mod_auth_sspi to offer Basic Authentication and to challenge Basic Authentication first and NTLM second. By default the mod_auth_sspi challenges NTLM first and does not offer Basic Authentication at all.

Locate your section for /svn in the httpd.conf (it should look like this):

<Location /svn>
  DAV svn
  SVNParentPath C:\repo
  AuthName "Subversion"
  AuthType SSPI
  SSPIAuth On
  SSPIAuthoritative On
  SSPIDomain yourWindowsDomain
  require valid-user
</Location>

Then add or change these two switches in the section to:

  SSPIOfferBasic On
  SSPIBasicPreferred On

See here for their meaning. Make sure to edit the httpd.conf as Administrator (Windows UAC is another PITA). Save the file. Restart the Apache service. Connect to Subversion via your Hudson job. Sm:)e.

Remarks

NTLM is awkward, if you can avoid it, don't use it! It may even be a security breach when your Apache with mod_auth_sspi serves the internet behind a proxy. If you (or your sysadmins) can't (or won't) bail out Microsoft products consider to use the mod_authnz_ldap from apache with Microsoft Active Directory, since the mod_auth_sspi discussed here seems to be discontinued by the developer(s) since 2006.

Labels:

Enter labels to add to this page:
Wait Image 
Looking for a label? Just start typing.
  1. May 28, 2011

    Daniel says:

    Hi @All! I am unable to establish a connection to a subversion repository&#...

    Hi @All!

    I am unable to establish a connection to a subversion repository! I am using Hudson 2.0.0 and need to connect to a repository. Therefore I enter my credentials, Hudson refuses to connect.

    I get the following Stacktrace, can someone guess why this does not work? Thanks in advance!
    FAILED: svn: OPTIONS of '/url: 403 Forbidden (https://url)

    org.tmatesoft.svn.core.SVNAuthenticationException: svn: OPTIONS of '/url': 403 Forbidden (https://url)
    at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:62)
    at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:51)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:624)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:275)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:263)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.exchangeCapabilities(DAVConnection.java:516)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.open(DAVConnection.java:98)
    at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.openConnection(DAVRepository.java:1001)
    at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.testConnection(DAVRepository.java:97)
    at hudson.scm.SubversionSCM$DescriptorImpl.postCredential(SubversionSCM.java:1754)
    at hudson.scm.SubversionSCM$DescriptorImpl.doPostCredential(SubversionSCM.java:1699)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:282)
    at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:149)
    at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:88)
    at org.kohsuke.stapler.MetaClass$1.doDispatch(MetaClass.java:102)
    at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:562)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:640)
    at org.kohsuke.stapler.MetaClass$7.doDispatch(MetaClass.java:242)
    at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:562)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:640)
    at org.kohsuke.stapler.MetaClass$7.doDispatch(MetaClass.java:242)
    at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:562)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:640)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:478)
    at org.kohsuke.stapler.Stapler.service(Stapler.java:160)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:45)
    at winstone.ServletConfiguration.execute(ServletConfiguration.java:249)
    at winstone.RequestDispatcher.forward(RequestDispatcher.java:335)
    at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:378)
    at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:94)
    at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:86)
    at winstone.FilterConfiguration.execute(FilterConfiguration.java:195)
    at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:368)
    at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:47)
    at winstone.FilterConfiguration.execute(FilterConfiguration.java:195)
    at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:368)
    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:84)
    at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:76)
    at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:164)
    at winstone.FilterConfiguration.execute(FilterConfiguration.java:195)
    at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:368)
    at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:81)
    at winstone.FilterConfiguration.execute(FilterConfiguration.java:195)
    at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:368)
    at winstone.RequestDispatcher.forward(RequestDispatcher.java:333)
    at winstone.RequestHandlerThread.processRequest(RequestHandlerThread.java:244)
    at winstone.RequestHandlerThread.run(RequestHandlerThread.java:150)
    at java.lang.Thread.run(Unknown Source)

  2. May 31, 2011

    Winston Prakash says:

    Daniel, could you send you issue to dev@hudson.java.net. You have better chance ...

    Daniel, could you send you issue to dev@hudson.java.net. You have better chance to get an answer there.