1

I have some questions about LDAP (ActiveDirectory) and an existing Java EE Application.

In our Java EE Application we have an mix in our permission handling. So sometimes we ask isUserInRole("rolename") and sometimes we ask hasUserPermission("permission).

Now, we want to bind this existing application to an LDAP, and I have no clue how a LDAP works ;-) So I have a few questions:

  1. Can a LDAP only works withs groups, or also with permissions?
  2. Where do I store the permissions? in LDAP or in my application database
  3. where do i the mapping between groups and permissions? (ldap or application)
  4. Do I need to use JAAS when using LDAP with my Java EE Application?

I hope you can help me with these hopefully simple questions!

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
mananana
  • 393
  • 3
  • 15
  • There are two ways in which I could interpret your first question: a) *"by what means can an LDAP-compliant directory **itself** perform access control, i.e., how can it restrict unauthorized operations from being performed on its **own** data?"*, and b) *"can Java EE solely authorize a caller based on its groups (when stored in an LDAP-compliant directory), or also based on its permissions?"*. Given the context you probably mean (b) but I believe it's not clear enough. – Uux Apr 18 '16 at 11:45
  • Also, what's a *permission* in your use case? A mere `String`? A `java.security.Permission`? Something else? And how is `hasUserPermission(String) implemented? Does it interact with the Java EE security model? – Uux Apr 18 '16 at 11:46
  • Sorry, for being unspecific. 1. How should a JEE app restrict users for doing some things with the help of a LDAP? 2. permission is a String, no it doesn't interact with the Java Security model – mananana Apr 18 '16 at 12:49

1 Answers1

2

Note: Wherever the term LDAP is used below, an LDAP-compliant directory service is what is actually being referred to.

1. How should a JEE app restrict users for doing some things with the help of a LDAP?

The Java EE security model remains, with respect to authorization, (predominantly) role-based (not to be confused with RBAC); at the end of the day the runtime will still authorize your users (callers in general) based on their application-level roles, regardless of where (LDAP, relational DB, SAML IdP, XML file, whatever) and how (i.e., as which SQL types, LDAP attribute types, etc.) those are persisted. In fact, some applications may not externally store their callers' role memberships at all, but calculate them during authentication instead, based on other attributes of the respective caller; an authentication mechanism might, as a contrived example, "see" that caller uid=jdoe, dc=users, dc=some, dc=org has a hireDate attribute that refers to a date more than 3 years in the past, and a jobTitle attribute of developer, thereby inferring that jdoe is a senior developer, assigning that as an actual role.

2. Where do I store the permissions? in LDAP or in my application database?
3. where do i the mapping between groups and permissions? (ldap or application)

First of all, your notion of a permission is not a good fit for the Java EE security model, thus my suggestion would be to drop permissions altogether and use corresponding roles directly. The benefit of doing so should be obvious: you can move from programmatic to purely declarative authorization, as the runtime would now be enabled to handle all authorization checks for you. Note that you are in no way mandated to think of roles solely as an equivalent to user groups; while they can indeed express something as coarse-grained as "editor" and "can-view-stats-panel", they can also express something as fine-grained as "can-access-method-void-getBonus(BigDecimal)-of-instance-123-of-EJB-BonusGranter-with-arg-not-greater-than-100$-during-working-hours-every-13th-of-every-January-between-08:00:10Z-and-08:01:09Z-if-hardworking-and-weather's-sunny-and-manager's-in-a-good-mood" (you would obviously have to come up with a good convention to be able to express all that both compactly and intuitively, but you get the idea).

There is also a spec called JACC which your Java EE product may or may not support. If you absolutely require more flexibility than what roles can offer, you could theoretically take advantage of it, as it essentially would allow you to use the Java SE Policy in order to determine--on the basis of Principal-assigned low-level, seemingly infinitely flexible java.security.Permissions--whether a caller indeed has a role. Regardless, the goal remains the same: separation of authorization-related code from business logic.

As for your actual two questions--and that should not only hold true for your permissions (if you wish to retain them), but for most of your persistent data--my simplistic answer would be that if the data in question is needed (or the probability of it being depended on in the foreseeable future is high) by other applications, and it can "fit" into a directory information tree (not necessarily the case), then it may be stored in LDAP. Otherwise, it should be stored "closer" to the application, e.g. in the application's "dedicated" DB, as you suggested. Also keep in mind that, at least traditionally, LDAP is (was) considered to be a poor choice of repository for storage of data with a low read-to-write ratio. I do not know to what extent--if at all--that performance consideration remains valid at present, but I would still not use LDAP for persisting highly dynamic data, like a web service's response time or availability percentage.

4. Do I need to use JAAS when using LDAP with my Java EE Application?

You do and should not have to (directly) rely on JAAS either for authentication or authorization in Java EE. The subject has been extensively discussed elsewhere, hence I will not elaborate it here. In order to leverage container-managed authorization, as addressed earlier, you still have to use container-managed authentication, the main purpose of which is to establish the identity (caller and group (role) Principals) of your callers with the runtime. Now, ideally you would just declare something like the following

<login-config>
    <auth-method>FORM</auth-method>
    <LDAP-identity-store>
        <base-DN>dc=users, dc=some, dc=org</base-DN>
        <bind-DN>uid=admin</bind-DN>
        <bind-credential>
            <credential-alias ref="admin_LDAP_pass"/>
        </bind-credential>
        <base-search-DN>dc=users, dc=some, dc=org</base-search-DN>
        <search-filter>(uid={username_HTTP_param})</search-filter>
    </LDAP-identity-store>
</login-config>

in your web.xml and authentication would just work. Unfortunately that is not the case for Java EE (at least as of version 7, as some much-promising changes in this area are expected to be included in the platform's next release). Assuming that you still want to use container-managed authentication, you have two options:

a) Author a portable authentication mechanism using JASPIC. Your javax.security.auth.message.module.ServerAuthModule would basically:

  1. connect to and authenticate your caller (i.e. its form-POSTed username) against the LDAP, and if successful,
  2. retrieve (and/or compute) the caller's roles (called groups at that point),
  3. instantiate a Principal representation of the authenticated caller,
  4. instantiate a String[] of group names (off of which the runtime will construct corresponding group Principals), and finally
  5. communicate the outcome of the previous two steps to the runtime via JASPIC-specific javax.security.Callbacks.

Advantages: Supported on all Full Java EE Profile implementations as well as on Jetty and Tomcat (since 9.0.0.M4).
Drawbacks: Requires a bit of effort and is not always optimally supported.

b) Author a vendor-specific authentication extension, JAAS-based or otherwise, essentially completing the same steps, although via proprietary APIs.

Advantages: Often zero new code (and certainly less boilerplate) needs to be written.
Drawbacks: Non-portable approach.


Further reading:
Community
  • 1
  • 1
Uux
  • 1,218
  • 1
  • 10
  • 21
  • 1
    Thx for the very detailed answer! Look's like a hard way for me, to migrate from a custom (self-written) authentication/authorization mechanism to a standard one... – mananana Apr 20 '16 at 09:28
  • @mananana I don't think Java EE security per se is hard--at least not as hard as familiarizing oneself with LDAP can be, imho. Migration can of course be time-consuming. I only suggested staying with "native" Java EE authZ because it sounded as if you were already using it to some degree (you mentioned (`HttpServletRequest`#)`isUserInRole(String)`), which means you're using container-managed authN too, even if only indirectly. If that's not the case then I got it all wrong from the very beginning, and transitioning from fully "homegrown" to "native" is indeed likely to be overkill. – Uux Apr 20 '16 at 10:27