Features#

Security Overview#

JSPWiki contains a rich and flexible set of security features. This makes JSPWiki well-suited for stand-alone deployments or as part of a larger corporate intranet. However, although JSPWiki's security subsystem is highly customizable, the default settings should be enough to get you started. Here's a description of the main features.

Feature Description Default
Anonymity and Trust Users can be anonymous, partially-trusted (aka "asserted" using a persistent cookie), or authenticated Anonymous and asserted users can read and edit the wiki.
Identity Management Users register themselves with the wiki by creating a profile with a password. After logging in, users can manage their own profiles. Profiles store their login id, full name, wiki name, e-mail address and (optionally) a password. JSPWiki's API allows any compliant user database to be plugged in for identity storage, such as LDAP or relational databases. JSPWiki uses a flat XML file as its user database for storing user profiles; passwords are hashed using SHA-1. It can also store profiles in any database that pros that specify who can view, edit, or modify them. ACLs can contain user names, Wiki names, wiki groups or externally-authorized roles. If the ACL contains a wiki group or role, the user must be a member of the group, or possess the role. An API allows administrators to store ACLs externally, in a manner independent from the page content.
ACLs are stored inside the wiki page itself, using special wiki markup.
Groups Users can create on-the-fly groups of users with a simple wizard. These groups can be added to ACLs to restrict access to particular pages. An API allows administrators to configure where group membership information is stored, such as in flat files or databases. JSPWiki stores group membership information in an XML file as its group database.
Roles Users may possess special roles that are associated with their identities, such as the "Authenticated" or "Admin" role. These roles can be added to ACLs to restrict access to particular pages. JSPWiki administrators can configure the wiki to consult an external "authorizer" such as a web container or database to determine whether a user possesses the role. JSPWiki consults the J2EE web container using isInRole to determine role possession.
Enterprise Integration Security policies are expressed using the J2SE-standard security policy file syntax; the location of the policy file can be customized by administrators. Authentication is managed using the Java Authentication and Authorization Service (JAAS); the location of the login configuration can be customized. The wiki can use supplemental J2EE web container constraints to supply authentication credentials and to enforce authorization checks. Container-managed authentication and authorization allows administrators to connect into enterprise security instructure components such as LDAP, Single Sign-On, PAM, Kerberos and Active Directory. Pre-configured Java2 security policy and JAAS configuration files are supplied, and loaded at startup time if administrators have not overridden them with their own versions. JSPwiki does not use J2EE container-managed authentication and authorization by default.

Getting Started#

You should not need to do anything special to get started with JSPWiki security; simply deploy the JSPWiki WAR and load it into your favorite servlet container. By default:
  • the default login configuration and security policy is loaded automatically
  • anonymous users can edit pages and create user profiles
  • users log in with a login name and password
  • user identities are stored in an XML file inside WEB-INF
  • wiki groups are stored in an XML file inside WEB-INF
  • container-managed authentication and authorization is turned off

The default settings allow users to create profiles, create pages and groups, and create page ACLs.

If you want to experiment with these features yourself, start up the wiki webapp. Try creating a profile for yourself by clicking on "My Prefs". You'll see the new user identity appear in WEB-INF/userdatabase.xml. Then, verify that you are logged in by looking for the "G'Day" message on the left-hand side of the screen.

Create a new page and add some ACL markup to the top of the page restricting everyone but you from viewing it:

[{ALLOW view AndyJ}]

Log out and try to view the page; the wiki should deny your request, and redirect you to the login page.

Next, log in again and create a new wiki group. Make sure you add yourself to it (which it should do by default). Then create a new wiki page and add an ACL allowing the new group to read it. Log out and try to view the page you just created; you should be redirected to the login page again.

Take a look at the WEB-INF/jspwiki.policy file; its syntax should be reasonably intuitive. You can experiment a bit if you like: for example, try removing "edit" rights for anonymous users. The next time you start up the webapp, it should work.

For More Information#

The remainder of this document contains more details about JSPWiki's security system. Read on if you're curious.

Authentication#

JSPWiki supports multiple levels of authentication and trust. Users can be anonymous, have "asserted" identities using cookies, be authenticated, or be administrators:
Status Description Left Menu Shows..
Anonymous User not logged in, and has not supplied a cookie (nothing)
Asserted User's browser contains a cookie called JSPWikiAssertedName "G'Day, username (not logged in)"
Authenticated User logged in with a login id and password "G'Day, username (authenticated)"

Depending on the default security policy and page access controls in place, users may (or may not) be required to authenticate.

When a user decides to log in — or is challenged to do so by a page access control or security policy — he or she sees a standard web form with a username field and a masked password field. After receiving the submitted web form, JSPWiki attempts to log the user in via either of these methods:

  • Custom authentication, which looks up and validates the user's id and password against those stored in JSPWiki's UserDatabase
  • Container authentication, which relies on the servlet container to perform the authentication and supply credentials

