/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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;
import java.security.Principal;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.observation.ObservationManager;
import javax.jcr.security.Privilege;
import org.apache.jackrabbit.api.JackrabbitWorkspace;
import org.apache.jackrabbit.core.ItemImpl;
import org.apache.jackrabbit.core.NodeImpl;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.id.ItemId;
import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
import org.apache.jackrabbit.core.security.SystemPrincipal;
import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.Path;
/**
* <code>AbstractAccessControlProvider</code>...
*/
public abstract class AbstractAccessControlProvider implements AccessControlProvider,
AccessControlUtils, AccessControlConstants {
/**
* Constant for the name of the configuration option "omit-default-permission".
* The option is a flag indicating whether default permissions should be
* created upon initialization of this provider.
* <p>
* If this option is present in the configuration no initial ACL content
* is created.<br>
* If this configuration option is omitted the default permissions are
* installed. Note however, that the initialization should not overwrite
* previously installed AC content.
*/
public static final String PARAM_OMIT_DEFAULT_PERMISSIONS = "omit-default-permission";
/**
* the system session this provider has been created for.
*/
protected SessionImpl session;
protected ObservationManager observationMgr;
protected PrivilegeManagerImpl privilegeManager;
private boolean initialized;
protected AbstractAccessControlProvider() {
}
/**
* Throws <code>IllegalStateException</code> if the provider has not
* been initialized or has been closed.
*/
protected void checkInitialized() {
if (!initialized) {
throw new IllegalStateException("Not initialized or already closed.");
}
}
/**
* @return the PrivilegeManager
* @throws RepositoryException
*/
protected PrivilegeManagerImpl getPrivilegeManagerImpl() throws RepositoryException {
return privilegeManager;
}
/**
* Returns compiled permissions for the administrator i.e. permissions
* that grants everything and returns the int representation of {@link Privilege#JCR_ALL}
* upon {@link CompiledPermissions#getPrivileges(Path)} for all
* paths.
*
* @return an implementation of <code>CompiledPermissions</code> that
* grants everything and always returns the int representation of
* {@link Privilege#JCR_ALL} upon {@link CompiledPermissions#getPrivileges(Path)}.
*/
protected CompiledPermissions getAdminPermissions() {
return new CompiledPermissions() {
public void close() {
//nop
}
public boolean grants(Path absPath, int permissions) {
return true;
}
public int getPrivileges(Path absPath) throws RepositoryException {
return PrivilegeRegistry.getBits(new Privilege[] {getAllPrivilege()});
}
public boolean hasPrivileges(Path absPath, Privilege... privileges) {
return true;
}
public Set<Privilege> getPrivilegeSet(Path absPath) throws RepositoryException {
return Collections.singleton(getAllPrivilege());
}
public boolean canReadAll() {
return true;
}
public boolean canRead(Path itemPath, ItemId itemId) {
return true;
}
private Privilege getAllPrivilege() throws RepositoryException {
return getPrivilegeManagerImpl().getPrivilege(Privilege.JCR_ALL);
}
};
}
/**
* Returns compiled permissions for a read-only user i.e. permissions
* that grants READ permission for all non-AC items.
*
* @return an implementation of <code>CompiledPermissions</code> that
* grants READ permission for all non-AC items.
*/
protected CompiledPermissions getReadOnlyPermissions() {
return new CompiledPermissions() {
public void close() {
//nop
}
public boolean grants(Path absPath, int permissions) throws RepositoryException {
if (isAcItem(absPath)) {
// read-only never has read-AC permission
return false;
} else {
return permissions == Permission.READ;
}
}
public int getPrivileges(Path absPath) throws RepositoryException {
if (isAcItem(absPath)) {
return PrivilegeRegistry.NO_PRIVILEGE;
} else {
return PrivilegeRegistry.getBits(new Privilege[] {getReadPrivilege()});
}
}
public boolean hasPrivileges(Path absPath, Privilege... privileges) throws RepositoryException {
if (isAcItem(absPath)) {
return false;
} else {
return privileges != null && privileges.length == 1 && getReadPrivilege().equals(privileges[0]);
}
}
public Set<Privilege> getPrivilegeSet(Path absPath) throws RepositoryException {
if (isAcItem(absPath)) {
return Collections.emptySet();
} else {
return Collections.singleton(getReadPrivilege());
}
}
public boolean canReadAll() {
return false;
}
public boolean canRead(Path itemPath, ItemId itemId) throws RepositoryException {
if (itemPath != null) {
return !isAcItem(itemPath);
} else {
return !isAcItem(session.getItemManager().getItem(itemId));
}
}
private Privilege getReadPrivilege() throws RepositoryException {
return getPrivilegeManagerImpl().getPrivilege(Privilege.JCR_READ);
}
};
}
//-------------------------------------------------< AccessControlUtils >---
/**
* @see org.apache.jackrabbit.core.security.authorization.AccessControlUtils#isAcItem(Path)
*/
public boolean isAcItem(Path absPath) throws RepositoryException {
Path.Element[] elems = absPath.getElements();
// start looking for a rep:policy name starting from the last element.
// NOTE: with the current content structure max. 3 levels must be looked
// at as the rep:policy node may only have ACE nodes with properties.
if (elems.length > 1) {
for (int index = elems.length-1, j = 1; index >= 0 && j <= 3; index--, j++) {
if (N_POLICY.equals(elems[index].getName())) {
return true;
}
}
}
return false;
}
/**
* Test if the given node is itself a rep:ACL or a rep:ACE node.
* @see org.apache.jackrabbit.core.security.authorization.AccessControlUtils#isAcItem(org.apache.jackrabbit.core.ItemImpl)
*/
public boolean isAcItem(ItemImpl item) throws RepositoryException {
NodeImpl n = ((item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent());
Name ntName = ((NodeTypeImpl) n.getPrimaryNodeType()).getQName();
return ntName.equals(NT_REP_ACL) ||
ntName.equals(NT_REP_GRANT_ACE) ||
ntName.equals(NT_REP_DENY_ACE);
}
/**
* @see AccessControlUtils#isAdminOrSystem(Set)
*/
public boolean isAdminOrSystem(Set<Principal> principals) {
for (Principal p : principals) {
if (p instanceof AdminPrincipal || p instanceof SystemPrincipal) {
return true;
}
}
return false;
}
/**
* @see AccessControlUtils#isReadOnly(Set)
*/
public boolean isReadOnly(Set<Principal> principals) {
// TODO: find ways to determine read-only status
return false;
}
//----------------------------------------------< AccessControlProvider >---
/**
* Tests if the given <code>systemSession</code> is a SessionImpl and
* retrieves the observation manager. The it sets the internal 'initialized'
* field to true.
*
* @throws RepositoryException If the specified session is not a
* <code>SessionImpl</code> or if retrieving the observation manager fails.
* @see AccessControlProvider#init(Session, Map)
*/
public void init(Session systemSession, Map configuration) throws RepositoryException {
if (initialized) {
throw new IllegalStateException("already initialized");
}
if (!(systemSession instanceof SessionImpl)) {
throw new RepositoryException("SessionImpl (system session) expected.");
}
session = (SessionImpl) systemSession;
observationMgr = systemSession.getWorkspace().getObservationManager();
privilegeManager = (PrivilegeManagerImpl) ((JackrabbitWorkspace) session.getWorkspace()).getPrivilegeManager();
initialized = true;
}
/**
* @see AccessControlProvider#close()
*/
public void close() {
checkInitialized();
initialized = false;
}
/**
* @see AccessControlProvider#isLive()
*/
public boolean isLive() {
return initialized && session.isLive();
}
}