This is version . It is not the current version, and thus it cannot be edited.
[Back to current version]   [Restore this version]

This page contains a quick overview of the AAA development for JSPWiki 2.3. There has been quite a bit of development done on it since January to merge the classic custom JSPWiki authorization scheme with web container authorization and standard Java 2 security. Here are the highlights. --Andrew Jaquith


Authentication#

The core concept is the WikiSession, an object that is stored in the user's HTTPSession. It contains a standard J2SE Subject with a collection of Principals. The Principals can be one of two types (more on how they get there in a minute).
  1. User Principals -- one or more, as supplied by the JAAS LoginModules
  2. Built-in Role Principals - represents the logical roles "admin", "authenticated",
"anonymous", "asserted" (user supplies a cookie saying who they are, but doesn't authenticate), and "all" (any of the preceding four)

So, how do the Principals get there? Easy--JAAS. Recall that JSPWiki can use either container-managed auth, or its own custom authentication scheme. Let's handle the container case first.

For container-managed auth, the WebContainerLoginModule tries to "sniff" the Principal from the HTTP request. If it's there, we use it and add that Principal and two Role Principals: ALL and AUTHENTICATED. If not, we try the RemoteUser property and manufacture a synthetic user Principal and the ALL and AUTHENTICATED Roles. If neither of these methods succeed, we manufacture a generic user Principal represeting an asserted user (if we can find a cookie using CookieAssertionLoginModule) or an anonymous user (if we cannot). The role principals in this case would be ALL (of course) and either ASSERTED or ANONYMOUS. The AnonymousLoginModule that runs last always succeeds.

The process I've just described happens automatically without user intervention. What's point to remember is that we will always have a populated WikiSession with a Subject containing some built-in roles that we can use for authorization purposes.

Let's go to the custom-auth scenario---we're not using container authentication, but JSPWiki's own authentication. In this case the UserDatabaseLoginModule takes data submitted on the login form (Login.jsp) and authenticates against the UserDatabase we've configured to use with JSPWiki. The default database persists to an XML file, but the interface is documented so you could use it with an RDBMS or LDAP if you wish. If the login suceeds, it replaces the Subject's Principal set with three user principals representing the user's login name, full name, and wiki name (for flexibility, so we don't need to be super-precise in ACLs). It also adds the built-in roles ALL and AUTHENTICATED.

The net result of the whole process is that we have at least one user Principal representing the user's identity, and at least two built-in role principals: ALL plus either ANONYMOUS, ASSERTED or AUTHENTICATED. (I'm glossing over some important stuff about how the ADMIN role gets populated, and about the anti-spoofing checks we need to do, but we can have that discussion later.) Because we're using JAAS for login, too, we can configure the login process however we like---although I think the defaults are pretty decent.

Authorization#

Authorization grants access based on 1) examination of the Principals the user possesses and 2) whether the user belongs to an external role or Wiki group. Recall that even "anonymous" users will still have the ANONYMOUS Role, so we can make decisions based on that.

What constitutes a request for access? A read, write, rename or delete operation on a page; attempt to self-register; create, save or delete a wiki group; create a page, etc. The calling JSP or Java code asks JSPWiki to authorize the action by calling AuthorizationManager.checkPermission(WikiContext, Permission). The Permission will either be a PagePermission (if it involves page-level operations) or a WikiPermission (for Wiki-level operations like registering a user, or creating a group, or page).

The authorization process works as follows:

  • If the Subject's principal set includes the Role principal that is the administrator
group, always allow the permission.
  • If there is no ACL at all, check to see if the Permission is allowed according
to the "static" security policy. The security policy (jspwiki.policy, see below) specifies what permissions are available by default
  • If there is an ACL, get the list of Principals assigned this permission in the
ACL: these will be Principals representing a role, arbitrary wiki group or user. Then determine whether the user (Subject) is considered to have any of these roles or principals. THAT process is as follows:
    • If the desired Principal is a built-in Role, the algorithm simply checks
to see if the Subject possesses it in its Principal set
    • If the desired Principal is a Role but not built-in, the external Authorizer's
isInRole method is called
    • If the desired principal is a wiki Group, the GroupManager's group authorizer
isInRole method is called
  • If the desired Principal is a user, check whether the Subject possesses it
in its Principal set
  • Otherwise, deny the permission

What this algorithm gives us is a way to use built-in roles (AUTHENTICATED, ALL etc) in our access checks, but also external groups (such as those provided by the web container) and ad-hoc, arbitary wiki groups. So, if you've got an external LDAP server wired up to your web container for authentication and authorization, you can use it! And if your users want to create their own wiki groups by creating a special Group* page, we can use that too.

Again, I'm glossing over some important details about name resolution, anti-spoofing and the like, but I think you can see how the overall authorization process works.

Security Policy#

