001/*
002 *  Copyright 2017 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.cms.rights;
017
018import java.io.UnsupportedEncodingException;
019import java.util.Map;
020
021import org.apache.avalon.framework.parameters.Parameters;
022import org.apache.avalon.framework.service.ServiceException;
023import org.apache.avalon.framework.service.ServiceManager;
024import org.apache.cocoon.ResourceNotFoundException;
025import org.apache.cocoon.acting.ServiceableAction;
026import org.apache.cocoon.environment.ObjectModelHelper;
027import org.apache.cocoon.environment.Redirector;
028import org.apache.cocoon.environment.Request;
029import org.apache.cocoon.environment.SourceResolver;
030import org.apache.commons.lang.StringUtils;
031
032import org.ametys.cms.repository.Content;
033import org.ametys.core.right.RightManager;
034import org.ametys.core.user.CurrentUserProvider;
035import org.ametys.core.user.UserIdentity;
036import org.ametys.core.util.FilenameUtils;
037import org.ametys.plugins.repository.AmetysObject;
038import org.ametys.plugins.repository.AmetysObjectResolver;
039import org.ametys.plugins.repository.UnknownAmetysObjectException;
040import org.ametys.runtime.authentication.AccessDeniedException;
041import org.ametys.runtime.authentication.AuthorizationRequiredException;
042
043/**
044 * Test if the accessed object is not restricted, i.e. an anonymous user has READ access
045 * or if the connected user has READ access on it.
046 * <ul>
047 * <li>If the object is not restricted, returns EMPTY_MAP.</li>
048 * <li>If the object is restricted and the current user is allowed, return null.</li>
049 * <li>If the object is restricted but the current user is not allowed, an {@link AccessDeniedException} is thrown.</li>
050 * <li>If the object is restricted but no one is logged in, an {@link AuthorizationRequiredException} is thrown.</li>
051 * </ul>
052 */
053public class CheckReadAccessAction extends ServiceableAction
054{
055    /** The Ametys object resolver. */
056    protected AmetysObjectResolver _resolver;
057    
058    /** The current user provider */
059    protected CurrentUserProvider _currentUserProvider;
060
061    /** The right manager */
062    protected RightManager _rightManager;
063    
064    @Override
065    public void service(ServiceManager serviceManager) throws ServiceException
066    {
067        super.service(serviceManager);
068        _rightManager = (RightManager) manager.lookup(RightManager.ROLE);
069        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
070        _currentUserProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE);
071    }
072    
073    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
074    {
075        Request request = ObjectModelHelper.getRequest(objectModel);
076            
077        UserIdentity user = _currentUserProvider.getUser();
078        
079        // Get the Ametys object from either the parameters or the request attributes.
080        AmetysObject ao = getAmetysObject(parameters, request);
081        if (ao == null)
082        {
083            throw new ResourceNotFoundException("CheckReadAccessAction: a valid ametys object must be provided.");
084        }
085        
086        if (_rightManager.hasAnonymousReadAccess(ao))
087        {
088            // Anonymous access allowed
089            return EMPTY_MAP;
090        }
091        else if (user == null)
092        {
093            // User not yet authenticated
094            throw new AuthorizationRequiredException();
095        }
096        else if (_rightManager.hasReadAccess(user, ao))
097        {
098            // User has read access
099            return null;
100        }
101        
102        // User is not authorized
103        throw new AccessDeniedException("Access to object " + ao.getId() + " is not allowed for user " + user);
104    }
105    
106    /**
107     * Get the Ametys object from either the parameters or the request attributes.
108     * @param parameters the action parameters.
109     * @param request the request.
110     * @return the Ametys object or null if not found.
111     * @throws UnsupportedEncodingException if failed to decode object path
112     */
113    protected AmetysObject getAmetysObject(Parameters parameters, Request request) throws UnsupportedEncodingException
114    {
115        try
116        {
117            String objectId = parameters.getParameter("objectId", "");
118            String objectPath = parameters.getParameter("objectPath", "");
119            if (StringUtils.isNotEmpty(objectId))
120            {
121                return _resolver.resolveById(objectId);
122            }
123            else if (StringUtils.isNotEmpty(objectPath))
124            {
125                String decodedPath = FilenameUtils.decode(objectPath);
126                return _resolver.resolveByPath(decodedPath);
127            }
128            else
129            {
130                Content content = (Content) request.getAttribute(Content.class.getName());
131                return content != null ? content : (AmetysObject) request.getAttribute(AmetysObject.class.getName());
132            }
133        }
134        catch (UnknownAmetysObjectException e)
135        {
136            return null;
137        }
138    }
139}