/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util.auth; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.text.StrBuilder; import org.apache.shiro.authz.Permission; import org.apache.shiro.authz.permission.InvalidPermissionStringException; import org.apache.shiro.authz.permission.WildcardPermission; import com.google.common.collect.ImmutableSet; /** * An Apache Shiro {@code Permission} that allows permission resolving to be extended. * <p> * This is a faster version of {@link WildcardPermission}. * See {@link ShiroPermissionResolver} for public access. */ final class ShiroWildcardPermission implements Permission { /** * The wildcard segment. */ private static final ImmutableSet<String> WILDCARD_SEGMENT = ImmutableSet.of("*"); /** * The permission segments. */ private final List<Set<String>> _segments = new ArrayList<>(); /** * The hash code. */ private final int _hashCode; /** * The string form. */ private final String _toString; /** * Creates an instance. * * @param permissionString the permission string, not null * @return the permission object, not null * @throws InvalidPermissionStringException if the permission string is invalid */ static Permission of(String permissionString) { return new ShiroWildcardPermission(permissionString); } //------------------------------------------------------------------------- /** * Creates an instance. * * @param permissionString the permission string, not null * @throws InvalidPermissionStringException if the permission string is invalid */ private ShiroWildcardPermission(final String permissionString) { String permStr = StringUtils.stripToNull(permissionString); if (permStr == null) { throw new InvalidPermissionStringException("Permission string must not be blank: " + permissionString, permissionString); } // case insensitive permStr = permStr.toLowerCase(Locale.ROOT); // split once List<Set<String>> wildcardSegments = new ArrayList<>(); String[] segmentStrs = StringUtils.splitPreserveAllTokens(permStr, ':'); for (String segmentStr : segmentStrs) { String[] partStrs = StringUtils.splitPreserveAllTokens(segmentStr, ','); if (partStrs.length == 0) { throw new InvalidPermissionStringException("Permission string must not contain an empty segment: " + permissionString, permissionString); } Set<String> parts = new LinkedHashSet<>(); for (String partStr : partStrs) { partStr = partStr.trim(); if (partStr.isEmpty()) { throw new InvalidPermissionStringException("Permission string must not contain an empty part: " + permissionString, permissionString); } if (partStr.contains("*") && partStr.equals("*") == false) { throw new InvalidPermissionStringException("Permission string wildcard can only be applied to whole segment: " + permissionString, permissionString); } parts.add(partStr); } // simplify if (parts.contains("*")) { wildcardSegments.add(WILDCARD_SEGMENT); } else { _segments.addAll(wildcardSegments); wildcardSegments.clear(); _segments.add(parts); } } _hashCode = _segments.hashCode(); _toString = createToString(_segments); } private static String createToString(List<Set<String>> segments) { StrBuilder buf = new StrBuilder(); for (Iterator<Set<String>> it1 = segments.iterator(); it1.hasNext();) { for (Iterator<String> it2 = it1.next().iterator(); it2.hasNext();) { buf.append(it2.next()); if (it2.hasNext()) { buf.append(','); } } if (it1.hasNext()) { buf.append(':'); } } return buf.toString(); } //------------------------------------------------------------------------- // this permission is the permission I have // the other permission is the permission being checked @Override public boolean implies(Permission requiredPermission) { if (requiredPermission instanceof ShiroWildcardPermission == false) { return false; } ShiroWildcardPermission requiredPerm = (ShiroWildcardPermission) requiredPermission; List<Set<String>> thisSegments = _segments; List<Set<String>> otherSegments = requiredPerm._segments; if (thisSegments.size() > otherSegments.size()) { return false; } int commonLen = Math.min(thisSegments.size(), otherSegments.size()); for (int i = 0; i < commonLen; i++) { Set<String> thisSegment = thisSegments.get(i); Set<String> otherSegment = otherSegments.get(i); if (thisSegment != WILDCARD_SEGMENT && thisSegment.containsAll(otherSegment) == false) { return false; } } return true; } //------------------------------------------------------------------------- @Override public boolean equals(Object obj) { if (obj instanceof ShiroWildcardPermission) { ShiroWildcardPermission other = (ShiroWildcardPermission) obj; return _segments.equals(other._segments); } return false; } @Override public int hashCode() { return _hashCode; } @Override public String toString() { return _toString; } }