Wednesday, August 14, 2013

Example of Using Basic Authentication In a Java Web Project

Adding basic authentication mechanism to your web project is very easy. You don't need to design a login form or a login page. You just need to define the protected resources and authorized roles for those records.
This  example will show you how to do this. I am using eclipse IDE in this example.

Create a new Dynamic Web project in Eclipse. I name the project as BasicAuthTest.








































Right click on the WebContent folder and create a new JSP page. I name it as home.jsp.
Change the content of the page as below.
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <h1>Hello User!</h1>
  </body>
</html>

Now open the web.xml file. You can find it in WEB-INF folder.

















Clear the default content between <webapp> </webapp> tags. Now the file will look like this.


Now add following block between the <webapp> </webapp> tags.
<security-constraint>
  <web-resource-collection>
    <web-resource-name>jsp pages</web-resource-name>
    <url-pattern>*.jsp</url-pattern>
    <http-method>GET</http-method>
  </web-resource-collection>

  <auth-constraint>
    <role-name>manager</role-name>
  </auth-constraint>
</security-constraint>

As you can understand in the above code we have introduced a security-constraint block. Within it we define a web-resource-collection. web-resource-collection is a collection of resources that we need to protect. First we give a name for the collection. Then we define a url pattern. It means all the resources which match this url pattern are protected. Note that the url pattern we have used is *.jsp. It means all the requests ends with .jsp require this authentication.

Similarly you can define a url pattern of a servlet within the url-pattern tags as below.
<url-pattern>/LoginServlet</url-pattern>
Then all the requests with this pattern(i.e. http://localhost:8080/BasicAuthTest/LoginServlet) also requires authentication.

The http-method specifies which HTTP methods should be refined by this security constraint. In above code we have only the GET defined as the http method. It means this constraint applies only to GET requests. You can have multiple http-method nodes within the <web-resource-collection> </web-resource-collection> block . If you didn't specify any http-methods this constraint is applied to all the HTTP methods.

Then within <auth-constraint> </auth-constraint> tags we define the role where users in which can access this resources. You can have multiple <role-name> tags within this <auth-constraint> </auth-constraint> tags. Here we have specified manager as the role where users belongs to which role can access these restricted resources. We should also have to define this role as a security role in web.xml. See below code.


Add following block after the <security-constraint> </security-constraint> block.

<login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>allPages</realm-name>
</login-config>
<security-role>
  <role-name>manager</role-name>
</security-role>

In above code within the <login-config> </login-config> block we define the auth-method (authentication method) as BASIC. This is because in this example we are going to use Basic Authentication.

Possible values for auth-method are:
✔ BASIC
✔ DIGEST
✔ CLIENT-CERT
✔ FORM

There is another node inside the <login-config> </login-config> tags. It is <realm-name>allPages</realm-name>. What does this do?
The tag realm-name is used to separate a certain authenticated area which can be accessed using same credentials. This realm value is included in the header of the server response and when the browser reads this it opens a dialog box asking the username and password for this realm.
Keep in mind that realm-name is used in Basic Authentication only.


Ok. That is it. Now right click on the project name BasicAuthTest ⇨ Run AsRun On Server
Select Tomcat server and click Finish.




















Now your application will be deployed in Tomcat server. After the server started, enter following url in the address bar of your web browser.
http://localhost:8080/BasicAuthTest/home.jsp (Assuming your Tomcat runs on port 8080)


✎ Note:-
I recommend to use FireFox because in chrome it is difficult to clear the cached credentials of Basic Authentication. In FireFox cached Basic Authentication Credentials are cleared after you restart the FireFox. If you still want to test this with chrome you may need to read this stackoverflow post.

Wow! You will see a dialog box asking for a username and a password to access the page.
















Enter arbitrary credentials and try. You will again and again receive the popup.

Configuring Tomcat users and Roles
In order to login you need to have a user with the role manager configured in tomcat-users.xml file.

In Project Explorer open the Servers folder and you will see your Tomcat instances. Expand the relevant tomcat folder and double click the tomcat-users.xml file.



















✎ Note:-
    In your Tomcat installation directory you can find another tomcat-user.xml file. However in the case you start the Tomcat through Eclipse, there is no effect of changing this default tomcat-user.xml file. When Tomcat is started through Eclipse it doesn't read configurations from this file. Instead it reads the tomcat-user.xml file I have shown in above screen.

Add following lines inside the <tomcat-users> </tomcat-users> tags. In first line we are creating a role named as "manager". In second line we are creating a user with username "admin" and password "admin" and assigns the role "manager" to that user.

<role rolename="manager"/>
<user password="admin" username="admin" roles="manager"/>

Save the tomcat-users.xml file and restart the Tomcat server. Restart FireFox and retry the url
http://localhost:8080/BasicAuthTest/home.jsp (Assuming your Tomcat runs on port 8080).
Enter the username and password as "admin" and "admin".
Now you should be able to login.

✎ Note:-
After you successfully logged in, you can again and again access your protected resources without being asked for the credentials. If you want to see the login box again just restart FireFox. For chrome users please take a visit to this stackoverflow post.

Thursday, August 8, 2013

Simple Servlet Filter

Servlet Filters can be very useful when you are developing web applications with servlets. As the name itself implies servlet filter is some what acts as a filter in between the client and the servlet. Following figure will give you a clear idea about its behavior.


 As in above image the request is first processed by the servlet filter. Then servlet filter decides what to do next. It may 
     ☛ forward the request to the target servlet
     ☛ forward to another servlet or jsp 
     ☛ forward to next filter (If there are multiple filters)
     ☛ decides to response to the request by itself
     ☛ etc.....

In following example I am going to show you how to create a simple servlet filter.This filter checks the clients IP address and let him to access the target servlet(HelloServlet) only if the IP is not contained in the prohibted IPs list.

First create a dynamic web project. I name it as FilterTest. 

























To create a servlet, right click the src folder ⇨ new ⇨ Servlet.





















I name the servlet as HelloServlet and the package as test.serv.
























Now change the doGet method of the servlet so that final view of your class would be as below. As you can understand we have overridden the doGet() method to send a html page saying "You are welcome".
package test.serv;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    PrintWriter writer = response.getWriter();
    writer.println("<html>");
    writer.println("<head>");
    writer.println("</div>");
    writer.println("<body>");
    writer.println("<h1>You are welcome</h1>");
    writer.println("<html>");
    writer.close();
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  }
}



