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.net.URLDecoder; 020import java.util.Map; 021 022import org.apache.avalon.framework.parameters.Parameters; 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.cocoon.ResourceNotFoundException; 026import org.apache.cocoon.acting.ServiceableAction; 027import org.apache.cocoon.environment.ObjectModelHelper; 028import org.apache.cocoon.environment.Redirector; 029import org.apache.cocoon.environment.Request; 030import org.apache.cocoon.environment.SourceResolver; 031import org.apache.commons.lang.StringUtils; 032 033import org.ametys.cms.repository.Content; 034import org.ametys.core.right.RightManager; 035import org.ametys.core.user.CurrentUserProvider; 036import org.ametys.core.user.UserIdentity; 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("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 = _decodePath(objectPath); 126 return _resolver.resolveByPath(decodedPath); 127 } 128 else 129 { 130 return (Content) request.getAttribute(Content.class.getName()); 131 } 132 } 133 catch (UnknownAmetysObjectException e) 134 { 135 return null; 136 } 137 } 138 139 private String _decodePath (String path) throws UnsupportedEncodingException 140 { 141 StringBuffer sb = new StringBuffer(); 142 143 String[] parts = path.split("/"); 144 for (String part : parts) 145 { 146 if (StringUtils.isNotEmpty(part)) 147 { 148 sb.append("/"); 149 sb.append(URLDecoder.decode(part, "utf-8").replaceAll("%3A", ":")); 150 } 151 } 152 return sb.toString(); 153 } 154 155}