Ouch! Nothing worse than finding that everything you thought was OK has been silently sabotaged.
J2EE container-managed security is covered in just about any decent introductory text on J2EE. Unfortunately, they usually then go and confuse the issue by showing a sample app with a user-written login process.
Since even user-designed security systems usually have enough wit to use SSL, there's usually a section on setting up transport security in web.xml. A properly thorough text will then cover URL patterns and roles.
The J2EE standard security system is primarily wrapped around the webapp rather than coded into it. That means that less coding is required and many exploits will be turned away by the server without every being able to interact with application code at all, thereby ensuring that application bugs cannot be exploited.
The heart of this architecture is based on secured URL patterns and security roles, both of which you define and associate in web.xml. If an incoming URL request matches one of the defined patterns, then the server checks to see if the user is logged in. If the user is not logged in, the server intercepts the request, sidelines it, presents the login page defined in web.xml (this must be a straight HTML or
JSP form, JSF doesn't work here), then (assuming the user logged in) resumes the sidelined request as though nothing had happened. If the request requires a role that the user doesn't possess, the server rejects the request, instead.
You can also augment this system in application code where needed using the HttpServletRequest method isUserInRole() to query for authorization. I do this, for example, when a URL can handle multiple roles, but only some roles are allowed to update data. Also available on the HttpServletRequest are the userName and userPrincipal properties. userPrincipal isn't much use directly, but it holds the userName, as supplied to the login service. The userName method is a shortcut way to retrieve this.
The actual configuration of userids, passwords and roles is done external to the web application, typically using a plug-in security services provider called a
Realm. Most common J2EE servers come with support for many different types of Realms. For example, among those available for the Tomcat server are the MemoryRealm, which is a crude service that uses an XML user/role configuration file and is good for testing, the JDBCRealm, which authorizes and authenticates using a database, and the LDAPRealm, which uses an LDAP server such as Microsoft's Active Directory. The webapp neither knows nor cares which Realm is in use, so it's easy to swap Realms for testing.
Because JSF abstracts the underlying server and transport mechanisms. if you need any of the properties and functions available from the HttpServletRequest, you have to dig through JSF's FacesConfig to get it. Rather than splatter a lot of JSF-specific code all over my webapps, I prefer to isolate this functionality into a security manager object, which can be at session or application scope, depending on whether I want my security manager to hold additional security information of its own or simply statically access the HttpServletRequest security features. So I can say "if ( userSecurity.inRole(UserSecurity.ROLE_AUDITOR)) ...".
One thing to be aware of in JSF, however. The container-managed security system secures
URLs, not resources. That's an important thing to know, since in JSF, the URL paths don't always track the resource paths. To ensure that there are no security holes introduced on this account, use the "<redirect/>" navigation element to force the URL to match the resource path.