Thursday 2 October 2014

How to Secure RESTful Webservice via Annotation in Jersey

In my previous how to secure restful webservice I have showed how to secure a RESTful Webservice by configuring in web.xml.

Now we see how to implement security via annotation.

We can provide authorization for JAX-RS resource using the below annotation.
  • @PermitAll - specifies that all security roles are permitted to access your JAX-RS resources
  • @DenyAll - specifies that no security roles are permitted to access your JAX-RS resources
  • @RolesAllowed - specifies the security roles that are permitted to access your JAX-RS resources
Below are the steps to implement security via annoataion. 

1. Create a Custome ResourcConfig by creating a new class and extend it. In the constructor register RolesAllowedDynamicFeature as shown below.

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;

@ApplicationPath("/")
public class ApplicationResourceConfig extends ResourceConfig{
  public ApplicationResourceConfig() {
         super(MyResource.class);
         register(RolesAllowedDynamicFeature.class);
     }
}

2. Now add Roles that can access the specific resources in JAX-RS resources. In below MyResource class I have added three method with sub path and Roles corresponding to them.


import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * Root resource (exposed at "myresource" path)
 */
@Path("myresource")
public class MyResource {

 /**
  * This method is allowed for all Roles
  * 
  * @return
  */
 @GET
 @Produces(MediaType.TEXT_PLAIN)
 @Path("/unsecured")
 @PermitAll
 public String getsecured() {
  return " Message For all Roles!";
 }

 /**
  * This method is allowed to only users with Role <b>secured</b>
  * 
  * @return
  */
 @GET
 @Produces(MediaType.TEXT_PLAIN)
 @Path("/secured")
 @RolesAllowed("secured")
 public String getSecured() {
  return "Message for user with Role secured!";
 }

 /**
  * This method is allowed to only users with Role <b>admin</b>
  * 
  * @return
  */
 @GET
 @Produces(MediaType.TEXT_PLAIN)
 @Path("/securedadmin")
 @RolesAllowed("admin")
 public String getSecuredadmin() {
  return "Message for user with Role admin!";
 }
}

3. Configure web.xml

Add Custom ResourceConfig create above in init-param


    <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.ranvanshi.jersey.basicsecurityannotation.ApplicationResourceConfig</param-value>
    </init-param>

Add security-constraint for the Resources. We have provided security entry for enire resources. User has to in Role admin to access the resources.


 <security-constraint>
  <web-resource-collection>
   <web-resource-name>Secured</web-resource-name>
   <url-pattern>/webapi/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
   <role-name>admin</role-name>
  </auth-constraint>
 </security-constraint>
 <security-role>
  <role-name>admin</role-name>
 </security-role>
 <login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Login</realm-name>
 </login-config>

Complete web.xml