JSPWiki is smart enough to detect which authentication method is in force. If certain <security-contraint> elements in web.xml are uncommented, container authentication is used. If not, JSPWiki uses custom authentication. In both cases, the user experience is identical.

Identity Management#

Creating Wiki Profiles#

Although some wikis are anonymous, many are not. Often, wikis give users the ability to create an identity for the website. JSPWiki includes a basic self-registration page that allows users to set up and manage their own wiki profiles.

To set up a wiki profile, users click on a link on the front page that opens the UserPreferences.jsp page; that is, the "My Prefs" link, then the "Profile" tab. By default, the form asks for:

  • A user ID
  • The user's desired "wiki name" (e.g., JanneJalkanen)
  • The user's full name (first and last name)
  • A password
  • E-mail address
If container-managed authentication is in force, the user ID will not be editable; the container will supply this value.

When the user saves the profile, JSPWiki checks to make sure that the new user id, wiki name and full name aren't already used by someone else. If so, the user is given the opportunity to choose different values.

User Profiles#

After a user creates a wiki profile, he or she may edit it at a later date via the My Prefs link on the front page. By default, users must be authenticated to edit their own profiles.

User Database#

When users save their profiles, they are persisted to a permanent storage area called a UserDatabase. By default, profiles are saved to an XML file called userdatabase.xml in the WEB-INF directory. Each user profile is a separate <user> entry. Passwords are hashed using SHA-1.

Starting with version 2.3.33, JSPWiki can also store profiles in any JDBC-compliant database. Like the XML user database, it plugs in transparently into the authentication subsystem. This means you can authenticate users and store profiles using a database. You can also share the user database with your web container, if that's what floats your boat.

Access Control#

JSPWiki is a wiki. Wikis foster openness and collaboration. By default, JSPWiki allows all users to view, create and edit all wiki pages. However, in many cases users will want to restrict access to particular pages. Access control lists, or ACLs, allow users to refine (usually, restrict) the privileges for particular pages. ACLs specify which users, Roles and wiki groups are allowed to perform particular actions.

Roles#

JSPWiki implements role-based security through the use of a class called a Role. Out of the box, JSPWiki defines four roles, which correspond to the user authentication status:
  • Anonymous
  • Asserted
  • Authenticated
  • All
The "All" role is special; it means "anybody, regardless of authentication status." The names are case-sensitive.

In addition to these built-in Roles, JSPWiki also recognizes Roles that are supplied by external authorizers such as the servlet container.

Wiki Groups#

Role-based security sounds terrific, but in practice it can be problematic for wikis. That's because traditional role-based access controls often assume that everything is configured by an administrator. This creates a support bottleneck, and a barrier to adoption.

To make role-based access controls more flexible, JSPWiki allows users to create wiki groups. These are special roles that users create themselves. Users create wiki groups by clicking on the front page link Create a new group. The JSP NewGroup.jsp opens. The user gives the group a name and enumerates its members. The "save" button creates a new wiki group that contains the membership list. By default, any member of the group can edit the membership list.

Roles and wiki groups (in conjunction with page access controls) are used to lock down a wiki. We discuss access controls next.

Access Control Lists#

Access control lists, or ACLs, allow users to refine (usually, reduce) the privileges for particular pages. An ACL is simply special wiki markup that defines who should be able to perform what actions on a particular page.
  • Who: User WikiNames or full names can be used; either will work just fine. Built-in Roles and wiki groups work, too.
  • What: Valid permissions include "view", "edit", "comment", "rename" and "delete".
The syntax is ALLOW permission userOrRole1, userOrRole2, userOrRole3, enclosed in [{ }] brackets.

For example, suppose you've just created a confidential page that only users Janne and Mike Morris should be able to view. Just add this to the top of the wiki page markup:

[{ALLOW view Janne,Mike Morris}]

This allows Janne and Mike to view the page, but nobody else can view it. Note that this particular ACL does not contain any "edit" privileges. If you wanted Janne to be able to edit the page as well, you would add this line:

[{ALLOW edit Janne}]

Access control lists can contain entries for roles and wiki groups. Suppose we wanted to broaden access to the wiki page so that all authenticated users could view the page, and all members of the wiki group "Managers" could edit it:

[{ALLOW view Janne,Mike Morris,Authenticated}]
[{ALLOW edit Janne,Managers}]

Roles, wiki groups and user/wiki names can sometimes have the same names. For security reasons, built-in Roles and container-defined Roles always take priority over wiki groups with the same name. Likewise, wiki groups override user names or wiki names. Thus, although it's technically possible to register a new user with the name "Authenticated", they won't magically receive access to everything that the role Authenticated is entitled to.