Now create a new servlet filter by right clicking the src folder ⇨ new ⇨ Other ⇨ Filter.





















Name the filter as IPFilter and the package as test.filter.

























Modify the IPFilter class as below.
package test.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.*;

public class IPFilter implements Filter {
  List<string> prohibitedIpsList = new ArrayList<string>();</string></string>

  public void init(FilterConfig fConfig) throws ServletException {
    prohibitedIpsList.add("127.0.0.1");
    //You can add more ips here
  }

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    String ipAddress = request.getRemoteAddr();
    System.out.println("IP=" + ipAddress);
    if(prohibitedIpsList.contains(ipAddress)) {
        PrintWriter pw = response.getWriter();
        pw.println("<html><head></head>><body><h1>
                    We don't trust you.</h1>
                    </body></html>");
        pw.close();
    } else {
        chain.doFilter(request, response);
    }
  }

  public void destroy() {
  }
}


The first method that the servlet container calls after creating the Filter object is init(). In this method we are adding the prohibited IP addresses to the prohibitedIpsList. You can see we have overridden the doFilter() method. In this method we check whether the prohibitedIpsList contains clients IP address. If so the filter does not forward the message to the HelloServlet. Instead the filter itself send a HTML page to the client saying "We don't trust you.".

Now open the WEB-INF folder. You can find it inside the WebContent folder. In WEB-INF folder you can see the auto generated web.xml file. Open it. The content of the file will be as below.


Change the url-pattern of the HelloServlet  and IPFilter  to "/hello".
Finally the web.xml should looks like this.


Look at the web.xml. HelloServlet and the IPFilter both uses the same url-pattern. It means if a request come which matches to this url-pattern, both IPFilter and HelloServlet are responsible to serve it.
But who serves first?
Actually servlet container first deliver the request to the servlet filter. If there are multiple filters configured in web.xml which matches the sames url, then servlet container processes them in the order that they appear in the web.xml.

Now right click the FilterTest project  and go to Run As  ⇨ Run On Server.
Select tomcat server and click Finish.
The server will start and your application will be deployed in it.

Now open the web browser and enter this url.
http://localhost:8080/FilterTest/hello
Note that I assume that your Tomcat server is running at port 8080.


Since our local host address 127.0.0.1 is in our prohibited IP addresses list in IPFilter, you should get the following page.









If you remove the IP address 127.0.0.1 from the prohibited IP addresses list, it should show the following page which is sent you by the HelloServlet.











That is it.

Note:-
    In web.xml, inside the the node, instead of specifying a url-pattern you can define a servlet name as below. 























If you configured the filter as above it means all the requests which are sent to the HelloServlet should be processed by the IPFilter. Change the web.xml as above and run your project. The result will be the same.