Understanding Security in Dekoh

Dekoh provides comprehensive security services for all your applications. In Dekoh, Security comprises of two main operations:
Authentication on Dekoh Network: This is the process of establishing whether the user is who they claim to be. A user can be generally an individual user, device or some other system which can perform an action in your application.

Authorization on Dekoh Desktop: This is the process of deciding whether the user must be allowed to perform an action in your application. To arrive at the point where an authorization decision is needed, the identity of the user has already been established by the authentication process.

Authentication

Typical Web Application Authentication Process

Consider a typical web application's authentication process:
  1. You visit the home page, and click on a link.
  2. A request goes to the server, and the server decides that you have asked for a protected resource.
  3. As you are not presently authenticated, the server sends back a response indicating that you must authenticate. The response will be either a HTTP response code, or a redirect to a particular web page.
  4. Depending on the authentication mechanism, your browser will redirect to the specific web page either so that you can fill out the form, or the browser will somehow retrieve your identity.
  5. The browser will then send back a response to the server. This will either be a HTTP POST containing the contents of the form that you filled out, or a HTTP header containing your authentication details.
  6. Next the server will decide whether or not the presented credentials are valid. If they're valid, the next step will happen. If they're invalid, usually your browser will be asked to try again (so you return to step two above).
  7. The original request that you made to cause the authentication process will be retried. Hopefully you've authenticated with sufficient granted authorities to access the protected resource. If you have sufficient access, the request will be successful. Otherwise, you'll receive back a HTTP error code 403, which means "forbidden".

Dekoh Authentication API (Local Requests)

Mapping the process above with Dekoh, we get the following scenario:
  1. You visit the Dekoh page. A request goes to the server, and if the server decides that you have asked for a protected resource, Dekoh serves a login page requesting for credentials.
  2. User tries to login to a Dekoh application using this Login Page
  3. The browser will then send back a response to the server. This will either be a HTTP POST containing the contents of the form that you filled out, or a HTTP header containing your authentication details.
  4. Based on the network connection, user credentials are either validated locally or using the Dekoh network using LoginManager APIs. If they're valid, server sets this session as authenticated and assigns a DesktopUser for this session.
  5. In case you are not, the server sends back a response indicating that you must authenticate. You will then be prompted for a username and password, and the Login API validates your session on the Dekoh Network.
  6. Any further requests to this session will carry the session information, from which server gets to know the autenticated user details.
  7. When you logout the session is invalidated and no further operations can be made. Any subsequent requests to protected resource, above cycle repeats.

Some Important Classes

Dekoh provides classes responsible for most of the steps described above. The main participant is LoginManager API, which helps validate credentials. Once the credentials are validated, LoginManager sets the authenticated session. For subsequent requests made on this session, you can use com.pramati.bfly.das.helper.SessionUtil. This retrieves the Desktop user currently logged into Dekoh (com.pramati.bfly.das.api.DesktopUser).
com.pramati.bfly.das.helper.SessionUtil
	* getLoggedInUser()
	* getLoggedInAccountId()
	* getLoggedInDesktopUser()
com.pramati.bfly.das.api.DesktopUser
	* getAccountId()
	* isRegistered()
	* getUsername()

Once you are logged into the Dekoh Network, when you make a request, you can find out the registered using sessionutil.getLoggedInDesktopUser(). This method returns an object called DesktopUser, with items such as UserName and AccountID.

Logging into any application (Portal or Non-Portal) using Dekoh API, will get you authenticated to all applications on Dekoh.

Portal Applications

To develop applications that enable more intrusive collaboration, wherein most of the functionality can be built into the applications itself, you will need Dekoh portal framework.

When developing applications on top of Dekoh Portal framework, you can enable authentication by simply setting up the portal login filter, HttpServletFilter implementation (dekoh.portal.login.PortalLoginFilter).

Use the following snippets of code inside your portal application’s web.xml file:

<filter>
        <filter-name>LoginFilter</filter-name>
        <filter-class>dekoh.portal.login.PortalLoginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

