2015/02/10
10 Feb, 2015

How to Write a Web Application Backed by WSO2 Middleware - Part 2

  • Hasitha Abeykoon
  • Associate Technical Lead - WSO2

Applies to

WSO2 Developer Studio Version 3.6.0
WSO2 Application Server Version 5.2.1
WSO2 Identity Server Version 4.6.0
WSO2 Data Services Server Version 3.2.1


Table of Contents

  1. Introduction
  2. Introducing WSO2 Identity Server (WSO2 IS)
  3. Creating users and roles in WSO2 IS server
    • Add roles
    • Add users
  4. Adding a login page for the web application
    • Front-end development
    • Back-end development
      • LoginServlet
      • LogoutServlet
      • AuthenticationFilter
        • What is a servlet filter
      • Something additional for front-end to be more informative
      • Testing the login functionality
  5. Adding authorization for the web application
    • XACML as declarative access control policy language

      Uploading and publishing XACML policy to WSO2 IS

      Modifying web application to communicate with IS

      Front-end modifications

      Testing XACML authorization

    • Conclusion and possible improvements


    Introduction

    Part 1 of this series focused on how you could develop a simple web application using WSO2 Developer Studio as the coding environment and how to deploy it in WSO2 Application Server. In this article, we discuss ways to bring security to the web application developed, which was explained in Part 1. In this article too WSO2 Developer Studio is referred to as the coding environment. We also introduce WSO2 Identity Server as the security provider. The key points discussed are as follows:

    Authentication

    1. How to add a login page to the web application
    2. Creating users and roles using WSO2 IS server

    Authorization

    1. What is XACML (eXtensible Access Control Markup Language) and how it is used for authorization
    2. Integrating XACML authorization to the web application developed so far

    As depicted above, the article is divided to two parts to discuss authentication and authorization separately.

    For more use cases of the WSO2 Identity Server read our case study on

    Introducing WSO2 Identity Server (WSO2 IS)

    WSO2 Identity Server provides sophisticated security and identity management of enterprise web applications, services, and APIs, and provides hassle-free, minimal monitoring and maintenance requirements. It has a rich management so that many operations and configurations can be performed via a web UI. In each WSO2 server, users can configure users and roles and give access, but having a central server to handle security related aspects is architecturally clean and hence easy to maintain.
    As the first step, let us see how to setup and configure WSO2 IS with several users and roles.


    Creating users and roles in WSO2 IS server

    1. Download WSO2 IS from here and extract it to a preferred location
    2. Open /repository/conf/carbon.xml file and set to 1
    3. Navigate to /bin and start the server using sh wso2server.sh command (run wso2server.bat for Windows)
    4. Login to the management console using default username “admin” and password “admin”. Go to Configure >> Users and Roles
    5. Figure 01

      Add roles

    6. Navigate to Roles >> Add New Role
    7. Figure 02

    8. Define a role as “read” and click finish
    9. In the same way define “write” role and roles. Note that there is another default role named “internal/everyone” which will be assigned to any user by default
    10. Figure 03

      Add users

    11. Navigate to Users and Roles >> Users >> Add New Users
    12. Define a user called “hasitha” with password “hasitha”
    13. Figure 04

    14. Click next and assign roles “read” and “write” and click finish
    15. In the same way create following users and roles inside WSO2 IS
    UserName Password Roles
    evanthika evanthika read
    senaka senaka write
    shammi shammi internal/everyone

    Figure 05

    Defining users and roles in the above way. The target is to configure the web application to enable the following:

    1. Allow Hasitha to enter new patients to the system and also to search patients.
    2. Allow Evanthika just to search patients in the system.
    3. Allow Senaka just to add new patients (he cannot search).
    4. Shammi will be another user, but not be allowed to either add new patients or to search.

    It should be noted here that WSO2 IS server’s built-in LDAP (powered by ApacheDS) is used. If users need to configure an external user store, such as Microsoft Active Directory, Apache Cassandra, or any JDBC database, it is possible with WSO2 IS.

    As users and roles are configured with WSO2 IS, now let us see how to perform authentication and authorization within the web application communicating with the IS server.


    Adding a login page for the web application

    1. Front-end-development
    • First of all, let us ensure landingPage.html of the web application is developed so far as a jsp page. Make sure all the references (“home” link at other pages and declaration at web.xml file) to that page is changed to landingPage.jsp
    • Create an HTML page called login.html inside WebContent folder. This will have the common theme that was used throughout the web application developed

      Figure 06

    • Now as soon as the web application is accessed, this page should be displayed instead of landingPage.html. Only successfully authenticated users should be redirected to landingPage.html. Hence,

        
      <welcome-file-list>
      	<welcome-file>login.html</welcome-file>
      </welcome-file-list>
      
    • login.html page will contain a form where the usernames and passwords are received as inputs.

        
      <input type="text" name="user" size="20">
      <input type="password" name="pwd" size="20">
      



      That form’s action will be as

        
      <form action="LoginServlet" method="post">
      

      so that it will post the inputs to the LoginServlet.

    • Each page that’s already designed for the web application should have a link called “Logout” so that the user can log out of the web application whenever he/she wishes to do so. When the user clicks this link, the request should be forwarded to LogoutServlet.
        
      <form action="LogoutServlet" method="post">
      	<input type="submit" value="Logout" >
      </form>
      

      Thus, landingPage.html, addPatient.jsp, getPatientDetails.jsp, patientInfoPage.jsp should bear this form (refer to attached sources to see how this form is inserted to each page).


  6. Back-end development
  7. 2.1. LoginServlet

    • When the user enters his userName and password in login.html page, that information will reach Login servlet.
        
      String user = request.getParameter("user");
      String pwd = request.getParameter("pwd");
      
    • Now we need to call the WSO2 IS server and see if this user is authenticated. WSO2 Identity Server enables you to manage users and roles in your system with its open web services API (RemoteUserStoreManagerService); therefore, any third-party application can consume this API to handle authentication and authorization with WSO2 Identity Server. Users can perform below operations with web calls to this API1:
      • Authenticates a user
      • Creates a new role
      • Creates a user and add the user to a new role
      • Adds a value to a predefined custom attribute under the user profile
      • Checks whether a given user belongs to a given role

      We are going to use the first operation to do the authentication. When the above operations are considered, it is evident that creating new users, assigning roles can also be done within the web application itself with custom user interfaces, etc. which is out of scope of this article.

    • In order to call the above API at the compile time we need the skeleton classes (RemoteUserStoreManagerServiceStub). You can find org.wso2.carbon.um.ws.api.stub_4.2.1.jar file that provides these classes at /repository/components/plugins. Add it to the classpath of the web application project.
    • The following code snippet will call the webservice and check whether the user has been authenticated.

        
      if (!(credential instanceof String)) {
          	throw new Exception("Unsupported type of password");
      }
      try {
              if(stub == null) {
              	stub = new RemoteUserStoreManagerServiceStub(null, serverUrl + "RemoteUserStoreManagerService");
              	HttpTransportProperties.Authenticator basicAuth = new HttpTransportProperties.Authenticator();
                      basicAuth.setUsername(basicAuthUserID);
                      basicAuth.setPassword(basicAuthPassword);
                      basicAuth.setPreemptiveAuthentication(true);
      
                      final Options clientOptions = stub._getServiceClient().getOptions();
                      clientOptions.setProperty(HTTPConstants.AUTHENTICATE, basicAuth);
                      stub._getServiceClient().setOptions(clientOptions);
      	}
              return stub.authenticate(userName, (String) credential);
      } catch (Exception e) {
              handleException(e.getMessage(), e);
      }
      return false;
      
    • Following points are very important to note;
      • serverUrl = https://localhost:9444/services/ (as we have started WSO2 IS with a port offset of 1)
      • We need to set basic auth headers, basicAuthUserID = admin and basicAuthPassword = admin by default.
    • If the user is successfully authenticated, the user logged in details are as follows;
      • set as a cookie to the session
        HttpSession session = request.getSession();
        session.setAttribute("user", user);
        Cookie userName = new Cookie("user", user);
        userName.setMaxAge(30*60);
        response.addCookie(userName);
        
      • set a session expiration

        //setting session to expiry in 30 mins
        session.setMaxInactiveInterval(30*60);
        
      • redirect the user to the landing page

        response.sendRedirect("landingPage.jsp");
        
    • If login fails, we do not navigate the user anywhere, but a text indicating login was unsuccessful is displayed in the login page itself in red.

      RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
      PrintWriter out= response.getWriter();
      out.println("Either user name or password is wrong.");
      rd.include(request, response);
      
    • Register the filter in WEB-INF/web.xml. Instead we can use annotations (javax.servlet.annotation.WebServlet) which was introduced in Servlet 3.0 to declare a servlet.

      @WebServlet("/LoginServlet")
      public class LoginServlet extends HttpServlet{
      } 
      

    2.2. LogoutServlet

    • What is needed to do here is
      HttpSession session = request.getSession(false);
      if(session != null){
      	session.invalidate();
      }
      
    • redirect user back to the login page

      response.sendRedirect("login.html");
      
    • Register the servlet using either web.xml file or annotations


    2.3. AuthenticationFilter

    Interestingly, If somebody directly accessed a web page without going through the login page, the user should not be granted access. In order to do that, we need to monitor every request that comes into the web application.

    This can be done using a Servlet filter.


    What is a servlet filter

    Servlet filters are pluggable Java components that we can use to intercept and process requests before they are sent to servlets and response after servlet code is finished and before the container sends the response back to the client. They also can be configured in the deployment descriptor (web.xml) file. There can be multiple filters for a single resource and a chain of filters can be created for a single resource in web.xml. The servlet filter is created by implementing javax.servlet.Filter interface.

    javax.servlet.annotation.WebFilter was introduced in Servlet 3.0 and this annotation is to declare a servlet filter. We can use this annotation to define init parameters, filter name and description, servlets, URL patterns and dispatcher types to apply the filter.

    Some common usages of servlet filters:

    • Logging request parameters to log files.
    • Authentication and authorization of request for resources.
    • Formatting of request body or header before sending it to servlet.
    • Compressing the response data sent to the client.
    • Alter response by adding some cookies, header information, etc.

    Applying a servlet filter for authentication is easy. Note that we need to exclude the requests that come into login.html or LoginServlet from this filter.

    if(session == null && !(uri.endsWith("html") || uri.endsWith("LoginServlet"))){
    	this.context.log("Unauthorized access request");
    	res.sendRedirect("login.html");
    }else{
    	// pass the request along the filter chain
    	chain.doFilter(request, response);
    }
    
    • Register the filter at web.xml file
      <filter>
      	<filter-name>AuthenticationFilter</filter-name>
      	<filter-class>org.wso2.sample.AuthenticationFilter</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>AuthenticationFilter</filter-name>
      	<url-pattern>/*</url-pattern>
      </filter-mapping>
      

    Now we have developed the backend of the authentication and also the front end. In order to make the web application look more interactive let us add one more thing.

  8. Something additional for front end to be more informative
  9. It is possible to display who the logged in user is when user is at landing page after a successful login. You can get the user using cookies at landingpage.jsp as following.

    Cookie[] cookies = request.getCookies();
    if(cookies !=null){
    	for(Cookie cookie : cookies){
    		if(cookie.getName().equals("user")) userName = (String) request.getSession(false).getAttribute("user");
    		if(cookie.getName().equals("JSESSIONID")) sessionID = cookie.getValue();
    	}
    }
    

    Now the content hierarchy of the web application should look like below.

    Figure 07

  10. Testing the login functionality
    • Start WSO2 Application Server and WSO2 Data Services Server as in the previous article of this series. WSO2 IS should also be running (AS offset=0, IS offset=1, DSS offset =2).
    • Export the modified web application as a .war file and upload to WSO2 AS.
    • After successful deployment access the URL of the web application. You will see the login page.

      Figure 08

    • Try logging in using a valid username and a password we have configured in the WSO2 IS server. You will be allowed to login.

      Figure 09

    • If you click on the logout button you will be logged out and redirected to the login page.
    • Try to login with a wrong password or using a user that is not registered with the IS server. You will see the error message in red.

      Figure 10

    • Log out and enter the following URL directly on the browser.



      You will be immediately redirected to the login page.

    • Try changing a password from the IS side, inserting a new user, etc.
  11. Adding authorization to the web aplication

    Access control in computer systems and networks rely on access policies. The access control process can be divided into the following two phases:

    1. Policy definition phase where access is authorized
    2. Policy enforcement phase where access requests are approved or disapproved

    Authorization is thus the function of the policy definition phase that precedes the policy enforcement phase where access requests are approved or disapproved based on the previously defined authorizations.


    XACML as declarative access control policy language

    XACML (eXtensible Access Control Markup Language) is one of the standards that defines a declarative access control policy language implemented in XML and a processing model describing how to evaluate access requests according to the rules defined in policies. XACML is primarily an attribute-based access control system (ABAC), where attributes (bits of data) associated with a user or action or resource are inputs into the decision of whether a given user may access a given resource in a particular way. Role-based access control (RBAC) can also be implemented in XACML as a specialization of ABAC2.

    This article describes how to use a XACML policy published in WSO2 IS to do a role-based access control. In the previous section, two roles were defined (read role and write role) and assigned to the users. Let us limit the search facility to the users having read role and adding new patients to the users having write role.

    The XACML policy will look like the attached file shown in the appendix with the above rules.

    Note the following on the XACML policy defined above.

    • Resource id: /WSO2HealthWebApplication/addPatient.jsp with action id : GET is conditioned by “write” role.
    • Resource id: /WSO2HealthWebApplication/(patientInfoPage|getPatientDetails).jsp with action id: GET is conditioned by “at least one of” write and read roles.


    Uploading and publishing XACML policy to WSO2 IS

    • Start the server and log into the management console
    • Navigate to Main >> EntitleMent >> PAP >> Policy Administration tab
    • Select policy type as “policy” and click on Add New Entitlement Policy
    • Figure 11

    • Select “Write Policy in XML” and copy paste the above policy there and save it.
    • Publish the policy clicking on “Publish to My PDP”.
    • Figure 12

    • Go to Main << EntitleMent << PDP << Policy View tab and enable the policy.

    Figure 13

    Now the policy we have defined is active in WSO2 IS3


    Modifying Web Application to communicate with IS

    Now the WSO2 Health Web Application need to be modified so that whenever a logged in user clicks on “”Search Patient Records” or “Register a new patient” link the policy published at WSO2 IS is evaluated and the permission is granted or rejected.

    • If permission granted search patient page or add new patient page will be displayed.
    • If permission not granted the user will be redirected to the login page.

    Interestly enough, WSO2 AS has a inbuilt filter named “EntitlementFilter” (org.wso2.carbon.identity.entitlement.filter.EntitlementFilter) that serves this functionality. Users do not need to write the filter code, instead this inbuilt filter can be declared in web.xml file and configured. At runtime this filter will be exposed to the web application, and the filtering will be done based on the permission given by the identity server4

    Please refer the web.xml file of the web application source attached to see how the configuration is done. Following are the highlighted points when configuring EntitlementFilter.

    To provide authorization for a user request for a web application, first you have to authenticate your user. For that we use Basic Authentication.




    Context parameters:

    The scope in which the subject would be available (how we pass the user to the filter) subjectScope request-param
    The name of the identifier by which to identify the subject subjectAttributeName user
    Username to perform EntitlementService query UserName admin
    Password to perform EntitlementService query password admin
    IS server url to send EntitlementService query remoteServiceUrl https://localhost:9444/services/



    EntitlementFilter initialization parameters:

    Client Class that extends AbstractEntitlementServiceClient client basicAuth
    URL to redirect to if authorization fails authRedirectUrl /login.html



    EntitlementCacheUpdateServlet initialization parameters:

    Authentication mode for cache update authentication wso2is
    HTTPS port of the web container used when redirecting request to come over https port for cache update authentication httpsPort 9453


    Filter mappings used to configure URLs that need to be authorized:

    • /getPatientDetails.jsp
    • /addPatient.jsp
    • /patientInfoPage.jsp

    With these configurations we have added role-based authorization for the web application. Next step is to build, deploy and test the functionality.


    Front-end modifications

    What we are securing with the XACML authorization is the links at landingPage.jsp. For the EntitlementFilter we gave the context parameters subjectScope=request-param and subjectAttributeName=user. Thus we need to pass the user as a request parameter.

    <a href="getPatientDetails.jsp?user=<%=userName%>">Search for patient records</a>
    <a href="addPatient.jsp?user=


    Testing XACML authorization

    • Build the web application using WSO2 Developer Studio and deploy it in WSO2 Application server (steps were discussed previously on the article series).
    • WSO2 DSS, WSO2 IS servers should also be running at the time of testing.
    • Login to the web application as “hasitha”. As it has read and write roles he would be able to search and also insert records.
    • Login to the web application as “Senaka”. If then clicked on “search patient details” it will not be allowed and you will be navigated to the login page.
    • If you try with the user “Shammi”, even though he is authenticated into the system, he can neither search nor insert records.


    Conclusion and possible improvements

    In this article, we discussed how to do authentication and authorization for a web application using WSO2 Identity Server. The authentication part was done validating the username and password. XACML is a standard way to do fine grain authorization with attributes of the users and the roles. The WSO2 middleware platform has management web console support for managing XACML policies and also integration with a web app was pretty straightforward with built-in filters. Going by the above example of a web application, readers would realize it is not very hard to design a web application that can create users, assign them roles, and grant permission to operations inside the web application depending on users’ roles and attributes.

    In the third and final part of this series, we bring in WSO2 Enterprise Service Bus to this solution.

    1. Proxy the data service using WSO2 ESB and handle security within ESB.
    2. Error handling with WSO2 ESB and displaying custom error messages to the user.


    References

    [1] https://blog.facilelogin.com/2010/05/managing-users-and-roles-with-wso2.html

    [2] https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xacml

    [3] https://wso2.com/library/articles/2013/11/fine-grained-xacml-authoriation-with-pip-points/

    [4] https://docs.wso2.com/display/AS521/Checking+the+Authorization+of+WebApp+Requests


    Appendix

    [1] https://wso2.com/files/EntitlementFilterPolicy.xml

    [2] https://wso2.com/files/How-to-write-a-web-apply-application-backed-by-wso2-middleware-02.zip

     

    About Author

    • Hasitha Abeykoon
    • Associate Technical Lead
    • WSO2