Author: mbenson Date: Tue Dec 18 21:31:24 2012 New Revision: 1423672 URL: http://svn.apache.org/viewvc?rev=1423672&view=rev Log: restore privilizer source
Added: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/ commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/ commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AccessLevel.java (with props) commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AlreadyWovenException.java (with props) commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Body.java (with props) commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/FilesystemPrivilizer.java (with props) commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Privilizer.java (with props) commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/URLArray.java (with props) Added: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AccessLevel.java URL: http://svn.apache.org/viewvc/commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AccessLevel.java?rev=1423672&view=auto ============================================================================== --- commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AccessLevel.java (added) +++ commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AccessLevel.java Tue Dec 18 21:31:24 2012 @@ -0,0 +1,56 @@ +/* + * Copyright the original author or authors. + * + * 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.apache.commons.privilizer.weave; + +import java.lang.reflect.Modifier; +import java.util.EnumSet; +import java.util.Locale; + +public enum AccessLevel { + PUBLIC(Modifier.PUBLIC), PROTECTED(Modifier.PROTECTED), PACKAGE(0), PRIVATE(Modifier.PRIVATE); + + private final int flag; + + private AccessLevel(int flag) { + this.flag = flag; + } + + public static AccessLevel of(int mod) { + if (Modifier.isPublic(mod)) { + return PUBLIC; + } + if (Modifier.isProtected(mod)) { + return PROTECTED; + } + if (Modifier.isPrivate(mod)) { + return PRIVATE; + } + return PACKAGE; + } + + public int merge(int mod) { + int remove = 0; + for (AccessLevel accessLevel : EnumSet.complementOf(EnumSet.of(this))) { + remove |= accessLevel.flag; + } + return mod & ~remove | flag; + } + + @Override + public String toString() { + return name().toLowerCase(Locale.US); + } +} Propchange: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AccessLevel.java ------------------------------------------------------------------------------ svn:eol-style = native Added: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AlreadyWovenException.java URL: http://svn.apache.org/viewvc/commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AlreadyWovenException.java?rev=1423672&view=auto ============================================================================== --- commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AlreadyWovenException.java (added) +++ commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AlreadyWovenException.java Tue Dec 18 21:31:24 2012 @@ -0,0 +1,41 @@ +/* + * Copyright the original author or authors. + * + * 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.apache.commons.privilizer.weave; + +import org.apache.commons.privilizer.weave.Privilizer.Policy; + +public class AlreadyWovenException extends IllegalStateException { + private static final long serialVersionUID = 1L; + private static final String MESSAGE = "%s already woven with policy %s"; + + private final String classname; + private final Policy policy; + + public AlreadyWovenException(String classname, Policy policy) { + super(String.format(MESSAGE, classname, policy)); + this.classname = classname; + this.policy = policy; + } + + public String getClassname() { + return classname; + } + + public Policy getPolicy() { + return policy; + } + +} Propchange: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/AlreadyWovenException.java ------------------------------------------------------------------------------ svn:eol-style = native Added: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Body.java URL: http://svn.apache.org/viewvc/commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Body.java?rev=1423672&view=auto ============================================================================== --- commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Body.java (added) +++ commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Body.java Tue Dec 18 21:31:24 2012 @@ -0,0 +1,107 @@ +/* + * Copyright the original author or authors. + * + * 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.apache.commons.privilizer.weave; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.text.StrBuilder; + +class Body implements CharSequence { + private final String indent = " "; + private final StrBuilder content = new StrBuilder(); + private int level = 0; + private boolean lineStarted; + + { + startBlock(); + } + + public char charAt(int index) { + return content.charAt(index); + } + + public int length() { + return content.length(); + } + + public CharSequence subSequence(int start, int end) { + return content.subSequence(start, end); + } + + @Override + public String toString() { + return content.toString(); + } + + Body append(char c) { + content.append(c); + return this; + } + + Body append(String format, Object... args) { + prepare(); + content.append(String.format(format, args)); + return this; + } + + Body appendLine(String format, Object... args) { + return append(format, args).appendNewLine(); + } + + Body appendNewLine() { + content.appendNewLine(); + lineStarted = false; + return this; + } + + Body complete() { + try { + return endBlock(); + } finally { + Validate.validState(level == 0); + } + } + + Body endBlock() { + if (level < 1) { + throw new IllegalStateException(); + } + level--; + prepare(); + append('}').appendNewLine(); + return this; + } + + Body startBlock() { + if (lineStarted) { + append(' '); + } + level++; + return append('{').appendNewLine(); + } + + Body startBlock(String format, Object... args) { + append(format, args); + return startBlock(); + } + + private void prepare() { + if (!lineStarted) { + lineStarted = true; + content.append(StringUtils.repeat(indent, level)); + } + } +} \ No newline at end of file Propchange: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Body.java ------------------------------------------------------------------------------ svn:eol-style = native Added: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/FilesystemPrivilizer.java URL: http://svn.apache.org/viewvc/commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/FilesystemPrivilizer.java?rev=1423672&view=auto ============================================================================== --- commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/FilesystemPrivilizer.java (added) +++ commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/FilesystemPrivilizer.java Tue Dec 18 21:31:24 2012 @@ -0,0 +1,166 @@ +/* + * Copyright the original author or authors. + * + * 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.apache.commons.privilizer.weave; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.LoaderClassPath; +import javassist.NotFoundException; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.RegexFileFilter; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.commons.privilizer.Privileged; +import org.apache.xbean.finder.AnnotationFinder; +import org.apache.xbean.finder.archive.FileArchive; + + +/** + * Handles weaving of methods annotated with {@link Privileged}. + */ +public class FilesystemPrivilizer extends Privilizer<FilesystemPrivilizer> { + private static ClassPool createClassPool(ClassLoader classpath, File target) { + final ClassPool result = new ClassPool(); + try { + result.appendClassPath(validTarget(target).getAbsolutePath()); + result.appendClassPath(new LoaderClassPath(classpath)); + result.appendPathList(System.getProperty("java.class.path")); + } catch (final NotFoundException e) { + throw new RuntimeException(e); + } + return result; + } + + private static Set<Class<?>> getDeclaringClasses(Iterable<Method> methods) { + final Set<Class<?>> declaringClasses = new HashSet<Class<?>>(); + for (final Method method : methods) { + declaringClasses.add(method.getDeclaringClass()); + } + return declaringClasses; + } + + private static Class<?> getOutermost(Class<?> type) { + Class<?> enclosing = type.getEnclosingClass(); + return enclosing == null ? type : getOutermost(enclosing); + } + + private static File validTarget(File target) { + Validate.notNull(target, "target"); + Validate.isTrue(target.isDirectory(), "not a directory"); + return target; + } + + private final ClassLoader classpath; + + private final File target; + + private final ClassFileWriter classFileWriter = new ClassFileWriter() { + @Override + public void write(CtClass type) throws CannotCompileException, IOException { + type.writeFile(target.getAbsolutePath()); + } + }; + + public FilesystemPrivilizer(ClassLoader classpath, File target) { + super(createClassPool(classpath, target)); + this.classpath = classpath; + this.target = target; + } + + public FilesystemPrivilizer(Policy policy, ClassLoader classpath, File target) { + super(policy, createClassPool(classpath, target)); + this.classpath = classpath; + this.target = target; + } + + /** + * Clear the way by deleting classfiles woven with a different + * {@link Policy}. + * + * @throws NotFoundException + */ + public void prepare() throws NotFoundException { + info("preparing %s; policy = %s", target, policy); + final Set<File> toDelete = new TreeSet<File>(); + for (final Class<?> type : getDeclaringClasses(findPrivilegedMethods())) { + final CtClass ctClass = classPool.get(type.getName()); + final String policyValue = toString(ctClass.getAttribute(generateName(POLICY_NAME))); + if (policyValue == null || policyValue.equals(policy.name())) { + continue; + } + debug("class %s previously woven with policy %s", type.getName(), policyValue); + final File packageDir = + new File(target, StringUtils.replaceChars(ctClass.getPackageName(), '.', File.separatorChar)); + + // simple classname of outermost class, plus any inner classes: + final String pattern = + new StringBuilder(getOutermost(type).getSimpleName()).append("(\\$.+)??\\.class").toString(); + + debug("searching %s for pattern '%s'", packageDir.getAbsolutePath(), pattern); + toDelete.addAll(FileUtils.listFiles(packageDir, new RegexFileFilter(pattern), null)); + } + if (toDelete.isEmpty()) { + return; + } + info("Deleting %s files...", toDelete.size()); + debug(toDelete.toString()); + for (File f : toDelete) { + if (!f.delete()) { + debug("Failed to delete %s", f); + } + } + } + + /** + * Weave all {@link Privileged} methods found. + * + * @throws NotFoundException + * @throws IOException + * @throws CannotCompileException + * @throws ClassNotFoundException + */ + public void weaveAll() throws NotFoundException, IOException, CannotCompileException, ClassNotFoundException { + int woven = 0; + for (final Class<?> type : getDeclaringClasses(findPrivilegedMethods())) { + if (weave(classPool.get(type.getName()))) { + woven++; + } + } + if (woven > 0) { + info("Wove %s classes.", woven); + } + } + + @Override + protected ClassFileWriter getClassFileWriter() { + return classFileWriter; + } + + private List<Method> findPrivilegedMethods() { + final AnnotationFinder annotationFinder = new AnnotationFinder(new FileArchive(classpath, target), false); + return annotationFinder.findAnnotatedMethods(Privileged.class); + } +} Propchange: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/FilesystemPrivilizer.java ------------------------------------------------------------------------------ svn:eol-style = native Added: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Privilizer.java URL: http://svn.apache.org/viewvc/commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Privilizer.java?rev=1423672&view=auto ============================================================================== --- commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Privilizer.java (added) +++ commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Privilizer.java Tue Dec 18 21:31:24 2012 @@ -0,0 +1,490 @@ +/* + * Copyright the original author or authors. + * + * 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.apache.commons.privilizer.weave; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.nio.charset.Charset; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Logger; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtField; +import javassist.CtMethod; +import javassist.CtNewConstructor; +import javassist.CtNewMethod; +import javassist.CtPrimitiveType; +import javassist.NotFoundException; +import javassist.bytecode.Descriptor; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.text.StrBuilder; +import org.apache.commons.privilizer.Privileged; + + +/** + * Handles weaving of methods annotated with {@link Privileged}. + */ +public abstract class Privilizer<SELF extends Privilizer<SELF>> { + public interface ClassFileWriter { + void write(CtClass type) throws CannotCompileException, IOException; + } + + public interface Log { + void debug(String message); + + void verbose(String message); + + void error(String message); + + void info(String message); + + void warn(String message); + } + + /** + * Weaving policy: when to use {@link PrivilegedAction}s. + */ + public enum Policy { + /** + * Disables weaving. + */ + NEVER, + + /** + * Weaves such that the check for an active {@link SecurityManager} is + * done once only. + */ + ON_INIT(generateName("hasSecurityManager")), + + /** + * Weaves such that the check for an active {@link SecurityManager} is + * done for each {@link Privileged} method execution. + */ + DYNAMIC(HAS_SECURITY_MANAGER_CONDITION), + + /** + * Weaves such that {@link Privileged} methods are always executed as + * such. + */ + ALWAYS; + + private final String condition; + + private Policy() { + this(null); + } + + private Policy(String condition) { + this.condition = condition; + } + + private boolean isConditional() { + return condition != null; + } + } + + protected static final String POLICY_NAME = "policyName"; + + private static final String ACTION_SUFFIX = "_ACTION"; + + private static final String GENERATE_NAME = "__privileged_%s"; + private static final String HAS_SECURITY_MANAGER_CONDITION = "System.getSecurityManager() != null"; + + protected static String generateName(String simple) { + return String.format(GENERATE_NAME, simple); + } + + protected static String toString(byte[] b) { + return b == null ? null : new String(b, Charset.forName("UTF-8")); + } + + protected final Policy policy; + + protected final ClassPool classPool; + + private boolean settingsReported; + + private Log log = new Log() { + final Logger logger = Logger.getLogger(Privilizer.class.getName()); + + @Override + public void debug(String message) { + logger.finer(message); + } + + @Override + public void verbose(String message) { + logger.fine(message); + } + + @Override + public void error(String message) { + logger.severe(message); + } + + @Override + public void info(String message) { + logger.info(message); + } + + @Override + public void warn(String message) { + logger.warning(message); + } + + }; + + private static final Comparator<CtMethod> CTMETHOD_COMPARATOR = new Comparator<CtMethod>() { + + @Override + public int compare(CtMethod arg0, CtMethod arg1) { + if (ObjectUtils.equals(arg0, arg1)) { + return 0; + } + if (arg0 == null) { + return -1; + } + if (arg1 == null) { + return 1; + } + final int result = ObjectUtils.compare(arg0.getName(), arg1.getName()); + return result == 0 ? ObjectUtils.compare(arg0.getSignature(), arg1.getSignature()) : result; + } + }; + + private static Set<CtMethod> getPrivilegedMethods(CtClass type) throws ClassNotFoundException { + final TreeSet<CtMethod> result = new TreeSet<CtMethod>(CTMETHOD_COMPARATOR); + for (final CtMethod m : type.getDeclaredMethods()) { + if (Modifier.isAbstract(m.getModifiers()) || m.getAnnotation(Privileged.class) == null) { + continue; + } + result.add(m); + } + return result; + } + + public Privilizer(ClassPool classPool) { + this(Policy.DYNAMIC, classPool); + } + + public Privilizer(Policy policy, ClassPool classPool) { + this.policy = Validate.notNull(policy, "policy"); + this.classPool = Validate.notNull(classPool, "classPool"); + } + + public SELF loggingTo(Log log) { + this.log = Validate.notNull(log); + settingsReported = false; + @SuppressWarnings("unchecked") + final SELF self = (SELF) this; + return self; + } + + /** + * Weave the specified class. + * + * @param type + * @return whether any work was done + * @throws NotFoundException + * @throws IOException + * @throws CannotCompileException + * @throws ClassNotFoundException + */ + public boolean weave(CtClass type) throws NotFoundException, IOException, CannotCompileException, + ClassNotFoundException { + reportSettings(); + final String policyName = generateName(POLICY_NAME); + final String policyValue = toString(type.getAttribute(policyName)); + if (policyValue != null) { + verbose("%s already woven with policy %s", type.getName(), policyValue); + if (!policy.name().equals(policyValue)) { + throw new AlreadyWovenException(type.getName(), Policy.valueOf(policyValue)); + } + return false; + } + boolean result = false; + if (policy.compareTo(Policy.NEVER) > 0) { + if (policy == Policy.ON_INIT) { + debug("Initializing field %s to %s", policy.condition, HAS_SECURITY_MANAGER_CONDITION); + type.addField(new CtField(CtClass.booleanType, policy.condition, type), + CtField.Initializer.byExpr(HAS_SECURITY_MANAGER_CONDITION)); + } + for (final CtMethod m : getPrivilegedMethods(type)) { + result |= weave(type, m); + } + if (result) { + type.setAttribute(policyName, policy.name().getBytes(Charset.forName("UTF-8"))); + getClassFileWriter().write(type); + } + } + log.verbose(String.format(result ? "Wove class %s" : "Nothing to do for class %s", type.getName())); + return result; + } + + protected void debug(String message, Object... args) { + log.debug(String.format(message, args)); + } + + protected void verbose(String message, Object... args) { + log.verbose(String.format(message, args)); + } + + protected void warn(String message, Object... args) { + log.warn(String.format(message, args)); + } + + protected abstract ClassFileWriter getClassFileWriter(); + + protected void info(String message, Object... args) { + log.info(String.format(message, args)); + } + + protected boolean permitMethodWeaving(AccessLevel accessLevel) { + return true; + } + + private CtClass createAction(CtClass type, CtMethod impl, Class<?> iface) throws NotFoundException, + CannotCompileException, IOException { + final boolean exc = impl.getExceptionTypes().length > 0; + + final CtClass actionType = classPool.get(iface.getName()); + + final String simpleName = generateActionClassname(impl); + debug("Creating action type %s for method %s", simpleName, toString(impl)); + final CtClass result = type.makeNestedClass(simpleName, true); + result.addInterface(actionType); + + final CtField owner; + if (Modifier.isStatic(impl.getModifiers())) { + owner = null; + } else { + owner = new CtField(type, generateName("owner"), result); + owner.setModifiers(Modifier.PRIVATE | Modifier.FINAL); + debug("Adding owner field %s to %s", owner.getName(), simpleName); + result.addField(owner); + } + + final List<String> propagatedParameters = new ArrayList<String>(); + int index = -1; + for (final CtClass param : impl.getParameterTypes()) { + final String f = String.format("arg%s", Integer.valueOf(++index)); + final CtField fld = new CtField(param, f, result); + fld.setModifiers(Modifier.PRIVATE | Modifier.FINAL); + debug("Copying parameter %s from %s to %s.%s", index, toString(impl), simpleName, f); + result.addField(fld); + propagatedParameters.add(f); + } + { + final StrBuilder constructor = new StrBuilder(simpleName).append('('); + boolean sep = false; + final Body body = new Body(); + + for (final CtField fld : result.getDeclaredFields()) { + if (sep) { + constructor.append(", "); + } else { + sep = true; + } + constructor.append(fld.getType().getName()).append(' ').append(fld.getName()); + body.appendLine("this.%1$s = %1$s;", fld.getName()); + } + constructor.append(") ").append(body.complete()); + + final String c = constructor.toString(); + debug("Creating action constructor:"); + debug(c); + result.addConstructor(CtNewConstructor.make(c, result)); + } + { + final StrBuilder run = new StrBuilder("public Object run() "); + if (exc) { + run.append("throws Exception "); + } + final Body body = new Body(); + final CtClass rt = impl.getReturnType(); + final boolean isVoid = rt.equals(CtClass.voidType); + if (!isVoid) { + body.append("return "); + } + final String deref = Modifier.isStatic(impl.getModifiers()) ? type.getName() : owner.getName(); + final String call = + String.format("%s.%s(%s)", deref, impl.getName(), StringUtils.join(propagatedParameters, ", ")); + + if (!isVoid && rt.isPrimitive()) { + body.appendLine("%2$s.valueOf(%1$s);", call, ((CtPrimitiveType) rt).getWrapperName()); + } else { + body.append(call).append(';').appendNewLine(); + + if (isVoid) { + body.appendLine("return null;"); + } + } + + run.append(body.complete()); + + final String r = run.toString(); + debug("Creating run method:"); + debug(r); + result.addMethod(CtNewMethod.make(r, result)); + } + getClassFileWriter().write(result); + debug("Returning action type %s", result); + return result; + } + + private String generateActionClassname(CtMethod m) throws NotFoundException { + final StringBuilder b = new StringBuilder(m.getName()); + if (m.getParameterTypes().length > 0) { + b.append("$$").append( + StringUtils.strip(Descriptor.getParamDescriptor(m.getSignature()), "(;)").replace("[", "ARRAYOF_") + .replace('/', '_').replace(';', '$')); + } + return b.append(ACTION_SUFFIX).toString(); + } + + private String toString(CtMethod m) { + return String.format("%s%s", m.getName(), m.getSignature()); + } + + private boolean weave(CtClass type, CtMethod method) throws ClassNotFoundException, CannotCompileException, + NotFoundException, IOException { + final AccessLevel accessLevel = AccessLevel.of(method.getModifiers()); + if (!permitMethodWeaving(accessLevel)) { + warn("Ignoring %s method %s.%s", accessLevel, type.getName(), toString(method)); + return false; + } + if (AccessLevel.PACKAGE.compareTo(accessLevel) > 0) { + warn("Possible security leak: granting privileges to %s method %s.%s", accessLevel, type.getName(), + toString(method)); + } + final String implName = generateName(method.getName()); + + final CtMethod impl = CtNewMethod.copy(method, implName, type, null); + impl.setModifiers(AccessLevel.PRIVATE.merge(method.getModifiers())); + type.addMethod(impl); + debug("Copied %2$s %1$s.%3$s to %4$s %1$s.%5$s", type.getName(), accessLevel, toString(method), + AccessLevel.PRIVATE, toString(impl)); + + final Body body = new Body(); + if (policy.isConditional()) { + body.startBlock("if (%s)", policy.condition); + } + + final boolean exc = method.getExceptionTypes().length > 0; + + if (exc) { + body.startBlock("try"); + } + + final Class<?> iface = exc ? PrivilegedExceptionAction.class : PrivilegedAction.class; + final CtClass actionType = createAction(type, impl, iface); + final String action = generateName("action"); + + body.append("final %s %s = new %s(", iface.getName(), action, actionType.getName()); + boolean firstParam; + if (Modifier.isStatic(impl.getModifiers())) { + firstParam = true; + } else { + body.append("$0"); + firstParam = false; + } + for (int i = 1, sz = impl.getParameterTypes().length; i <= sz; i++) { + if (firstParam) { + firstParam = false; + } else { + body.append(", "); + } + body.append('$').append(Integer.toString(i)); + } + body.appendLine(");"); + + final CtClass rt = method.getReturnType(); + final boolean isVoid = rt.equals(CtClass.voidType); + + final String doPrivileged = String.format("%1$s.doPrivileged(%2$s)", AccessController.class.getName(), action); + if (isVoid) { + body.append(doPrivileged).append(';').appendNewLine(); + if (policy.isConditional()) { + body.appendLine("return;"); + } + } else { + final String cast = rt.isPrimitive() ? ((CtPrimitiveType) rt).getWrapperName() : rt.getName(); + // don't worry about wrapper NPEs because we should be simply + // passing back an autoboxed value, then unboxing again + final String result = generateName("result"); + body.appendLine("final %1$s %3$s = (%1$s) %2$s;", cast, doPrivileged, result); + body.append("return %s", result); + if (rt.isPrimitive()) { + body.append(".%sValue()", rt.getName()); + } + body.append(';').appendNewLine(); + } + + if (exc) { + body.endBlock(); + final String e = generateName("e"); + body.startBlock("catch (%1$s %2$s)", PrivilegedActionException.class.getName(), e).appendNewLine(); + + final String wrapped = generateName("wrapped"); + + body.appendLine("final Exception %1$s = %2$s.getCause();", wrapped, e); + for (final CtClass thrown : method.getExceptionTypes()) { + body.startBlock("if (%1$s instanceof %2$s)", wrapped, thrown.getName()); + body.appendLine("throw (%2$s) %1$s;", wrapped, thrown.getName()); + body.endBlock(); + } + body.appendLine( + "throw %1$s instanceof RuntimeException ? (RuntimeException) %1$s : new RuntimeException(%1$s);", + wrapped); + body.endBlock(); + } + + if (policy.isConditional()) { + // close if block we opened before: + body.endBlock(); + // no security manager=> just call impl: + if (!isVoid) { + body.append("return "); + } + body.appendLine("%s($$);", impl.getName()); + } + + final String block = body.complete().toString(); + debug("Setting body of %s to:\n%s", toString(method), block); + method.setBody(block); + return true; + } + + private void reportSettings() { + if (!settingsReported) { + settingsReported = true; + info("Weave policy == %s", policy); + } + } +} Propchange: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/Privilizer.java ------------------------------------------------------------------------------ svn:eol-style = native Added: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/URLArray.java URL: http://svn.apache.org/viewvc/commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/URLArray.java?rev=1423672&view=auto ============================================================================== --- commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/URLArray.java (added) +++ commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/URLArray.java Tue Dec 18 21:31:24 2012 @@ -0,0 +1,83 @@ +/* + * Copyright the original author or authors. + * + * 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.apache.commons.privilizer.weave; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * {@link URL} Array utilities. + */ +public abstract class URLArray { + private URLArray() { + } + + /** + * Convert an {@link Iterable} of filesystem paths. + * + * @param files + * @return URL[] + */ + public static URL[] fromPaths(final Iterable<String> files) { + return fromFiles(new Iterable<File>() { + + public Iterator<File> iterator() { + final Iterator<String> path = files.iterator(); + return new Iterator<File>() { + + public boolean hasNext() { + return path.hasNext(); + } + + public File next() { + final String p = path.next(); + return p == null ? null : new File(p); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }); + } + + /** + * Convert an {@link Iterable} of {@link File}s. + * + * @param files + * @return URL[] + */ + public static URL[] fromFiles(Iterable<File> files) { + final ArrayList<URL> result = new ArrayList<URL>(); + for (File f : files) { + if (f == null) { + result.add(null); + continue; + } + try { + result.add(f.toURI().toURL()); + } catch (MalformedURLException e) { + // this shouldn't happen + throw new RuntimeException(e); + } + } + return result.toArray(new URL[result.size()]); + } +} Propchange: commons/sandbox/privilizer/trunk/modules/privilizer/weaver/src/main/java/org/apache/commons/privilizer/weave/URLArray.java ------------------------------------------------------------------------------ svn:eol-style = native