Use extensions for fine grained security

The <security-constraint> item in web.xml implements role-based security restrictions for your web application. Its <http-method> attribute lets you to specify POST, GET and so on, to restrict what kind of action is taken.

However, there's a big problem with this technique: browsers typically implement only POST and GET; they typically don't implement PUT and DELETE. This means that <http-method> is not very useful, in practice, for implementing fine-grained security constraints.

(It's important to note that the role-based security restrictions defined by the servlet specification do nothing for restrictions based on ownership of data, such as seen in many public web sites. Such restrictions prevent one user from editing items created by some other user, for example.)

There's an alternative to using <http-method>: use the extension appearing in the URL. In this case, URLs take the form:

When thinking of security, it's natural to think in terms of nouns and verbs:

In the above example, Account is the noun, while the extension (.list, .add, and so on) is the verb. With this style, any degree of granularity for security constraints can be implemented. One can mix and match the nouns and the verbs independently of each other, in a natural way.

Example 1
Only a manager can perform this specific delete operation :

<security-constraint>
 <web-resource-collection>
  <web-resource-name>Deleting Members</web-resource-name>
  <url-pattern>/main/member/MemberAction.delete</url-pattern>
 </web-resource-collection>
 <auth-constraint>
  <role-name>manager</role-name>
 </auth-constraint>
</security-constraint>

Example 2

A reader can read, but not write to the database :

<security-constraint>
 <web-resource-collection>
  <web-resource-name>View Operations</web-resource-name>
  <url-pattern>*.list</url-pattern>
  <url-pattern>*.fetch</url-pattern>
 </web-resource-collection>
 <auth-constraint>
  <role-name>reader</role-name>
 </auth-constraint>
</security-constraint>

Example 3

An editor can both read and write to a database :

<security-constraint>
 <web-resource-collection>
  <web-resource-name>Edit Operations</web-resource-name>
  <url-pattern>*.list</url-pattern>
  <url-pattern>*.fetch</url-pattern>
  <url-pattern>*.add</url-pattern>
  <url-pattern>*.change</url-pattern>
  <url-pattern>*.delete</url-pattern>
  <url-pattern>*.fetchForChange</url-pattern>
 </web-resource-collection>
 <auth-constraint>
  <role-name>editor</role-name>
 </auth-constraint>
</security-constraint>

Example 4

Only a webmaster can access URLs starting with /webmaster/* :

<security-constraint>
 <web-resource-collection>
  <web-resource-name>Webmaster</web-resource-name>
  <url-pattern>/webmaster/*</url-pattern>
 </web-resource-collection>
 <auth-constraint>
  <role-name>webmaster</role-name>
 </auth-constraint>
</security-constraint>

Example 5

Only a megawebmaster can access /webmaster/Logs.delete :

<security-constraint>
 <web-resource-collection>
  <web-resource-name>Log Deletion</web-resource-name>
  <url-pattern>/webmaster/Logs.delete</url-pattern>
 </web-resource-collection>
 <auth-constraint>
  <role-name>megawebmaster</role-name>
 </auth-constraint>
</security-constraint>

Here's a table showing whether access is granted in various cases, given the above constraints:

For User With Role(s) Accessing URL Allow Access?
editor ../Account.list Y
editor ../Account.delete Y
reader ../Account.list Y
reader ../Account.delete N
editor /main/member/MemberAction.delete N
reader, manager /main/member/MemberAction.delete Y
reader /webmaster/Logs.list N
webmaster /webmaster/Logs.list Y
webmaster /webmaster/Logs.delete N