The LoginFilter marks all application that match the URL pattern (/*),as secure and redirect them to the login page for authentication before enabling them to access the application page. This enables you to perform all authentication for a single user for that particular session, without writing any extra code in your application.

Example:
When you request myapp/index.jsp which is a protected resource (i.e filter applied for this url), the filter sees that no user is authenticated, and then redirect you to the login page. On success, LoginManager marks this session as authenticated, and redirects back to myapp/index.jsp page. Now as session is authenticated, filter again sees this requests as protected but also sees it as authenticated and forwards to the target page. Inside the index.jsp page, you can call the sessionutil.getLoggedInDesktopUser() to get the current logged in desktop user and do any authorization checks if needed.

Note: To know more about setting up authenticated access, read the “Setting Up Authenticated Access” seciton in the Portal Reference Document.

Non-Portal Applications

To develop applications wherein all of the functionality is built into the applications, with very little collaboration, you can build non-portal applications. When developing non-portal applications on Dekoh, you need to perform a few additional steps to authenticate your application, when compared to portal applications.
  1. First checks whether the user request is for a protected resource, and if it is then also check whether the session is authenticated using SessionUtil.getLoggedInDesktopUser().
  2. If the session is not authenticated, use LoginManager.getLoginURL(HttpServletRequest request, String targetUrl) to retrieve the Login URL and transferrs the control to a different webpage (returned value) using sendRedirect.
  3. After successfully logging in and validating the session, Dekoh redirects the user to the “targetUrl” specified in getLoginURL method.
  4. The filter also redirects the user to the target page for all requests made subsequently.
  5. Using the above methods enables you to perform all authentication for a single user for the specifc session.

Sample Login Filter
/*
 * Copyright (c) 2007 Pramati Technologies Private Ltd. All Rights Reserved.
 *
 * This software is the confidential and proprietary information of Pramati
 * Technologies. You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the source code
 * license agreement you entered into with Pramati Technologies.
 *
 */
package dekoh.portal.login;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.pramati.bfly.das.api.LoginManager;
import com.pramati.bfly.das.helper.SessionUtil;
public class SampleFilter
        implements Filter
{
    public void init(FilterConfig filterConfig) throws ServletException
    {
    }
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException
    {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        boolean authenticated;
        try {
            authenticated = SessionUtil.getLoggedInDesktopUser(request) != null;
        } catch (RuntimeException ia) {
            authenticated = false;
        }
        if (authenticated || !isProtectedRequest(request)) {
            filterChain.doFilter(request, response);
        } else {
            /* If should target url is the one for which request is made. if user needs some other url as target use:
               String loginURL = LoginManager.getLoginURL(request, "targetUrl");*/
            String loginURL = LoginManager.getLoginURL(request);
            response.sendRedirect(loginURL);
        }
    }
    /**
     * To check whether given request is a protected request which an authenticated user can only access.
     * <p/>
     * Users should implement this method according to ther needs.
     *
     * @param request
     * @return true, if request uri needs authnetication to be done. else would reurn false.
     */
    private boolean isProtectedRequest(HttpServletRequest request)
    {
        return true;
    }
    public void destroy()
    {
    }
}

Authorization

As mentioned previously, once the user is authenticated on the Dekoh Network, they must also be authorized to perform specific actions in the application. To arrive at the point where an authorization decision is needed, the identity of the user has already been established by the authentication process.

Authorization requires the Dekoh Desktop to first find out whether the request is originating from a local network (Dekoh Desktop) or remote network. To know whether a requests is local or remote use DekohNetworkRequestHelper.isRemoteRequest().

Local Request

Local Requests are requests which are made to a Dekoh desktop directly. Example of a local request is a Dekoh owner adding, or editing content into his Dekoh application.

Use the sessionUtil.getLoggedinUser() method to get the user id associated with the current session (currently logged-in user). This value is stored for the duration of the session..

Remote Requests

Remote requests are requests made for files/applications on the Dekoh network from a third machine. A contact accessing shared content from your Dekoh application is an example of a remote request.

Use the method, DekohNetworkRequestHelper.isRemoteRequest() to check whether an incoming request is being invoked from a remote or local network.

Use getIncomingUserAliases() to get a list of contacts representing all the aliases of the incoming remote request user. This is especially useful in scenarios where one Dekoh user may have multiple user accounts and links all accounts.

Use getIncomingUser() to filter out the aliases returned by getIncomingUserAliases and return the most appropriate match from the supplied “allAllowedContacts”.

Example on how to check whether incoming is authorized to access a resource for both remote and local:

Use a filter similar to the below code to check whether an incoming request user is the authorized user. Apply this filter for resources that need authorization check (both local and remote requests).

/*
 * Copyright (c) 2007 Pramati Technologies Private Ltd. All Rights Reserved.
 *
 * This software is the confidential and proprietary information of Pramati
 * Technologies. You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the source code
 * license agreement you entered into with Pramati Technologies.
 *
 */
package dekoh.portal.login;
import java.io.IOException;
import java.util.Set;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.pramati.bfly.das.api.DesktopUser;
import com.pramati.bfly.das.contacts.helper.DekohNetworkRequestHelper;
import com.pramati.bfly.das.contacts.persistence.Contact;
import com.pramati.bfly.das.helper.SessionUtil;
public class AuthorizeFilter
        implements Filter
{
    public void init(FilterConfig filterConfig) throws ServletException
    {
    }
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException
    {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        boolean isRemote = DekohNetworkRequestHelper.isRemoteRequest(request);
        if (!isRemote) {
            DesktopUser user = SessionUtil.getLoggedInDesktopUser(request);
            if (isUserAuthorizedForLocal(user, "targetUserName")) {
                chain.doFilter(request, response);
            } else {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "unauthorize user");
            }
        } else {
            Set<Contact> contacts = DekohNetworkRequestHelper.getIncomingUserAliases(request);
            if (isUserAuthorizedForRemote(contacts, "targetUserName")) {
                chain.doFilter(request, response);
            } else {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "unauthorize user");
            }
        }
    }
    /**
     * To check whether the authenticated user has permission to access a request.
     *
     * @param authenticatedUser User who is authenticated and stored on the session during authentication process.
     * @param authorizedUser    Target user, who has the permission to access a resource.
     * @return true, if authenticated user is the authorizedUser, else will return false.
     */
    private boolean isUserAuthorizedForLocal(DesktopUser authenticatedUser, String authorizedUser)
    {
        return authenticatedUser != null && authenticatedUser.getUsername().equalsIgnoreCase(authorizedUser);
    }

    private boolean isUserAuthorizedForRemote(Set<Contact> contacts, String authorizedUser)
    {
        for (Contact contact : contacts) {
            if (contact.getContactIdName().equalsIgnoreCase(authorizedUser)) {
                return true;
            }
        }
        return false;
    }
    public void destroy()
    {
    }
}