/**
* Copyright (C) 2011 JTalks.org Team
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jtalks.jcommune.web.tags;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
import org.jtalks.common.service.security.SecurityContextFacade;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* An implementation of {@link Tag} that allows its body through if some
* authorizations are granted to the request's object.
* Typical use case: <br>
* <code>
* <jtalks:haspermission targetId="${topic.branch.id}" targetType="BRANCH"<br>
* permission="BranchPermission.DELETE_OWN_POSTS">
* <br> Some jsp code<br>
* </jtalks:haspermission>
* </code>
*
* @author Vyacheslav Mishcheryakov
*/
@SuppressWarnings("serial")
public class HasPermission extends TagSupport {
private transient PermissionEvaluator aclEvaluator;
private transient SecurityContextFacade securityContextFacade;
/** Identifier of object to check permission */
private Long targetId;
/** Type of object (e.g. BRANCH) */
private String targetType;
/** Simple name of permission (enum value). See
* {@link org.jtalks.common.model.permissions.JtalksPermission} and its
* subclasses
*/
private String permission;
/**
* @param targetId the ID of object to check permission
*/
public void setTargetId(Long targetId) {
this.targetId = targetId;
}
/**
* @param targetType type of targeted object
*/
public void setTargetType(String targetType) {
this.targetType = targetType;
}
/**
* @param permission Simple name of permission (enum value)
*/
public void setPermission(String permission) {
this.permission = permission;
}
/**
* {@inheritDoc}
*/
@Override
public int doStartTag() throws JspException {
if (isAnyParameterMissed()) {
throw new JspException("Some parameter is missed or empty");
}
Authentication authentication = securityContextFacade.getContext().getAuthentication();
//Authentication can be null when request not goes through spring security filters
if (authentication == null) {
return Tag.SKIP_BODY;
}
if (aclEvaluator.hasPermission(authentication, targetId, targetType, permission)) {
return Tag.EVAL_BODY_INCLUDE;
}
return Tag.SKIP_BODY;
}
/**
* Checks if any required tag parameter is missed or blank
* @return true if any required parameter is not specified.
*/
private boolean isAnyParameterMissed() {
boolean isTargetIdMissed = targetId == null;
boolean isTargetTypeMissed = targetType == null || "".equals(targetType);
boolean isPermissionMissed = permission == null || "".equals(permission);
return isTargetIdMissed || isTargetTypeMissed || isPermissionMissed;
}
/**
* Fetches all required beans from Spring context when page context is set.
* This guaranteed that all services will be initialized before actual
* page rendering
*
* @param pageContext page context to be set for this tag invocation
*
*/
@Override
public void setPageContext(PageContext pageContext) {
super.setPageContext(pageContext);
WebApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(pageContext.getServletContext());
aclEvaluator = ctx.getBean(PermissionEvaluator.class);
securityContextFacade = ctx.getBean(SecurityContextFacade.class);
}
}