org.itracker.web.util.LoginUtilities.java Source code

Java tutorial

Introduction

Here is the source code for org.itracker.web.util.LoginUtilities.java

Source

/*
 * This software was designed and created by Jason Carroll.
 * Copyright (c) 2002, 2003, 2004 Jason Carroll.
 * The author can be reached at jcarroll@cowsultants.com
 * ITracker website: http://www.cowsultants.com
 * ITracker forums: http://www.cowsultants.com/phpBB/index.php
 *
 * This program is free software; you can redistribute it and/or modify
 * it only under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

package org.itracker.web.util;

import org.itracker.core.AuthenticationConstants;
import org.itracker.core.resources.ITrackerResources;
import org.itracker.model.*;
import org.itracker.model.util.UserUtilities;
import org.itracker.services.UserService;
import org.itracker.services.authentication.ITrackerUserDetails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.security.Principal;
import java.util.*;

public class LoginUtilities {

    private static final Logger logger = LoggerFactory.getLogger(LoginUtilities.class);
    private static final int DEFAULT_SESSION_TIMEOUT = 30;

    public static boolean checkAutoLogin(HttpServletRequest request, boolean allowSaveLogin) {
        boolean foundLogin = false;

        if (request != null) {
            int authType = getRequestAuthType(request);

            // Check for auto login in request
            if (authType == AuthenticationConstants.AUTH_TYPE_REQUEST) {
                String redirectURL = request.getRequestURI().substring(request.getContextPath().length())
                        + (request.getQueryString() != null ? "?" + request.getQueryString() : "");
                request.setAttribute(Constants.AUTH_TYPE_KEY, AuthenticationConstants.AUTH_TYPE_REQUEST);
                request.setAttribute(Constants.AUTH_REDIRECT_KEY, redirectURL);
                request.setAttribute("processLogin", "true");
                foundLogin = true;

            }

            // Add in check for client certs

            // Check for auto login with cookies, this will only happen if users
            // are allowed to save
            // their logins to cookies
            if (allowSaveLogin && !foundLogin) {
                Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                    for (Cookie cookie : cookies) {
                        if (Constants.COOKIE_NAME.equals(cookie.getName())) {
                            int seperator = cookie.getValue().indexOf('~');
                            final String login;
                            if (seperator > 0) {
                                login = cookie.getValue().substring(0, seperator);
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Attempting autologin for user " + login + ".");
                                }

                                String redirectURL = request.getRequestURI()
                                        .substring(request.getContextPath().length())
                                        + (request.getQueryString() != null ? "?" + request.getQueryString() : "");
                                request.setAttribute(Constants.AUTH_LOGIN_KEY,
                                        cookie.getValue().substring(0, seperator));
                                request.setAttribute(Constants.AUTH_TYPE_KEY,
                                        AuthenticationConstants.AUTH_TYPE_PASSWORD_ENC);

                                request.setAttribute(Constants.AUTH_VALUE_KEY,
                                        cookie.getValue().substring(seperator + 1));
                                request.setAttribute(Constants.AUTH_REDIRECT_KEY, redirectURL);
                                request.setAttribute("processLogin", "true");
                                foundLogin = true;
                            }
                        }
                    }
                }
            }

        }

        return foundLogin;
    }

    public static int getRequestAuthType(HttpServletRequest request) {
        int authType = AuthenticationConstants.AUTH_TYPE_UNKNOWN;

        try {
            if (request.getAttribute(Constants.AUTH_TYPE_KEY) != null) {
                authType = (Integer) request.getAttribute(Constants.AUTH_TYPE_KEY);
            }
            if (request.getParameter(Constants.AUTH_TYPE_KEY) != null) {
                authType = Integer.valueOf(request.getParameter(Constants.AUTH_TYPE_KEY));
            }
        } catch (Exception e) {
            logger.debug("Error retrieving auth type while checking auto login.  " + e.getMessage());
        }

        return authType;
    }

    /**
     * Get a locale from request
     * <p/>
     * <p>
     * TODO the order of retrieving locale from request should be:
     * <ol>
     * <li>request-attribute Constants.LOCALE_KEY</li>
     * <li>request-param 'loc'</li>
     * <li>session attribute <code>Constants.LOCALE_KEY</code></li>
     * <li>cookie 'loc'</li>
     * <li>request.getLocale()/request.getLocales()</li>
     * <li>ITrackerResources.DEFAULT_LOCALE</li>
     * </ol>
     * </p>
     */
    @SuppressWarnings("unchecked")
    public static Locale getCurrentLocale(HttpServletRequest request) {
        Locale requestLocale = null;
        HttpSession session = request.getSession(true);
        try {

            requestLocale = (Locale) request.getAttribute(Constants.LOCALE_KEY);

            if (logger.isDebugEnabled()) {
                logger.debug("getCurrentLocale: request-attribute was {}", requestLocale);
            }

            if (null == requestLocale) {
                // get locale from request param
                String loc = request.getParameter("loc");
                if (null != loc && loc.trim().length() > 1) {
                    requestLocale = ITrackerResources.getLocale(loc);
                }

                logger.debug("getCurrentLocale: request-parameter was {}", loc);

            }

            if (null == requestLocale) {
                // get it from the session
                requestLocale = (Locale) session.getAttribute(Constants.LOCALE_KEY);
                //            if (logger.isDebugEnabled()) {
                //               logger.debug("getCurrentLocale: session-attribute was "
                //                     + requestLocale);
                //            }
            }

            if (null == requestLocale) {
                ResourceBundle bundle = ITrackerResources.getBundle(request.getLocale());
                if (logger.isDebugEnabled()) {
                    logger.debug("getCurrentLocale: trying request header locale " + request.getLocale());
                }
                if (bundle.getLocale().getLanguage().equals(request.getLocale().getLanguage())) {
                    requestLocale = request.getLocale();
                    if (logger.isDebugEnabled()) {
                        logger.debug("getCurrentLocale: request-locale was " + requestLocale);
                    }
                }
            }

            // is there no way to detect supported locales of current
            // installation?

            if (null == requestLocale) {
                Enumeration<Locale> locales = (Enumeration<Locale>) request.getLocales();
                ResourceBundle bundle;
                Locale locale;
                while (locales.hasMoreElements()) {
                    locale = locales.nextElement();
                    bundle = ITrackerResources.getBundle(locale);

                    logger.debug("getCurrentLocale: request-locales processing {}, bundle: {}", locale, bundle);

                    if (bundle.getLocale().getLanguage().equals(locale.getLanguage())) {
                        requestLocale = locale;

                        logger.debug("getCurrentLocale: request-locales locale was {}", requestLocale);

                    }
                }
            }

        } finally {
            if (null == requestLocale) {
                // fall back to default locale
                requestLocale = ITrackerResources.getLocale();

                logger.debug("getCurrentLocale: fallback default locale was {}", requestLocale);

            }
            session.setAttribute(Constants.LOCALE_KEY, requestLocale);
            request.setAttribute(Constants.LOCALE_KEY, requestLocale);
            request.setAttribute("currLocale", requestLocale);

            logger.debug("getCurrentLocale: request and session was setup with {}", requestLocale);

        }

        return requestLocale;
    }

    /**
     * get current user from request-attribute currUser, if not set from request-session
     *
     * @return current user or null if unauthenticated
     * @throws NullPointerException if the request was null
     */
    @Deprecated
    public static User getCurrentUser(HttpServletRequest request) {

        final String remoteUser = request.getRemoteUser();
        if (null == remoteUser) {
            return null;
        }
        User currUser = (User) request.getAttribute("currUser");
        if (null != currUser && currUser.getLogin().equals(remoteUser)) {
            if (logger.isDebugEnabled()) {
                logger.debug("found user in request: " + remoteUser);
            }
        }
        if (null == currUser) {
            currUser = (User) request.getSession().getAttribute("currUser");
            if (null != currUser && currUser.getLogin().equals(remoteUser)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("found user in session: " + remoteUser);
                }
            }
        }
        if (null == currUser) {
            currUser = ServletContextUtils.getItrackerServices().getUserService().getUserByLogin(remoteUser);
            if (null != currUser && currUser.getLogin().equals(remoteUser)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("found user by login: " + remoteUser);
                }
            }
        }

        return currUser;
    }

    /**
     * Utility for accessing the current logged in user's principal
     * @return current user principal
     */
    public static ITrackerUserDetails getPrincipal() {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal instanceof ITrackerUserDetails) {
            return (ITrackerUserDetails) principal;
        }

        return null;
    }

    public static Boolean allowSaveLogin(HttpServletRequest request) {
        return (boolean) request.getAttribute("allowSaveLogin");
    }

    public static User setupSession(String login, HttpServletRequest request, HttpServletResponse response) {
        if (null == login) {
            logger.warn("setupSession: null login", (logger.isDebugEnabled() ? new RuntimeException() : null));
            throw new IllegalArgumentException("null login");
        }
        UserService userService = ServletContextUtils.getItrackerServices().getUserService();
        User user = userService.getUserByLogin(login);
        if (user != null) {
            String encPassword = null;
            Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    if (Constants.COOKIE_NAME.equals(cookie.getName())) {
                        int seperator = cookie.getValue().indexOf('~');
                        if (seperator > 0) {
                            encPassword = cookie.getValue().substring(seperator + 1);
                        }
                    }
                }
            }

            return setupSession(user, encPassword, request, response);
        }
        return null;
    }

    public static User setupSession(User user, String encPassword, HttpServletRequest request,
            HttpServletResponse response) {
        if (user == null) {
            logger.warn("setupSession: null user", (logger.isDebugEnabled() ? new RuntimeException() : null));
            throw new IllegalArgumentException("null user");
        }

        UserService userService = ServletContextUtils.getItrackerServices().getUserService();

        if (logger.isDebugEnabled()) {
            logger.debug("Creating new session");
        }
        HttpSession session = request.getSession(true);

        if (logger.isDebugEnabled()) {
            logger.debug("Setting session timeout to " + getConfiguredSessionTimeout() + " minutes");
        }
        session.setMaxInactiveInterval(getConfiguredSessionTimeout() * 60);

        if (logger.isDebugEnabled()) {
            logger.debug("Setting session tracker");
        }
        session.setAttribute(Constants.SESSION_TRACKER_KEY, new SessionTracker(user.getLogin(), session.getId()));

        if (logger.isDebugEnabled()) {
            logger.debug("Setting user information");
        }
        session.setAttribute(Constants.USER_KEY, user);

        if (logger.isDebugEnabled()) {
            logger.debug("Setting preferences for user " + user.getLogin());
        }
        UserPreferences userPrefs = user.getPreferences();
        // TODO : this is a hack, remove when possible
        if (userPrefs == null) {
            logger.warn("setupSession: got user with no preferences!: " + user + " (prefs: " + user.getPreferences()
                    + ")");
            userPrefs = new UserPreferences();
        }
        session.setAttribute(Constants.PREFERENCES_KEY, userPrefs);

        if (logger.isDebugEnabled()) {
            logger.debug("Setting user " + user + " locale to "
                    + ITrackerResources.getLocale(userPrefs.getUserLocale()));
        }
        session.setAttribute(Constants.LOCALE_KEY, ITrackerResources.getLocale(userPrefs.getUserLocale()));

        // TODO: cookie could be removed
        Cookie cookie = new Cookie(Constants.COOKIE_NAME, "");
        cookie.setPath(request.getContextPath());

        cookie.setValue("");
        cookie.setMaxAge(0);

        response.addCookie(cookie);

        if (logger.isDebugEnabled()) {
            logger.debug("Setting permissions for user " + user.getLogin());
        }
        Map<Integer, Set<PermissionType>> usersMapOfProjectIdsAndSetOfPermissionTypes = userService
                .getUsersMapOfProjectIdsAndSetOfPermissionTypes(user, AuthenticationConstants.REQ_SOURCE_WEB);
        session.setAttribute(Constants.PERMISSIONS_KEY, usersMapOfProjectIdsAndSetOfPermissionTypes);

        // Reset some session forms
        session.setAttribute(Constants.SEARCH_QUERY_KEY, null);

        SessionManager.clearSessionNeedsReset(user.getLogin());
        if (logger.isDebugEnabled()) {
            logger.debug("User session data updated.");
        }
        return user;
    }

    public static int getConfiguredSessionTimeout() {
        return (ServletContextUtils.getItrackerServices().getConfigurationService()
                .getIntegerProperty("web_session_timeout", DEFAULT_SESSION_TIMEOUT));
    }

    @Deprecated
    public static boolean hasPermission(int permissionNeeded, HttpServletRequest request,
            HttpServletResponse response) throws IOException, ServletException {
        return hasPermission(PermissionType.valueOf(permissionNeeded), request, response);
    }

    public static boolean hasPermission(PermissionType permissionNeeded, HttpServletRequest request,
            HttpServletResponse response) throws IOException, ServletException {

        return hasPermission(new PermissionType[] { permissionNeeded }, request, response);

    }

    @Deprecated
    public static boolean hasPermission(PermissionType[] permissionsNeeded, HttpServletRequest request,
            HttpServletResponse response) throws IOException, ServletException {
        try {
            UserDetails user = LoginUtilities.getPrincipal();

            HttpSession session = request.getSession(false);
            Map<Integer, Set<PermissionType>> permissions = (session == null) ? null
                    : RequestHelper.getUserPermissions(session);
            return UserUtilities.hasPermission(permissions, permissionsNeeded);
        } catch (RuntimeException re) {
            logger.debug("hasPermission: failed to check permission", re);
            return false;
        }
    }

    /**
     * Returns true if the user has any of required permissions for the project.
     */
    public static boolean hasAnyPermission(Project project, PermissionType[] permissionsNeeded) {

        if (null == permissionsNeeded || permissionsNeeded.length == 0) {
            permissionsNeeded = PermissionType.values();
        }
        for (PermissionType permissionType : permissionsNeeded) {
            if (hasPermission(project, permissionType)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns true if the user has all of required permissions for the project.
     */
    public static boolean hasPermission(Project project, PermissionType[] permissionsNeeded) {

        for (PermissionType permissionType : permissionsNeeded) {
            if (!hasPermission(project, permissionType)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Returns true if the user has all the required permissions.
     *
     * @param permissionNeeded the permission to check for
     */
    public static boolean hasPermission(PermissionType permissionNeeded) {
        return hasPermission(null, permissionNeeded);
    }

    /**
     * Returns true if the user has the required permission for the given project.
     *
     * @param project project to which permission is checked for
     * @param permissionNeeded the permission to check for
     */
    public static boolean hasPermission(Project project, PermissionType permissionNeeded) {
        UserDetails user = getPrincipal();
        if (null == user) {
            return false;
        }
        if (permissionNeeded != PermissionType.USER_ADMIN && hasPermission(PermissionType.USER_ADMIN)) {
            return true;
        } else if (null != project && permissionNeeded != PermissionType.PRODUCT_ADMIN
                && hasPermission(project, PermissionType.PRODUCT_ADMIN)) {
            return true;
        }
        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
        String permissionName = permissionNeeded.name(project);
        for (GrantedAuthority authority : authorities) {
            if (authority.getAuthority().equals(permissionName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns true if the user has permission to view the requested issue.
     *
     * @param issue       an IssueModel of the issue to check view permission for
     */
    public static boolean canViewIssue(Issue issue) {
        return canViewIssue(issue, getPrincipal());
    }

    /**
     * Returns true if the user has permission to view the requested issue.
     *
     * @param issue       an IssueModel of the issue to check view permission for
     * @param user        the user principal of the user to check permission for
     */
    public static boolean canViewIssue(Issue issue, UserDetails user) {
        if (hasAnyPermission(issue.getProject(),
                new PermissionType[] { PermissionType.PRODUCT_ADMIN, PermissionType.ISSUE_VIEW_ALL })) {
            return true;
        }

        // TODO option on project that all users can view own issues
        boolean canViewUsers = true;// hasPermission(issue.getProject(), PermissionType.ISSUE_VIEW_USERS);

        // I think owner & creator should always be able to view the issue
        // otherwise it makes no sense of creating the issue itself.
        // So put these checks before checking permissions for the whole project.
        if (canViewUsers && issue.getCreator().getLogin().equals(user.getUsername())) {
            if (logger.isInfoEnabled()) {
                logger.info("canViewIssue: issue: " + issue + ", user: " + user.getUsername()
                        + ", permission: is creator");
            }
            return true;
        }

        if (canViewUsers && issue.getOwner() != null) {
            if (issue.getOwner().getLogin().equals(user.getUsername())) {

                if (logger.isInfoEnabled()) {
                    logger.info("canViewIssue: issue: " + issue + ", user: " + user.getUsername()
                            + ", permission: is owner");
                }
                return true;
            }
        }
        return false;
    }

    public static boolean canEditIssue(Issue issue) {
        return canEditIssue(issue, getPrincipal());
    }

    public static boolean canEditIssue(Issue issue, UserDetails user) {
        if (issue == null) {
            return false;
        }

        if (hasAnyPermission(issue.getProject(), new PermissionType[] { PermissionType.ISSUE_EDIT_ALL })) {
            return true;
        }

        if (!hasPermission(issue.getProject(), PermissionType.ISSUE_EDIT_USERS)) {
            if (logger.isDebugEnabled()) {
                logger.debug("canEditIssue: user " + user.getUsername() + " has not permission  to edit issue "
                        + issue.getId() + ":" + PermissionType.ISSUE_EDIT_USERS);
            }
            return false;
        }

        if (issue.getCreator().getLogin().equals(user.getUsername())) {
            if (logger.isDebugEnabled()) {
                logger.debug("canEditIssue: user " + user.getUsername() + " is creator of issue " + issue.getId());
            }
            return true;
        }
        if (issue.getOwner() != null) {
            if (issue.getOwner().getLogin().equals(user.getUsername())) {
                if (logger.isDebugEnabled()) {
                    logger.debug(
                            "canEditIssue: user " + user.getUsername() + " is owner of issue " + issue.getId());
                }
                return true;
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug("canEditIssue: user " + user.getUsername() + " could not match permission, denied");
        }
        return false;
    }
}