blob: fb6cc19d29d493d71e61a60582f3820b46e45669 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.rave.portal.security.impl;
import org.apache.rave.model.Page;
import org.apache.rave.model.PageUser;
import org.apache.rave.model.Region;
import org.apache.rave.model.User;
import org.apache.rave.portal.repository.RegionRepository;
import org.apache.rave.portal.repository.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Component
public class DefaultRegionPermissionEvaluator extends AbstractModelPermissionEvaluator<Region>{
private Logger log = LoggerFactory.getLogger(getClass());
private RegionRepository regionRepository;
private UserRepository userRepository;
@Autowired
public DefaultRegionPermissionEvaluator(RegionRepository regionRepository, UserRepository userRepository) {
this.regionRepository = regionRepository;
this.userRepository = userRepository;
}
@Override
public Class<Region> getType() {
return Region.class;
}
/**
* Checks to see if the Authentication object has the supplied Permission
* on the supplied Region object. This method invokes the private hasPermission
* function with the trustedDomainObject parameter set to false since we don't
* know if the model being passed in was modified in any way from the
* actual entity in the database.
*
* @param authentication the current Authentication object
* @param region the Region model object
* @param permission the Permission to check
* @return true if the Authentication has the proper permission, false otherwise
*/
@Override
public boolean hasPermission(Authentication authentication, Region region, Permission permission) {
return hasPermission(authentication, region, permission, false);
}
/**
* Checks to see if the Authentication object has the supplied Permission
* for the Entity represented by the targetId(entityId) and targetType(model class name).
* This method invokes the private hasPermission function with the
* trustedDomainObject parameter set to true since we must pull the entity
* from the database and are guaranteed a trusted domain object,
* before performing our permission checks.
*
* @param authentication the current Authentication object
* @param targetId the entityId of the model to check, or a RaveSecurityContext object
* @param targetType the class of the model to check
* @param permission the Permission to check
* @return true if the Authentication has the proper permission, false otherwise
*/
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Permission permission) {
boolean hasPermission = false;
if (targetId instanceof RaveSecurityContext) {
hasPermission = verifyRaveSecurityContext(authentication, (RaveSecurityContext) targetId);
} else {
hasPermission = hasPermission(authentication, regionRepository.get((String) targetId), permission, true);
}
return hasPermission;
}
private boolean hasPermission(Authentication authentication, Region region, Permission permission, boolean trustedDomainObject) {
// this is our container of trusted region objects that can be re-used
// in this method so that the same trusted region object doesn't have to
// be looked up in the repository multiple times
List<Region> trustedRegionContainer = new ArrayList<Region>();
// first execute the AbstractModelPermissionEvaluator's hasPermission function
// to see if it allows permission via it's "higher authority" logic
if (super.hasPermission(authentication, region, permission)) {
return true;
}
// perform the security logic depending on the Permission type
boolean hasPermission = false;
switch (permission) {
case ADMINISTER:
// if you are here, you are not an administrator, so you can't administer Region
break;
case CREATE:
case DELETE:
case UPDATE:
// anyone can create, delete, read, or update a region that they own
hasPermission = isRegionOwner(authentication, region, trustedRegionContainer, trustedDomainObject)
|| isRegionMember(authentication, region, trustedRegionContainer, trustedDomainObject, true);
break;
case READ:
hasPermission = isRegionOwner(authentication, region, trustedRegionContainer, trustedDomainObject)
|| isRegionMember(authentication, region, trustedRegionContainer, trustedDomainObject, false);
default:
log.warn("unknown permission: " + permission);
break;
}
return hasPermission;
}
// returns a trusted Region object, either from the RegionRepository, or the
// cached container list
private Region getTrustedRegion(String regionId, List<Region> trustedRegionContainer) {
Region region = null;
if (trustedRegionContainer.isEmpty()) {
region = regionRepository.get(regionId);
trustedRegionContainer.add(region);
} else {
region = trustedRegionContainer.get(0);
}
return region;
}
// checks to see if the Authentication object principal is the owner of the supplied region object
// if trustedDomainObject is false, pull the entity from the database first to ensure
// the model object is trusted and hasn't been modified
private boolean isRegionOwner(Authentication authentication, Region region, List<Region> trustedRegionContainer, boolean trustedDomainObject) {
Region trustedRegion = null;
if (trustedDomainObject) {
trustedRegion = region;
} else {
trustedRegion = getTrustedRegion(region.getId(), trustedRegionContainer);
}
return isRegionOwnerByUserId(authentication, trustedRegion.getPage().getOwnerId());
}
private boolean isRegionOwnerByUserId(Authentication authentication, String userId) {
return ((User)authentication.getPrincipal()).getId().equals(userId);
}
private boolean isRegionOwnerById(Authentication authentication, String userId) {
return ((User)authentication.getPrincipal()).getId().equals(userId);
}
private boolean verifyRaveSecurityContext(Authentication authentication, RaveSecurityContext raveSecurityContext) {
Class<?> clazz = null;
try {
clazz = Class.forName(raveSecurityContext.getType());
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("unknown class specified in RaveSecurityContext: ", ex);
}
// perform the permissions check based on the class supplied to the RaveSecurityContext object
if (User.class == clazz) {
return isRegionOwnerById(authentication, (String) raveSecurityContext.getId());
} else {
throw new IllegalArgumentException("unknown RaveSecurityContext type: " + raveSecurityContext.getType());
}
}
private boolean isRegionMember(Authentication authentication, Region region, List<Region> trustedRegionContainer, boolean trustedDomainObject, boolean checkEditorStatus) {
Region trustedRegion = null;
if (trustedDomainObject) {
trustedRegion = region;
} else {
trustedRegion = getTrustedRegion(region.getId(), trustedRegionContainer);
}
Page containerPage = trustedRegion.getPage();
if (containerPage.getMembers() == null){
return false;
}
//
// Check that the viewer is a member
// Make sure we check parent page permissions as well
//
String viewer = ((User)authentication.getPrincipal()).getUsername();
do {
for (PageUser pageUser:containerPage.getMembers()){
User user = userRepository.get(pageUser.getUserId());
if (user != null && user.getUsername().equals(viewer)){
log.info("User "+viewer+" is a member of page "+containerPage.getId());
if(checkEditorStatus){
return pageUser.isEditor();
}
return true;
}
}
} while((containerPage = containerPage.getParentPage()) != null);
return false;
}
}