Added: felix/trunk/framework/security/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java URL: http://svn.apache.org/viewvc/felix/trunk/framework/security/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java?rev=634480&view=auto ============================================================================== --- felix/trunk/framework/security/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java (added) +++ felix/trunk/framework/security/src/main/java/org/osgi/service/condpermadmin/BundleLocationCondition.java Thu Mar 6 16:37:30 2008 @@ -0,0 +1,133 @@ +/* + * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/BundleLocationCondition.java,v 1.18 2006/06/16 16:31:37 hargrave Exp $ + * + * Copyright (c) OSGi Alliance (2005, 2006). 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.condpermadmin; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Hashtable; + +import org.apache.felix.framework.FilterImpl; +import org.osgi.framework.*; + +/** + * Condition to test if the location of a bundle matches a pattern. Pattern + * matching is done according to the filter string matching rules. + * + * @version $Revision: 1.18 $ + */ +public class BundleLocationCondition +{ + private static final String CONDITION_TYPE = + "org.osgi.service.condpermadmin.BundleLocationCondition"; + + /** + * Constructs a condition that tries to match the passed Bundle's location + * to the location pattern. + * + * @param bundle + * The Bundle being evaluated. + * @param info + * The ConditionInfo to construct the condition for. The args + * of the ConditionInfo must be a single String which + * specifies the location pattern to match against the Bundle + * location. Matching is done according to the filter string + * matching rules. Any '*' characters in the location + * argument are used as wildcards when matching bundle + * locations unless they are escaped with a '\' character. + * @return Condition object for the requested condition. + */ + static public Condition getCondition(final Bundle bundle, ConditionInfo info) + { + if (!CONDITION_TYPE.equals(info.getType())) + throw new IllegalArgumentException( + "ConditionInfo must be of type \"" + CONDITION_TYPE + "\""); + String[] args = info.getArgs(); + if (args.length != 1) + throw new IllegalArgumentException("Illegal number of args: " + + args.length); + String bundleLocation = + (String) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return bundle.getLocation(); + } + }); + Filter filter = null; + try + { + filter = + new FilterImpl("(location=" + escapeLocation(args[0]) + ")"); + } + catch (InvalidSyntaxException e) + { + // this should never happen, but just incase + throw new RuntimeException("Invalid filter: " + e.getFilter()); + } + Hashtable matchProps = new Hashtable(2); + matchProps.put("location", bundleLocation); + return filter.match(matchProps) ? Condition.TRUE : Condition.FALSE; + } + + private BundleLocationCondition() + { + // private constructor to prevent objects of this type + } + + /** + * Escape the value string such that '(', ')' and '\' are escaped. The '\' + * char is only escaped if it is not followed by a '*'. + * + * @param value + * unescaped value string. + * @return escaped value string. + */ + private static String escapeLocation(String value) + { + boolean escaped = false; + int inlen = value.length(); + int outlen = inlen << 1; /* inlen * 2 */ + + char[] output = new char[outlen]; + value.getChars(0, inlen, output, inlen); + + int cursor = 0; + for (int i = inlen; i < outlen; i++) + { + char c = output[i]; + switch (c) + { + case '\\': + if (i + 1 < outlen && output[i + 1] == '*') + break; + case '(': + case ')': + output[cursor] = '\\'; + cursor++; + escaped = true; + break; + } + + output[cursor] = c; + cursor++; + } + + return escaped ? new String(output, 0, cursor) : value; + } +}
Added: felix/trunk/framework/security/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java URL: http://svn.apache.org/viewvc/felix/trunk/framework/security/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java?rev=634480&view=auto ============================================================================== --- felix/trunk/framework/security/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java (added) +++ felix/trunk/framework/security/src/main/java/org/osgi/service/condpermadmin/BundleSignerCondition.java Thu Mar 6 16:37:30 2008 @@ -0,0 +1,229 @@ +/* + * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/BundleSignerCondition.java,v 1.10 2006/06/16 16:31:37 hargrave Exp $ + * + * Copyright (c) OSGi Alliance (2005, 2006). 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.condpermadmin; + +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Dictionary; +import java.util.Hashtable; + +import org.apache.felix.framework.FilterImpl; +import org.osgi.framework.Bundle; +import org.osgi.framework.Filter; +import org.osgi.framework.InvalidSyntaxException; + +/** + * Condition to test if the signer of a bundle matches a pattern. Since the + * bundle's signer can only change when the bundle is updated, this condition is + * immutable. + * <p> + * The condition expressed using a single String that specifies a Distinguished + * Name (DN) chain to match bundle signers against. DN's are encoded using IETF + * RFC 2253. Usually signers use certificates that are issued by certificate + * authorities, which also have a corresponding DN and certificate. The + * certificate authorities can form a chain of trust where the last DN and + * certificate is known by the framework. The signer of a bundle is expressed as + * signers DN followed by the DN of its issuer followed by the DN of the next + * issuer until the DN of the root certificate authority. Each DN is separated + * by a semicolon. + * <p> + * A bundle can satisfy this condition if one of its signers has a DN chain that + * matches the DN chain used to construct this condition. Wildcards (`*') can be + * used to allow greater flexibility in specifying the DN chains. Wildcards can + * be used in place of DNs, RDNs, or the value in an RDN. If a wildcard is used + * for a value of an RDN, the value must be exactly "*" and will match any value + * for the corresponding type in that RDN. If a wildcard is used for a RDN, it + * must be the first RDN and will match any number of RDNs (including zero + * RDNs). + * + * @version $Revision: 1.10 $ + */ +/* + * TODO: In our case the above is not correct. We don't make this an immutable + * condition because the spec is somewhat ambiguous in regard to when the + * signature change. This probably has to be clarified and then revisited later. + */ +public class BundleSignerCondition +{ + /* + * NOTE: A framework implementor may also choose to replace this class in + * their distribution with a class that directly interfaces with the + * framework implementation. This replacement class MUST NOT alter the + * public/protected signature of this class. + */ + + private static final String CONDITION_TYPE = + "org.osgi.service.condpermadmin.BundleSignerCondition"; + + /** + * Constructs a Condition that tries to match the passed Bundle's location + * to the location pattern. + * + * @param bundle + * The Bundle being evaluated. + * @param info + * The ConditionInfo to construct the condition for. The args + * of the ConditionInfo specify a single String specifying + * the chain of distinguished names pattern to match against + * the signer of the Bundle. + * @return A Condition which checks the signers of the specified bundle. + */ + static public Condition getCondition(Bundle bundle, ConditionInfo info) + { + if (!CONDITION_TYPE.equals(info.getType())) + throw new IllegalArgumentException( + "ConditionInfo must be of type \"" + CONDITION_TYPE + "\""); + final String[] args = info.getArgs(); + if (args.length != 1) + throw new IllegalArgumentException("Illegal number of args: " + + args.length); + + return new ConditionImpl(bundle, "(signer=" + escapeFilter(args[0]) + + ")"); + + } + + private static String escapeFilter(String string) + { + boolean escaped = false; + int inlen = string.length(); + int outlen = inlen << 1; /* inlen * 2 */ + + char[] output = new char[outlen]; + string.getChars(0, inlen, output, inlen); + + int cursor = 0; + for (int i = inlen; i < outlen; i++) + { + char c = output[i]; + switch (c) + { + case '\\': + case '(': + case ')': + case '*': + output[cursor] = '\\'; + cursor++; + escaped = true; + break; + } + + output[cursor] = c; + cursor++; + } + + return escaped ? new String(output, 0, cursor) : string; + } + + private BundleSignerCondition() + { + // private constructor to prevent objects of this type + } +} + +final class ConditionImpl implements Condition, PrivilegedExceptionAction +{ + private static final Method m_getSignerMatcher; + + static + { + m_getSignerMatcher = + (Method) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + Method getSignerMatcher = null; + try + { + getSignerMatcher = + Class.forName( + "org.apache.felix.framework.BundleImpl") + .getDeclaredMethod("getSignerMatcher", null); + getSignerMatcher.setAccessible(true); + } + catch (Exception ex) + { + ex.printStackTrace(); + getSignerMatcher = null; + } + return getSignerMatcher; + } + }); + } + + private final Bundle m_bundle; + private final Filter m_filter; + private final Dictionary m_dict; + + ConditionImpl(Bundle bundle, String filter) + { + m_bundle = bundle; + try + { + m_filter = new FilterImpl(filter); + } + catch (InvalidSyntaxException e) + { + throw new IllegalArgumentException(e.getMessage()); + } + try + { + Object signerMatcher = AccessController.doPrivileged(this); + m_dict = new Hashtable(); + m_dict.put("signer", signerMatcher); + } + catch (PrivilegedActionException e) + { + if (e.getException() instanceof RuntimeException) + { + throw (RuntimeException) e.getException(); + } + + throw new RuntimeException(e.getException().getMessage()); + } + } + + public boolean isMutable() + { + return true; + } + + public boolean isPostponed() + { + return false; + } + + public Object run() throws Exception + { + return m_getSignerMatcher.invoke(m_bundle, null); + } + + public boolean isSatisfied() + { + return m_filter.match(m_dict); + } + + public boolean isSatisfied(Condition[] conditions, Dictionary context) + { + return false; + } +} \ No newline at end of file
