001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.shiro.authz; 018 019import org.apache.shiro.authz.Permission; 020import org.apache.shiro.authz.permission.WildcardPermission; 021 022import java.lang.reflect.Method; 023import java.util.List; 024import java.util.Set; 025 026/** 027 * @since 5.10.0 028 */ 029public class ActiveMQWildcardPermission extends WildcardPermission { 030 031 private final boolean caseSensitive; 032 033 public ActiveMQWildcardPermission(String wildcardString) { 034 this(wildcardString, true); 035 } 036 037 public ActiveMQWildcardPermission(String wildcardString, boolean caseSensitive) { 038 super(wildcardString, caseSensitive); 039 this.caseSensitive = caseSensitive; 040 } 041 042 @Override 043 public boolean implies(Permission p) { 044 // By default only supports comparisons with other WildcardPermissions 045 if (!(p instanceof WildcardPermission)) { 046 return false; 047 } 048 049 WildcardPermission wp = (WildcardPermission) p; 050 051 List<Set<String>> otherParts = getParts(wp); 052 053 int i = 0; 054 for (Set<String> otherPart : otherParts) { 055 // If this permission has less parts than the other permission, everything after the number of parts contained 056 // in this permission is automatically implied, so return true 057 if (getParts().size() - 1 < i) { 058 return true; 059 } else { 060 Set<String> thisPart = getParts().get(i); 061 062 for (String token : thisPart) { 063 if (token.equals(WILDCARD_TOKEN)) { 064 continue; 065 } 066 for (String otherToken : otherPart) { 067 if (!caseSensitive) { 068 otherToken = otherToken.toLowerCase(); 069 } 070 if (!matches(token, otherToken)) { 071 return false; 072 } 073 } 074 } 075 i++; 076 } 077 } 078 079 // If this permission has more parts than the other parts, only imply it if all of the other parts are wildcards 080 for (; i < getParts().size(); i++) { 081 Set<String> part = getParts().get(i); 082 if (!part.contains(WILDCARD_TOKEN)) { 083 return false; 084 } 085 } 086 087 return true; 088 } 089 090 /** 091 * Tests whether or not a string matches against a pattern. 092 * The pattern may contain two special characters:<br> 093 * '*' means zero or more characters<br> 094 * '?' means one and only one character 095 * 096 * @param pattern pattern to match against. 097 * Must not be <code>null</code>. 098 * @param value string which must be matched against the pattern. 099 * Must not be <code>null</code>. 100 * @return <code>true</code> if the string matches against the 101 * pattern, or <code>false</code> otherwise. 102 */ 103 protected boolean matches(String pattern, String value) { 104 105 char[] patArr = pattern.toCharArray(); 106 char[] valArr = value.toCharArray(); 107 int patIndex = 0; 108 int patEndIndex = patArr.length - 1; 109 int valIndex = 0; 110 int valEndIndex = valArr.length - 1; 111 char ch; 112 113 boolean patternContainsStar = false; 114 for (char patternChar : patArr) { 115 if (patternChar == '*') { 116 patternContainsStar = true; 117 break; 118 } 119 } 120 121 if (!patternContainsStar) { 122 // No '*'s, so we make a shortcut 123 if (patEndIndex != valEndIndex) { 124 return false; // Pattern and string do not have the same size 125 } 126 for (int i = 0; i <= patEndIndex; i++) { 127 ch = patArr[i]; 128 if (ch != '?') { 129 if (ch != valArr[i]) { 130 return false;// Character mismatch 131 } 132 } 133 } 134 return true; // String matches against pattern 135 } 136 137 138 // Process characters before first star 139 while ((ch = patArr[patIndex]) != '*' && valIndex <= valEndIndex) { 140 if (ch != '?') { 141 if (ch != valArr[valIndex]) { 142 return false;// Character mismatch 143 } 144 } 145 patIndex++; 146 valIndex++; 147 } 148 if (valIndex > valEndIndex) { 149 // All characters in the value are used. Check if only '*'s remain 150 // in the pattern. If so, we succeeded. Otherwise failure. 151 for (int i = patIndex; i <= patEndIndex; i++) { 152 if (patArr[i] != '*') { 153 return false; 154 } 155 } 156 return true; 157 } 158 159 // Process characters after last star 160 while ((ch = patArr[patEndIndex]) != '*' && valIndex <= valEndIndex) { 161 if (ch != '?') { 162 if (ch != valArr[valEndIndex]) { 163 return false;// Character mismatch 164 } 165 } 166 patEndIndex--; 167 valEndIndex--; 168 } 169 if (valIndex > valEndIndex) { 170 // All characters in the value are used. Check if only '*'s remain 171 // in the pattern. If so, we succeeded. Otherwise failure. 172 for (int i = patIndex; i <= patEndIndex; i++) { 173 if (patArr[i] != '*') { 174 return false; 175 } 176 } 177 return true; 178 } 179 180 // process pattern between stars. patIndex and patEndIndex always point to a '*'. 181 while (patIndex != patEndIndex && valIndex <= valEndIndex) { 182 int innerPatternIndex = -1; 183 for (int i = patIndex + 1; i <= patEndIndex; i++) { 184 if (patArr[i] == '*') { 185 innerPatternIndex = i; 186 break; 187 } 188 } 189 if (innerPatternIndex == patIndex + 1) { 190 // Two stars next to each other, skip the first one. 191 patIndex++; 192 continue; 193 } 194 // Find the pattern between patIndex & innerPatternIndex in the value between 195 // valIndex and valEndIndex 196 int innerPatternLength = (innerPatternIndex - patIndex - 1); 197 int innerValueLength = (valEndIndex - valIndex + 1); 198 int foundIndex = -1; 199 innerValueLoop: 200 for (int i = 0; i <= innerValueLength - innerPatternLength; i++) { 201 for (int j = 0; j < innerPatternLength; j++) { 202 ch = patArr[patIndex + j + 1]; 203 if (ch != '?') { 204 if (ch != valArr[valIndex + i + j]) { 205 continue innerValueLoop; 206 } 207 } 208 } 209 210 foundIndex = valIndex + i; 211 break; 212 } 213 214 if (foundIndex == -1) { 215 return false; 216 } 217 218 patIndex = innerPatternIndex; 219 valIndex = foundIndex + innerPatternLength; 220 } 221 222 // All characters in the string are used. Check if only '*'s are left 223 // in the pattern. If so, we succeeded. Otherwise failure. 224 for (int i = patIndex; i <= patEndIndex; i++) { 225 if (patArr[i] != '*') { 226 return false; 227 } 228 } 229 230 return true; 231 } 232 233 protected List<Set<String>> getParts(WildcardPermission wp) { 234 if (wp instanceof ActiveMQWildcardPermission) { 235 return ((ActiveMQWildcardPermission) wp).getParts(); 236 } else { 237 return getPartsByReflection(wp); 238 } 239 } 240 241 protected List<Set<String>> getPartsByReflection(WildcardPermission wp) { 242 try { 243 return doGetPartsByReflection(wp); 244 } catch (Exception e) { 245 String msg = "Unable to obtain WildcardPermission instance's 'parts' value."; 246 throw new IllegalStateException(msg, e); 247 } 248 } 249 250 @SuppressWarnings("unchecked") 251 protected List<Set<String>> doGetPartsByReflection(WildcardPermission wp) throws Exception { 252 Method getParts = WildcardPermission.class.getDeclaredMethod("getParts"); 253 getParts.setAccessible(true); 254 return (List<Set<String>>) getParts.invoke(wp); 255 } 256 257 @Override 258 public String toString() { 259 StringBuilder buffer = new StringBuilder(); 260 for (Set<String> part : getParts()) { 261 if (buffer.length() > 0) { 262 buffer.append(":"); 263 } 264 boolean first = true; 265 for (String token : part) { 266 if (!first) { 267 buffer.append(","); 268 } 269 buffer.append(token); 270 first = false; 271 } 272 } 273 return buffer.toString(); 274 } 275}