/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
package org.internna.iwebmvc.dao;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.internna.iwebmvc.model.AbstractOwnedDomainEntity;
import org.internna.iwebmvc.model.DomainEntity;
import org.internna.iwebmvc.model.UUID;
import org.internna.iwebmvc.model.User;
import org.internna.iwebmvc.model.security.UserImpl;
import org.internna.iwebmvc.security.UserManager;
import org.internna.iwebmvc.utils.Assert;
import org.internna.iwebmvc.utils.CollectionUtils;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.annotation.Transactional;
/**
* A DAO proxy that changes the queries transparently to ensure that owned entities are not
* fetched by other users.
*
* @author Jose Noheda
* @since 2.0
*/
public final class OwnedByFilteringDAO extends DelegateProxyDAO {
private UserManager userManager;
public OwnedByFilteringDAO(DAO dao) {
super(dao);
}
@Required
public void setUserManager(UserManager userManager) {
this.userManager = userManager;
}
private User getCurrentUser() {
try {
return userManager.getActiveUser();
} catch (Exception ex) {
return null;
}
}
/**
* Checks if the entity must have a creator and does not already have one. If true tries
* to set the current logged user.
*/
@Transactional
@Override public void create(DomainEntity entity, boolean flush) {
if (entity instanceof AbstractOwnedDomainEntity) {
AbstractOwnedDomainEntity owned = (AbstractOwnedDomainEntity) entity;
if (CollectionUtils.isEmpty(owned.getOwners())) {
User user = getCurrentUser();
if (user instanceof UserImpl) {
if (logger.isDebugEnabled()) logger.debug("Adding default owner [" + user + "] to entity [" + entity + "]");
owned.addOwner((UserImpl) user);
}
}
}
super.create(entity, flush);
}
private boolean isViewer(AbstractOwnedDomainEntity entity) {
User current = getCurrentUser();
if (!current.isAnonymous() && CollectionUtils.isNotEmpty(entity.getViewers())) {
for (User user : entity.getViewers())
if (user.getUsername().equals(current.getUsername()))
return true;
}
return false;
}
/**
* Finds an entity and checks if the creator was the current logged user otherwise it's filtered.
*/
@Transactional
@Override public <T extends DomainEntity> T find(Class<T> entityClass, UUID pk) {
T entity = super.find(entityClass, pk);
if (entity instanceof AbstractOwnedDomainEntity) {
AbstractOwnedDomainEntity owned = (AbstractOwnedDomainEntity) entity;
if ((!owned.isPublicView()) && (!isViewer(owned))) {
entity = null;
if (logger.isDebugEnabled()) logger.debug("Entity [" + entityClass + "] with PK [" + pk + "] filtered for current user");
}
}
return entity;
}
/**
* If this type of entities are owned by specific users then transforms the findAll named query in a query filtered by the current user.
*/
@Override
@Transactional
public <T extends DomainEntity> List<T> find(Class<T> entityClass, int offset, int max) {
Assert.notNull(entityClass);
if (AbstractOwnedDomainEntity.class.isAssignableFrom(entityClass)) {
User user = getCurrentUser();
Map<String, Object> parameters = new HashMap<String, Object>(1);
parameters.put("owner", user != null && user.isAnonymous() ? null : user);
return findByQuery("SELECT e FROM " + entityClass.getSimpleName() + " e WHERE ( ( e.publicView = true ) OR ( :owner IN ELEMENTS(e.viewers) ) )", offset, max, parameters);
} else {
return super.find(entityClass, offset, max);
}
}
/**
* Checks that if the entity has an owner then he's the current user.
*/
protected final boolean isAllowed(DomainEntity entity) {
if (AbstractOwnedDomainEntity.class.isInstance(entity)) {
AbstractOwnedDomainEntity owned = (AbstractOwnedDomainEntity) entity;
User current = getCurrentUser();
if ((current != null) && (!current.isAnonymous())) {
for (User user : owned.getOwners())
if (user.getUsername().equals(current.getUsername()))
return true;
}
return false;
}
return true;
}
/**
* Checks the user has permissions over this entity before proceeding.
*/
@Transactional
@Override public void remove(DomainEntity entity) {
if ((entity != null) && (isAllowed(entity))) super.remove(entity);
}
/**
* Checks the user has permissions over this entity before proceeding.
*/
@Transactional
@Override public DomainEntity update(DomainEntity entity) {
return (entity != null) && (isAllowed(entity)) ? super.update(entity) : null;
}
}