001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kew.web;
017
018import org.apache.commons.lang.StringUtils;
019import org.apache.log4j.MDC;
020import org.kuali.rice.core.api.config.property.ConfigurationService;
021import org.kuali.rice.core.api.exception.RiceRuntimeException;
022import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
023import org.kuali.rice.coreservice.framework.parameter.ParameterService;
024import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
025import org.kuali.rice.kew.api.KewApiConstants;
026import org.kuali.rice.kim.api.KimConstants;
027import org.kuali.rice.kim.api.identity.AuthenticationService;
028import org.kuali.rice.kim.api.identity.IdentityService;
029import org.kuali.rice.kim.api.identity.principal.Principal;
030import org.kuali.rice.kim.api.permission.PermissionService;
031import org.kuali.rice.kim.api.services.KimApiServiceLocator;
032import org.kuali.rice.krad.UserSession;
033import org.kuali.rice.krad.exception.AuthenticationException;
034import org.kuali.rice.krad.service.KRADServiceLocator;
035import org.kuali.rice.krad.util.KRADConstants;
036import org.kuali.rice.krad.util.KRADUtils;
037
038import javax.servlet.Filter;
039import javax.servlet.FilterChain;
040import javax.servlet.FilterConfig;
041import javax.servlet.ServletException;
042import javax.servlet.ServletRequest;
043import javax.servlet.ServletResponse;
044import javax.servlet.http.Cookie;
045import javax.servlet.http.HttpServletRequest;
046import javax.servlet.http.HttpServletResponse;
047import javax.xml.namespace.QName;
048import java.io.IOException;
049import java.util.Collections;
050import java.util.UUID;
051
052
053/**
054 * A filter for processing user logins and creating a {@link UserSession}.
055 *
056 * @see UserSession
057 * @author Kuali Rice Team (rice.collab@kuali.org)
058 */
059public class UserLoginFilter implements Filter {
060
061        private static final String MDC_USER = "user";
062        
063        private IdentityService identityService;
064    private PermissionService permissionService;
065        private ConfigurationService kualiConfigurationService;
066        private ParameterService parameterService;
067        
068        private FilterConfig filterConfig;
069        
070        @Override
071        public void init(FilterConfig config) throws ServletException {
072                this.filterConfig = config;
073        }
074
075        @Override
076        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
077                this.doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
078        }
079        
080        private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
081                
082                try {
083                        establishUserSession(request);
084                        establishSessionCookie(request, response);
085                        establishBackdoorUser(request);
086                        
087                        addToMDC(request);
088                        
089                        chain.doFilter(request, response);
090                } finally {
091                        removeFromMDC();
092                }
093                
094        }
095
096        @Override
097        public void destroy() {
098                filterConfig = null;
099        }
100        
101        /**
102         * Checks if a user can be authenticated and if so establishes a UserSession for that user.
103         */
104        private void establishUserSession(HttpServletRequest request) {
105                if (!isUserSessionEstablished(request)) {
106                        String principalName = ((AuthenticationService) GlobalResourceLoader.getResourceLoader().getService(new QName("kimAuthenticationService"))).getPrincipalName(request);
107            if (StringUtils.isBlank(principalName)) {
108                                throw new AuthenticationException( "Blank User from AuthenticationService - This should never happen." );
109                        }
110                        
111                        Principal principal = getIdentityService().getPrincipalByPrincipalName( principalName );
112                        if (principal == null) {
113                                throw new AuthenticationException("Unknown User: " + principalName);
114                        }
115                        
116                        if (!isAuthorizedToLogin(principal.getPrincipalId())) {
117                                throw new AuthenticationException("You cannot log in, because you are not an active Kuali user.\nPlease ask someone to activate your account if you need to use Kuali Systems.\nThe user id provided was: " + principalName + ".\n");
118                        }
119
120                        final UserSession userSession = new UserSession(principalName);
121                        if ( userSession.getPerson() == null ) {
122                                throw new AuthenticationException("Invalid User: " + principalName);
123                        }
124                        
125                        request.getSession().setAttribute(KRADConstants.USER_SESSION_KEY, userSession);
126                }
127        }
128        
129        /** checks if the passed in principalId is authorized to log in. */
130        private boolean isAuthorizedToLogin(String principalId) {
131                return getPermissionService().isAuthorized(
132                                principalId, 
133                                KimConstants.KIM_TYPE_DEFAULT_NAMESPACE, 
134                                KimConstants.PermissionNames.LOG_IN,
135                                Collections.singletonMap("principalId", principalId));
136        }
137        
138        
139        /**
140         * Creates a session id cookie if one does not exists.  Write the cookie out to the response with that session id.
141         * Also, sets the cookie on the established user session.
142         */
143        private void establishSessionCookie(HttpServletRequest request, HttpServletResponse response) {
144                String kualiSessionId = this.getKualiSessionId(request.getCookies());
145                if (kualiSessionId == null) {
146                        kualiSessionId = UUID.randomUUID().toString();
147                        response.addCookie(new Cookie(KRADConstants.KUALI_SESSION_ID, kualiSessionId));
148                }
149                KRADUtils.getUserSessionFromRequest(request).setKualiSessionId(kualiSessionId);
150        }
151        
152        /** gets the kuali session id from an array of cookies.  If a session id does not exist returns null. */
153        private String getKualiSessionId(final Cookie[] cookies) {
154                if (cookies != null) {
155                        for (Cookie cookie : cookies) {
156                                if (KRADConstants.KUALI_SESSION_ID.equals(cookie.getName())) {
157                                        return cookie.getValue();
158                                }
159                        }
160                }
161                return null;
162        }
163        
164        /** establishes the backdoor user on the established user id if backdoor capabilities are valid. */
165        private void establishBackdoorUser(HttpServletRequest request) {
166                final String backdoor = request.getParameter(KRADConstants.BACKDOOR_PARAMETER);
167        if ( StringUtils.isNotBlank(backdoor) ) {
168                        if ( !getKualiConfigurationService().getPropertyValueAsString(KRADConstants.PROD_ENVIRONMENT_CODE_KEY)
169                .equalsIgnoreCase(
170                        getKualiConfigurationService().getPropertyValueAsString(KRADConstants.ENVIRONMENT_KEY)) ) {
171                                if ( getParameterService().getParameterValueAsBoolean(KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE, KRADConstants.DetailTypes.BACKDOOR_DETAIL_TYPE, KewApiConstants.SHOW_BACK_DOOR_LOGIN_IND) ) {
172                    try{
173                            KRADUtils.getUserSessionFromRequest(request).setBackdoorUser(backdoor);
174                    }catch(RiceRuntimeException re){
175                     //Ignore so BackdoorAction can redirect to invalid_backdoor_portal
176                    }
177                                }
178                        }
179                }
180
181      }
182        
183        private void addToMDC(HttpServletRequest request) {
184                MDC.put(MDC_USER, KRADUtils.getUserSessionFromRequest(request).getPrincipalName());
185        }
186        
187        private void removeFromMDC() {
188                MDC.remove(MDC_USER);
189        }
190        
191        /**
192         * Checks if the user who made the request has a UserSession established
193         * 
194         * @param request the HTTPServletRequest object passed in
195         * @return true if the user session has been established, false otherwise
196         */
197        private boolean isUserSessionEstablished(HttpServletRequest request) {
198                return (request.getSession().getAttribute(KRADConstants.USER_SESSION_KEY) != null);
199        }
200        
201    private IdentityService getIdentityService() {
202        if (this.identityService == null) {
203                this.identityService = KimApiServiceLocator.getIdentityService();
204        }
205        
206        return this.identityService;
207    }
208
209    private PermissionService getPermissionService() {
210        if (this.permissionService == null) {
211                this.permissionService = KimApiServiceLocator.getPermissionService();
212        }
213
214        return this.permissionService;
215    }
216    
217    private ConfigurationService getKualiConfigurationService() {
218        if (this.kualiConfigurationService == null) {
219                this.kualiConfigurationService = KRADServiceLocator.getKualiConfigurationService();
220        }
221        
222        return this.kualiConfigurationService;
223    }
224    
225    private ParameterService getParameterService() {
226        if (this.parameterService == null) {
227                this.parameterService = CoreFrameworkServiceLocator.getParameterService();
228        }
229        
230        return this.parameterService;
231    }
232}