JEE 6 Security in a JSF application

This blog is about how to add web security (Authentication and Authorization) to a JSF/web application using JAAS.

Whats is JAAS?
Java Authentication and Authorization Service (JAAS): JAAS is a set of APIs that enable services to authenticate and enforce access controls upon users. JAAS provides a pluggable and extensible framework for programmatic user authentication and authorization. JAAS is a core Java SE API and is an underlying technology for Java EE security mechanisms. It is also known as container provided security.
A container provides two kinds of security: declarative and programmatic.
Declarative security expresses an application component’s security requirements by using either deployment descriptors or annotations.
Programmatic security is embedded  in an application and is used to make security decisions. Programmatic security is useful when declarative security alone is not sufficient to express the security model of an application.

The task of securing a web application can primarily be broken down into following sub tasks:

a) Develop/add desired declarative (annotation) and/or programmatic security and artifacts (like login page) to the application.
b) Set up security in the container; which includes
  1. Configuring Security Realm
  2. Setting up security repository (file or jdbc)
  3. Configuring Security for Application in web.xml
  4. Setting up Groups and Roles in web.xml
  5. Enable secure communication (HTTPS) in web.xml
c) Configure application security i.e define how to authenticate and who has what authorizations, in web.xml and glassfish-web.xml

Tools: Glassfish 3.X or 4, netbeans 7.3

I have created a sample application to demonstrate JAAS, which can be Downloaded from Git here

About the sample application.

A very simple JSF based application which the following security requirements:
1) Only validated users should be able to access this application.
2) Extra security feature is needed for pages in "admin" sub-context; the pages should be accessible only to users belonging to "Admin" role and secured using SSL.


Getting started

Add Security in the application

To take care of the first security requirement, we will add  "Form  Based Authentication" to the application i.e. when an user tries to access application, he be presented with a login form.
Here "j_username", "j_password" and "j_security_check" are JEE standards, use them as is, container understands and handles it based on the configuration that we will be doing later.

To take care of second security requirement (partially here, the rest is taken care with configuration in web.xml) , we will add programmatic security (see index.xhtml).

<h:link value="click For Admin Page - " outcome="/admin/adminOnly" rendered="#{request.isUserInRole('Admin')}" />

The link for Admin page will appear only if the user has Admin Role.

Now lets see how to set up "Container" security and add users and groups.

Configure Security Realm in Glassfish

Start/load glassfish  domain administration module in a browser and go to Configuration -> Server-Config -> Security -> Realms

Create a New Realm


set  form fields to following value
Name                 LoginRealm
className          com.sun.enterprise.security.auth.realm.file.FileRealm        (from dropdown menu)
JAAS Context    fileRealm
keyFile                C:\\glassfish4\\glassfish\\domains\\domain1\\loginRealm\\users.txt  
Assign Groups    Basic, Admin

Note: make sure JAAS Context is "fileRealm"
click OK, and the Realm definition should look like this.



Click on Manage User add following users and their roles

User Id: David       Group: Basic, Admin   Password: demo
User Id: Mike        Group: Basic                Password: demo
User Id: Temp                                             Password: demo

This completes Glassfish Container Security configuration.

Configure Application Security:


All the security is defined in web.xml.

First we need to specify the login mechanism and 
 <login-config>
     <auth-method>FORM</auth-method>
     <realm-name>LoginRealm</realm-name>
     <form-login-config>
         <form-login-page>/faces/login.xhtml</form-login-page>
         <form-error-page>/faces/login.xhtml</form-error-page>
     </form-login-config>
 </login-config>


The <auth-method> specifies that the application uses "Form" based authentication; <realm-name> specifies to use LoginRealm (the one we just defined in Glassfish) for authentication and authorization; <form-login-page> specifies the actual custom login page.

Now its time to define Roles of the application
<security-role>
  <description>Basic User</description>
  <role-name>Basic</role-name>
 </security-role>
 <security-role>
   <description>AdminUser</description>
   <role-name>Admin</role-name>
 </security-role>


These Roles will be used later in auth-constraints for web-resources.

Now on to adding Access Control and SSL to the application

<security-constraint>
        <display-name>AdminAccess</display-name>
        <web-resource-collection>
            <web-resource-name>AllAdminOperations</web-resource-name>
            <description/>
            <url-pattern>/faces/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description>Admin Only Access</description>
            <role-name>Admin</role-name>
        </auth-constraint>
        <user-data-constraint>
            <description>Secured Login</description>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>


A security constraint is used to define the access privileges to a collection of resources using their URL mapping. <url-pattern> within  <web-resource-collection> describes set of  resources that need to be protected. <auth-constraint> <role-name> describes Roles that can access resources specified by above pattern (In our case only users with Admin role can access admin pages). <user-data-constraint> <transport-guarantee> describes whether data in transfer needs to be protected or Not. Usually CONFIDENTIAL or INTEGRAL means SSL is required.

Now map Roles to Group we just defined in the Glassfish container

<security-role-mapping>
    <role-name>Admin</role-name>
    <group-name>Admin</group-name>
  </security-role-mapping>
  <security-role-mapping>
    <role-name>Basic</role-name>
    <group-name>Basic</group-name>
  </security-role-mapping>

That's all what is required to set up a secured web application.

Run Application

Now deploy the downloaded application to the glassfish server and run it; First you will be presented with a login page, enter credential "Mike" & "demo", these being valid credentials, you will be redirected to index.xhtml. Now click on "logout" link, and you will be redirected back to the login screen. This time enter credential "David" & "demo",  again these being valid credentials,you will be again redirected to index.xhtml., but this time you will see a link to "admin" page (link visible to only Admin group). click on it, [you will get a security alert stating that the connection is untrusted; ignore warning and click proceed for now] you will be redirected to adminOnly.xhtml, also notice that the URL protocol in the address bar has changed to "https".

Note: adminOnly.xhtml is configured such that only users in "Admin" group can access it and communication is protected with SSL.

As you can see adding web security is very simple and JEE provides a very clean and non intrusive way of managing security.

If you have any question or suggestion, please post your comment.

Prasanna Bhale

6 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Thank you this works ! super !!!!

    ReplyDelete
  3. Can I change my password in application? How can I do?

    ReplyDelete
  4. How if I want the admin to create users and assign Roles, How can we make a web page for that?

    ReplyDelete
  5. thank you for your great post,
    but one remark
    instead of using
    C:\\glassfish4\\glassfish\\domains\\domain1\\loginRealm\\users.txt
    use
    ${com.sun.aas.instanceRoot}/loginRealm/users.txt
    to avoid hard coding

    ReplyDelete
  6. Login.xhtml takes me to the context Root while printing "404 resource is not available.

    ReplyDelete