com.fbr.services.SecurityService.java Source code

Java tutorial

Introduction

Here is the source code for com.fbr.services.SecurityService.java

Source

package com.fbr.services;

/*
 *  ***********************************************************
 *   Copyright (c) 2013 VMware, Inc.  All rights reserved.
 *  ***********************************************************
 */

import com.fbr.Constants.ResourceType;
import com.fbr.Dao.SQL.Authorization.AuthorizationMappingDao;
import com.fbr.Dao.SQL.Authorization.Entities.AuthorizationMappingDbType;
import com.fbr.Dao.SQL.License.Entities.RoleType;
import com.fbr.Dao.SQL.License.Entities.UserDbType;
import com.fbr.Dao.SQL.License.UserDao;
import com.fbr.Dao.SQL.Security.Entities.SessionDbType;
import com.fbr.Dao.SQL.Security.SessionDao;
import com.fbr.RestException.CustomExceptions.AuthorizationException;
import com.fbr.RestException.CustomExceptions.BadRequestException;
import com.fbr.RestException.CustomExceptions.RestException;
import com.fbr.RestException.ErrorCode;
import com.fbr.RestException.ErrorType;
import com.fbr.Utilities.LoggerUtil;
import com.fbr.domain.Security.LoginResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MultiValueMap;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
import java.util.Map.Entry;

@Service
public class SecurityService {

    @Autowired
    UserService userService;

    @Autowired
    SessionDao sessionDao;

    @Autowired
    UserDao userDao;

    @Autowired
    LicenseService licenseService;

    @Autowired
    AuthorizationMappingDao authorizationMappingDao;

    @Value("${session.idle_timeout:30}")
    private int idle_session_timeout;

    private static final Logger logger = Logger.getLogger(SecurityService.class);

    private static final String[] LOGIN_EXCEPTION_VALUES = new String[] { "/feedback-review/login",
            "/feedback-review/license/register", "/feedback-review/contactUs" };
    private static final Set<String> LOGIN_EXCEPTION_URIS = new HashSet<String>(
            Arrays.asList(LOGIN_EXCEPTION_VALUES));

    @Transactional
    public HttpStatus checkAuthenticationAndAuthorization(HttpServletRequest httpRequest) {

        logger.debug("Request uri is {}" + httpRequest.getRequestURI());
        if (!LOGIN_EXCEPTION_URIS.contains(httpRequest.getRequestURI())) {

            String sessionId = httpRequest.getHeader("sessionId");
            Enumeration<String> headers = httpRequest.getHeaderNames();
            if (headers != null) {
                logger.debug("Headers are");
                while (headers.hasMoreElements()) {
                    logger.debug(headers.nextElement());
                }
            }
            if (sessionId != null) {
                Date idleExpirationDate = DateUtils.addMinutes(new Date(), -idle_session_timeout);
                SessionDbType sessionDbType = sessionDao.validateSessionId(sessionId, idleExpirationDate);
                if (sessionDbType == null) {
                    logger.debug("Session " + sessionId + " was not found in the database");
                    return HttpStatus.UNAUTHORIZED;
                }
                logger.debug("Session " + sessionId + " is validated");
                sessionDbType.setLastAccessTime(new Date());
                sessionDao.update(sessionDbType);
                if (!isAuthorizedForApi(httpRequest.getMethod(), httpRequest.getRequestURI(),
                        httpRequest.getQueryString(), sessionDbType)) {
                    logger.debug(httpRequest.getMethod() + " on " + httpRequest.getRequestURI()
                            + " for this user is not authorized");
                    return HttpStatus.FORBIDDEN;
                }

                logger.debug("Session " + sessionId + "is Authorized");

            } else {
                logger.debug("sessionId was not found in the header");
                return HttpStatus.UNAUTHORIZED;
            }

        }
        return HttpStatus.OK;
    }

