/*!
* Copyright 2010 - 2015 Pentaho Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jackrabbit.core.security.authorization.acl;
import org.apache.jackrabbit.api.JackrabbitWorkspace;
import org.apache.jackrabbit.api.security.principal.PrincipalManager;
import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.core.security.authorization.AccessControlConstants;
import org.apache.jackrabbit.core.security.authorization.GlobPattern;
import org.apache.jackrabbit.core.security.authorization.PrivilegeBits;
import org.apache.jackrabbit.core.security.authorization.PrivilegeManagerImpl;
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.spi.Name;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import java.security.Principal;
import java.security.acl.Group;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Copy-and-paste of {@code org.apache.jackrabbit.core.security.authorization.acl.Entry} in Jackrabbit 2.10.0.
* This class is in {@code org.apache.jackrabbit.core.security.authorization.acl} package due to the scope of
* collaborating classes.
*
* <p/>
* <p/>
* <p> Changes to original: </p> <ul> <li>{@code Entry} has a single private constructor, we changed the
* scope to public {@code null} {@code nextId}.</li>
* <p/>
* </ul>
*/
public class PentahoEntry implements AccessControlConstants {
private static final Logger log = LoggerFactory.getLogger( ACLTemplate.class );
private final String principalName;
private final boolean isGroupEntry;
private final PrivilegeBits privilegeBits;
private final boolean isAllow;
private final NodeId id;
private final GlobPattern pattern;
private final boolean hasRestrictions;
/**
* https://issues.apache.org/jira/browse/JCR-3882
*
* We can't use 'pattern.equals( other.pattern )' for the time being, this is a
* workaround while the above issue does not get pushed into a stable jackrabbit release
*/
private final String path;
private final String restriction;
/**
* end workaround
*/
private int hashCode;
public PentahoEntry(NodeId id, String principalName, boolean isGroupEntry,
PrivilegeBits privilegeBits, boolean allow, String path, Value globValue) throws RepositoryException {
this.principalName = principalName;
this.isGroupEntry = isGroupEntry;
this.privilegeBits = privilegeBits;
this.isAllow = allow;
this.id = id;
this.pattern = calculatePattern(path, globValue);
this.hasRestrictions = (globValue != null);
/**
* https://issues.apache.org/jira/browse/JCR-3882
*
* We can't use 'pattern.equals( other.pattern )' for the time being, this is a
* workaround while the above issue does not get pushed into a stable jackrabbit release
*/
this.path = path;
this.restriction = globValue != null ? globValue.getString() : null;
/**
* end workaround
*/
}
public PentahoEntry(NodeId id, String principalName, boolean isGroupEntry,
PrivilegeBits privilegeBits, boolean allow, String path, Map<Name, Value> restrictions ) throws RepositoryException {
this.principalName = principalName;
this.isGroupEntry = isGroupEntry;
this.privilegeBits = privilegeBits;
this.isAllow = allow;
this.id = id;
this.pattern = calculatePattern( path, ( restrictions != null ? restrictions.get( P_GLOB ) : null ) );
this.hasRestrictions = ( restrictions != null && restrictions.get( P_GLOB ) != null );
/**
* https://issues.apache.org/jira/browse/JCR-3882
*
* We can't use 'pattern.equals( other.pattern )' for the time being, this is a
* workaround while the above issue does not get pushed into a stable jackrabbit release
*/
this.path = path;
this.restriction = restrictions != null && restrictions.get( P_GLOB ) != null ?
restrictions.get( P_GLOB ).getString() : null;
/**
* end workaround
*/
}
static List<PentahoEntry> readEntries(NodeImpl aclNode, String path) throws RepositoryException {
if (aclNode == null || !NT_REP_ACL.equals(aclNode.getPrimaryNodeTypeName())) {
throw new IllegalArgumentException("Node must be of type 'rep:ACL'");
}
SessionImpl sImpl = (SessionImpl) aclNode.getSession();
PrincipalManager principalMgr = sImpl.getPrincipalManager();
PrivilegeManagerImpl privilegeMgr = (PrivilegeManagerImpl) ((JackrabbitWorkspace) sImpl.getWorkspace()).getPrivilegeManager();
NodeId nodeId = aclNode.getParentId();
List<PentahoEntry> entries = new ArrayList<PentahoEntry>();
// load the entries:
NodeIterator itr = aclNode.getNodes();
while (itr.hasNext()) {
NodeImpl aceNode = (NodeImpl) itr.nextNode();
try {
String principalName = aceNode.getProperty(P_PRINCIPAL_NAME).getString();
boolean isGroupEntry = false;
Principal princ = principalMgr.getPrincipal(principalName);
if (princ != null) {
isGroupEntry = (princ instanceof Group );
}
InternalValue[] privValues = aceNode.getProperty(P_PRIVILEGES).internalGetValues();
Name[] privNames = new Name[privValues.length];
for (int i = 0; i < privValues.length; i++) {
privNames[i] = privValues[i].getName();
}
Value globValue = null;
if (aceNode.hasProperty(P_GLOB)) {
globValue = aceNode.getProperty(P_GLOB).getValue();
}
boolean isAllow = NT_REP_GRANT_ACE.equals(aceNode.getPrimaryNodeTypeName());
PentahoEntry ace = new PentahoEntry(nodeId, principalName, isGroupEntry, privilegeMgr.getBits(privNames),
isAllow, path, globValue);
entries.add(ace);
} catch (RepositoryException e) {
log.debug("Failed to build ACE from content. {}", e.getMessage());
}
}
return entries;
}
private static GlobPattern calculatePattern(String path, Value globValue) throws RepositoryException {
if (path == null) {
return null;
} else {
if (globValue == null) {
return GlobPattern.create(path);
} else {
return GlobPattern.create(path, globValue.getString());
}
}
}
/**
* @param nodeId
* @return <code>true</code> if this entry is defined on the node
* at <code>nodeId</code>
*/
boolean isLocal(NodeId nodeId) {
return id != null && id.equals(nodeId);
}
/**
*
* @param jcrPath
* @return
*/
boolean matches(String jcrPath) {
return pattern != null && pattern.matches(jcrPath);
}
PrivilegeBits getPrivilegeBits() {
return privilegeBits;
}
boolean isAllow() {
return isAllow;
}
String getPrincipalName() {
return principalName;
}
boolean isGroupEntry() {
return isGroupEntry;
}
boolean hasRestrictions() {
return hasRestrictions;
}
//-------------------------------------------------------------< Object >---
/**
* @see Object#hashCode()
*/
@Override
public int hashCode() {
if (hashCode == -1) {
int h = 17;
h = 37 * h + principalName.hashCode();
h = 37 * h + privilegeBits.hashCode();
h = 37 * h + Boolean.valueOf(isAllow).hashCode();
h = 37 * h + pattern.hashCode();
hashCode = h;
}
return hashCode;
}
/**
* @see Object#equals(Object)
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof PentahoEntry) {
PentahoEntry other = (PentahoEntry) obj;
return principalName.equals( other.principalName ) &&
privilegeBits.equals( other.privilegeBits ) &&
isAllow == other.isAllow &&
/* pattern.equals( other.pattern ) */
/**
* https://issues.apache.org/jira/browse/JCR-3882
*
* We can't use 'pattern.equals( other.pattern )' for the time being, this is a
* workaround while the above issue does not get pushed into a stable jackrabbit release
*/
(
path.equals( other.path ) &&
( (restriction == null) ? other.restriction == null : restriction.equals(other.restriction) )
)
/**
* end workaround
*/
;
}
return false;
}
}