blob: 5e3caa58835e16a3cb9e4795cf98515c11caa56e [file] [log] [blame]
/*
* 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.oak.security.authorization.permission;
import java.security.Principal;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.commons.LongUtils;
import org.apache.jackrabbit.oak.security.authorization.ProviderCtx;
import org.apache.jackrabbit.oak.spi.mount.Mount;
import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
import org.apache.jackrabbit.oak.spi.security.Context;
import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
import org.jetbrains.annotations.NotNull;
import static com.google.common.collect.Lists.newArrayList;
public class MountPermissionProvider extends PermissionProviderImpl {
@NotNull
public static String getPermissionRootName(@NotNull Mount mount, @NotNull String workspace) {
if (mount.isDefault()) {
return workspace;
} else {
return mount.getPathFragmentName() + "-" + workspace;
}
}
private final MountInfoProvider mountInfoProvider;
public MountPermissionProvider(@NotNull Root root, @NotNull String workspaceName,
@NotNull Set<Principal> principals, @NotNull RestrictionProvider restrictionProvider,
@NotNull ConfigurationParameters options, @NotNull Context ctx,
@NotNull ProviderCtx providerCtx) {
super(root, workspaceName, principals, restrictionProvider, options, ctx, providerCtx);
this.mountInfoProvider = providerCtx.getMountInfoProvider();
}
@Override
protected PermissionStore getPermissionStore(Root root, String workspaceName,
RestrictionProvider restrictionProvider) {
List<PermissionStoreImpl> stores = newArrayList();
stores.add(new PermissionStoreImpl(root, workspaceName, restrictionProvider));
for (Mount m : mountInfoProvider.getNonDefaultMounts()) {
String psRoot = getPermissionRootName(m, workspaceName);
PermissionStoreImpl ps = new PermissionStoreImpl(root, psRoot, restrictionProvider);
stores.add(ps);
}
return new MountPermissionStore(stores);
}
private static class MountPermissionStore implements PermissionStore {
private final List<PermissionStoreImpl> stores;
public MountPermissionStore(List<PermissionStoreImpl> stores) {
this.stores = stores;
}
@NotNull
@Override
public Collection<PermissionEntry> load(@NotNull String principalName,
@NotNull String path) {
for (PermissionStoreImpl store : stores) {
Collection<PermissionEntry> col = store.load(principalName, path);
if (col != null && !col.isEmpty()) {
return col;
}
}
return null;
}
@NotNull
@Override
public PrincipalPermissionEntries load(@NotNull String principalName) {
PrincipalPermissionEntries ppe = new PrincipalPermissionEntries();
for (PermissionStoreImpl store : stores) {
ppe.putAllEntries(store.load(principalName).getEntries());
}
ppe.setFullyLoaded(true);
return ppe;
}
@NotNull
@Override
public NumEntries getNumEntries(@NotNull String principalName, long max) {
long num = 0;
boolean isExact = true;
for (PermissionStoreImpl store : stores) {
NumEntries ne = store.getNumEntries(principalName, max);
num = LongUtils.safeAdd(num, ne.size);
if (!ne.isExact) {
isExact = false;
}
// if any of the stores doesn't reveal the exact number and max
// is reached, stop asking the remaining stores.
// as long as every store is reporting the exact number continue
// in order to (possibly) be able to return the exact number.
if (num >= max && !isExact) {
break;
}
}
return NumEntries.valueOf(num, isExact);
}
@Override
public void flush(@NotNull Root root) {
for (PermissionStoreImpl store : stores) {
store.flush(root);
}
}
}
}