    public UserDbType getUserDbType(String sessionId) {
        try {
            if (!StringUtils.isBlank(sessionId)) {
                return sessionDao.getUserDbType(sessionId);
            }
            throw new AuthorizationException("session id is empty or not given");
        } catch (Exception e) {
            logger.debug(LoggerUtil.getStackTrace(e));
            throw new AuthorizationException("session id is wrong");
        }
    }

    @Transactional
    public String createLogin(final MultiValueMap<String, String> credentials, LoginResponse loginResponse) {
        UserDbType userDbType = null;
        String password = "";
        UUID uuid = null;
        boolean isAppUser = false;
        final Map<String, String> credentialsMap = credentials.toSingleValueMap();
        for (Entry<String, String> nameValuePair : credentialsMap.entrySet()) {
            if (nameValuePair.getKey().equals("username")) {
                logger.debug("Username given is {0}" + nameValuePair.getValue());
                userDbType = userService.findUserName(nameValuePair.getValue());
            } else if (nameValuePair.getKey().equals("password")) {
                logger.debug("password given is {0}" + nameValuePair.getValue());
                password = nameValuePair.getValue();
            } else if (nameValuePair.getKey().equals("uuid")) {
                logger.debug("uuid given is {0}" + nameValuePair.getValue());
                uuid = UUID.fromString(nameValuePair.getValue());
                isAppUser = true;
            }
        }
        if (isAppUser) {
            userDbType = licenseService.validateUUID(uuid);
            logger.debug("uuid " + uuid + " validated");
        } else {
            userService.validatePassword(userDbType, password);

            logger.debug("password is validated");
        }
        int companyId = userDbType.getCompanyDbType().getCompanyId();
        loginResponse.setCompanyId(companyId);
        loginResponse.setRole(userDbType.getRole());

        SessionDbType sessionDbType = new SessionDbType();
        Date now = new Date();
        sessionDbType.setCreationTime(now);
        sessionDbType.setLastAccessTime(now);
        sessionDbType.setUserDbType(userDbType);
        sessionDao.add(sessionDbType);

        return sessionDbType.getId();
    }

    @Transactional
    public void deleteLogin(String sessionId) {

        if (StringUtils.isEmpty(sessionId)) {
            throw new AuthorizationException("sessionId could not be found");
        }
        logger.debug("session id given is {0}" + sessionId);
        if (sessionDao.delete(sessionId) == 1) {
            logger.debug("Session id " + sessionId + " is successfully deleted");
        }
    }

    private boolean isUriTokenMatch(UserDbType userDbType, String uriToken, String givenUriToken,
            String beforeToken) {
        if (StringUtils.equalsIgnoreCase(uriToken, givenUriToken)) {
            return true;
        }

        if (uriToken.startsWith("{") && uriToken.endsWith("}")) {
            if (beforeToken != null && beforeToken.equalsIgnoreCase("company")) {
                return userService.validateCompanyId(userDbType, Integer.parseInt(givenUriToken));
            } else if (beforeToken != null && beforeToken.equalsIgnoreCase("branch")) {
                return userService.validateBranchId(userDbType, Integer.parseInt(givenUriToken));
            }
            logger.debug("Escaping the placeholder");
            return true;

        }
        return false;
    }

    private String findPath(String uri) {
        String uris[] = uri.split("\\?");
        uri = uris[0];
        uri = uri.concat("/");
        uri = "/".concat(uri);
        uri = uri.replaceAll("/+", "/");
        return uri;
    }

    private void printStrings(String[] strings) {
        logger.debug("Tokens =====");
        for (String str : strings) {
            logger.debug("Token - " + str);
        }
    }