<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container, 
 see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <servlet>
  <servlet-name>Jersey Web Application</servlet-name>
  <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
  <init-param>
   <param-name>jersey.config.server.provider.packages</param-name>
   <param-value>com.ranvanshi.jersey.basicsecurityannotation</param-value>
  </init-param>
  <init-param>
   <param-name>javax.ws.rs.Application</param-name>
   <param-value>com.ranvanshi.jersey.basicsecurityannotation.ApplicationResourceConfig</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>Jersey Web Application</servlet-name>
  <url-pattern>/webapi/*</url-pattern>
 </servlet-mapping>
 <security-constraint>
  <web-resource-collection>
   <web-resource-name>Secured</web-resource-name>
   <url-pattern>/webapi/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
   <role-name>admin</role-name>
  </auth-constraint>
 </security-constraint>
 <security-role>
  <role-name>admin</role-name>
 </security-role>
 <login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Login</realm-name>
 </login-config>
</web-app>


This post explains about implementing security via annotation in  Jersey.

Thanks !

Wednesday 1 October 2014

How to Secure RESTful Webservice in Jersey and Tomcat

This example explain how to make JAX-RS resource secured using HTTP Basic Auth.

I will enable HTTP Basic Authentication for the RESTful Webservice created in my previous blog Creating Jersey Restful Webservice.

Secure Resource With web.xml

You need to define the <security-constraint> elements in the web.xml and assign roles which are able to access these resources.


  <security-constraint>
    <web-resource-collection>
      <web-resource-name>BasicSecurityExample</web-resource-name>
      <url-pattern>/webapi/myresource</url-pattern>
      <http-method>GET</http-method>
    </web-resource-collection>
    <auth-constraint>
      <description>Authorized role is admin</description>
      <role-name>MyRole</role-name>
    </auth-constraint>
  </security-constraint>
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Login</realm-name>
   </login-config>

To Secure multiple resources we have to add <security-constraint> for each resource we need to securr or we can secure multiple resource using wildcard in <url-pattern> like below.


  <security-constraint>
    <web-resource-collection>
      <web-resource-name>BasicSecurityExample</web-resource-name>
      <url-pattern>/webapi/*</url-pattern>
      <http-method>GET</http-method>
    </web-resource-collection>
    <auth-constraint>
      <description>Authorized role is admin</description>
      <role-name>MyRole</role-name>
    </auth-constraint>
  </security-constraint>

Create User in Tomcat Server.


In Tomcat we can add user in tomcat-users.xml file which is located in <TOMCAT_HOME>/conf folder. Add the below entry in tomcat-user.xml file to add a User test with Password test with role as MyRole.


<user password="test" roles="MyRole" username="test"/>


Now our GET method in the resource /webapi/myresource is secure. Run the application.

Open any browser and go to the below link http://localhost:8080/FirstDemo/
You will See the index page for the application.
Click on the Jersey resource to access the Jesery REST service.
When we click on the link we will be asked for Username and Password to login. GIve username and password as test to access the resource.


This post explains about enabling security in web.xml  without touching the java code.In my next blog i will share how to enable security via annoatation in java code.

Wednesday 24 September 2014

ADF : Show Pop Up while af:fileDownloadActionListener is taking long time to complete.

Following example shows how to show a Pop-up and block the user from doing anything on the page until the fileDownloadActionListener Completes its process.


Steps to Implement the above Scenario:

1: Create a new Fusion Web Application(ADF) in Jdeveloper.

2: Create a Jsp Page(FileDownload.jspx). While Creating select Create as XML Documnet(*.jspx) option.

3.Drag and Drop a PanelGroupLayout in the pageand then drag and drop two Command Buttons inside the PanelGroupLayout.Then Drag and Drop Poll component from Operations tab in Component pallete.

Add ClientListener to first CommandButton.


 <af:commandButton text="Click Me Download !" id="cb1">

      <af:clientListener method="launchDownloadProcess" type="action"/>

 </af:commandButton> 

For second Command Button  set ClientComponent attribute to true and visible attribute to false.Add FileDownloadActionListener to second Command Button. Create a Bean class (in view Scope) and add the method to handle filedownload. Set the filename,contentType and charset attribute as shown below.


    <af:commandButton text="Invisible" id="cb2" clientComponent="true"
                      visible="false">
      <af:fileDownloadActionListener method="#{viewScope.FileDownloadBean.downloadFile}" filename="download.txt"
                                        contentType="text/plain; charset=utf-8"/>
    </af:commandButton>

Add the poll Listener For the Poll component, Set the interval as "-1". Also add binding for the poll Component.We will add the method content later.


 <af:poll id="pol1" pollListener="#{viewScope.FileDownloadBean.pollListener}"
             binding="#{viewScope.FileDownloadBean.poll}" interval='-1'
             clientComponent="true"/>


4. Add Pop Up to the PanalGroupLayout. And design the popup accoring to your requirement.
But autoCancel attribute should be disabled and dialog components closeIconVisible attribute should be false . Below is sample how i have designed my popup.


<af:popup childCreation="deferred" autoCancel="disabled" id="busyStatePopup"
              contentDelivery="immediate" binding="#{viewScope.FileDownloadBean.popup}">
      <af:dialog id="d2" closeIconVisible="false" type="none"
                 title="Information">
        <af:outputText value="Please wait while the report is generated ..."
                       id="ot1"/>
      </af:dialog>
    </af:popup>

5. Add the below javascript source in the document.


      function launchDownloadProcess(evt) {
           // find and Show the popup
           var popup = evt.getSource().findComponent('longRunningPopup');
            if (popup != null) {
               popup.show();
            }
            // find and set the interval for the poll so the polling starts
            var poll = evt.getSource().findComponent('pol1');
            if (poll!= null) {
               poll.setInterval(2000);
            }
            // Find and queue the event associated with the invisible button 
            var invisibleButton = evt.getSource().findComponent('cb2');
            AdfActionEvent.queue(invisibleButton, true); 
 }

And the Complete page will look like.

FileDownload.jspx


<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view>
    <af:document id="d1">
      <af:resource type="javascript">
      function launchDownloadProcess(evt) {
        // find and Show the popup var popup =
        evt.getSource().findComponent('longRunningPopup');
        if (popup != null) {
            popup.show();
        }
        //find and set the interval for the poll so the polling starts
        var poll = evt.getSource().findComponent('pol1');
        if (poll != null) {
            poll.setInterval(2000);
        }
        // Find and queue the event associated with the invisible button
        var invisibleButton = evt.getSource().findComponent('cb2');
        AdfActionEvent.queue(invisibleButton, true);
      }    
      </af:resource>
      <af:form id="f1">
        <af:panelGroupLayout id="pgl1" layout="scroll">
          <af:commandButton text="Click Me Download !" id="cb1">
            <af:clientListener method="launchDownloadProcess" type="action"/>
            <!--<af:fileDownloadActionListener method="#{FileDownloadBean.downloadFile}" filename="download.txt"
                                        contentType="text/plain; charset=utf-8"/>-->
          </af:commandButton>
          <af:commandButton text="Invisible" id="cb2" clientComponent="true"
                            visible="false">
            <af:fileDownloadActionListener method="#{viewScope.FileDownloadBean.downloadFile}"
                                           filename="download.txt"
                                           contentType="text/plain; charset=utf-8"/>
          </af:commandButton>
          <af:poll id="pol1"
                   pollListener="#{viewScope.FileDownloadBean.pollListener}"
                   binding="#{viewScope.FileDownloadBean.poll}" interval='-1'
                   clientComponent="true"/>
          <af:popup childCreation="deferred" autoCancel="disabled"
                    id="busyStatePopup" contentDelivery="immediate"
                    binding="#{viewScope.FileDownloadBean.popup}">
            <af:dialog id="d2" closeIconVisible="false" type="none"
                       title="Information">
              <af:outputText value="Please wait while the report is generated ..."
                             id="ot1"/>
            </af:dialog>
          </af:popup>
        </af:panelGroupLayout>
      </af:form>
    </af:document>
  </f:view>
</jsp:root>

6. Add the below code in the FileDownloadBean's downloadFile method. 

        isProcessing = true;
        isPopUpVisible = true;
        //Added Sleep just to illustrate the use case
        Thread.currentThread().sleep(5000);
        OutputStreamWriter w = new OutputStreamWriter(outputStream, "UTF-8");
        w.write("File Generated by FileDownloadActionListener");
        // The stream is automatically closed, but since we wrapped it,
        // we'd better flush our writer
        w.flush();
        isProcessing = false;

7. Add the below Code in th Poll listener method body


        if (!isProcessing && isPopUpVisible) {
            popup.hide();
            isPopUpVisible = false;
            //Set the poll interval to -1 so that further polling doesn't happen
            poll.setInterval(-1);
            AdfFacesContext.getCurrentInstance().addPartialTarget(poll);
        }

Complete FileDownloadBean.java files.
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

import javax.faces.context.FacesContext;

import oracle.adf.view.rich.component.rich.RichPoll;
import oracle.adf.view.rich.component.rich.RichPopup;
import oracle.adf.view.rich.context.AdfFacesContext;

import org.apache.myfaces.trinidad.event.PollEvent;


public class FileDownloadBean {
    private RichPopup popup;

    private boolean isProcessing = false;
    private boolean isPopUpVisible = false;
    private RichPoll poll;

    public FileDownloadBean() {
    }

    public void downloadFile(FacesContext facesContext,
                             OutputStream outputStream) throws InterruptedException,
                                                               UnsupportedEncodingException,
                                                               IOException {
        isProcessing = true;
        isPopUpVisible = true;
        //Added Sleep just to illustrate the use case
        Thread.currentThread().sleep(5000);
        OutputStreamWriter w = new OutputStreamWriter(outputStream, "UTF-8");
        w.write("File Generated by FileDownloadActionListener");
        // The stream is automatically closed, but since we wrapped it,
        // we'd better flush our writer
        w.flush();
        isProcessing = false;
    }

    public void pollListener(PollEvent pollEvent) {
        if (!isProcessing && isPopUpVisible) {
            popup.hide();
            isPopUpVisible = false;
            //Set the poll interval to -1 so that further polling doesn't happen
            poll.setInterval(-1);
            AdfFacesContext.getCurrentInstance().addPartialTarget(poll);
        }
    }

    public void setPopup(RichPopup popup) {
        this.popup = popup;
    }

    public RichPopup getPopup() {
        return popup;
    }

    public void setPoll(RichPoll poll) {
        this.poll = poll;
    }

    public RichPoll getPoll() {
        return poll;
    }
}


8. All the done changes are done. Run the FileDownload.jspx. When we click the Click to Download File button the Popup will open and prevent user from doing any activity in the page. Once the file is ready for download the popup will close.



Wednesday 17 September 2014

Creating Jersey RESTful Webservice Using Maven ,Eclipse and Apache Tomcat

This tutorial explains how to develop Jersey RESTful Webservice using Maven, Eclipse and Apache Tomcat.

Pre- Requisite:

Java:

Download and install the latest version of Java. Note the version used in this articale is Java 1.8.0_05.

Apache Tomcat:

Download and install the latest version of Apache Tomcat.  Note the version used in this article is 7.0.54.

Eclipse:

Download and Install the latest version of Eclipse Kepler Eclipse. Note the version used in this article is 4.3

Maven

Download and Install the latest version of Maven. Note the version used in this article is 3.2.1.

Setting up Eclipse:

Configure Maven in Eclipse:

EclipseAlready has build-in maven support but i have added the maven which i downloaded in Eclipse so that my maven from command-line and eclipse point to the same.

Go to Windows ---> Preference in Eclipse. Select Maven --> Installations from the popup.
Click Add and select the folder where Maven is Installed. 
(Below is how it looks after adding the external Maven. I have installed maven in C:\apache-maven-3.2.1 folder)

Configure Tomcat in Eclipse:

Go to Windows ---> Preference in Eclipse.Select Server -- > Runtime Environments.Click add and Select Apache --> Apache Tomcat v7.0 in popup.

Click Next and Select the Tomcat installation directory that you have installed. Click finish.


Creating the Simple Jersey RESTful Webservice Using Maven.

1.Open Command Prompt and Navigate to the Folder/WorkSpace where you want to create the project.

2.Execute the below Command to create the Jersey Project.


mvn archetype:generate -DarchetypeGroupId=org.glassfish.jersey.archetypes -DarchetypeArtifactId=jersey-quickstart-webapp -DarchetypeVersion=2.12

3.After Downloading the required repository maven will ask for values for below properties

PropertyValue
groupId
com.ranvanshi.jersey
artifactId

FirstDemo
version
1.0
package
com.ranvanshi.jersey.first

4.After you Confirm the Jersey project is created.

Importing the Maven Project in Eclipse.

1. Open Eclipse if not already open.Select File --> Import. And select Maven -->Existing Maven Project


2. Click Next and Browser the Project that you have created and click Finsh.

3. There will be JSP Problem error in the project. To solve this error Right Click the project and Select Properties. Then Select Project Facets and select the Runtime Tab on Right Side. And Select the Tomcat Server That we have added earlier and Apply changes and click OK button.


Run the Project

Right Click the project and Select Run As --> Run on Server. Select the Server and click Finish.
Server will start and you application will be deployed.

Open any browser and go to the below link http://localhost:8080/FirstDemo/
You will See the index page for the application.
Click on the Jersey resource to access the Jesery REST service.

Conclusion:

We have seen how to create a Jersey RESTful webservice using Maven, Eclipse and Apache Tomcat. This tutorial doesn't explain about the details of the Jersey RESTful webservice instead explains about the how to set up the environment for developing and create a sample application.