1

I need to integrate IBM Security Access Manger with Tomcat 9 to authenticate users. I have a properly configured Webseal (junction) for the IBM SAM part. It takes the user's credentials, authenticates again the SAM server, and then if successful redirects to Tomcat while passing the headers iv-user, iv-group, and iv-creds. I now need to write a custom Tomcat Valve to implement the authentication and allow access to apps based on the user's group. What would be the best way to go about doing this?

My current idea is to extend the org.apache.catalina.valves.AuthenticatorBase so that I can use the following setup in the web.xml of my application:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Application</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method>POST</http-method>
        <http-method>GET</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>MyRoleName</role-name>
    </auth-constraint>
</security-constraint>
<login-config>
    <auth-method>BASIC</auth-method>
</login-config>

The headers from the Webseal can be parsed and used to generate a org.apache.catalina.realm.GenericPrincipal and then used to authenticate into a role added to the given realm (or written into tomcat-users.xml).

I'm a bit shaky onto how to actually implement this authentication, so any help no matter how basic would be much appreciated.

willh99
  • 185
  • 1
  • 18

1 Answers1

2

The most important thing is to ensure that Tomcat doesn't install its own Authenticator in response to your specifying BASIC as the authentication scheme. Extending from AuthenticatorBase is a great idea, and you can avoid Tomcat's standard authenticator by configuring your authenticator as a in your application's META-INF/context.xml file.

Next, you'll be required to implement two methods on AuthenticatorBase:

  1. boolean doAuthenticate(Request request, HttpServletResponse response)
  2. String getAuthMethod()

The second one is easy: return whatever you want. You might want to make it make some kind of sense, like "IBMSAM".

The first one is where the meat of the authenticator lies, of course.

If you can get everything you need from the request, then that's great: it's already there, so you can get what you need. Your method needs to do two things:

  1. Set the principal of the request to an appropriate value (e.g. request.setUserPrincipal(new GenericPrincipal(username, null, roles));
  2. Return true

I think once you get it working with a straightforward situation, you'll be able to play-around with the edge-cases from there.

Christopher Schultz
  • 20,221
  • 9
  • 60
  • 77
  • Thanks! This definitely helps solidify the process in my mind. One quick question, IBM has a valve they built (which doesn't work for my version of Tomcat) which allows an `addRoles` and `enableStacktrace` functionality in the valve when placed in `server.xml`. Is this functionality that I could emulate by setting configurations in a `startInternal` method? – willh99 Dec 31 '18 at 14:43
  • 1
    I'm not entirely sure what you are asking. Maybe give a longer explanation in a new SO question. Or, join the Tomcat mailing list and you will likely get more focused attention. – Christopher Schultz Jan 02 '19 at 15:36
  • Sure I'll probably create a separate question if need be once I make some significant progress on these fundamental steps. – willh99 Jan 02 '19 at 17:05
  • So I've written up an authenticator, but it is causing my server to fail to start and I'm not sure why. I've posted the question to [here](https://stackoverflow.com/questions/54132227/tomcat-9-valve-causing-server-start-failure). I'm a bit stuck as to what to do from here – willh99 Jan 10 '19 at 16:40