This page refers to JSPWiki 2.2 security model. In JSPWiki 2.4 and above we use the standard JAAS security model.

Please RefactorMe.

At the simple level the Container needs to be able to Authenticate you. It can be done in a number of ways. If you use the Simple Authentication method, the container will pop a window up with user and password fields that the user can use to Authenticate into the system

Another method is to build your own login. To some extent UserPreferences.jsp does that. It currently collects the username and uses that to identify the user. It would be easy for a site admin to change that form to:

     <form method="POST" action="j_security_check">
           <tr><td>Username: </td><td><input type="text" name="j_username"></td></tr>
           <tr><td>Password: </td><td><input type="password" name="j_password"></td></tr>
           <tr><td> </td><td><input type=submit value="Login"></td></tr>
Where the j_security_check is the container login method, it expects to get j_username and j_password to do the validation.

Other methods involve using NT style domains, LDAP, or custom Authentication systems.

Once validated, the Wiki uses context.request.remoteUser to get the user name, and can use isUserInRole to get the role name. Presently it checks the request first and then the cookie dropped by UserPreferences.

None of this is too hard to do. The issue is the Wiki software gets deployed to a number of different places, some with Authentication and Authorization, some without. This is the issue that most developers have, the deployment is all over the place. (Think of all the permutations of Operating Systems (and their releases) , Java (and 1.2, 1.3, 1.4), Application servers (and their release levels and Browsers (let's not forget compatibility with Netscape 4.7) So trying to simplify is always a good idea.

Granted that the page could use getAuthType() to see if the container was doing any Auth functions and decide what to do with the UserPreferences page makes it easy for you to build and post a "works everywhere" login. --FosterSchucker

This is how it works today, if there is information in remoteUser, JSPWiki uses that. Otherwise it uses the information that is in the cookie that is set by UserPreferences. --FosterSchucker
hmmm.... it doesn't check or use the principal.
Does it need the principal? -- FosterSchucker
I would like to see it check for userPrincipal first, then remoteUser. IMHO, it should never trust user-supplied cookies, but then, I am a security freak. --AndrewJaquith
At some point you probably want to take it int consideration. I know it's possible for remoteUser to be non-null while principal is still null. I assume this depends on your configuration, but if a user is authenticated against the web server, then a container may pass this on as remoteUser even if they haven't been authenticated against the J2EE container itself. That is, they are really not logged in so there is no principal or roles available. --ST

JSPWiki 2.2 (2.1 Alpha) Standard J2EE, Container Managed Security#

(I guess some of this stuff should be move onto the non-discussion page, but anyway it's a preface to questions I have below...)

Container Managed, Standard J2EE (Web only) Security Overview
J2EE offers a standard way of working with security, sometimes referred to as Container Managed Security. The container (Tomcat, JBoss, etc) handles user authentication so the application doesn't have to know how users and roles are maintained (LDAP, SQL, or some wiki editable database). And this could even be switched without changing the application. Standard APIs are then used to determine a users identity and role membership for programmatic J2EE security. Or for declarative J2EE security, one can specify security restraints in the web.xml file. In the case of JSPWiki, typically one would declare security for Edit.jsp and Delete.jsp, but leave Wiki.jsp open. Page authorization then depends on programmatic security (however this is currently is done without J2EE security APIs).

The auth-method : FORM vs. BASIC
There are different steps in the J2EE web authentication. The first is how to get the username and password. This is specified in the web.xml as the <auth-method>. This is either BASIC which uses a standard browser popup or FORM which uses a custom login page which contains HTML like:

    <form method="POST" action="j_security_check">
    <input type="text" name="j_username">
    <input type="password" name="j_password">
    <input type=submit value="Login">

Realms and Authenticators
After getting the username and password it must be authenticated against a particular Realm. A Realm is a database of users (usernames, passwords, groups/roles). Containers usually come with authenticators for many different Realms, LDAP, JDBC (SQL), XML, etc., as well as offer the option to write you own custom authenticator. For example, you could write one that used a Wiki editable database.

Users and Roles
Once the user is authenticated, the users identity or Principal is available from request.getUserPrincipal() The user name is available as request.getUserPrincipal().getName(). The username is also available as .remoteUser but it is possible for remoteUser() to return a value without the user authenticating against the J2EE container. Once he has, it should be the same value. It is possible for a user to be part of a group, or have a role. A user can have many roles, many users can have the same role. If the user has a role it can be checked by isUserInRole(roleToCheck). This makes it possible to have a very flexible system by being able to check users and or roles.

Roles vs. Groups. The J2EE APIs only exposes the concept of Roles. You may think of roles and groups as synonymous and depending on what container you are using they may be. I think of "groups" as how users are organized outside of J2EE in my user database, say LDAP, and roles as something within the application. Some containers then offer group<->role mapping. So that a J2EE role might map to one or more LDAP groups. This offers some nice flexibility, especially when using pre-existing groups within your organization.

Single Sign-On, Portals, etc
As long as all you webapps are using standard J2EE security, it's possible (depending on the container) to have single sign-on across the application on a single container (or cluster of the same). A new standard, JSR 168 Java Portlets, formalizes a solution to single sign-on and allows a parent application or Portal to be made up of a aggregation of separate webapps. So separate webapps can be used for Wiki, Calendar, Forum, News without having to deal with separate login for every application.

Issues with getting JSPWiki to work fully with Standard J2EE, Container Managed Security#

Active / Passive Authentication issues
Container Managed Security generally uses passive authentication. Instead of having a login available at anytime (like in the left menu), the container prompts the user for login (via BASIC or FORM method) when a secure resource is requested. So the question for this is how do you programmatically trigger the container login? is there some J2EE exception you can throw or what?

The login is triggered when the user attemps to access a protected resource and has not yet authenticated to the system. Which is why you can't call it directly. --FosterSchucker
sure, when you have declarative security (in web.xml). I was looking for a solution to problems like page authorization in JSPWiki. I am only hoping here, but I thought there might be a way to do this programmatically. Actually, the active authentication solution I linked to below might could be used for this, but I thought there might be a simple standard exception to throw to which the container would respond just like it had declarative security and ask for the login. So instead of just redirecting to LoginError, trigger a login the same as they went to page secured in the web.xml. Anyway, it sounds easy enough. I may keep looking for it if no one can else here already knows. --ST

Active-Passive Authentication#

It's not hard to force an authentication to take place, simply create a servlet or jsp called ActiveLogin.jsp. Add that jsp to a secure area of your web.xml. The only code in ActiveLogin.jsp is a scriptlet to
  1. Cache the user's login credential in the session so we can keep track (read on)
  2. Redirect the user to their 'referer' page

The normal problem: the UserPrincipal is only visible to the web app on pages that are within the 'secure area' of the app. Anytime you look at an insecure page the user becomes *null* The solution is as we did above, caching the user for reference in the session. Then anytime you need to know who the user is check first for the request.getUserPrincipal() then check for the cached one in the session. If they're both null then the user hasn't authenticated and you can throw them at the ActiveLogin.jsp and force them to sign in.

--Louis, 2008-03-13

Another set of problems arise when trying to get Active authentication working. That is providing a login to be used at anytime. To do this you would want to use FORM based login. But if you call the form directly or actively instead of letting the container do it, Tomcat will throw an error.

message: Invalid direct reference to form login page
description: The request sent by the client was syntactically incorrect 
             (Invalid direct reference to form login page).

I have found this article on a possible solution to Active authentication.

What you can do is have a protected page (Loggedin.jsp) and have your Login link point to that JSP. The user clicks the link, the container steps in, uses your login.jsp form to do the login and then calls the final destination (Loggedin.jsp). That page can do something or be a redirect back to a location in the Wiki or back to the page the user was looking at before they logged in. --FosterSchucker
What Foster said. :) This is a solved problem; the trick is to remember that you can only access the Login form indirectly. See my Clean Template for a solution. In my example, I have a Login button at the top of the page which links to a page called LoginRedirect.jsp. This is a protected resource defined in the web.xml file. When the user tries to access LoginRedirect (i.e., log in), the container forces the user to go to LoginForm, which is what actually collects credentials from the user. After authentication, the protected resource the user requested (LoginRedirect) is displayed, which instantly redirects to the Main page. The Logout link, but the way, is a JSP page with a scriptlet that contains session.invalidate(), and redirects to Main when it is done. By the way, the LoginForm I mentioned is a "top-level" JSP and does an include of /templates/clean/LoginTemplate.jsp, which means it is easily adaptable to other templates. Have a look. PS, Basic Authentication is vastly inferior to form login due to 1) the fact that the user's name and password travels in the header (unless digested, which is rare) and 2) the authentication persists until the user closes the browser. In contrast, forms provide instant gratification -- just hit logout, and you are indeed logged out. --Andrew Jaquith
that's a useful workaround but not "active" authentication. I am also just looking into what it takes to get all the JspWiki functionality working including the login form in the LeftMenu. --ST

This brings up other issues, such as if we implement active authentication for standard security do we deal with integration issues with existing non-standard JSPWiki security?

I'm missing the problem. If you turn on authorization in your container, and JSPWiki gets a user name when it calls remote.User then it's working.
I don't totally remember what I was thinking, but I was assuming active authentication with login form in the LeftMenu and a solution that could become a part the official JspWiki. I'd be adding some classes and changing some JSP. I could do this as just my own version or a way to integrate into the existing code.
I have released a JAASRealm implementation for Tomcat that would work with WikiPrincipal and associated classes, essentially allowing us to fuse J2EE container security with the JSPWiki Principal classes. So we would be able to use request.isUserInRole and request.getUserPrincipal. The next step is to write a WikiPrincipal adapter for it, now that the basic bits are done. --Andrew Jaquith

Groups / Roles
Since groups in JSPWiki aren't working yet, I haven't looked into this much. Although the current direction seems incompatible with standard J2EE roles. User identity happens to work since JSPWiki checks for remoteUser which the container sets if a user is logged in. But groups look very problematic. How could you, while implementing the JSPWiki interfaces, get to the standard APIs which depended on having something like a Request, for request.isUserInRole(). Also, is there even a way to implement getGroupsForPrincipal() with standard APIs?

Wiki is based on users, the hack that I put together for the Auth Plugin treats a role like it would a user. Janne will need to comment on how hard it would be to put roles in. --FosterSchucker
there is some code that mentions "groups", but I am looking at 2.1.86 which is relatively old. I really wish he was using standard J2EE APIs for accessing users/roles and then extending rather then re-inventing the wheel.


It was suggested that someone write an adapter for the J2EE authentication, however I don't think this is possible. I think the JSPWiki interfaces are incompatible with that approach. So that means either branching or having either/or cases (if using J2EE security check for user/role info this way, else use the JSPWiki way) in the code. Which sounds ugly. What is the best approach on this? Is JSPWiki deadset on using non-standard security? Or could we not use standard security and implement the desired wiki-editable user databases as a Realm/Authenticator plugin for container manager security?
Let me cut in and say someting. I think JSPWiki is attractively simple and active. I like it because I want to integrate it with other apps it is a great candidate with J2EE security and 2.0.x. Single sign-on is a big issue for integration. -Aron
See my comment above; my Tomcat JAASRealm implementation is essentially a "J2EE authentication adapter." The Tomcat part is just a very thin wrapper to a JAAS LoginModule, so it should not be hard to make this work with other containers. --AndrewJaquith

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-28) was last changed on 16-Jul-2009 15:02 by