    private boolean isPathMatch(UserDbType userDbType, String uri, String givenUri) {

        logger.debug("stored uri path is " + uri);
        logger.debug("given uri path is " + givenUri);

        String[] uriTokens = uri.split("/");
        String[] givenUriTokens = givenUri.split("/");

        String beforeToken = null;

        if ((uriTokens.length + 1) != givenUriTokens.length) {
            logger.debug("Tokens lengths did not match");
            return false;
        }

        if (givenUriTokens.length == 0) {
            return false;
        }

        int i = 1, j = 2; // uri in the database does not consist of 'feedback-review'

        for (; i < uriTokens.length; i++, j++) {
            if (!isUriTokenMatch(userDbType, uriTokens[i], givenUriTokens[j], beforeToken)) {
                logger.debug("Tokens -" + uriTokens[i] + "," + givenUriTokens[j] + "- did not match");
                return false;
            } else {
                beforeToken = uriTokens[i];
            }
        }

        if (i == uriTokens.length && j == givenUriTokens.length) {
            return true;
        }

        return false;

    }

    public Map<String, String> splitQuery(String queryString) throws UnsupportedEncodingException {
        final Map<String, String> query_pairs = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
        final String[] pairs = queryString.split("&");
        for (String pair : pairs) {
            final int idx = pair.indexOf("=");
            final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair;
            final String value = idx > 0 && pair.length() > idx + 1
                    ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8")
                    : null;
            query_pairs.put(key, value);
        }
        return query_pairs;
    }

    private boolean isQueryStringMatch(UserDbType userDbType, int roleType, String queryString,
            String givenQueryString) {
        Map<String, String> queryStringMap = null;
        Map<String, String> givenQueryStringMap = null;

        logger.debug("query string - " + queryString);
        logger.debug("given query string - " + givenQueryString);
        try {
            queryStringMap = splitQuery(queryString);
            givenQueryStringMap = splitQuery(givenQueryString);
        } catch (Exception e) {
            throw new BadRequestException(e.getMessage());
        }

        if (queryStringMap.get("branch") != null) {
            String branchId = givenQueryStringMap.get("branch");
            logger.debug("branchId is - " + branchId);

            if (branchId == null && !userService.validateRole(roleType, RoleType.CompanyOwner)) {

                throw new RestException(new ErrorType(ResourceType.USER, ErrorCode.INVALID_ROLE,
                        "This user " + " Can not perform this action"));
            }
            int branchIdInt = Integer.parseInt(branchId);
            return userService.validateBranchId(userDbType, branchIdInt);
        }
        return false;

    }

    private boolean isUriMatch(UserDbType userDbType, int roleType, String uri, String givenUri,
            String givenQueryString) {

        String uriPath = findPath(uri);
        String givenUriPath = findPath(givenUri);

        if (!isPathMatch(userDbType, uriPath, givenUriPath)) {
            logger.debug("Path authorization failed");
            return false;
        }

        String[] queryStrings = uri.split("\\?");
        if (queryStrings.length == 2 && roleType == RoleType.BranchManager.getRoleValue()) {
            if (!isQueryStringMatch(userDbType, roleType, queryStrings[1], givenQueryString)) {
                logger.debug("Query string authorization failed");
                return false;
            }
        }

        return true;
    }

    public boolean isAuthorizedForApi(String method, String uri, String queryString, SessionDbType sessionDbType) {

        UserDbType userDbType = sessionDbType.getUserDbType();
        int roleType = userDbType.getRole();
        logger.debug("User name for the session id given is " + userDbType.getUsername());
        logger.debug("Password for the session id given is " + userDbType.getPassword());

        List<AuthorizationMappingDbType> authorizationMappingDbTypeList = authorizationMappingDao.findAll();
        String userName = userDbType.getUsername();
        logger.debug("Role of the user - " + userName + " is - " + roleType);
        for (AuthorizationMappingDbType authorizationMappingDbType : authorizationMappingDbTypeList) {
            if (method.equalsIgnoreCase(authorizationMappingDbType.getMethod())
                    && isUriMatch(userDbType, roleType, authorizationMappingDbType.getUri(), uri, queryString)) {

                if (userService.validateRole(roleType, authorizationMappingDbType.getRoleType())) {
                    return true;
                }
            }
        }

        return false;
    }
}