001/* 002 * Licensed to DuraSpace under one or more contributor license agreements. 003 * See the NOTICE file distributed with this work for additional information 004 * regarding copyright ownership. 005 * 006 * DuraSpace licenses this file to you under the Apache License, 007 * Version 2.0 (the "License"); you may not use this file except in 008 * compliance with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.fcrepo.auth.webac; 019 020import static java.util.Arrays.stream; 021import static java.util.Collections.unmodifiableMap; 022import static org.fcrepo.auth.webac.URIConstants.FOAF_AGENT_VALUE; 023import static org.fcrepo.auth.webac.URIConstants.WEBAC_MODE_CONTROL_VALUE; 024import static org.fcrepo.auth.webac.URIConstants.WEBAC_MODE_READ_VALUE; 025import static org.fcrepo.auth.webac.URIConstants.WEBAC_MODE_WRITE_VALUE; 026import static org.modeshape.jcr.ModeShapePermissions.ADD_NODE; 027import static org.modeshape.jcr.ModeShapePermissions.MODIFY_ACCESS_CONTROL; 028import static org.modeshape.jcr.ModeShapePermissions.READ; 029import static org.modeshape.jcr.ModeShapePermissions.READ_ACCESS_CONTROL; 030import static org.modeshape.jcr.ModeShapePermissions.REMOVE; 031import static org.modeshape.jcr.ModeShapePermissions.REMOVE_CHILD_NODES; 032import static org.modeshape.jcr.ModeShapePermissions.SET_PROPERTY; 033 034import java.security.Principal; 035import java.util.HashMap; 036import java.util.Map; 037import java.util.Set; 038 039import javax.jcr.Session; 040 041import org.fcrepo.auth.roles.common.AbstractRolesAuthorizationDelegate; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045/** 046 * Authorization Delegate responsible for resolving Fedora's permissions using Web Access Control (WebAC) access 047 * control lists. 048 * 049 * @author Peter Eichman 050 * @since Aug 24, 2015 051 */ 052public class WebACAuthorizationDelegate extends AbstractRolesAuthorizationDelegate { 053 054 /** 055 * Class-level logger. 056 */ 057 private static final Logger LOGGER = LoggerFactory.getLogger(WebACAuthorizationDelegate.class); 058 059 private static final Map<String, String> actionMap; 060 061 static { 062 final Map<String, String> map = new HashMap<>(); 063 // WEBAC_MODE_READ Permissions 064 map.put(READ, WEBAC_MODE_READ_VALUE); 065 // WEBAC_MODE_WRITE Permissions 066 map.put(ADD_NODE, WEBAC_MODE_WRITE_VALUE); 067 map.put(REMOVE, WEBAC_MODE_WRITE_VALUE); 068 map.put(REMOVE_CHILD_NODES, WEBAC_MODE_WRITE_VALUE); 069 map.put(SET_PROPERTY, WEBAC_MODE_WRITE_VALUE); 070 // WEBAC_MODE_CONTROL Permissions 071 map.put(MODIFY_ACCESS_CONTROL, WEBAC_MODE_CONTROL_VALUE); 072 map.put(READ_ACCESS_CONTROL, WEBAC_MODE_CONTROL_VALUE); 073 actionMap = unmodifiableMap(map); 074 } 075 076 /** 077 * The security principal for every request, that represents the foaf:Agent agent class that is used to designate 078 * "everyone". 079 */ 080 private static final Principal EVERYONE = new Principal() { 081 082 @Override 083 public String getName() { 084 return FOAF_AGENT_VALUE; 085 } 086 087 @Override 088 public String toString() { 089 return getName(); 090 } 091 092 }; 093 094 @Override 095 public boolean rolesHavePermission(final Session userSession, final String absPath, 096 final String[] actions, final Set<String> roles) { 097 098 /* 099 * If any value in the actions Array is NOT also in the roles Set, the request should be denied. 100 * Otherwise, e.g. all of the actions values are contained in the roles set, the request is approved. 101 * 102 * The logic here may not be immediately obvious. The process is thus: 103 * map: map the modeshape action to a webac action 104 * allMatch: verify that ALL actions MUST exist in the roles Set 105 */ 106 final boolean permit = stream(actions).map(actionMap::get).allMatch(roles::contains); 107 108 LOGGER.debug("Request for actions: {}, on path: {}, with roles: {}. Permission={}", 109 actions, absPath, roles, permit); 110 111 return permit; 112 } 113 114 @Override 115 public Principal getEveryonePrincipal() { 116 return EVERYONE; 117 } 118 119}