Apache Tomcat 1.7 How to pass additional parameters to JAAS
Asked Answered
D

3

9

According to Apache Tomcat 1.7 documentation:

Write your own LoginModule, User and Role classes based on JAAS (see the JAAS Authentication Tutorial and the JAAS Login Module Developer's Guide) to be managed by the JAAS Login Context (javax.security.auth.login.LoginContext) When developing your LoginModule, note that JAASRealm's built-in CallbackHandler only recognizes the NameCallback and PasswordCallback at present.

It only supports NameCallback and PasswordCallback. I want to pass additional parameters to the JAAS login module but could not due to this restriction.

How do i pass additional paramaters to JAAS login module?

Dornick answered 9/8, 2015 at 12:58 Comment(11)
You define them in the jaas.config file along with the login module(s) and retrieve them during initialization.Lubricious
@EJP I'm using the default tomcat org.apache.catalina.realm.JAASRealm which i defined in the context.xml. This JAASRealm by default call its own callback handler. Even though i have custom callback handler defined, this won't get called by JAASRealm. How do i force this JAASRealm defined in my context.xml to use this custom callback handler?Dornick
Tomcat 1.7, sure? Or rather Tomcat 7, as indicated by the tags you used?Matrix
You seem to be confused here. The JAAS Realm calls login modules, and they call handlers. You're going to have to write your own login module, to call your handler.Lubricious
@EJP I think you've misunderstood me. Tomcat JAASRealm (org.apache.catalina.realm.JAASRealm) does not requires creation of LoginContext. FYI, LoginContext allows usage of custom callback handler. Since Tomcat JAASRealm does not requires that, it means it uses its own callback handler. That's the issue i'm having nowDornick
@EJP what's the solution here?Dornick
Why are those params necessary?Pedant
@Pedant User "abc" is registered as a customer in LDAP (e.g cn="abc", groupofnames="customer"). User "abc" and an parameter "customer" being sent to JAAS will authenticate successfully but should a parameter "contractor" being sent then authentication should fail since there is no user "abc" under groupofnames = "contractor" in LDAP. This third parameter needs to be passed along with user id & password to the JAAS login module else how would the LDAP knows if the query should look up groupofnames = "customers" or "contractors" for this userDornick
@Dornick You should rethink your directory structure. Our AD has > 500 000 accounts and principal + password is sufficient.Pedant
@Pedant I don't think you fully understand what my whole problem is. Anyway thanksDornick
@Dornick Were you able to figure it out? I am facing a similar problem with JAASRealms.Withdrawn
P
1

Write your own CallbackHandler. For details, see http://docs.oracle.com/javase/7/docs/technotes/guides/security/jaas/tutorials/GeneralAcnOnly.html

For example, a MyCallbackHandler could support an additional TextOutputCallback

public void handle(Callback[] callbacks)
  throws IOException, UnsupportedCallbackException {

  for (int i = 0; i < callbacks.length; i++) {
    if (callbacks[i] instanceof TextOutputCallback) {

      // display a message according to a specified type
      . . .

    } else if (callbacks[i] instanceof NameCallback) {

      // prompt the user for a username
      . . .

    } else if (callbacks[i] instanceof PasswordCallback) {

      // prompt the user for a password
      . . .

    } else {
        throw new UnsupportedCallbackException
         (callbacks[i], "Unrecognized Callback");
    }
  }
}
Prae answered 9/8, 2015 at 13:4 Comment(10)
I did exactly that but the default org.apache.catalina.realm.JAASRealm defined in the context.xml does not call that. It call other callback handler. How do i force this JAASRealm to call my custom callback handler?Dornick
Looking at the org.apache.catalina.realm.JAASRealm source code, I see that it always uses new JAASCallbackHandler() to pass the callback handler. I'm starting to think it's not possible to set a custom one with Tomcat's JAAS. In standalone applications, you would create a LoginContext with your handler: loginContext = new LoginContext("Sample", new MyCallbackHandler());Prae
So what's the solution here?Dornick
Let's go back one step and ask: why do you need an additional parameter? What's your use for it?Prae
I'm building a home advisor site where customer could login and request a service from contractor. A contractor could also login to register as a professional contractor. The actual authentication is in the JAAS login module. This user name will be checked using LDAP authentication. However LDAP authentication needs to know if this user name is a customer or a contractor. A customer username e.g. abcdef should login successfully as a customer but should fail if this is being used as a contractor user name. Additional parameter is needed to JAAS indicating customer or contractorDornick
If you're authenticating against LDAP, wouldn't JNDIRealm be better suited? Or the com.sun.security.auth.module.LdapLoginModule?Prae
JAAS login module is the recommended choice now for authentication. It is used to pass credential to LDAP for authenticationDornick
There are two other ways I can see at this point: 1. Figure out another way to discern if a user is a customer or contractor solely based on username (this info could be stored somewhere in your database, if it's not already). This way you would not need a third callback parameter. 2. Or you could write a custom Realm yourself, one that does a similar job like JAASRealm (maybe extend it, if possible). Then, this custom realm could use your custom MyCallbackHandler. This option seems a bit extreme, though...Prae
Issue here is there's a clear separation between JAAS module with the container layer where most of the request/servlet/context layer information resides. I do not want to spend time writing a custom Realm since that would throw me off from my actual business work. I don't see any other quick solutions except the one proposed by sibnickDornick
I still need a third parameter. Please see my comments which i responded to Michael-ODornick
M
1

The conventional way to approach this is to map your contractor and customer groups to roles.

  • Download a copy of the Servlet 3.0 Specification (Tomcat 7.0 is an implementation of this) and read the chapter on Security to see the multitude of options that are provided by the servlet container for authenticating users based upon username and password and then authorising users based upon their role.
  • Follow the instructions in the Tomcat documentation for configuring a JNDIRealm. This provides a way of configuring Tomcat to use an LDAP server for authentication (username/password) and authorisation (role checking).

Using the specification based approach like this has the added benefit of ensuring your solution is portable should you decide to migrate to a full blown Java EE solution (such as JBossAS/WildFly, Glassfish, WebSphere, etc) in the future.

Additionally, if you're able to migrate to Tomcat 8 you would have access to the additional authentication features that have been added in the Servlet 3.1 specification.

Masque answered 17/8, 2015 at 13:44 Comment(6)
What happen if a user has multiple roles? On the login screen using just username / password which role would that person be when he logins? Bear in mind different roles could present different authorization access to different pagesDornick
This solution permits multiple roles. It's up to you how this is managed. What should happen if a user is both a contractor and a customer?Masque
Yeap. Say user abc is both contractor and customr. Each role has its own access privileges to certain screens. At login screen abc login just using his id and password. Which roles would the server know? There's no way server side would know. Solution you need login screen with another field informing server user abc is now logging in as a contractor (as an example). Server then knows to assign contractor role to abc and give him access to screens related to contractor (not customers). See the picture now?Dornick
No. The whole point is that the server does know. For example at any time in a servlet you can test: if (httpServletRequest.isUserInRole("contractor")) { ... }Masque
I understand the javaee security model. Let's come back to basic. This user abc has customer & contractor role defined in LDAP. At login screen user abc login using abc/password. Which role should JAAS assign to this newly login abc? Your statement "isUserInRole" only happen after a role has been assigned and used for authorization to different resources.Dornick
A user can have any number of roles. After authentication they are deemed to be in every role to which they have been assignedMasque
G
-4

Simplest way: concat all parameters to one string, and split it later

Grubstake answered 9/8, 2015 at 15:5 Comment(1)
Yes. I thought of that even though it's really not a good one. I don't see any other solution. So surprise that such a simple problem cannot be addressed by TomcatDornick

© 2022 - 2024 — McMap. All rights reserved.