Note: there is no support for "deny" access control entries. That is a deliberate, philosophical design choice — it is far easier to deny by default than to worry about whether grants or denies take precedence.

By default, wiki pages do not have access control lists. When a page doesn't have an ACL, the default security policy for the page applies. We discuss security policy next.

Security Policies#

JSPWiki decides whether to allow an action by consulting two sources of information:
  • Page access control lists - per-page markup defining access restrictions (discussed in the previous section)
  • Security policy - a pre-defined set of privileges for each type of user
To make it easy for users to quickly get productive, JSPWiki ships with a fairly loose default policy out of the box:

Permission Anonymous users Asserted users (with cookie) Authenticated users Admin group
View all pages x x x x
Edit all pages x x x x
Upload attachments to all pages x x
Modify all pages (edit + upload) x x
Comment on all existing pages x x x x
Create new pages x x x x
Rename all pages x x
Delete all pages x
View all groups x x x
Edit all groups x x
Rename all groups x x
Delete all groups x
Create new groups x x
Create profile x x x x
Edit user preferences x x
Edit user profile x x

These privileges are the defaults. For page actions such as viewing, editing, and commenting, the privileges can be restricted further by adding an ACL to particular pages. It is important to note that ACLs cannot elevate privileges above those already granted by the policy. For example, if the policy states that Anonymous users can read all pages (but not edit), an ACL on page Main that attempts to grant the Edit privilege to Anonymous will not work.

JSPWiki uses the standard Java 2 security policy APIs under the covers. Default permissions are granted using standard security policy file syntax. When JSPWiki starts up, it loads the default policy file (stored in WEB-INF/jspwiki.policy).

JSPWiki's default policy is suitable for a small team. It is probably too loose for a corporate intranet or public wiki. See the next section, Modifying the Default Security Policy for details on how to tighten the policy, or for information on running JSPWiki with an existing security policy.

Customizing JSPWiki Security#

Modifying the Default Security Policy#

How the Security Policy Works#

JSPWiki's security policy system is based on Java 2 policy APIs. The default policy file, stored in WEB-INF/jspwiki.policy, expresses what the page permissions of the wiki should be when the user hasn't supplied a page ACL. The policy also governs what other non-page-related actions users are allowed to take, such as registering user profiles and creating groups.

The jspwiki.policy file is a standard Java policy file, so if you are familiar with the syntax it should be easy to understand. The default policy is aimed at a standard "workgroup wiki" use case. Policy blocks typically grant four main types of permissions, PagePermission, GroupPermission, WikiPermission and AllPermission to users having a particular Role:

  • PagePermission is a permitted action on a particular target page or set of pages: view, edit, modify, comment, rename, upload, delete. PagePermission supports wildcards
  • GroupPermission controls who can access or manage groups: view, edit, delete
  • WikiPermission is a permitted action on a particular target wiki: createGroups, createPages, login, editPreferences, editProfile
  • AllPermission grants all privileges for a given wiki. It is roughly analogous to the root privilege on Unix systems

The syntax, generally speaking, for WikiPermission, GroupPermission and PagePermission specifies the target followed by the actions allowed on that target. For WikiPermission, the target is the name of the wiki; this is the jspwiki.applicationName property in jspwiki.properties. For PagePermission, the target is the name of the wiki, plus a delimeter (colon), followed by the page name or page collection. GroupPermission works the same way. The action string, as noted above, is permission-specific.

You can grant the fourth type of permission, AllPermission, that confers administrative privileges on Principals who possess it. A user who has been granted AllPermission for a given wiki can do anything, and is not subjected to further permission checks, regardless of the ACLs that a page might possess. The AllPermission permission accepts a single target, which is the name of the wiki it applies to.

Security Policy Example#

Here's an example "grant" block from the default policy file.
grant signedBy "jspwiki", 
  principal org.apache.wiki.auth.authorize.Role "Anonymous" {
    permission org.apache.wiki.auth.permissions.PagePermission "*:*", "view";
    permission org.apache.wiki.auth.permissions.PagePermission "*:*", "modify";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "createPages";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "editPreferences";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "editProfile";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "login";
};

This policy block grants a fairly wide set of privileges to anonymous users. Users can view and edit any page that doesn't have an ACL, and can create new pages, edit preferences, log in and create profiles on all wikis. Note that because they possess the modify page permission, they can edit page text and upload attachments. We can customize this policy as needed. For example, let's cut this down a bit so that anonymous users can't edit existing pages or create new ones — we'd like them to create a profile first (and authenticate) before allowing them to do these things. Here's what the revised policy block would look like:

grant signedBy "jspwiki", 
  principal org.apache.wiki.auth.authorize.Role "Anonymous" {
    permission org.apache.wiki.auth.permissions.PagePermission "*:*", "view";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "editPreferences";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "editProfile";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "login";
};

