/*
* 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.wicket.security.hive.authorization.permissions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.wicket.Component;
import org.apache.wicket.security.actions.Inherit;
import org.apache.wicket.security.actions.WaspAction;
import org.apache.wicket.security.components.SecureComponentHelper;
import org.apache.wicket.security.hive.authorization.Permission;
/**
* Permission for certain components. Can have actions like access, render or enable.
*
* @author marrink
*/
public class ComponentPermission extends ActionPermission
{
private static final long serialVersionUID = 8950870313751454034L;
private final List<String[]> parents;
private final String[] path;
/**
* Creates a new ComponentPermission with the specified actions.
*
* @param component
* the component
* @param action
* the action(s)
*/
public ComponentPermission(Component component, WaspAction action)
{
super(SecureComponentHelper.alias(component), action);
path = getName().split(SecureComponentHelper.PATH_SEPARATOR);
String[] aliasses = SecureComponentHelper.containerAliasses(component);
if (aliasses != null && aliasses.length > 0)
{
this.parents = new ArrayList<String[]>(aliasses.length);
for (int i = 0; i < aliasses.length; i++)
this.parents.add(aliasses[i].split(SecureComponentHelper.PATH_SEPARATOR));
}
else
this.parents = Collections.emptyList();
}
/**
* Creates a new ComponentPermission with the specified actions.
*
* @param componentAlias
* an alias as produced by {@link SecureComponentHelper}
* @param actions
* the granted action(s)
*/
public ComponentPermission(String componentAlias, WaspAction actions)
{
super(componentAlias, actions);
path = getName().split(SecureComponentHelper.PATH_SEPARATOR);
parents = Collections.emptyList();
}
/**
* Overrides {@link ActionPermission#implies(Permission)} to also include inheritance
* between several levels of parent containers. The same rules still apply
*
* @see Permission#implies(Permission)
*/
@Override
public boolean implies(Permission permission)
{
if (permission instanceof ComponentPermission)
{
ComponentPermission other = (ComponentPermission) permission;
if (getAction().implies(getAction().getActionFactory().getAction(Inherit.class)))
return getAction().implies(other.getAction())
&& (implies(other.path, path) || impliesHierarchy(other));
return getAction().implies(other.getAction()) && equals(other.path, path);
}
return false;
}
private boolean impliesHierarchy(ComponentPermission other)
{
if (other == null)
return false;
for (int i = 0; i < other.parents.size(); i++)
{
if (implies(path, other.parents.get(i)))
return true;
}
return false;
}
protected boolean equals(String[] path1, String[] path2)
{
if (path1.length != path2.length)
return false;
for (int count = 0; count < path1.length; count++)
{
if (!path1[count].equals(path2[count]))
return false;
}
return true;
}
protected boolean implies(String[] path1, String[] path2)
{
int i = 0;
int j = 0;
for (; i < path1.length && j < path2.length; j++)
{
if (path1[i].equals(path2[j]))
{
i++;
}
else if (i > 0)
return false;
}
return path1.length == i;
// TODO wildcards would be nice:
// e.g org.MyPage:*:SomeComponent * fits just one parts
// org.MyPage:**:SomeComponent ** fits one or more parts so
// Panel1:Panel2 would be valid and we could grant permissions for
// components at an unknown depth
// ? could be used to fit a single char wildcard
}
}