Underpinning the authorization process is a standard Java 2 security policy (jspwiki.policy). The policy file gives us a way to express what the static page permissions of the wiki should be in the absence of page ACLs---these are the PagePermission grant statements. It also controls certain aspects of what a user can do for non-page operations---these are the WikiPermission grants. It's a standard Java policy file, so if you are familiar with the syntax it should be easy to understand. The PagePermission grant statements, in particular, support wildcards. I think the default policy is pretty decent---the defaults are aimed at a standard "internal wiki" use case.

One might think that an administrator could limit anonymous access by removing the "AnonymousLoginModule SUFFICIENT" line from jspwiki.jaas. That's a very good guess, but not quite correct. The right way to do it would be to edit jspwiki.policy and look for this grant entry:

grant signedBy "jspwiki" principal com.ecyrd.jspwiki.auth.authorize.Role
"Anonymous" {

You'd edit this line:

    permission com.ecyrd.jspwiki.auth.permissions.PagePermission "*", 
"view,comment";

...to reflect that users should be able to see the "Oops! You need to register!" wiki page, and probably a few others, but nothing else. That's something we will tweak as development on JSPWiki continues... feedback would be much appreciated.

Likewise, if you wanted to limit the capabilities of "asserted" users (as I would in a production environment), you could simply remove the block for asserted users, e.g.,:

grant signedBy "jspwiki" principal com.ecyrd.jspwiki.auth.authorize.Role
"Asserted" {...};

An important limitation (for the moment) in the security policy implementation is that the policy grammar (PagePermission/WikiPermission) doesn't yet support multiple wikis---you could get around this by having separate policy files per wiki if you wanted. This isn't as big of a limitation as you might think---the default policies for all wikis on a server are likely to be the same: i.e., anonymous users either can/cannot self-register, create new pages or groups, etc. So you will probably just need one policy file.

Groups and Authorizers#

Recall that the authorization algorithm checks for the presence of built-in role Principals or user Principals when making decisions. It also can make decisions based on wiki group membership or membership in a role as determined by an external Authorizer. The external authorizer has priority. The default Authorizer (WebContainerAuthorizer) delegates to the web container via the HttpRequest's isUserInRole(String) method. There's a documented interface, so you could easily add your own implementation such as an RDBMS authorizer. If you use your own Authorizer, you'd need to specify the implementation class in jspwiki.properties.

Group membership is much more ad hoc---these are groups that JSPWiki users create themselves. The default implementation reads membership lists from WikiPages with the prefix "Group." Janne and I have discussed doing this using other methods such as sub-pages, but for now they're just plain wiki pages. The wiki markup "" enumerates the members. Again, you are free to use your own GroupManager implementation.

Access Control Lists#

The Java security policy for JSPWiki applies to all pages that don't have an ACL.

But ACLs are often required to refine (usually, reduce) the privileges for particular pages. Here's the wiki markup syntax---it's just like earlier versions of JSPWiki:

[{ALLOW view Janne,Mike Morris}]

This allows Janne and Mike to view the page, but nobody else can view it. Note that if this was the *only* ACL entry for the page, only ADMIN would be able to edit it! Thus, I've implemented JSP logic so when pages are created, the ACL is "pre-populated" with the current user's name.

Note: there is no support for "deny" access control entries. That's a deliberate, philosophical choice---it's far easier to deny by default than to worry about whether the grants or denies take precedence. The code's much cleaner too. That said, there's nothing in the design that precludes "deny" ACL entries. The consensus we got during the requirements phase was that this was a wish-list item, but not critical for the next release.

Implementation#

At present, to use the new AAA scheme you need to specify the location of the JSPWiki security policy (jspwiki.policy) and JAAS login configuration file (jspwiki.jaas). Janne's recent e-mails were on this subject.

To make the security policy active, you will need to specify its location by setting the JVM system property 'java.security.policy' in the command line script you use to start your web container. The file location should be the absolute path to the jspwiki.policy file. For example:

java -jar myservletcontainer.jar -Djava.security.policy=/path-to/jspwiki.policy
Some servlet containers make this very easy by looking for an environment variable and automatically appending the contents to the 'java' command. For example, Tomcat users just need to set the CATALINA_OPTS variable:
export CATALINA_OPTS="-Djava.security.policy=/path-to/jspwiki.policy"

The system property for the JAAS login configuration works the same way, except the property is called "java.security.auth.login.config". In security-conscious environments you will probably want to store jspwiki.policy and jspwiki.jaas in the Tomcat config directory (CATALINA_HOME/conf).

Short-term development will likely focus on making the AAA configuration easier, so that a decent default policy & login configuration are loaded "by default" from WEB-INF... thus preserving the "it just works" quality of JSPWiki.

Add new attachment

Only authorized users are allowed to upload new attachments.
« This particular version was published on 19-Jul-2005 01:48 by 80.58.0.42.