/*
* Copyright (c) 2005-2011 Grameen Foundation USA
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* See also http://www.apache.org/licenses/LICENSE-2.0.html for an
* explanation of the license and how it is applied.
*/
package org.mifos.framework.struts.action;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.Globals;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.tiles.TilesRequestProcessor;
import org.mifos.application.servicefacade.ApplicationContextProvider;
import org.mifos.customers.client.util.helpers.ClientConstants;
import org.mifos.framework.util.helpers.Constants;
import org.mifos.framework.util.helpers.PreviousRequestValues;
import org.mifos.security.rolesandpermission.persistence.LegacyRolesPermissionsDao;
import org.mifos.security.util.ActivityContext;
import org.mifos.security.util.ActivityMapper;
import org.mifos.security.util.SecurityConstants;
import org.mifos.security.util.UserContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MifosRequestProcessor extends TilesRequestProcessor {
private static final Logger logger = LoggerFactory.getLogger(MifosRequestProcessor.class);
private ActivityContext setActivityContextFromRequest(HttpServletRequest request, Short activityId) {
HttpSession session = request.getSession();
ActivityContext activityContext = (ActivityContext) session.getAttribute("ActivityContext");
if (activityContext != null) {
// get the values from the request
String recordOfficeId = request.getParameter("recordOfficeId");
String recordLoanOfficerId = request.getParameter("recordLoanOfficerId");
short recordOffId = -1;
short recordLoOffId = -1;
try {
/*
* The null case is if one or both parameters was omitted.
* What's the difference between supplying these as parameters
* versus the UserContext, versus just using what is in the
* ActivityContext?
*/
if (recordOfficeId != null) {
recordOffId = Short.valueOf(recordOfficeId).shortValue();
}
if (recordLoanOfficerId != null) {
recordLoOffId = Short.valueOf(recordLoanOfficerId).shortValue();
}
} catch (NumberFormatException e) {
throw new RuntimeException(e);
}
if (recordOffId > 0 && recordLoOffId > 0) {
activityContext.setRecordOfficeId(recordOffId);
activityContext.setRecordLoanOfficer(recordLoOffId);
} else if (recordOffId == 0 && recordLoOffId == 0) {
if (session.getAttribute("UserContext") != null) {
UserContext uc = (UserContext) session.getAttribute("UserContext");
activityContext.setRecordOfficeId(uc.getBranchId());
activityContext.setRecordLoanOfficer(uc.getId());
}
}
activityContext.setActivityId(activityId);
return activityContext;
} else {
// No activity context
// TODO: Can this happen? Why? Is null right?
return null;
}
}
protected boolean checkProcessRoles(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) {
boolean returnValue = true;
if (request.getSession() != null && request.getSession().getAttribute("UserContext") != null)
{
HttpSession session = request.getSession();
ActivityMapper activityMapper = ActivityMapper.getInstance();
String path = mapping.getPath();
String method = request.getParameter("method");
String key = path + "-" + method;
Short activityId = null;
if (null != method
&& (method.equals("cancel") || method.equals("validate") || method.equals("searchPrev") || method
.equals("searchNext"))) {
return true;
}
String activityKey = null;
if (isReportRequest(request)) {
String reportId = request.getParameter("reportId");
activityKey = key + "-" + reportId;
activityId = activityMapper.getActivityId(activityKey);
} else {
activityId = activityMapper.getActivityId(key);
request.setAttribute(Globals.ERROR_KEY, null);
}
if (null == activityId) {
activityKey = path + "-" + request.getParameter("viewPath");
activityId = activityMapper.getActivityId(activityKey);
}
// Check for fine-grained permissions
if (null == activityId) {
activityKey = key + "-" + session.getAttribute(SecurityConstants.SECURITY_PARAM);
activityId = activityMapper.getActivityId(activityKey);
}
if (null == activityId) {
return false;
} else if (activityId.shortValue() == 0) {
return true;
}
returnValue = ApplicationContextProvider.getBean(LegacyRolesPermissionsDao.class).isActivityAllowed(
(UserContext) session.getAttribute("UserContext"),
setActivityContextFromRequest(request, activityId));
}
return returnValue;
}
/*
* Seems bolted-on. Is there a more elegant way to control per-report
* permissions?
*/
private boolean isReportRequest(HttpServletRequest request) {
String reportId = request.getParameter("reportId");
String method = request.getParameter("method");
return StringUtils.isNotEmpty(reportId) && "loadAddList".equals(method);
}
/**
* This method is overridden because in case of exception we need to
* populate the request with the old values so that when the user goes back
* to the previous page it has all the values in the request.For this we
* create an object which will store the values of previous request in case
* the request is successful and if there is an exception it reads values
* from that object and context and dups all in the request.
*/
@Override
protected ActionForward processActionPerform(HttpServletRequest request, HttpServletResponse response,
Action action, ActionForm form, ActionMapping mapping) throws IOException, ServletException {
ActivityContext activityContext = null;
ActionForward forward = null;
HttpSession session = request.getSession();
// gets the object where we will store values from request.
PreviousRequestValues previousRequestValues = (PreviousRequestValues) session
.getAttribute(Constants.PREVIOUS_REQUEST);
if (null == previousRequestValues) {
previousRequestValues = new PreviousRequestValues();
session.setAttribute(Constants.PREVIOUS_REQUEST, previousRequestValues);
}
// getting the activity context from the session
activityContext = (ActivityContext) session.getAttribute("ActivityContext");
// check if the action desired is permissible or not.
// if allowed invoke the execute method of the action class
try {
String currentFlowKey = request.getParameter(Constants.CURRENTFLOWKEY);
if (currentFlowKey != null) {
previousRequestValues.getPreviousRequestValueMap().put(Constants.CURRENTFLOWKEY, currentFlowKey);
}
forward = (action.execute(mapping, form, request, response));
String method = request.getParameter("method");
if (method.equals(ClientConstants.METHOD_RETRIEVE_PICTURE)) {
forward = mapping.findForward("get_success");
}
// set the last forward in the activity context
if (activityContext != null) {
activityContext.setLastForward(forward);
}
// read the request and add the values to the PreviousRequestValues
// object. this will set every thing in the request apart from
// context and value object.
Enumeration requestAttributes = request.getAttributeNames();
while (requestAttributes.hasMoreElements()) {
String nextName = (String) requestAttributes.nextElement();
if (nextName.startsWith(Constants.STORE_ATTRIBUTE)
|| nextName.equalsIgnoreCase(Constants.CURRENTFLOWKEY)) {
logger.debug(nextName + "=" + request.getAttribute(nextName));
previousRequestValues.getPreviousRequestValueMap().put(nextName, request.getAttribute(nextName));
}
}
}
catch (Exception e) {
// processException logs an error (see MifosExceptionHandler)
forward = (processException(request, response, e, form, mapping));
// set the last forward in the activity context
if (activityContext != null) {
activityContext.setLastForward(forward);
}
populateTheRequestFromPreviousValues(request, previousRequestValues);
} finally {
try {
session.removeAttribute(SecurityConstants.SECURITY_PARAM);
} catch (Exception e) {
// FIXME: yikes, what is being swallowed here?
}
}
if (null != forward) {
logger.info("forward.path=" + forward.getPath());
}
return forward;
}
private void populateTheRequestFromPreviousValues(HttpServletRequest request,
PreviousRequestValues previousRequestValues) {
// also read the previous request values map and put things in
// request.
Set<String> keySet = previousRequestValues.getPreviousRequestValueMap().keySet();
if (null != keySet) {
for (String key : keySet) {
request.setAttribute(key, previousRequestValues.getPreviousRequestValueMap().get(key));
}
}
}
@Override
protected boolean processRoles(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
throws IOException, ServletException {
HttpSession session = request.getSession();
PreviousRequestValues previousRequestValues = (PreviousRequestValues) session
.getAttribute(Constants.PREVIOUS_REQUEST);
if (null == previousRequestValues) {
previousRequestValues = new PreviousRequestValues();
session.setAttribute(Constants.PREVIOUS_REQUEST, previousRequestValues);
}
if (!checkProcessRoles(request, response, mapping)) {
ActionErrors error = new ActionErrors();
error.add(SecurityConstants.KEY_ACTIVITY_NOT_ALLOWED, new ActionMessage(
SecurityConstants.KEY_ACTIVITY_NOT_ALLOWED));
request.setAttribute(Globals.ERROR_KEY, error);
ActivityContext activityContext = (ActivityContext) request.getSession().getAttribute("ActivityContext");
populateTheRequestFromPreviousValues(request, previousRequestValues);
processForwardConfig(request, response, activityContext.getLastForward());
return false;
}
return true;
}
}