001/* 002 * Copyright 2016 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.plugins.core.impl.right; 017 018import java.util.Collections; 019import java.util.HashSet; 020import java.util.Set; 021import java.util.regex.Pattern; 022 023import org.apache.avalon.framework.configuration.Configurable; 024import org.apache.avalon.framework.configuration.Configuration; 025import org.apache.avalon.framework.configuration.ConfigurationException; 026import org.apache.commons.lang3.StringUtils; 027 028import org.ametys.core.right.RightAssignmentContext; 029 030/** 031 * This implementation will manage hierarchical string (parents separated by '/'). 032 * For example '/node1/node2/node3', will seek for rights on '/node1/node2/node3', if nothing is found will try on '/node1/node2', and finally on '/node1'. 033 * Configurable with several <prefix>/myprefix</prefix> 034 * 035 * If this AcessController is limited to a workspace (by the corresponding {@link RightAssignmentContext}), this should be specified 036 * with a configuration <workspace> that is a negativable regexp of a workspace context (such as '/cms' or '!/admin') 037 */ 038public class StringHierarchicalAccessController extends AbstractHierarchicalAccessController<String> implements Configurable 039{ 040 /** The separator character */ 041 protected static final char SEPARATOR = '/'; 042 /** The prefixes */ 043 protected Set<String> _prefixes; 044 /** The regexp that should match current workspace */ 045 protected Pattern _workspaceMatcher; 046 /** Consider _workspaceMatcher negatively */ 047 protected boolean _reverseWorkspaceMather; 048 049 public void configure(Configuration configuration) throws ConfigurationException 050 { 051 _prefixes = new HashSet<>(); 052 053 for (Configuration prefixConfiguration : configuration.getChildren("prefix")) 054 { 055 String prefix = prefixConfiguration.getValue(); 056 _prefixes.add(prefix); 057 } 058 059 String workspace = configuration.getChild("workspace").getValue(""); 060 if (StringUtils.isNotBlank(workspace)) 061 { 062 if (workspace.startsWith("!")) 063 { 064 _reverseWorkspaceMather = true; 065 workspace = workspace.substring(1); 066 } 067 _workspaceMatcher = Pattern.compile(workspace); 068 } 069 } 070 071 /** 072 * Get the prefix of the path accepted 073 * @return The non-null and non-empty prefixes, starting by '/' 074 */ 075 protected Set<String> getSupportedPrefixes() 076 { 077 return _prefixes; 078 } 079 080 /** 081 * Get the prefix of the path accepted 082 * @return The non-null and non-empty prefixes, starting by '/' 083 */ 084 protected Set<String> getRootPrefixes() 085 { 086 return _prefixes; 087 } 088 089 @Override 090 protected Set<? extends Object> _convertWorkspaceToRootRightContexts(Set<Object> workspacesContexts) 091 { 092 if (_workspaceMatcher != null) 093 { 094 for (Object workspaceContext : workspacesContexts) 095 { 096 if (workspaceContext instanceof String) 097 { 098 boolean match = _workspaceMatcher.matcher((String) workspaceContext).matches(); 099 if (!match && _reverseWorkspaceMather || match && !_reverseWorkspaceMather) 100 { 101 return getRootPrefixes(); 102 } 103 } 104 } 105 return null; 106 } 107 else 108 { 109 return getRootPrefixes(); 110 } 111 } 112 113 public boolean isSupported(Object object) 114 { 115 if (!(object instanceof String)) 116 { 117 return false; 118 } 119 String context = (String) object; 120 121 Set<String> prefixes = getSupportedPrefixes(); 122 if (prefixes != null) 123 { 124 for (String prefix : prefixes) 125 { 126 if (StringUtils.isNotBlank(prefix) && StringUtils.equals(context, prefix) || context.startsWith(prefix + SEPARATOR)) 127 { 128 return true; 129 } 130 } 131 } 132 133 return false; 134 } 135 136 @Override 137 protected Set<String> _getParents(String object) 138 { 139 if (object == null) 140 { 141 return null; 142 } 143 144 int index = object.lastIndexOf(SEPARATOR); 145 if (index <= 1) 146 { 147 return null; 148 } 149 150 return Collections.singleton(object.substring(0, index)); 151 } 152}