But suppose even this isn't strict enough; perhaps users should only be able to read the front page, and nothing else. Here's a policy block that would accomplish that goal:

grant signedBy "jspwiki", 
  principal org.apache.wiki.auth.authorize.Role "Anonymous" {
    permission org.apache.wiki.auth.permissions.PagePermission "*:Main", "view";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "editPreferences";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "editProfile";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "login";
};

Let's make another change: we want to enable anonymous users to view the membership lists of all wiki groups. Normally this isn't a privilege that's enabled by default. But in this case, we will assume that group member information by itself isn't too sensitive. Here's the permission we would need to add: GroupPermission "*:*", "view". The amended block now looks like this:

grant signedBy "jspwiki", 
  principal org.apache.wiki.auth.authorize.Role "Anonymous" {
    permission org.apache.wiki.auth.permissions.PagePermission "*:Main", "view";
    permission org.apache.wiki.auth.permissions.GroupPermission "*:*", "view";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "editPreferences";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "editProfile";
    permission org.apache.wiki.auth.permissions.WikiPermission "*", "login";
};

Finally, let's create a wiki group called "Admin" and give this group administrative privileges aka Ultimate Power:

grant
  principal org.apache.wiki.auth.GroupPrincipal "Admin" {
    permission org.apache.wiki.auth.permissions.AllPermission "JSPWiki";
};

Any members of the Admin wiki group will be considered administrators the next time you start JSPWiki. Thus, any members listed in the wiki group Admin will be administrators. The Admin group's member list is empty by default; you must create it manually (or run the Install.jsp installer to enable it.

Note: the signedBy "jspwiki" section of the "grant" block ensures that calling code is signed and trusted. If you customize the default policy, we highly recommend that you include this statement in all "grant" blocks.
Note2: as of Version 2.8, the "signedBy" entry disappeared, no matter what security it provided

You can also check another example on how to configure your public JSPWiki instance for private use.

Wildcards#

The policy syntax for PagePermission accepts wildcards as a prefix or suffix to a page target. This keeps policy blocks nice and concise. For example, a page target of "Main*" applies to pages "MainPage", "MainStreet" and "MainWelcome". The wildcard "*" means all pages in the wiki. GroupPermissions use the same syntax: the wildcard means "all groups". Here are two wildcard examples:
permission org.apache.wiki.auth.permissions.PagePermission "*:Main*", "edit";
permission org.apache.wiki.auth.permissions.GroupPermission "*:*Test", "edit";
The PagePermission applies to all pages that start with "Main", in all wikis. The GroupPermission matches all groups that end with "Test", in all wikis.

Note that the wildcard (*) must either be the first character in the target, or the last one. Multiple wildcards (or a wildcard that is in the middle of a target string) aren't supported at this time. Thus, the page targets *UserPages* and Andy*Page are illegal.

WikiPermission and AllPermisson also accept the wildcard character as a target; their presence means, in essence, "all wikis".

Implied Permissions#

