/*
* Copyright (c) 2010 Lockheed Martin Corporation
*
* 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.eurekastreams.server.action.authorization.stream;
import java.util.List;
import org.apache.commons.logging.Log;
import org.eurekastreams.commons.actions.AuthorizationStrategy;
import org.eurekastreams.commons.actions.context.Principal;
import org.eurekastreams.commons.actions.context.service.ServiceActionContext;
import org.eurekastreams.commons.exceptions.AuthorizationException;
import org.eurekastreams.commons.logging.LogFactory;
import org.eurekastreams.server.action.request.stream.PostActivityRequest;
import org.eurekastreams.server.domain.stream.ActivityDTO;
import org.eurekastreams.server.persistence.mappers.DomainMapper;
import org.eurekastreams.server.persistence.mappers.GetAllPersonIdsWhoHaveGroupCoordinatorAccess;
import org.eurekastreams.server.persistence.mappers.stream.GetDomainGroupsByShortNames;
import org.eurekastreams.server.search.modelview.DomainGroupModelView;
import org.eurekastreams.server.search.modelview.PersonModelView;
/**
* Authorization Strategy for Posting an activity.
*
*/
public class PostActivityAuthorizationStrategy implements AuthorizationStrategy<ServiceActionContext>
{
/**
* Local logger instance.
*/
private final Log logger = LogFactory.make();
/**
* Local instance of the {@link GetDomainGroupsByShortNames} mapper.
*/
private final GetDomainGroupsByShortNames domainGroupsByShortNameMapper;
/**
* Mapper to get a PersonModelView from an accountid.
*/
private final DomainMapper<String, PersonModelView> getPersonModelViewByAccountIdMapper;
/**
* The mapper to get all coordinators of a group.
*/
private final GetAllPersonIdsWhoHaveGroupCoordinatorAccess groupCoordMapper;
/**
* Group follower ids DAO.
*/
private final DomainMapper<Long, List<Long>> groupFollowersDAO;
/**
* Constructor for the PostActivityAuthorizationStrategy.
*
* @param inDomainGroupsByShortNameMapper
* - instance of the {@link GetDomainGroupsByShortNames} mapper.
* @param inGroupCoordMapper
* - instance of the {@link GetAllPersonIdsWhoHaveGroupCoordinatorAccess} mapper.
* @param inGroupFollowersDAO
* - instance of the {@link GetGroupFollowerIds} mapper.
* @param inGetPersonModelViewByAccountIdMapper
* mapper to get a personmodelview by accountid
*/
public PostActivityAuthorizationStrategy(final GetDomainGroupsByShortNames inDomainGroupsByShortNameMapper,
final GetAllPersonIdsWhoHaveGroupCoordinatorAccess inGroupCoordMapper,
final DomainMapper<Long, List<Long>> inGroupFollowersDAO,
final DomainMapper<String, PersonModelView> inGetPersonModelViewByAccountIdMapper)
{
domainGroupsByShortNameMapper = inDomainGroupsByShortNameMapper;
groupCoordMapper = inGroupCoordMapper;
groupFollowersDAO = inGroupFollowersDAO;
getPersonModelViewByAccountIdMapper = inGetPersonModelViewByAccountIdMapper;
}
/**
* Check the DestinationStream type and perform the appropriate authorization strategy. {@inheritDoc}.
*/
public void authorize(final ServiceActionContext inActionContext)
{
Principal currentPrincipal = inActionContext.getPrincipal();
PostActivityRequest currentRequest = (PostActivityRequest) inActionContext.getParams();
switch (currentRequest.getActivityDTO().getDestinationStream().getType())
{
case PERSON:
if (logger.isTraceEnabled())
{
logger.trace("Performing authorization to post to a Person based stream: "
+ currentRequest.getActivityDTO().getDestinationStream().getUniqueIdentifier());
}
performPersonAuthorization(currentPrincipal, currentRequest.getActivityDTO());
break;
case GROUP:
if (logger.isTraceEnabled())
{
logger.trace("Performing authorization to post to a Group based stream: "
+ currentRequest.getActivityDTO().getDestinationStream().getUniqueIdentifier());
}
performGroupAuthorization(currentPrincipal, currentRequest.getActivityDTO());
break;
case RESOURCE:
// anyone can post to resource stream.
break;
default:
logger.error("Error occurred Performing authorization to post an Activity to stream, unsupported"
+ "destination stream type.");
throw new AuthorizationException("Unsupported Destination Stream Type.");
}
}
/**
* Helper method to perform Authorization on activity when the destination stream is a Person type.
*
* @param inPrincipal
* - current {@link Principal} for the Action Context.
* @param inActivityDTO
* - current {@link ActivityDTO} to be posted.
*/
private void performPersonAuthorization(final Principal inPrincipal, final ActivityDTO inActivityDTO)
{
PersonModelView currentPerson = getPersonModelViewByAccountIdMapper.execute(inActivityDTO
.getDestinationStream().getUniqueIdentifier());
if (currentPerson == null)
{
throw new AuthorizationException("Cannot locate current person. The activity destination stream id is "
+ inActivityDTO.getDestinationStream().getUniqueIdentifier());
}
boolean isActorTheStreamOwner = inPrincipal.getAccountId().equalsIgnoreCase(
inActivityDTO.getDestinationStream().getUniqueIdentifier());
// Test if the user is the owner of the stream being posted to or the stream
// has been authorized for this type of interaction.
if (isActorTheStreamOwner || currentPerson.isStreamPostable())
{
return;
}
throw new AuthorizationException("Current user does not have access rights to post this activity.");
}
/**
* Helper method to perform Authorization on activity when the destination stream is a Group type.
*
* @param inPrincipal
* - current {@link Principal} for the Action Context.
* @param inActivityDTO
* - current {@link ActivityDTO} to be posted.
*/
private void performGroupAuthorization(final Principal inPrincipal, final ActivityDTO inActivityDTO)
{
DomainGroupModelView currentDomainGroup = domainGroupsByShortNameMapper.fetchUniqueResult(inActivityDTO
.getDestinationStream().getUniqueIdentifier());
boolean isUserCoordinator = groupCoordMapper.execute(currentDomainGroup.getEntityId()).contains(
inPrincipal.getId());
// if group is public check to see if the current stream interaction is allowed based on configuration,
// if so then short-circuit.
if (currentDomainGroup.isPublic())
{
if (currentDomainGroup.isStreamPostable() || isUserCoordinator)
{
return;
}
else
{
throw new AuthorizationException("Group is public but the poster is not a "
+ "coordinator and the group is configured to not allow stream posts.");
}
}
// The group is private, continue forward testing private group authorization.
if (isUserCoordinator)
{
// user is a coordinator
return;
}
if (groupFollowersDAO.execute(currentDomainGroup.getEntityId()).contains(inPrincipal.getId())
&& currentDomainGroup.isStreamPostable())
{
// user is a follower
return;
}
throw new AuthorizationException("Current user does not have access rights to post this activity.");
}
}