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.
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
:boolean doAuthenticate(Request request, HttpServletResponse response)
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:principal
of the request to an appropriate value (e.g.request.setUserPrincipal(new GenericPrincipal(username, null, roles));
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.