Certain permissions imply others:
  • The "rename" PagePermission implies "modify" (from v2.6 on, this is no longer the case (see http://www.ecyrd.com/JSPWiki/wiki/NewIn2.6)
  • The "modify" PagePermission implies "edit" and "upload"
  • The "edit" PagePermission implies "view" and "comment"
  • The "upload" PagePermission implies "view"
  • The "delete" PagePermission implies "edit"
  • The "createGroups" WikiPermission implies "createPages"
  • The "edit" GroupPermission implies "view"
  • The "delete" GroupPermission" implies "edit" and "view"
  • '"AllPermission" for a particular wiki implies all PagePermissions and WikiPermissions for that wiki

Specifying Principals in Policy Blocks#

As noted previously, each "grant" block in the policy file grants privileges to a particular role. The role is specified with the principal type "principalName" portion of the grant statement. The type can be any class that implements the java.security.Principal interface; for standard JSPWiki roles this Principal type is org.apache.wiki.auth.authorize.Role. The principal name can be any value that is returned by the Principal type's getName() method. In the case of Role, JSPWiki contains these standard names:
  • "Anonymous"
  • "Asserted"
  • "Authenticated"
  • "All"
Note: for roles, only built-in Role Principals (Anonymous, Asserted, Authenticated, All) are supported.

JSPWiki's security policy can grant privileges to wiki groups. In the policy file, specific wiki groups are identified using the Principal type GroupPrincipal. Thus, a wiki group called "SocialCommittee" corresponds to GroupPrincipal "SocialCommittee":

grant signedBy "jspwiki",
  principal org.apache.wiki.auth.GroupPrincipal "SocialCommittee" {
    permission org.apache.wiki.auth.permissions.PagePermission "*:Group*", "edit";
}; 

JSPWiki's security policy can also grant privileges to roles returned by an external Authorizer, such as your web container. In the policy file, external roles are identified using same Principal type as for the built-in roles: org.apache.wiki.auth.authorize.Role. Thus, a container role called "ContainerAdmin" corresponds to Role "ContainerAdmin":

grant signedBy "jspwiki",
  principal org.apache.wiki.auth.authorize.Role "ContainerAdmin" {
    permission org.apache.wiki.auth.permissions.AllPermission "JSPWiki";
}; 

You can, of course, also grant privileges to specific users if you wish. The principals named in the block should correspond to a user's wiki name, full name, or login name. For example, here is an example of a policy block that grants default edit privileges to the user named "Janne":

grant signedBy "jspwiki", 
  principal org.apache.wiki.auth.WikiPrincipal "Janne" {
    permission org.apache.wiki.auth.permissions.PagePermission "*:*", "edit";
};

We discourage specifying individual users in policy files. It is much better to specify roles (wiki groups, built-in roles or external roles) instead.

Implementing Custom Policies#

At startup time, JSPWiki looks to see if the user has previously specified a JVM-wide security policy by checking to see if the system property java.security.policy was set. In most cases, a custom security policy has not been loaded, so JSPWiki will load the default policy from WEB-INF/jspwiki.policy.

However, in some cases adminstrators would like to use their own Java security policies, or would like to customize the JSPWiiki default policy. In these cases, you should set 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, or whatever you've decided to call it. For example:

java -jar myservletcontainer.jar -Djava.security.policy=/etc/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"

In security-conscious environments you should store jspwiki.policy in a directory far away from JSPWiki, for example in $CATALINA_HOME/conf.

Note: JSPWiki defines custom security Permission classes. In order for the JVM to use these classes to make security policy decisions, the jspwiki.jar file is signed with a self-issued digital certificate with the alias jspwiki. The keystore jspwiki.jks that contains this certificate should be present in the same directory as the policy file, which by default is /WEB-INF. If you build JSPWiki from source, the Ant build script will offer to generate a certificate and keystore for you. If the JSPWiki security policy file cannot figure out how to find its associated keystore, JSPWiki will absolutely, positively stop working. Therefore, it is critical that the jspwiki.jks keystore be present in the same directory as your security policy file._

Customizing the Authentication Process#

How Authentication Works#

JSPWiki uses the Java Authentication and Authorization Service (JAAS) to log users in and out of the wiki. JAAS is conceptually very similar to PAM, which is a "stackable" authentication framework for Linux, Solaris and other operating systems.

Under the covers, JSPWiki tracks each user throughout its lifecycle using an object called a WikiSession. The WikiSession is analogous to (and associated with) the HttpSession. As the user progresses from anonymity to asserted status, then to authenticated status, the WikiSession object stays constant, but the series of credentials associated with his or her login status changes.

In particular, each user's WikiSession contains a standard J2SE Subject with a collection of Principals. The Principals can be one of four types:

  1. User Principals, which represent one or more user credentials, as supplied by the custom or container JAAS LoginModules
  2. Built-in Role Principals, which represents the logical Role objects "authenticated","anonymous", "asserted" and "all"
  3. External Role Principals, which represents the logical Role objects from an external Authorizer, such as the web container
  4. Group Principals, which represents the wiki groups the user belongs to

So, how do the Principals get there? Easy — JAAS. Recall that JSPWiki can use either container-managed auth, or its own custom authentication scheme. The default authentication "stack" works slightly differently in each case:

  1. Container-managed authentication. The WebContainerLoginModule first tries to "log in" by sniffing 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 (perhaps because the user hasn't had to log in yet), we manufacture a generic user Principal representing 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". If the other modules fail, the AnonymousLoginModule that runs last always succeeds.
  2. Custom Authentication. In this case, the UserDatabaseLoginModule takes data submitted on the login form (Login.jsp) and authenticates against the configured UserDatabase. The default database persists to an XML file. 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".

In both cases, the login process causes Principals to be injected into the user's Subject; these are the user Principals plus role and group Principals.

This process described is invisible to the user, and happens behind the scenes. What's important to remember is that WikiSession will always have a Subject containing some built-in roles that we can use for authorization purposes. Specifically, WikiSession's Subject will always possess at least one user Principal that represents the user's identity, plus at least two built-in Role Principals: "All" plus either "Anonymous", "Asserted" or "Authenticated". The Subject will also contain one GroupPrincipal object for each wiki group the user belongs to, and a Role object for each role the external Authorizer says the user possesses.

Customizing JSPWiki's JAAS Configuration#

These default login process should be quite sufficient. However, because JSPWiki uses JAAS, you can configure the login process however you like. Here's the default jspwiki.jaas file, loaded by default from the WEB-INF directory:
JSPWiki-container {
  org.apache.wiki.auth.login.WebContainerLoginModule    SUFFICIENT;
  org.apache.wiki.auth.login.CookieAssertionLoginModule SUFFICIENT;
  org.apache.wiki.auth.login.AnonymousLoginModule       SUFFICIENT;
};

JSPWiki-custom {
  org.apache.wiki.auth.login.UserDatabaseLoginModule    REQUIRED;
};

The first block (JSPWiki-Container) shows how the authentication process is invoked during WikiContext creation. If the user isn't authenticated already, the configuration tells JSPWiki to try the logging the user in using WebContainerLoginModule, CookieAssertionLoginModule, and AnonymousLoginModule, in order. The first module to succeed will be the one that populates the WikiSession's Subject with Principal credentials. Changing this block modifies the default behavior. For example, removing the CookieAssertionLoginModule prevents users from asserting their identities with browser cookies. You should not remove the AnonymousLoginModule line; this guarantees that unauthenticated sessions will posesss (at least) the "Anonymous" credential. Also, if you are using container-managed authentication, you should keep the WebContainerLoginModule line. (And even if you aren't, there's no harm in keeping it there because it will just no-op.)

The second block (JSP-custom) specifies that JSPWiki should use the UserDatabase for custom authentication. You can easily replace this with any JAAS LoginModule implementation, if you wish. For example, the Sun JDK ships with a Kerberos LoginModule and a native OS LoginModule (Unix JDK distributions use PAM; the Windows version uses the local SAM).

If you customize the JAAS configuration, you should save the new configuration in a separate file. You can (and should!) tell JSPWiki where this file is by setting the JVM system property java.security.auth.login.config to the absolute path of the file:

java -jar myservletcontainer.jar -Djava.security.auth.login.config==/etc/jspwiki.jaas

Similar to configuration of custom security policies, your web container may have a recommended way of setting the JAAS property at startup. Tomcat makes it very easy; just append the system property to CATALINA_OPTS:

export CATALINA_OPTS="-Djava.security.auth.login.config==/etc/jspwiki.jaas"

In security-conscious environments you should store jspwiki.jaas in a directory far away from JSPWiki, for example $CATALINA_HOME/conf.

Note: if your web container is running additional applications that use JAAS, you should append the contents of your revised jspwiki.jaas configuration into your existing JAAS configuration file.

Note for JBoss users: JBoss uses a special JAAS configuration file format. You should add the following (adjusted for your needs if necessary) to your server's login-config.xml file, which is by default in server/default/conf/login-config.xml:

    <application-policy name="JSPWiki-container">
      <authentication>
        <login-module code="org.apache.wiki.auth.login.WebContainerLoginModule"
          flag="sufficient"/>
        <login-module code="org.apache.wiki.auth.login.CookieAssertionLoginModule"
          flag="sufficient"/>
        <login-module code="org.apache.wiki.auth.login.AnonymousLoginModule"
          flag="sufficient"/>
      </authentication>
    </application-policy>

    <application-policy name="JSPWiki-custom">
      <authentication>
        <login-module code="org.apache.wiki.auth.login.UserDatabaseLoginModule"
          flag="required"/>
      </authentication>
    </application-policy>

Integrating JSPWiki with Container-Managed Authentication#

By default, JSPWiki logs in users via custom authentication. That is, it validates the username and password against those stored in the configured UserDatabase. However, many corporations prefer to use container-managed authentication. This allows JSPWiki to use credentials obtained from the web container realm. Depending on the container's realm configuration, this sharply expands the range of authentication mechanisms available to JSPWiki. Many containers support LDAP, database, Kerberos, SecurID, Shibboleth, SAML and NT domain controller authentication among others.

Configuring JSPWiki to rely on container-managed authentication is simple. First, configure your web container to use a security realm for the JSPWiki webapp. For example, in Tomcat, the <realm> element configures container-managed authentication for particular webapps (or for the container as a whole). Here's a sample MySQL realm configuration:

      <Realm  className="org.apache.catalina.realm.JDBCRealm"
             driverName="org.gjt.mm.mysql.Driver"
          connectionURL="jdbc:mysql://localhost/authority"
         connectionName="test" connectionPassword="test"
              userTable="users" userNameCol="user_name" userCredCol="user_pass"
          userRoleTable="user_roles" roleNameCol="role_name" />

Other containers (WebSphere, WebLogic, JBoss, et al) configure realms differently, but the principles are the same.

After configuring the security realm for the JSPWiki webapp, enable container authentication by uncommenting these <security-constraint> elements in WEB-INF/web.xml:

   <!--  REMOVE ME TO ENABLE CONTAINER-MANAGED AUTH
   
   <security-constraint>
       <web-resource-collection>
           <web-resource-name>Administrative Area</web-resource-name>
           <url-pattern>/Delete.jsp</url-pattern>
       </web-resource-collection>
       <auth-constraint>
           <role-name>Admin</role-name>
       </auth-constraint>
       <user-data-constraint>
           <transport-guarantee>CONFIDENTIAL</transport-guarantee>
       </user-data-constraint>
   </security-constraint>
      
   <security-constraint>
       <web-resource-collection>
           <web-resource-name>Authenticated area</web-resource-name>
           <url-pattern>/Edit.jsp</url-pattern>
           <url-pattern>/Comment.jsp</url-pattern>
           <url-pattern>/Login.jsp</url-pattern>
           <url-pattern>/NewGroup.jsp</url-pattern>
           <url-pattern>/Rename.jsp</url-pattern>
           <url-pattern>/Upload.jsp</url-pattern>
           <http-method>DELETE</http-method>
           <http-method>GET</http-method>
           <http-method>HEAD</http-method>
           <http-method>POST</http-method>
           <http-method>PUT</http-method>
       </web-resource-collection>

...

   <security-role>
       <description>
           This logical role includes all authenticated users
       </description>
       <role-name>Authenticated</role-name>
   </security-role>

   <security-role>
       <description>
           This logical role includes all administrative users
       </description>
       <role-name>Admin</role-name>
   </security-role>
   
   REMOVE ME TO ENABLE CONTAINER-MANAGED AUTH  -->

When JSPWiki starts up, it parses the JSPWiki's web application descriptor (WEB-INF/web.xml) and identifies whether certain constraints exist. Specifically, it checks to see if a logical role is required to access /Delete.jsp and Login.jsp. If you have uncommented the <security-constraint> block, this will be true, and JSPWiki will conclude that is should use container authentication instead of custom.

The default container-managed security constraints in web.xml will force users to log in when they try to edit a page, upload a file, comment on a page, create a new group, or edit their user profiles. This supplements, and is slightly stricter than, the default security policy. It should be sufficient for most corporate intranets and public wikis. You can tweak the constraints if you wish, although you must retain the constraint for Login.jsp for the "Log in" link on the menu bar to work correctly.

When using container authentication, the <role-name> values are significant and should match the role names retrieved by your web container's security realm. For the default configuration to work correctly, you should configure your container so that the roles of "Admin" and/or "Authenticated" are assigned approriately by the web container at login time.

For example, if you are using Tomcat's built-in "memory realm", you should edit the $CATALINA_HOME/conf/tomcat-users.xml file and add the desired actual user accounts. Each user must possess one or both of the Admin or Authenticated roles. For other realm types, consult your web container's documentation.

Alternatively, you could also replace all references to "Authenticated" and "Admin" with role names that match those returned by your container's security realm. JSPWiki doesn't care either way, as long as they match.

Note also that accessing protected resources will cause your container to try to use SSL to secure the web session. This, of course, assumes your web container (or web server) is configured with SSL support. If you do not wish to use SSL, remove the <user-data-constraint> elements.

Warning: when using container-managed authentication, 2.3.x versions of JSPWiki require (but do not enforce) that users accept cookies in their browsers. This is so the web container can properly set the JSESSSIONID session identifier cookie.

Customizing Identity Management#

JSPWiki uses something called a "user database" to store identity information about wiki members. The user's identify is stored in a user profile. User profile attributes include, for example, the user's login name, full name, wiki-name, and e-mail address. If JSPWiki's custom authentication scheme is used (instead of container-managed authentication), the user profile wll also contain the user's password. The login name, by the way, is the unique identifier that connects the container-managed identity with the JSPWiki identity.

Out of the box, JSPWiki uses a standard UserDatabase implementation org.apache.wiki.auth.user.XMLUserDatabase for loading and persisting user profiles. This implementation is good enough for workgroups and small-scale public wikis. By default, JSPWiki looks for a file called userdatabase.xml in WEB-INF/web.xml. You can (and should) specify a permanent location for this file by editing the jspwiki.xmlUserDatabaseFile property in jspwiki.properties. The location should be outside of the JSPWiki webapp directory, ideally in a place like /etc.

In addition to the default XML implementation, JSPWiki 2.3.33 and higher can store user profiles in relational databases. The implementation, logically enough, is called JDBCUserDatabase. Features of the JDBC user database:

  • JNDI-based DataSource lookups (suitable for container-managed connection pools; JSPWiki does not have access to the database passwords)
  • Support for all JDBC databases
  • Customizable table and column names
  • Exclusive use of prepared statements (i.e., it is immune to SQL injection attacks)
  • Sample JDBC user table creation scripts (McKoi and PostgreSQL now, MySQL planned...)

To use the JDBCUserDatabase, you need to specify the implementation class in jspwiki.properties:

jspwiki.userdatabase = org.apache.wiki.auth.user.JDBCUserDatabase
In addition, you need to configure several additional properties in jspwiki.properties to tell JSPWiki how to find the DataSouce (i.e., which JNDI name to look up) and which tables and column names it should use for finding and saving users. You should also install the JDBC driver for your database into the servlet container's classpath. For example, if you are using MySQL with Tomcat 4 or 5, copy the MySQL JDBC driver jar to the CATALINA_HOME/common/lib directory.

See the jspwiki.properties file and the Javadoc for org.apache.wiki.auth.user.JDBCUserDatabase for more details.

Detailed procedures for setting up container based authentication through LDAP are also available.

If either of these options don't work for you, you can write your own alternative implementation that relies on, for example, LDAP. The interface org.apache.wiki.user.UserDatabase defines standard methods for finding, loading and saving user profiles. If you use your own UserDatabase, you need to specify the implementation class in jspwiki.properties:

jspwiki.userdatabase = com.example.wiki.MyLDAPUserDatabase

Customizing the Authorization Process#

How Authorization Works#

Internally, the JSP authorization algorithm 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 possess Role "Anonymous", thus even these users can be subjected to authorization checks.

What constitutes a request for access? Any action requiring a Permission, such as a read, write, rename or delete operation on a page; user preference change; an attempt to create a profile; create, save or delete a wiki group; create a page, etc. Before executing the action, the calling JSP or Java code asks JSPWiki for authorization by calling AuthorizationManager's checkPermission method. As a parameter to this method, the calling code passes a Permission object that will either be a PagePermission (if it involves page-level operations) or a WikiPermission (for Wiki-level operations like creating a profile, or creating a group, or page).

The authorization process checks whether the Permission was granted to the Subject associated with the WikiSession. The Permission-checking algorithm works as follows:

  1. If the Subject's Principal set includes a GroupPrincipal, Role or user Principal that has been granted the AllPermission, the Permission is always allowed. By definition, administrators can do anything.
  2. For all permissions, check to see if the Permission is allowed according to the default security policy. If it isn't, deny the permission and halt further processing.
  3. For pages with ACLs, we retrieve the list of Principals assigned this permission in the ACL: these will be Principals representing a Role, wiki group or user. Then, we determine whether the Subject is considered to have any of these Roles or Principals. That process is as follows:
    1. If the Principal in the ACL is a built-in Role, the algorithm simply checks to see if the Subject possesses it in its Principal set
    2. If the Principal in the ACL is a Role but not built-in, the external Authorizer's isInRole method is called
    3. If the Principal in the ACL is a wiki Group, the algorithm checks to see if the Subject possesses the corresponding GroupPrincipal
    4. If the Principal in the ACL is a user, check whether the Subject possesses it in its Principal set
  4. Otherwise, deny the permission

In short, this algorithm provides a way to use built-in roles ("Authenticated", "All" etc) in 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, we can use those too.

As mentioned previously, ACLs cannot elevate privileges above those already granted by the policy. For example, if the policy states that Anonymous users can read all pages (but not edit), an ACL on page Main that attempts to grant the Edit privilege to Anonymous will not work.

Consulting External 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 Authorizer interface (org.apache.wiki.auth.Authorizer) provides a standard set of methods for querying an external authorizer. You can easily create your own implementation class that consults an RDBMS authorizer or LDAP. If you use your own Authorizer, you need to specify the implementation class in jspwiki.properties:

jspwiki.authorizer = com.example.wiki.MyRDBMSAuthorizer

JSPWiki's default Authorizer is org.apache.wiki.auth.authorize.WebContainerAuthorizer, which delegates to the web container via the HttpRequest's isUserInRole(String) method.

The GroupManager interface (org.apache.wiki.auth.authorize.GroupManager) extents Authorizer, and defines additional methods for loading, saving and querying group member lists. GroupManager works with a back-end GroupDatabase class that performs the back-end persistence. The default implementation (org.apache.wiki.auth.authorize.XMLGroupDatabase) reads and saves membership lists to an XML file called groupdatabase.xml, which is stored in WEB-INF. You are free to create your own GroupDatabase implementation. If you do, you need to specify the implementation class in jspwiki.properties:

jspwiki.groupdatabase = com.example.wiki.MyRDBMSGroupDatabase

What's the difference between and Authorizer and GroupManager/GroupDatabase? They perform similar functions, in the sense that they both authorize actions based on whether or not users possesses a particular roles. The difference is that GroupManager is explicitly designed for wiki group storage: in combination with GroupDatabase, it loads, saves and manages discretionary roles that users create themselves. An Authorizer, on the other hand, is generally a back-end service provided by infrastructure under control of IT administrators. The external Authorizer does not provide the ability to create new roles; only the ability to determine whether users are members of the ones that have already been defined. We wanted to keep the boundaries between these two authorization methods clear.

The benefit of this approach is that it provides a lot of flexibilty. For the default, out-of-the box configuration, it means we can use a GroupManager/GroupDatabase plus an external Authorizer that takes advantage of the web container's authorization APIs.


Category.Documentation