/**
* Copyright 2010 JBoss Inc
*
* 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.drools.guvnor.server.security;
import static org.jboss.seam.ScopeType.APPLICATION;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import org.drools.guvnor.server.ServiceImplementation;
import org.drools.guvnor.server.util.LoggingHelper;
import org.drools.repository.RulesRepositoryException;
import org.jboss.seam.Component;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.security.permission.PermissionResolver;
/**
* PermissionResolvers are chained together to resolve permission check, the check returns true if
* one of the PermissionResolvers in the chain returns true.
*
* This PermissionResolver resolves category-based permissions and package-based permissions.
*
* If the input is category-based request, the resolver returns true under following situations:
* 1. The user is admin
* Or
* 2. The user has at least one analyst role that has access to the requested category path.
*
* If the input is package-based request, the resolver returns true under following situations:
* 1. The user is admin
* Or
* 2. The user has one of the following roles package.admin|package.developer|package.readonly on the requested
* package, and requested role requires lower privilege than assigned role(I.e., package.admin>package.developer>package.readonly)
*
*
* @author Jervis Liu
*/
@Name("org.jboss.seam.security.roleBasedPermissionResolver")
@Scope(APPLICATION)
@BypassInterceptors
@Install(precedence = org.jboss.seam.annotations.Install.APPLICATION)
@Startup
public class RoleBasedPermissionResolver
implements
PermissionResolver,
Serializable {
private static final LoggingHelper log = LoggingHelper.getLogger(RoleBasedPermissionResolver.class);
private boolean enableRoleBasedAuthorization = false;
@Create
public void create() {
}
/**
* check permission
*
* @param requestedObject
* the requestedObject must be an instance of CategoryPathType,
* or PackageNameType or PackageUUIDType.
* Otherwise return false;
* @param requestedPermission
* the requestedRole must be an instance of String, its value has to be one of the
* followings: admin|analyst|package.admin|package.developer|package.readonly,
* otherwise return false;
* @return true if the permission can be granted on the requested object with the
* requested role; return false otherwise.
*
*/
public boolean hasPermission(Object requestedObject,
String requestedPermission) {
if ( !((requestedObject instanceof CategoryPathType) || (requestedObject instanceof PackageNameType) || (requestedObject instanceof WebDavPackageNameType) || (requestedObject instanceof AdminType) || (requestedObject instanceof PackageUUIDType)) ) {
log.debug("Requested permission is not an instance of CategoryPathType|PackageNameType|WebDavPackageNameType|AdminType|PackageUUIDType");
return false;
}
if ( !enableRoleBasedAuthorization ) {
return true;
}
RoleBasedPermissionManager permManager = (RoleBasedPermissionManager) Component.getInstance( "roleBasedPermissionManager" );
List<RoleBasedPermission> permissions = permManager.getRoleBasedPermission();
if ( hasAdminPermission( permissions ) ) {
//admin can do everything,no need for further checks.
return true;
} else if ( RoleTypes.ADMIN.equals( requestedPermission ) ) {
return hasAdminPermission( permissions );
}
if ( requestedObject instanceof CategoryPathType ) {
String requestedPath = ((CategoryPathType) requestedObject).getCategoryPath();
String requestedPermType = (requestedPermission == null) ? RoleTypes.ANALYST : requestedPermission;
if ( requestedPermType.equals( "navigate" ) ) {
for ( RoleBasedPermission p : permissions ) {
if ( p.getCategoryPath() != null ) {
if ( p.getCategoryPath().equals( requestedPath ) ) return true;
if ( isSubPath( requestedPath,
p.getCategoryPath() ) ) {
log.debug("Requested permission: " + requestedPermType + ", Requested object: "
+ requestedPath + " , Permission granted: Yes");
return true;
} else if ( isSubPath( p.getCategoryPath(),
requestedPath ) ) {
log.debug("Requested permission: " + requestedPermType + ", Requested object: "
+ requestedPath + " , Permission granted: Yes");
return true;
}
}
}
log.debug("Requested permission: " + requestedPermType + ", Requested object: "
+ requestedPath + " , Permission granted: No");
return false;
} else {
for ( RoleBasedPermission pbp : permissions ) {
// Check if there is a analyst or analyst.readonly role
if ( pbp.getRole().equals( RoleTypes.ANALYST ) || pbp.getRole().equals( RoleTypes.ANALYST_READ ) ) {
// Check if user has permissions for the current category
if ( requestedPermType.equals( pbp.getRole() ) || (requestedPermType.equals( RoleTypes.ANALYST_READ ) && pbp.getRole().equals( RoleTypes.ANALYST )) ) {
if ( isPermittedCategoryPath( requestedPath,
pbp.getCategoryPath() ) ) {
log.debug("Requested permission: " + requestedPermType + ", Requested object: "
+ requestedPath + " , Permission granted: Yes");
return true;
}
}
}
}
log.debug("Requested permission: " + requestedPermType + ", Requested object: "
+ requestedPath + " , Permission granted: No");
return false;
}
} else {
String targetName = "";
if ( requestedObject instanceof PackageUUIDType ) {
String targetUUID = ((PackageUUIDType) requestedObject).getUUID();
try {
ServiceImplementation si = (ServiceImplementation) Component.getInstance( "org.drools.guvnor.client.rpc.RepositoryService" );
targetName = si.repository.loadPackageByUUID( targetUUID ).getName();
} catch ( RulesRepositoryException e ) {
return false;
}
} else if ( requestedObject instanceof PackageNameType ) {
targetName = ((PackageNameType) requestedObject).getPackageName();
}
for ( RoleBasedPermission pbp : permissions ) {
if ( targetName.equalsIgnoreCase( pbp.getPackageName() ) && isPermittedPackage( requestedPermission,
pbp.getRole() ) ) {
log.debug("Requested permission: " + requestedPermission + ", Requested object: "
+ targetName + " , Permission granted: Yes");
return true;
}
}
log.debug("Requested permission: " + requestedPermission + ", Requested object: "
+ targetName + " , Permission granted: No");
return false;
}
}
private boolean hasAdminPermission(List<RoleBasedPermission> permissions) {
for ( RoleBasedPermission p : permissions ) {
if ( RoleTypes.ADMIN.equalsIgnoreCase( p.getRole() ) ) {
log.debug("Requested permission: unknown, Permission granted: Yes");
return true;
}
}
log.debug("Requested permission: admin, Permission granted: No");
return false;
}
private boolean isPermittedCategoryPath(String requestedPath,
String allowedPath) {
if ( requestedPath == null && allowedPath == null ) {
return true;
} else if ( requestedPath == null || allowedPath == null ) {
return false;
}
return requestedPath.equals( allowedPath ) || isSubPath( allowedPath,
requestedPath );
}
private boolean isPermittedPackage(String requestedAction,
String role) {
if ( RoleTypes.PACKAGE_ADMIN.equalsIgnoreCase( role ) ) {
return true;
} else if ( RoleTypes.PACKAGE_DEVELOPER.equalsIgnoreCase( role ) ) {
if ( RoleTypes.PACKAGE_ADMIN.equalsIgnoreCase( requestedAction ) ) {
return false;
} else if ( RoleTypes.PACKAGE_DEVELOPER.equalsIgnoreCase( requestedAction ) ) {
return true;
} else if ( RoleTypes.PACKAGE_READONLY.equalsIgnoreCase( requestedAction ) ) {
return true;
}
} else if ( RoleTypes.PACKAGE_READONLY.equalsIgnoreCase( role ) ) {
if ( RoleTypes.PACKAGE_ADMIN.equalsIgnoreCase( requestedAction ) ) {
return false;
} else if ( RoleTypes.PACKAGE_DEVELOPER.equalsIgnoreCase( requestedAction ) ) {
return false;
} else if ( RoleTypes.PACKAGE_READONLY.equalsIgnoreCase( requestedAction ) ) {
return true;
}
}
return false;
}
public boolean isSubPath(String parentPath,
String subPath) {
parentPath = (parentPath.startsWith( "/" )) ? parentPath.substring( 1 ) : parentPath;
subPath = (subPath.startsWith( "/" )) ? subPath.substring( 1 ) : subPath;
String[] parentTags = parentPath.split( "/" );
String[] subTags = subPath.split( "/" );
if ( parentTags.length > subTags.length ) return false;
for ( int i = 0; i < parentTags.length; i++ ) {
if ( !parentTags[i].equals( subTags[i] ) ) return false;
}
return true;
}
public void filterSetByAction(Set<Object> targets,
String action) {
}
public boolean isEnableRoleBasedAuthorization() {
return enableRoleBasedAuthorization;
}
public void setEnableRoleBasedAuthorization(boolean enableRoleBasedAuthorization) {
this.enableRoleBasedAuthorization = enableRoleBasedAuthorization;
}
}