| /* |
| * Copyright (c) OSGi Alliance (2004, 2010). 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.osgi.service.application; |
| |
| import java.security.Permission; |
| import java.util.Hashtable; |
| import java.util.StringTokenizer; |
| import java.util.Vector; |
| |
| import org.osgi.framework.Filter; |
| import org.osgi.framework.FrameworkUtil; |
| import org.osgi.framework.InvalidSyntaxException; |
| |
| /** |
| * This class implements permissions for manipulating applications and their |
| * instances. |
| * <P> |
| * ApplicationAdminPermission can be targeted to applications that matches the |
| * specified filter. |
| * <P> |
| * ApplicationAdminPermission may be granted for different actions: |
| * {@code lifecycle}, {@code schedule} and {@code lock}. The |
| * permission {@code schedule} implies the permission |
| * {@code lifecycle}. |
| * |
| * @version $Id$ |
| */ |
| public class ApplicationAdminPermission extends Permission { |
| private static final long serialVersionUID = 1L; |
| |
| /** |
| * Allows the lifecycle management of the target applications. |
| */ |
| public static final String LIFECYCLE_ACTION = "lifecycle"; |
| |
| /** |
| * Allows scheduling of the target applications. The permission to |
| * schedule an application implies that the scheduler can also |
| * manage the lifecycle of that application i.e. {@code schedule} |
| * implies {@code lifecycle} |
| */ |
| public static final String SCHEDULE_ACTION = "schedule"; |
| |
| /** |
| * Allows setting/unsetting the locking state of the target applications. |
| */ |
| public static final String LOCK_ACTION = "lock"; |
| |
| private ApplicationDescriptor applicationDescriptor; |
| |
| /** |
| * Constructs an ApplicationAdminPermission. The {@code filter} |
| * specifies the target application. The {@code filter} is an |
| * LDAP-style filter, the recognized properties are {@code signer} |
| * and {@code pid}. The pattern specified in the {@code signer} |
| * is matched with the Distinguished Name chain used to sign the application. |
| * Wildcards in a DN are not matched according to the filter string rules, |
| * but according to the rules defined for a DN chain. The attribute |
| * {@code pid} is matched with the PID of the application according to |
| * the filter string rules. |
| * <p> |
| * If the {@code filter} is {@code null} then it matches |
| * {@code "*"}. If |
| * {@code actions} is {@code "*"} then it identifies all the |
| * possible actions. |
| * |
| * @param filter |
| * filter to identify application. The value {@code null} |
| * is equivalent to {@code "*"} and it indicates "all application". |
| * @param actions |
| * comma-separated list of the desired actions granted on the |
| * applications or "*" means all the actions. It must not be |
| * {@code null}. The order of the actions in the list is |
| * not significant. |
| * @throws InvalidSyntaxException |
| * is thrown if the specified {@code filter} is not syntactically |
| * correct. |
| * |
| * @exception NullPointerException |
| * is thrown if the actions parameter is {@code null} |
| * |
| * @see ApplicationDescriptor |
| * @see org.osgi.framework.AdminPermission |
| */ |
| public ApplicationAdminPermission(String filter, String actions) throws InvalidSyntaxException { |
| super(filter == null ? "*" : filter); |
| |
| if( filter == null ) |
| filter = "*"; |
| |
| if( actions == null ) |
| throw new NullPointerException( "Action string cannot be null!" ); |
| |
| this.applicationDescriptor = null; |
| this.filter = (filter == null ? "*" : filter); |
| this.actions = actions; |
| |
| if( !filter.equals( "*" ) && !filter.equals( "<<SELF>>" ) ) |
| FrameworkUtil.createFilter( this.filter ); // check if the filter is valid |
| init(); |
| } |
| |
| /** |
| * This contructor should be used when creating {@code ApplicationAdminPermission} |
| * instance for {@code checkPermission} call. |
| * @param application the tareget of the operation, it must not be {@code null} |
| * @param actions the required operation. it must not be {@code null} |
| * @throws NullPointerException if any of the arguments is null. |
| */ |
| public ApplicationAdminPermission(ApplicationDescriptor application, String actions) { |
| super(application.getApplicationId()); |
| |
| if( application == null || actions == null ) |
| throw new NullPointerException( "ApplicationDescriptor and action string cannot be null!" ); |
| |
| this.filter = application.getApplicationId(); |
| this.applicationDescriptor = application; |
| this.actions = actions; |
| |
| init(); |
| } |
| |
| /** |
| * This method can be used in the {@link java.security.ProtectionDomain} |
| * implementation in the {@code implies} method to insert the |
| * application ID of the current application into the permission being |
| * checked. This enables the evaluation of the |
| * {@code <<SELF>>} pseudo targets. |
| * @param applicationId the ID of the current application. |
| * @return the permission updated with the ID of the current application |
| */ |
| public ApplicationAdminPermission setCurrentApplicationId(String applicationId) { |
| ApplicationAdminPermission newPerm = null; |
| |
| if( this.applicationDescriptor == null ) { |
| try { |
| newPerm = new ApplicationAdminPermission( this.filter, this.actions ); |
| }catch( InvalidSyntaxException e ) { |
| throw new RuntimeException(e); /* this can never happen */ |
| } |
| } |
| else |
| newPerm = new ApplicationAdminPermission( this.applicationDescriptor, this.actions ); |
| |
| newPerm.applicationID = applicationId; |
| |
| return newPerm; |
| } |
| |
| /** |
| * Checks if the specified {@code permission} is implied by this permission. |
| * The method returns true under the following conditions: |
| * <UL> |
| * <LI> This permission was created by specifying a filter (see {@link #ApplicationAdminPermission(String, String)}) |
| * <LI> The implied {@code otherPermission} was created for a particular {@link ApplicationDescriptor} |
| * (see {@link #ApplicationAdminPermission(ApplicationDescriptor, String)}) |
| * <LI> The {@code filter} of this permission mathes the {@code ApplicationDescriptor} specified |
| * in the {@code otherPermission}. If the filter in this permission is the |
| * {@code <<SELF>>} pseudo target, then the currentApplicationId set in the |
| * {@code otherPermission} is compared to the application Id of the target |
| * {@code ApplicationDescriptor}. |
| * <LI> The list of permitted actions in this permission contains all actions required in the |
| * {@code otherPermission} |
| * </UL> |
| * Otherwise the method returns false. |
| * @param otherPermission the implied permission |
| * @return true if this permission implies the {@code otherPermission}, false otherwise. |
| */ |
| @Override |
| public boolean implies(Permission otherPermission) { |
| if( otherPermission == null ) |
| return false; |
| |
| if(!(otherPermission instanceof ApplicationAdminPermission)) |
| return false; |
| |
| ApplicationAdminPermission other = (ApplicationAdminPermission) otherPermission; |
| |
| if( !filter.equals("*") ) { |
| if( other.applicationDescriptor == null ) |
| return false; |
| |
| if( filter.equals( "<<SELF>>") ) { |
| if( other.applicationID == null ) |
| return false; /* it cannot be, this might be a bug */ |
| |
| if( !other.applicationID.equals( other.applicationDescriptor.getApplicationId() ) ) |
| return false; |
| } |
| else { |
| Hashtable props = new Hashtable(); |
| props.put( "pid", other.applicationDescriptor.getApplicationId() ); |
| props.put( "signer", new SignerWrapper( other.applicationDescriptor ) ); |
| |
| Filter flt = getFilter(); |
| if( flt == null ) |
| return false; |
| |
| if( !flt.match( props ) ) |
| return false; |
| } |
| } |
| |
| if( !actionsVector.containsAll( other.actionsVector ) ) |
| return false; |
| |
| return true; |
| } |
| |
| @Override |
| public boolean equals(Object with) { |
| if( with == null || !(with instanceof ApplicationAdminPermission) ) |
| return false; |
| |
| ApplicationAdminPermission other = (ApplicationAdminPermission)with; |
| |
| // Compare actions: |
| if( other.actionsVector.size() != actionsVector.size() ) |
| return false; |
| |
| for( int i=0; i != actionsVector.size(); i++ ) |
| if( !other.actionsVector.contains( actionsVector.get( i ) ) ) |
| return false; |
| |
| |
| return equal(this.filter, other.filter ) && equal(this.applicationDescriptor, other.applicationDescriptor) |
| && equal(this.applicationID, other.applicationID); |
| } |
| |
| /** |
| * Compares parameters for equality. If both object are null, they are considered |
| * equal. |
| * @param a object to compare |
| * @param b other object to compare |
| * @return true if both objects are equal or both are null |
| */ |
| private static boolean equal(Object a, Object b) { |
| // This equation is true if both references are null or both point |
| // to the same object. In both cases they are considered as equal. |
| if( a == b ) { |
| return true; |
| } |
| |
| return a.equals(b); |
| } |
| |
| @Override |
| public int hashCode() { |
| int hc = 0; |
| for( int i=0; i != actionsVector.size(); i++ ) |
| hc ^= ((String)actionsVector.get( i )).hashCode(); |
| hc ^= (null == this.filter )? 0 : this.filter.hashCode(); |
| hc ^= (null == this.applicationDescriptor) ? 0 : this.applicationDescriptor.hashCode(); |
| hc ^= (null == this.applicationID) ? 0 : this.applicationID.hashCode(); |
| return hc; |
| } |
| |
| /** |
| * Returns the actions of this permission. |
| * @return the actions specified when this permission was created |
| */ |
| @Override |
| public String getActions() { |
| return actions; |
| } |
| |
| private String applicationID; |
| |
| private static final Vector ACTIONS = new Vector(); |
| private Vector actionsVector; |
| private final String filter; |
| private final String actions; |
| private Filter appliedFilter = null; |
| |
| static { |
| ACTIONS.add(LIFECYCLE_ACTION); |
| ACTIONS.add(SCHEDULE_ACTION); |
| ACTIONS.add(LOCK_ACTION); |
| } |
| |
| private static Vector actionsVector(String actions) { |
| Vector v = new Vector(); |
| StringTokenizer t = new StringTokenizer(actions.toUpperCase(), ","); |
| while (t.hasMoreTokens()) { |
| String action = t.nextToken().trim(); |
| v.add(action.toLowerCase()); |
| } |
| |
| if( v.contains( SCHEDULE_ACTION ) && !v.contains( LIFECYCLE_ACTION ) ) |
| v.add( LIFECYCLE_ACTION ); |
| |
| return v; |
| } |
| |
| |
| private static class SignerWrapper extends Object { |
| private String pattern; |
| private ApplicationDescriptor appDesc; |
| |
| /** |
| * @param pattern |
| */ |
| public SignerWrapper(String pattern) { |
| this.pattern = pattern; |
| } |
| |
| SignerWrapper(ApplicationDescriptor appDesc) { |
| this.appDesc = appDesc; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (!(o instanceof SignerWrapper)) |
| return false; |
| SignerWrapper other = (SignerWrapper) o; |
| ApplicationDescriptor matchAppDesc = (ApplicationDescriptor) (appDesc != null ? appDesc : other.appDesc); |
| String matchPattern = appDesc != null ? other.pattern : pattern; |
| return matchAppDesc.matchDNChain(matchPattern); |
| } |
| } |
| |
| private void init() { |
| actionsVector = actionsVector( actions ); |
| |
| if ( actions.equals("*") ) |
| actionsVector = actionsVector( LIFECYCLE_ACTION + "," + SCHEDULE_ACTION + "," + LOCK_ACTION ); |
| else if (!ACTIONS.containsAll(actionsVector)) |
| throw new IllegalArgumentException("Illegal action!"); |
| |
| applicationID = null; |
| } |
| |
| private Filter getFilter() { |
| if (appliedFilter == null) { |
| try { |
| appliedFilter = FrameworkUtil.createFilter(filter); |
| } catch (InvalidSyntaxException e) { |
| //we will return null |
| } |
| } |
| return appliedFilter; |
| } |
| } |