blob: d60f1f853f50a1820647c952718729ae99db19e0 [file] [log] [blame]
This page contains a quick overview of the AAA development for JSPWiki 2.3. The new system has been in development since January 2005, and is nearly stable in the current 2.3.x branches. The goal of the new security system was to merge the classic custom JSPWiki authorization scheme with web container authorization and standard Java 2 security. __This page applies to JSPWiki versions 2.3.28 and higher__.
This guide should give you a good idea of how to use JSPWiki's security features. In addition to this page, see also:
* [JSPWiki:Authorization And Authentication 2.3 FAQ], which contains questions and answers to common problems
* [JSPWiki:PluginsAndAuthorization2.3], which points out some areas where we could stand to make further improvements :)
''Note: the security policy syntax has changed since the initial 2.3 builds. If you're using a custom security policy and have recently upgraded to 2.3.21 or higher, please see the __Modifying the Default Security Policy__ section below.''
[{TableOfContents}]
!!!Features
!!Security Overview
JSPWiki 2.3 and higher contain 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.
|| Feeature || 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. 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.
| Authentication | The wiki can authenticate users against its own user database with the user's password, or can accept authenticated credentials from the J2EE container. | JSPWiki authenticates users against its own database ("custom authentication").
| Security Policy | The wiki's security policy enforces what actions users are allowed to perform. For example, the policy can control whether anonymous, asserted and authenticated users can read, edit, rename and delete pages; self-register; manage their profiles; or create new pages and wiki groups. The policy can be overridden on a page-by-page basis using access control liists (ACLs). | JSPWiki's default security policy grants wide privileges to most classes of users.
| Access Controls Lists | Authors can add ACLs to wiki pages that specify who can view, edit, or modify them. ACLs can contain user names, wilk 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 special wiki pages prefixed with "Group."
| 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 self-register
* users log in with a login name and password
* user identities are stored in an XML file inside WEB-INF
* container-managed authentication and authorization is turned off
The default settings allow users to register themselves, create pages and groups, and create page ACLs.
If you want to experiment with these features yourself, start up the wiki webapp. Try registering yourself as a new user. You'll see new user identity appear in {{WEB-INF/userdatabase.xml}}. Then, click on "Edit your profile" to view your identity information (for example, your wiki name might be ''AndyJ'').
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 | "You are anonymous"
| 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)"
| Admin | User logged in with a login id and password, ''and'' this id has been pre-designated as the Admin user | "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
!!Self-Registration
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 {{Register.jsp}} page. 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 is registered, he or she may edit the wiki profile at a later date via the {{Edit your profile}} 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.
!!!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 five roles, which correspond to the user authentication status:
* Anonymous
* Asserted
* Authenticated
* Admin
* All
The "All" role is special; it means "anybody, regardless of authentication status."
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 a 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 page with the prefix "Group" that contains the membership list. By defaut, any member listed in the group member list can edit the group.
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 || Administrator
| View all pages | x | x | x | x
| Edit all pages | x | x | x | x
| Upload attachments to all pages | x | x | 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
| Delete all groups | | | | x
| Create new groups | | | x | x
| Register as new user | x | x | x | x
| Edit user preferences | | | 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 two types of permissions, PagePermission and WikiPermission to users having a particular Role:
* __PagePermission__ is a permitted action on a particular target page or set of pages: {{view}}, {{edit}}, {{comment}}, {{rename}}, {{upload}}, {{delete}}. PagePermission supports wildcards.
* __WikiPermission__ is a permitted action on a particular target wiki: {{createPages}}, {{createGroups}}, {{registerUser}}, {{editPreferences}}
The syntax, generally speaking, for WikiPermissions and PagePermissions 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. The action string, as noted above, is permission-specific.
Here's an example "grant" block from the default policy file.
{{{grant signedBy "jspwiki"
principal com.ecyrd.jspwiki.auth.authorize.Role "Anonymous" {
permission com.ecyrd.jspwiki.auth.permissions.PagePermission "*:*", "view";
permission com.ecyrd.jspwiki.auth.permissions.PagePermission "*:*", "edit";
permission com.ecyrd.jspwiki.auth.permissions.WikiPermission "*", "createPages";
permission com.ecyrd.jspwiki.auth.permissions.WikiPermission "*", "registerUser";
};}}}
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 and self-register on all wikis. But this policy can be customized 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 register first (and authenticate) before allowing them to do these things. Here's what the revised policy block would look like:
{{{grant signedBy "jspwiki"
principal com.ecyrd.jspwiki.auth.authorize.Role "Anonymous" {
permission com.ecyrd.jspwiki.auth.permissions.PagePermission "*:*", "view";
permission com.ecyrd.jspwiki.auth.permissions.WikiPermission "*", "registerUser";
};}}}
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 com.ecyrd.jspwiki.auth.authorize.Role "Anonymous" {
permission com.ecyrd.jspwiki.auth.permissions.PagePermission "*:Main", "view";
permission com.ecyrd.jspwiki.auth.permissions.WikiPermission "*", "registerUser";
};}}}
''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.''
!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 other than group pages. Group pages have a page prefix of "Group" and are used to define wiki groups. You must ''explicitly'' grant permissions for a Group page or collection of Group pages, ''e.g.'':
{{{permission com.ecyrd.jspwiki.auth.permissions.PagePermission "*:GroupManagers", "edit";}}}
or
{{{permission com.ecyrd.jspwiki.auth.permissions.PagePermission "*:Group*", "edit";}}}
!Implied Permissions
Certain permissions imply others:
* The "edit" PagePermission implies "view", "comment" and "upload"
* The "upload" PagePermission implies "view"
* The "delete" PagePermission implies "edit"
* The "editPreferences" WikiPermission implies "registerUser"
* The "createGroups" WikiPermission implies "createPages"
!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 {{com.ecyrd.jspwiki.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"
* "Admin"
* "All"
You can also use user-specfied Role names with certain external Authorizer implenentations, such as WebContainerAuthorizer. You can grant privileges to container-managed roles by specifying a Principal type of Role, with the name of the role as the target. For example: suppose JSPWiki is configured to use container-managed authentication, and that the container knows about an externally-defined role called "SystemAdministrator". You would grant privileges using this principal:
{{{principal com.ecyrd.jspwiki.auth.authorize.Role "SystemAdministrator"}}}
You are not restricted to using Principals of type Role, however. You can also specify wiki Groups or any other type of Principal. For example, suppose one of your wiki pages defines an arbitrary wiki group called "Managers". You'd like this group to be able to manage all group membership lists and to delete or rename pages, just like an administrator could. Here's a policy block that accomplishes that goal:
{{{grant signedBy "jspwiki"
principal com.ecyrd.jspwiki.auth.authorize.Group "Managers" {
permission com.ecyrd.jspwiki.auth.permissions.PagePermission "*:*", "edit,rename,delete";
permission com.ecyrd.jspwiki.auth.permissions.PagePermission "*:Group*", "edit";
};}}}
The possibilities are endless. That said, it's wise not to go too crazy with the policy file---they should be as simple as possible, but no simpler.
!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 two types:
# __User Principals__, which represent one or more user credentials, as supplied by the custom or container JAAS LoginModules
# __Built-in Role Principals__, which represents the logical Role objects "admin", "authenticated","anonymous", "asserted" and "all"
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:
# __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 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". If the other modules fail, the {{AnonymousLoginModule}} that runs last ''always'' succeeds.
# __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".
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".
!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 {
com.ecyrd.jspwiki.auth.login.WebContainerLoginModule SUFFICIENT;
com.ecyrd.jspwiki.auth.login.CookieAssertionLoginModule SUFFICIENT;
com.ecyrd.jspwiki.auth.login.AnonymousLoginModule SUFFICIENT;
};
JSPWiki-custom {
com.ecyrd.jspwiki.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.''
!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>/Register.jsp</url-pattern>
<url-pattern>/Rename.jsp</url-pattern>
<url-pattern>/Upload.jsp</url-pattern>
<url-pattern>/UserPreferences.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 -->}}}
''Note: for versions of JSPWiki earlier than 2.3.28, the contents of this file may appear slightly different.''
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}}, {{/UserPreferences.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 {{LoginRedirect.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, versions of JSPWiki through 2.3.28 ''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 {{com.ecyrd.jspwiki.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, you can write your own alternative implementation that relies on, for example, LDAP or a relational database for persistent storage. The interface {{com.ecyrd.jspwiki.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.MyRDBMSUserDatabase}}}
!!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; attempt to self-register; 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 registering a user, 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:
# If the Subject's Principal set includes the Role Principal that represents the administrator group ("administrator"), the Permission is always allowed. By definition, administrators can do anything.
# 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.
# 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:
## 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
## If the Principal in the ACL is a Role but ''not'' built-in, the external Authorizer's {{isInRole}} method is called
## If the Principal in the ACLl is a wiki Group, the GroupManager's group authorizer {{isInRole}} method is called
## If the Principal in the ACL is a user, check whether the Subject possesses it in its Principal set
# 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 by creating a special Group* page, 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 ({{com.ecyrd.jspwiki.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 {{com.ecyrd.jspwiki.auth.authorize.WebContainerAuthorizer}}, which delegates to the web container via the HttpRequest's {{isUserInRole(String)}} method.
The GroupManager interface ({{com.ecyrd.jspwiki.auth.authorize.GroupManager}}) extents Authorizer, and defines additional methods for loading, saving and querying group member lists.The default implementation ({{com.ecyrd.jspwiki.auth.authorize.DefaultGroupManager}}) reads membership lists from WikiPages that have the prefix "Group". You are free to create your own GroupManager implementation. If you do, you need to specify the implementation class in {{jspwiki.properties}}:
{{{jspwiki.groupManager = com.example.wiki.MyRDBMSGroupManager}}}
What's the difference between and Authorizer and a GroupManager? 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: 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 ''plus'' an external Authorizer that takes advantage of the web container's authorization APIs.