You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mb...@apache.org on 2013/07/30 17:18:02 UTC
svn commit: r1508483 - in
/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver: ./
src/main/java/org/apache/commons/weaver/privilizer/
src/main/java/org/apache/commons/weaver/privilizer/asm/
src/main/resources/META-INF/services/
Author: mbenson
Date: Tue Jul 30 15:18:01 2013
New Revision: 1508483
URL: http://svn.apache.org/r1508483
Log:
privilizer with ASM working
Added:
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java (with props)
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java (with props)
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java (with props)
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java (with props)
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java (with props)
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java (with props)
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java (with props)
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java (with props)
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java (with props)
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java (with props)
Removed:
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilizer.java
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerWeaver.java
Modified:
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/pom.xml
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/ (props changed)
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/AccessLevel.java
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerCleaner.java
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Cleaner
commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Weaver
Modified: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/pom.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/pom.xml?rev=1508483&r1=1508482&r2=1508483&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/pom.xml (original)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/pom.xml Tue Jul 30 15:18:01 2013
@@ -52,15 +52,10 @@
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
- <dependency>
- <groupId>org.ow2.asm</groupId>
- <artifactId>asm</artifactId>
- </dependency>
</dependencies>
-
<build>
<plugins>
- <plugin>
+ <!--plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
<configuration>
@@ -83,7 +78,42 @@
</goals>
</execution>
</executions>
- </plugin>
+ </plugin-->
</plugins>
</build>
+ <profiles>
+ <profile>
+ <id>basic</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-commons</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-tree</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-util</artifactId>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>dev</id>
+ <dependencies>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-debug-all</artifactId>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
</project>
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Jul 30 15:18:01 2013
@@ -0,0 +1 @@
+bytecode
Modified: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/AccessLevel.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/AccessLevel.java?rev=1508483&r1=1508482&r2=1508483&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/AccessLevel.java (original)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/AccessLevel.java Tue Jul 30 15:18:01 2013
@@ -18,6 +18,10 @@ package org.apache.commons.weaver.privil
import java.lang.reflect.Modifier;
import java.util.EnumSet;
import java.util.Locale;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
public enum AccessLevel {
PUBLIC(Modifier.PUBLIC), PROTECTED(Modifier.PROTECTED), PACKAGE(0), PRIVATE(Modifier.PRIVATE);
@@ -29,16 +33,21 @@ public enum AccessLevel {
}
public static AccessLevel of(int mod) {
+ final Set<AccessLevel> matched = EnumSet.noneOf(AccessLevel.class);
if (Modifier.isPublic(mod)) {
- return PUBLIC;
+ matched.add(PUBLIC);
}
if (Modifier.isProtected(mod)) {
- return PROTECTED;
+ matched.add(PROTECTED);
}
if (Modifier.isPrivate(mod)) {
- return PRIVATE;
+ matched.add(PRIVATE);
+ }
+ if (matched.isEmpty()) {
+ return PACKAGE;
}
- return PACKAGE;
+ Validate.isTrue(matched.size() == 1, "%s seems to declare multiple access modifiers: %s", mod, matched);
+ return matched.iterator().next();
}
public int merge(int mod) {
@@ -62,4 +71,17 @@ public enum AccessLevel {
public static AccessLevel defaultValue() {
return AccessLevel.PRIVATE;
}
+
+ /**
+ * Parse from a {@link String} returning {@link #defaultValue()} for blank/null input.
+ *
+ * @param s
+ * @return {@link AccessLevel}
+ */
+ public static AccessLevel parse(String s) {
+ if (StringUtils.isBlank(s)) {
+ return defaultValue();
+ }
+ return valueOf(s.trim().toUpperCase(Locale.US));
+ }
}
Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,77 @@
+/*
+ * 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.commons.weaver.privilizer;
+
+import java.security.PrivilegedAction;
+import java.util.Locale;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 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,
+
+ /**
+ * Weaves such that the check for an active {@link SecurityManager} is done for each {@link Privileged} method
+ * execution.
+ */
+ DYNAMIC,
+
+ /**
+ * Weaves such that {@link Privileged} methods are always executed as such.
+ */
+ ALWAYS;
+
+ /**
+ * Get the {@link Policy} value that should be used as a default.
+ *
+ * @return {@link Policy#DYNAMIC}
+ */
+ public static Policy defaultValue() {
+ return DYNAMIC;
+ }
+
+ /**
+ * Parse from a {@link String} returning {@link #defaultValue()} for blank/null input.
+ *
+ * @param s
+ * @return {@link Policy}
+ */
+ public static Policy parse(String s) {
+ if (StringUtils.isBlank(s)) {
+ return defaultValue();
+ }
+ return valueOf(s.trim().toUpperCase(Locale.US));
+ }
+
+ public boolean isConditional() {
+ return this == ON_INIT || this == DYNAMIC;
+ }
+
+}
\ No newline at end of file
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Policy.java
------------------------------------------------------------------------------
svn:executable = *
Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,30 @@
+/*
+ * 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.commons.weaver.privilizer;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Class-retention annotation to mark privilized classes.
+ */
+@Target(ElementType.TYPE)
+public @interface Privilized {
+ Policy value();
+}
\ No newline at end of file
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/Privilized.java
------------------------------------------------------------------------------
svn:executable = *
Modified: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerCleaner.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerCleaner.java?rev=1508483&r1=1508482&r2=1508483&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerCleaner.java (original)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/PrivilizerCleaner.java Tue Jul 30 15:18:01 2013
@@ -17,23 +17,18 @@ package org.apache.commons.weaver.privil
import java.io.File;
import java.lang.annotation.ElementType;
-import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.apache.commons.lang3.StringUtils;
import org.apache.commons.weaver.model.ScanRequest;
import org.apache.commons.weaver.model.Scanner;
import org.apache.commons.weaver.model.WeavableClass;
import org.apache.commons.weaver.model.WeaveEnvironment;
import org.apache.commons.weaver.model.WeaveInterest;
-import org.apache.commons.weaver.privilizer.Privilizer.Policy;
-import org.apache.commons.weaver.privilizer.Privilizer.Privilized;
+import org.apache.commons.weaver.privilizer.asm.Privilizer;
import org.apache.commons.weaver.spi.Cleaner;
-import org.apache.commons.weaver.utils.URLArray;
-import org.apache.xbean.finder.archive.FileArchive;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
@@ -41,30 +36,22 @@ import org.objectweb.asm.Opcodes;
/**
* Removes classes privilized with a different policy.
*/
-/*
- * Implemented with ASM in anticipation of the rest of the privilizer being rewritten :P
- */
public class PrivilizerCleaner implements Cleaner {
private static final int ASM_FLAGS = ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES;
private static final Logger LOG = Logger.getLogger(PrivilizerCleaner.class.getName());
@Override
public boolean clean(WeaveEnvironment environment, Scanner scanner) {
- final ClassLoader classLoader = new URLClassLoader(URLArray.fromPaths(environment.classpath));
- final FileArchive fileArchive = new FileArchive(classLoader, environment.target);
+ final Privilizer privilizer = new Privilizer(environment);
- final String policyConfig = environment.config.getProperty(PrivilizerWeaver.CONFIG_POLICY);
- final Privilizer.Policy policy =
- StringUtils.isEmpty(policyConfig) ? Privilizer.Policy.defaultValue() : Privilizer.Policy
- .valueOf(policyConfig);
final List<String> toDelete = new ArrayList<String>();
final ScanRequest scanRequest = new ScanRequest().add(WeaveInterest.of(Privilized.class, ElementType.TYPE));
- LOG.log(Level.FINE, "Cleaning classes privilized with policy other than {0}", policy);
+ LOG.log(Level.FINE, "Cleaning classes privilized with policy other than {0}", privilizer.policy);
for (WeavableClass<?> weavableClass : scanner.scan(scanRequest).getClasses().with(Privilized.class)) {
final Policy privilizedPolicy = weavableClass.getAnnotation(Privilized.class).value();
- if (privilizedPolicy == policy) {
+ if (privilizedPolicy == privilizer.policy) {
continue;
}
final String className = weavableClass.getTarget().getName();
@@ -72,7 +59,7 @@ public class PrivilizerCleaner implement
new Object[] { className, privilizedPolicy });
try {
- final ClassReader classReader = new ClassReader(fileArchive.getBytecode(className));
+ final ClassReader classReader = new ClassReader(privilizer.fileArchive.getBytecode(className));
classReader.accept(new ClassVisitor(Opcodes.ASM4) {
@Override
public void visit(int version, int access, String name, String signature, String superName,
Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,229 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.util.Map;
+
+import javassist.Modifier;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.lang3.builder.Builder;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.signature.SignatureReader;
+import org.objectweb.asm.signature.SignatureVisitor;
+import org.objectweb.asm.signature.SignatureWriter;
+
+/**
+ * Generates the Privileged[Exception?]Action class to privilize a given Method.
+ */
+class ActionGenerator extends Privilizer.WriteClass implements Builder<Type> {
+ final PrivilizingVisitor owner;
+ final Method m;
+ final boolean exc;
+ final Type[] exceptions;
+ final String simpleName;
+ final Type action;
+ final Method impl;
+ final int index;
+ final boolean implIsStatic;
+ final Method helper;
+ final Type result;
+ final Field[] fields;
+ private final Type actionInterface;
+
+ ActionGenerator(final int access, final Method m, final String[] exceptions, PrivilizingVisitor owner) {
+ owner.privilizer().super(new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES));
+ this.m = m;
+ this.exc = ArrayUtils.isNotEmpty(exceptions);
+ this.exceptions = exc ? new Type[] { Type.getType(Exception.class) } : null;
+ this.owner = owner;
+ this.simpleName = generateName(m);
+ this.action = Type.getObjectType(owner.className + '$' + simpleName);
+
+ int privilegedAccessIndex = -1;
+ String implName = null;
+ for (Map.Entry<Method, String> e : owner.privilegedMethods.entrySet()) {
+ privilegedAccessIndex++;
+ if (e.getKey().equals(m)) {
+ implName = e.getValue();
+ break;
+ }
+ }
+ Validate.validState(implName != null);
+
+ this.index = privilegedAccessIndex;
+
+ this.impl = new Method(implName, m.getDescriptor());
+ this.implIsStatic = Modifier.isStatic(access);
+ final Type[] args = implIsStatic ? m.getArgumentTypes() : ArrayUtils.add(m.getArgumentTypes(), 0, owner.target);
+ this.helper = new Method(privilizer().generateName("access$" + index), m.getReturnType(), args);
+ this.result = privilizer().wrap(m.getReturnType());
+ this.fields = fields(args);
+ this.actionInterface = Type.getType(exc ? PrivilegedExceptionAction.class : PrivilegedAction.class);
+ }
+
+ private static String generateName(Method m) {
+ final StringBuilder b = new StringBuilder(m.getName());
+ if (m.getArgumentTypes().length > 0) {
+ b.append("$$");
+ for (Type arg : m.getArgumentTypes()) {
+ b.append(arg.getDescriptor().replace("[", "arrayOf").replace('/', '_').replace(';', '$'));
+ }
+ }
+ return b.append("_ACTION").toString();
+ }
+
+ private static Field[] fields(Type[] args) {
+ final Field[] result = new Field[args.length];
+
+ for (int i = 0; i < args.length; i++) {
+ final String name = new StringBuilder("f").append(i + 1).toString();
+ result[i] = new Field(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, name, args[i]);
+ }
+ return result;
+ }
+
+ @Override
+ public Type build() {
+ generateHelper();
+ begin();
+ init();
+ impl();
+ visitEnd();
+ owner.privilizer().debug("Generated %s implementation %s to call %s#%s", actionInterface.getClassName(),
+ action.getClassName(), owner.target.getClassName(), helper);
+ return action;
+ }
+
+ /**
+ * We must add special methods for inner classes to invoke their owners' methods, according to the scheme "access$n"
+ * where n is the index into this (ordered) map. Additionally we will prefix the whole thing like we usually do
+ * (__privileged_):
+ */
+ private void generateHelper() {
+ owner.privilizer().debug("Generating static helper method %s.%s to call %s", owner.target.getClassName(),
+ helper, impl);
+ final GeneratorAdapter mg =
+ new GeneratorAdapter(Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, helper, null, exceptions, owner);
+
+ mg.visitCode();
+ mg.loadArgs();
+ if (implIsStatic) {
+ mg.invokeStatic(owner.target, impl);
+ } else {
+ mg.invokeVirtual(owner.target, impl);
+ }
+ mg.returnValue();
+ mg.endMethod();
+ }
+
+ private void begin() {
+ owner.visitInnerClass(action.getInternalName(), owner.className, simpleName, Opcodes.ACC_PRIVATE
+ | Opcodes.ACC_STATIC);
+
+ final SignatureWriter type = new SignatureWriter();
+ final SignatureVisitor actionImplemented = type.visitInterface();
+ actionImplemented.visitClassType(actionInterface.getInternalName());
+ final SignatureVisitor visitTypeArgument = actionImplemented.visitTypeArgument('=');
+ final SignatureReader result = new SignatureReader(privilizer().wrap(m.getReturnType()).getDescriptor());
+ result.accept(visitTypeArgument);
+ actionImplemented.visitEnd();
+
+ final String signature = type.toString();
+
+ visit(Opcodes.V1_5, Opcodes.ACC_SUPER | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL, action.getInternalName(),
+ signature, Type.getType(Object.class).getInternalName(), new String[] { actionInterface.getInternalName() });
+ }
+
+ /**
+ * Add fields and generate constructor.
+ *
+ * @param cv
+ */
+ private void init() {
+ for (Field field : fields) {
+ visitField(field.access, field.name, field.type.getDescriptor(), null, null).visitEnd();
+ }
+ final Method init = new Method("<init>", Type.VOID_TYPE, helper.getArgumentTypes());
+
+ final GeneratorAdapter mg =
+ new GeneratorAdapter(Opcodes.ACC_PRIVATE, init, null, Privilizer.EMPTY_TYPE_ARRAY, this);
+
+ mg.visitCode();
+ final Label begin = mg.mark();
+
+ // invoke super constructor
+ mg.loadThis();
+ mg.invokeConstructor(Type.getType(Object.class), Method.getMethod("void <init> ()"));
+ // assign remaining fields
+
+ int arg = 0;
+ for (Field field : fields) {
+ mg.loadThis();
+ mg.loadArg(arg++);
+ mg.putField(action, field.name, field.type);
+ }
+
+ mg.returnValue();
+ final Label end = mg.mark();
+
+ // declare local vars
+ mg.visitLocalVariable("this", action.getDescriptor(), null, begin, end, 0);
+ arg = 1;
+ for (Field field : fields) {
+ mg.visitLocalVariable("arg" + arg, field.type.getDescriptor(), null, begin, end, arg++);
+ }
+ mg.endMethod();
+ }
+
+ /**
+ * Generate impl method.
+ *
+ * @param cv
+ */
+ private void impl() {
+ final Method run = new Method("run", result, Privilizer.EMPTY_TYPE_ARRAY);
+
+ final GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, run, null, exceptions, this);
+
+ for (Field field : fields) {
+ mg.loadThis();
+ mg.getField(action, field.name, field.type);
+ }
+
+ mg.invokeStatic(owner.target, helper);
+
+ if (m.getReturnType().getSort() < Type.ARRAY) {
+ mg.valueOf(m.getReturnType());
+ }
+
+ mg.returnValue();
+
+ mg.endMethod();
+ }
+
+}
\ No newline at end of file
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/ActionGenerator.java
------------------------------------------------------------------------------
svn:executable = *
Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,489 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.weaver.privilizer.Privileged;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.AdviceAdapter;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.MethodNode;
+
+class BlueprintingVisitor extends Privilizer.PrivilizerClassVisitor {
+
+ private final Set<Type> blueprintTypes = new HashSet<Type>();
+ private final Map<Pair<Type, Method>, MethodNode> blueprintRegistry = new HashMap<Pair<Type, Method>, MethodNode>();
+
+ private final Map<Pair<Type, Method>, String> importedMethods = new HashMap<Pair<Type, Method>, String>();
+
+ private final Map<Type, Map<Method, MethodNode>> methodCache = new HashMap<Type, Map<Method, MethodNode>>();
+ private final Map<Pair<Type, String>, FieldAccess> fieldAccessMap = new HashMap<Pair<Type, String>, FieldAccess>();
+
+ private final ClassVisitor next;
+
+ BlueprintingVisitor(Privilizer privilizer, ClassVisitor cv, Privilizing config) {
+ privilizer.super(new ClassNode(Opcodes.ASM4));
+ this.next = cv;
+
+ // load up blueprint methods:
+ for (Privilizing.CallTo callTo : config.value()) {
+ final Type blueprintType = Type.getType(callTo.value());
+ blueprintTypes.add(blueprintType);
+ for (Map.Entry<Method, MethodNode> e : getMethods(blueprintType).entrySet()) {
+ boolean found = false;
+ if (callTo.methods().length == 0) {
+ found = true;
+ } else {
+ for (String name : callTo.methods()) {
+ if (e.getKey().getName().equals(name)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (found) {
+ blueprintRegistry.put(Pair.of(blueprintType, e.getKey()), e.getValue());
+ }
+ }
+ }
+ }
+
+ private Map<Method, MethodNode> getMethods(final Type type) {
+ if (methodCache.containsKey(type)) {
+ return methodCache.get(type);
+ }
+ final ClassNode classNode = read(type.getClassName());
+ final Map<Method, MethodNode> result = new HashMap<Method, MethodNode>();
+
+ @SuppressWarnings("unchecked")
+ final List<MethodNode> methods = classNode.methods;
+
+ for (MethodNode methodNode : methods) {
+ if (Modifier.isStatic(methodNode.access) && !"<clinit>".equals(methodNode.name)) {
+ result.put(new Method(methodNode.name, methodNode.desc), methodNode);
+ }
+ }
+ methodCache.put(type, result);
+ return result;
+ }
+
+ private ClassNode read(String className) {
+ final ClassNode result = new ClassNode(Opcodes.ASM4);
+ try {
+ new ClassReader(privilizer().fileArchive.getBytecode(className)).accept(result, ClassReader.SKIP_DEBUG
+ | ClassReader.EXPAND_FRAMES);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return result;
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ Validate.isTrue(!blueprintTypes.contains(Type.getObjectType(name)),
+ "Class %s cannot declare itself as a blueprint!", name);
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+ return new MethodInvocationHandler(mv) {
+ @Override
+ boolean shouldImport(Pair<Type, Method> methodKey) {
+ return blueprintRegistry.containsKey(methodKey);
+ }
+ };
+ }
+
+ private String importMethod(Pair<Type, Method> key) {
+ if (importedMethods.containsKey(key)) {
+ return importedMethods.get(key);
+ }
+ final String result =
+ new StringBuilder(key.getLeft().getInternalName().replace('/', '_')).append("$$")
+ .append(key.getRight().getName()).toString();
+ importedMethods.put(key, result);
+
+ privilizer().debug("importing %s#%s as %s", key.getLeft().getClassName(), key.getRight(), result);
+ final int access = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC;
+
+ final MethodNode source = getMethods(key.getLeft()).get(key.getRight());
+
+ @SuppressWarnings("unchecked")
+ final String[] exceptions = (String[]) source.exceptions.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
+
+ // non-public fields accessed
+ final Set<FieldAccess> fieldAccesses = new LinkedHashSet<FieldAccess>();
+
+ source.accept(new FieldAccessAccumulator(fieldAccesses));
+
+ final MethodNode withAccessibleAdvice =
+ new MethodNode(access, result, source.desc, source.signature, exceptions);
+
+ // spider own methods:
+ MethodVisitor mv = new NestedMethodInvocationHandler(withAccessibleAdvice, key.getLeft());
+
+ if (!fieldAccesses.isEmpty()) {
+ // accessesNonPublicFields = true;
+ mv = new AccessibleAdvisor(mv, access, result, source.desc, new ArrayList<FieldAccess>(fieldAccesses));
+ }
+
+ source.accept(mv);
+
+ if (Modifier.isPrivate(source.access)) {
+ // can only be called by other privileged methods, so no need to mark as privileged
+ } else {
+ withAccessibleAdvice.visitAnnotation(Type.getType(Privileged.class).getDescriptor(), false).visitEnd();
+ }
+
+ withAccessibleAdvice.accept(this.cv);
+
+ return result;
+ }
+
+ private FieldAccess fieldAccess(final Type owner, String name, Type desc) {
+ final Pair<Type, String> key = Pair.of(owner, name);
+ if (!fieldAccessMap.containsKey(key)) {
+ try {
+ final MutableObject<Type> next = new MutableObject<Type>(owner);
+ final Deque<Type> stk = new ArrayDeque<Type>();
+ while (next.getValue() != null) {
+ stk.push(next.getValue());
+ new ClassReader(privilizer().fileArchive.getBytecode(next.getValue().getInternalName())).accept(
+ privilizer().new PrivilizerClassVisitor() {
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ next.setValue(Type.getObjectType(superName));
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature,
+ Object value) {
+ for (Type type : stk) {
+ final Pair<Type, String> k = Pair.of(type, name);
+ // skip shadowed fields:
+ if (!fieldAccessMap.containsKey(k)) {
+ fieldAccessMap.put(k, new FieldAccess(access, target, name, Type.getType(desc)));
+ }
+ }
+ return null;
+ }
+ }, ClassReader.SKIP_CODE);
+ if (fieldAccessMap.containsKey(key)) {
+ break;
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+
+ }
+ Validate.isTrue(fieldAccessMap.containsKey(key), "Could not locate %s.%s", owner.getClassName(), name);
+ }
+ return fieldAccessMap.get(key);
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+// if (privilizer().verify) {
+// final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+// ((ClassNode) cv).accept(classWriter);
+// privilizer().verify(target, classWriter.toByteArray());
+// }
+ ((ClassNode) cv).accept(next);
+ }
+
+ private abstract class MethodInvocationHandler extends MethodVisitor {
+ MethodInvocationHandler(MethodVisitor mv) {
+ super(Opcodes.ASM4, mv);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+ if (opcode == Opcodes.INVOKESTATIC) {
+ final Method m = new Method(name, desc);
+ final Pair<Type, Method> methodKey = Pair.of(Type.getObjectType(owner), m);
+ if (shouldImport(methodKey)) {
+ final String importedName = importMethod(methodKey);
+ super.visitMethodInsn(opcode, className, importedName, desc);
+ return;
+ }
+ }
+ super.visitMethodInsn(opcode, owner, name, desc);
+ }
+
+ abstract boolean shouldImport(Pair<Type, Method> methodKey);
+ }
+
+ class NestedMethodInvocationHandler extends MethodInvocationHandler {
+ final Type owner;
+
+ NestedMethodInvocationHandler(MethodVisitor mv, Type owner) {
+ super(mv);
+ this.owner = owner;
+ }
+
+ @Override
+ boolean shouldImport(Pair<Type, Method> methodKey) {
+ // call anything called within a class hierarchy:
+ final Type called = methodKey.getLeft();
+ // "I prefer the short cut":
+ if (called.equals(owner)) {
+ return true;
+ }
+ try {
+ final Class<?> inner = load(called);
+ final Class<?> outer = load(owner);
+ return inner.isAssignableFrom(outer);
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+
+ private Class<?> load(Type t) throws ClassNotFoundException {
+ return privilizer().classLoader.loadClass(t.getClassName());
+ }
+ }
+
+ private class FieldAccessAccumulator extends MethodVisitor {
+ final Set<FieldAccess> fieldAccesses;
+
+ FieldAccessAccumulator(Set<FieldAccess> fieldAccesses) {
+ super(Opcodes.ASM4);
+ this.fieldAccesses = fieldAccesses;
+ }
+
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ final FieldAccess fieldAccess = fieldAccess(Type.getObjectType(owner), name, Type.getType(desc));
+
+ super.visitFieldInsn(opcode, owner, name, desc);
+ if (!Modifier.isPublic(fieldAccess.access)) {
+ fieldAccesses.add(fieldAccess);
+ }
+ }
+
+ }
+
+ private class AccessibleAdvisor extends AdviceAdapter {
+ final Type bitSetType = Type.getType(BitSet.class);
+ final Type classType = Type.getType(Class.class);
+ final Type fieldType = Type.getType(java.lang.reflect.Field.class);
+ final Type fieldArrayType = Type.getType(java.lang.reflect.Field[].class);
+ final Type stringType = Type.getType(String.class);
+
+ final List<FieldAccess> fieldAccesses;
+ final Label begin = new Label();
+ int localFieldArray;
+ int bitSet;
+ int fieldCounter;
+
+ AccessibleAdvisor(MethodVisitor mv, int access, String name, String desc, List<FieldAccess> fieldAccesses) {
+ super(ASM4, mv, access, name, desc);
+ this.fieldAccesses = fieldAccesses;
+ }
+
+ @Override
+ protected void onMethodEnter() {
+ localFieldArray = newLocal(fieldArrayType);
+ bitSet = newLocal(bitSetType);
+ fieldCounter = newLocal(Type.INT_TYPE);
+
+ // create localFieldArray
+ push(fieldAccesses.size());
+ newArray(fieldArrayType.getElementType());
+ storeLocal(localFieldArray);
+
+ // create bitSet
+ newInstance(bitSetType);
+ dup();
+ push(fieldAccesses.size());
+ invokeConstructor(bitSetType, Method.getMethod("void <init>(int)"));
+ storeLocal(bitSet);
+
+ // populate localFieldArray
+ push(0);
+ storeLocal(fieldCounter);
+ for (FieldAccess access : fieldAccesses) {
+ prehandle(access);
+ iinc(fieldCounter, 1);
+ }
+ mark(begin);
+ }
+
+ private void prehandle(FieldAccess access) {
+ // push owner.class literal
+ visitLdcInsn(access.owner);
+ push(access.name);
+ final Label next = new Label();
+ invokeVirtual(classType, new Method("getDeclaredField", fieldType, new Type[] { stringType }));
+
+ dup();
+ // store the field at localFieldArray[fieldCounter]:
+ loadLocal(localFieldArray);
+ swap();
+ loadLocal(fieldCounter);
+ swap();
+ arrayStore(fieldArrayType.getElementType());
+
+ dup();
+ invokeVirtual(fieldArrayType.getElementType(), Method.getMethod("boolean isAccessible()"));
+
+ final Label setAccessible = new Label();
+ // if false, setAccessible:
+ ifZCmp(EQ, setAccessible);
+
+ // else pop field instance
+ pop();
+ // and record that he was already accessible:
+ loadLocal(bitSet);
+ loadLocal(fieldCounter);
+ invokeVirtual(bitSetType, Method.getMethod("void set(int)"));
+ goTo(next);
+
+ mark(setAccessible);
+ push(true);
+ invokeVirtual(fieldArrayType.getElementType(), Method.getMethod("void setAccessible(boolean)"));
+
+ mark(next);
+ }
+
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ final Pair<Type, String> key = Pair.of(Type.getObjectType(owner), name);
+ final FieldAccess fieldAccess = fieldAccessMap.get(key);
+ Validate.isTrue(fieldAccesses.contains(fieldAccess), "Cannot find field %s", key);
+ final int fieldIndex = fieldAccesses.indexOf(fieldAccess);
+
+ privilizer().debug("accessing field %s with opcode %s", fieldIndex, opcode);
+ visitInsn(NOP);
+ loadLocal(localFieldArray);
+ push(fieldIndex);
+ arrayLoad(fieldArrayType.getElementType());
+ checkCast(fieldType);
+
+ final Method access;
+ if (opcode == PUTSTATIC) {
+ // value should have been at top of stack on entry; position the field under the value:
+ swap();
+ // add null object for static field deref and swap under value:
+ push((String) null);
+ swap();
+ if (fieldAccess.type.getSort() < Type.ARRAY) {
+ // box value:
+ valueOf(fieldAccess.type);
+ }
+ access = Method.getMethod("void set(Object, Object)");
+ } else {
+ access = Method.getMethod("Object get(Object)");
+ // add null object for static field deref:
+ push((String) null);
+ }
+
+ invokeVirtual(fieldType, access);
+
+ if (opcode == GETSTATIC) {
+ checkCast(privilizer().wrap(fieldAccess.type));
+ if (fieldAccess.type.getSort() < Type.ARRAY) {
+ unbox(fieldAccess.type);
+ }
+ }
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals) {
+ // put try-finally around the whole method
+ final Label fy = mark();
+ // null exception type signifies finally block:
+ final Type exceptionType = null;
+ catchException(begin, fy, exceptionType);
+ onFinally();
+ throwException();
+ super.visitMaxs(maxStack, maxLocals);
+ }
+
+ @Override
+ protected void onMethodExit(int opcode) {
+ if (opcode != ATHROW) {
+ onFinally();
+ }
+ }
+
+ private void onFinally() {
+ // loop over fields and return any non-null element to being inaccessible:
+ push(0);
+ storeLocal(fieldCounter);
+
+ final Label test = mark();
+ final Label increment = new Label();
+ final Label endFinally = new Label();
+
+ loadLocal(fieldCounter);
+ push(fieldAccesses.size());
+ ifCmp(Type.INT_TYPE, GeneratorAdapter.GE, endFinally);
+
+ loadLocal(bitSet);
+ loadLocal(fieldCounter);
+ invokeVirtual(bitSetType, Method.getMethod("boolean get(int)"));
+
+ // if true, increment:
+ ifZCmp(NE, increment);
+
+ loadLocal(localFieldArray);
+ loadLocal(fieldCounter);
+ arrayLoad(fieldArrayType.getElementType());
+ push(false);
+ invokeVirtual(fieldArrayType.getElementType(), Method.getMethod("void setAccessible(boolean)"));
+
+ mark(increment);
+ iinc(fieldCounter, 1);
+ goTo(test);
+ mark(endFinally);
+ }
+ }
+}
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/BlueprintingVisitor.java
------------------------------------------------------------------------------
svn:executable = *
Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,72 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.objectweb.asm.Type;
+
+/**
+ * Represents a Java field.
+ */
+public class Field {
+ public final int access;
+ public final String name;
+ public final Type type;
+
+ public Field(int access, String name, Type type) {
+ super();
+ this.access = access;
+ this.name = Validate.notNull(name);
+ this.type = Validate.notNull(type);
+ }
+
+ /**
+ * Considers name and type.
+ *
+ * @param obj
+ * @return whether equal
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Field == false) {
+ return false;
+ }
+ final Field other = (Field) obj;
+ return StringUtils.equals(other.name, name) && ObjectUtils.equals(other.type, type);
+ }
+
+ /**
+ * Considers name and type.
+ *
+ * @return hashCode
+ */
+ @Override
+ public int hashCode() {
+ int result = 57 << 2;
+ result |= name.hashCode();
+ result <<= 4;
+ result |= type.hashCode();
+ return result;
+ }
+}
\ No newline at end of file
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Field.java
------------------------------------------------------------------------------
svn:executable = *
Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,48 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import org.objectweb.asm.Type;
+
+public class FieldAccess extends Field {
+ public final Type owner;
+
+ public FieldAccess(int access, Type owner, String name, Type type) {
+ super(access, name, type);
+ this.owner = owner;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof FieldAccess == false) {
+ return false;
+ }
+ return super.equals(obj) && ((FieldAccess) obj).owner.equals(owner);
+ }
+
+ @Override
+ public int hashCode() {
+ final int result = super.hashCode() << 4;
+ return result | owner.hashCode();
+ }
+
+}
\ No newline at end of file
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/FieldAccess.java
------------------------------------------------------------------------------
svn:executable = *
Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,80 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.util.Map;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.tree.ClassNode;
+
+/**
+ * For any privileged method called from another privileged method (actually the internal implementation method copied
+ * from the original method body) the call is replaced by a call to the target's internal implementation method, thus
+ * avoiding nested privileged invocations when possible. Persists everything to a tree model until the parent is
+ * complete; allowing us to use a tree model while yet building the high-level view as a stack of visitors.
+ */
+class InlineNestedPrivilegedCalls extends ClassNode {
+ private final Privilizer privilizer;
+
+ private final ClassVisitor next;
+
+ /**
+ * Map of original method to name of internal implementation method
+ */
+ private final Map<Method, String> privilegedMethods;
+
+ InlineNestedPrivilegedCalls(Privilizer privilizer, Map<Method, String> privilegedMethods, ClassVisitor next) {
+ super(Opcodes.ASM4);
+ this.privilizer = privilizer;
+ this.privilegedMethods = privilegedMethods;
+ this.next = next;
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+
+ accept(new ClassVisitor(Opcodes.ASM4, next) {
+ @Override
+ public MethodVisitor visitMethod(int access, final String name, String desc, String signature,
+ String[] exceptions) {
+ final Method outer = new Method(name, desc);
+ final MethodVisitor orig = super.visitMethod(access, name, desc, signature, exceptions);
+ if (privilegedMethods.containsValue(name)) {
+ return new MethodVisitor(Opcodes.ASM4, orig) {
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+ if (owner.equals(InlineNestedPrivilegedCalls.this.name)) {
+ final Method m = new Method(name, desc);
+ if (privilegedMethods.containsKey(m)) {
+ name = privilegedMethods.get(m);
+ privilizer.debug("Inlining call from %s to %s as %s", outer, m, name);
+ }
+ }
+ super.visitMethodInsn(opcode, owner, name, desc);
+ }
+ };
+ }
+ return orig;
+ }
+ });
+ }
+}
\ No newline at end of file
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/InlineNestedPrivilegedCalls.java
------------------------------------------------------------------------------
svn:executable = *
Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,249 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URLClassLoader;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.weaver.model.WeaveEnvironment;
+import org.apache.commons.weaver.privilizer.AccessLevel;
+import org.apache.commons.weaver.privilizer.Policy;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.utils.URLArray;
+import org.apache.xbean.finder.archive.FileArchive;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.util.CheckClassAdapter;
+import org.objectweb.asm.util.TraceClassVisitor;
+
+public class Privilizer {
+ abstract class PrivilizerClassVisitor extends ClassVisitor {
+ String className;
+ Type target;
+
+ protected PrivilizerClassVisitor() {
+ this(null);
+ }
+
+ protected PrivilizerClassVisitor(ClassVisitor cv) {
+ super(Opcodes.ASM4, cv);
+ }
+
+ protected Privilizer privilizer() {
+ return Privilizer.this;
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ className = name;
+ target = Type.getObjectType(name);
+ }
+ }
+
+ class WriteClass extends PrivilizerClassVisitor {
+ WriteClass(ClassWriter cw) {
+ super(cw);
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+ final byte[] bytecode = ((ClassWriter) cv).toByteArray();
+
+ if (verify) {
+ verify(target, bytecode);
+ }
+
+ final File f = new File(fileArchive.getDir(), className.replace('.', File.separatorChar) + ".class");
+ try {
+ FileUtils.writeByteArrayToFile(f, bytecode);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public static final String CONFIG_WEAVER = "privilizer.";
+
+ public static final String CONFIG_ACCESS_LEVEL = CONFIG_WEAVER + "accessLevel";
+
+ public static final String CONFIG_POLICY = CONFIG_WEAVER + "policy";
+
+ public static final String CONFIG_VERIFY = CONFIG_WEAVER + "verify";
+
+ private static final Logger log = Logger.getLogger(PrivilizerWeaver.class.getName());
+
+ private static final String GENERATE_NAME = "__privileged_%s";
+
+ static final Type[] EMPTY_TYPE_ARRAY = new Type[0];
+
+ public final AccessLevel accessLevel;
+ public final ClassLoader classLoader;
+ public final FileArchive fileArchive;
+ public final Policy policy;
+ public final boolean verify;
+
+ private final List<String> classpath;
+ final Set<Class<?>> woven;
+
+ public Privilizer(WeaveEnvironment weaveEnvironment) {
+ super();
+ this.policy = Policy.parse(weaveEnvironment.config.getProperty(CONFIG_POLICY));
+ this.accessLevel = AccessLevel.parse(weaveEnvironment.config.getProperty(CONFIG_ACCESS_LEVEL));
+ this.classpath = weaveEnvironment.classpath;
+ classLoader = new URLClassLoader(URLArray.fromPaths(weaveEnvironment.classpath));
+ fileArchive = new FileArchive(classLoader, weaveEnvironment.target);
+ verify = BooleanUtils.toBoolean(weaveEnvironment.config.getProperty(CONFIG_VERIFY));
+ woven = new HashSet<Class<?>>();
+ }
+
+ protected void debug(String message, Object... args) {
+ log.fine(String.format(message, args));
+ }
+
+ protected void verbose(String message, Object... args) {
+ log.fine(String.format(message, args));
+ }
+
+ protected void warn(String message, Object... args) {
+ log.warning(String.format(message, args));
+ }
+
+ protected void info(String message, Object... args) {
+ log.info(String.format(message, args));
+ }
+
+ protected void error(String message, Object... args) {
+ log.severe(String.format(message, args));
+ }
+
+ String generateName(String simple) {
+ return String.format(GENERATE_NAME, simple);
+ }
+
+ Type wrap(Type t) {
+ switch (t.getSort()) {
+ case Type.BOOLEAN:
+ return Type.getType(Boolean.class);
+ case Type.BYTE:
+ return Type.getType(Byte.class);
+ case Type.SHORT:
+ return Type.getType(Short.class);
+ case Type.INT:
+ return Type.getType(Integer.class);
+ case Type.CHAR:
+ return Type.getType(Character.class);
+ case Type.LONG:
+ return Type.getType(Long.class);
+ case Type.FLOAT:
+ return Type.getType(Float.class);
+ case Type.DOUBLE:
+ return Type.getType(Double.class);
+ case Type.VOID:
+ return Type.getType(Void.class);
+ default:
+ return t;
+ }
+ }
+
+ void blueprint(final Class<?> type, final Privilizing privilizing) {
+ debug("blueprinting class %s %s", type.getName(), privilizing);
+ try {
+ final ClassReader classReader = new ClassReader(fileArchive.getBytecode(type.getName()));
+
+ ClassVisitor cv;
+ cv = new WriteClass(new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
+ cv = new PrivilizingVisitor(this, cv);
+ cv = new BlueprintingVisitor(this, cv, privilizing);
+
+ classReader.accept(cv, ClassReader.EXPAND_FRAMES);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void privilize(final Class<?> type) {
+ debug("privilizing class %s", type.getName());
+ try {
+ final ClassReader classReader = new ClassReader(fileArchive.getBytecode(type.getName()));
+ ClassVisitor cv;
+ cv = new WriteClass(new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
+ cv = new PrivilizingVisitor(this, cv);
+
+ classReader.accept(cv, ClassReader.EXPAND_FRAMES);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void verify(final Type target, final byte[] bytecode) {
+ final ClassReader reader = new ClassReader(bytecode);
+
+ // use a new classloader that is always up to date:
+ final ClassLoader verifyClassLoader = new URLClassLoader(URLArray.fromPaths(classpath)) {
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (target.getClassName().equals(name)) {
+ final Class<?> result = defineClass(target.getClassName(), bytecode, 0, bytecode.length);
+ resolveClass(result);
+ return result;
+ }
+ return super.findClass(name);
+ }
+ };
+
+ final StringWriter w = new StringWriter();
+ CheckClassAdapter.verify(reader, verifyClassLoader, false, new PrintWriter(w));
+ final String error = w.toString();
+ if (!error.isEmpty()) {
+ error(error);
+ final StringWriter trace = new StringWriter();
+ reader.accept(new TraceClassVisitor(new PrintWriter(trace)), ClassReader.SKIP_DEBUG);
+ debug(trace.toString());
+ throw new IllegalStateException();
+ }
+ Validate.validState(StringUtils.isBlank(error), error);
+
+ final ClassVisitor checkInnerClasses = new ClassVisitor(Opcodes.ASM4, null) {
+ final Set<String> innerNames = new HashSet<String>();
+
+ @Override
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ super.visitInnerClass(name, outerName, innerName, access);
+ Validate.validState(innerNames.add(innerName), "%s already defined", innerName);
+ }
+ };
+ reader.accept(checkInnerClasses, ClassReader.SKIP_CODE);
+ }
+}
\ No newline at end of file
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/Privilizer.java
------------------------------------------------------------------------------
svn:executable = *
Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,84 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.lang.annotation.ElementType;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.commons.lang3.Validate;
+import org.apache.commons.weaver.model.ScanRequest;
+import org.apache.commons.weaver.model.Scanner;
+import org.apache.commons.weaver.model.WeavableClass;
+import org.apache.commons.weaver.model.WeaveEnvironment;
+import org.apache.commons.weaver.model.WeaveInterest;
+import org.apache.commons.weaver.privilizer.Policy;
+import org.apache.commons.weaver.privilizer.Privileged;
+import org.apache.commons.weaver.privilizer.Privilized;
+import org.apache.commons.weaver.privilizer.Privilizing;
+import org.apache.commons.weaver.spi.Weaver;
+
+public class PrivilizerWeaver implements Weaver {
+ @Override
+ public boolean process(WeaveEnvironment weaveEnvironment, Scanner scanner) {
+ final Privilizer privilizer = new Privilizer(weaveEnvironment);
+
+ final Set<Class<?>> privilizedTypes = new LinkedHashSet<Class<?>>();
+
+ // handle blueprints:
+ for (WeavableClass<?> type : scanner.scan(
+ new ScanRequest().add(WeaveInterest.of(Privilizing.class, ElementType.TYPE))).getClasses()) {
+
+ final Class<?> t = type.getTarget();
+ if (privilizedTypes.add(t) && validateRequest(privilizer, type)) {
+ privilizer.blueprint(t, type.getAnnotation(Privilizing.class));
+ }
+ }
+
+ // handle remaining classes declaring @Privileged methods:
+
+ for (WeavableClass<?> type : scanner.scan(
+ new ScanRequest().add(WeaveInterest.of(Privileged.class, ElementType.METHOD))).getClasses()) {
+ final Class<?> t = type.getTarget();
+ if (privilizedTypes.add(t) && validateRequest(privilizer, type)) {
+ privilizer.privilize(t);
+ }
+ }
+ return !privilizedTypes.isEmpty();
+ }
+
+ /**
+ * Validate a weaving request for a given target type.
+ *
+ * @param privilizer
+ * @param type
+ *
+ * @return whether weaving should proceed
+ * @throws IllegalStateException if class has already been woven with some other policy
+ */
+ private boolean validateRequest(Privilizer privilizer, WeavableClass<?> type) {
+ Privilized marker = type.getAnnotation(Privilized.class);
+ if (marker == null) {
+ return privilizer.policy != Policy.NEVER;
+ }
+ Validate.validState(privilizer.policy == marker.value(), "%s already privilized with policy %s", type
+ .getTarget().getName(), marker.value());
+ return false;
+ }
+}
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizerWeaver.java
------------------------------------------------------------------------------
svn:executable = *
Added: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java?rev=1508483&view=auto
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java (added)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java Tue Jul 30 15:18:01 2013
@@ -0,0 +1,234 @@
+/*
+ * 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.commons.weaver.privilizer.asm;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javassist.Modifier;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.weaver.privilizer.AccessLevel;
+import org.apache.commons.weaver.privilizer.Policy;
+import org.apache.commons.weaver.privilizer.Privileged;
+import org.apache.commons.weaver.privilizer.Privilized;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.commons.StaticInitMerger;
+
+class PrivilizingVisitor extends Privilizer.PrivilizerClassVisitor {
+ final Map<Method, String> privilegedMethods = new LinkedHashMap<Method, String>();
+ boolean annotated;
+ final Policy policy;
+ final AccessLevel accessLevel;
+
+ PrivilizingVisitor(Privilizer privilizer, ClassVisitor cv) {
+ privilizer.super();
+ this.policy = privilizer.policy;
+ this.accessLevel = privilizer.accessLevel;
+ this.cv =
+ new InlineNestedPrivilegedCalls(privilizer, privilegedMethods, new StaticInitMerger(
+ privilizer.generateName("clinit"), cv));
+ }
+
+ private void annotate() {
+ if (!annotated) {
+ annotated = true;
+ final AnnotationVisitor privilizedVisitor =
+ super.visitAnnotation(Type.getType(Privilized.class).getDescriptor(), false);
+ privilizedVisitor.visitEnum("value", Type.getType(Policy.class).getDescriptor(), policy.name());
+ privilizedVisitor.visitEnd();
+ }
+ }
+
+ @Override
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ annotate();
+ super.visitInnerClass(name, outerName, innerName, access);
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+ annotate();
+ return super.visitField(access, name, desc, signature, value);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature,
+ final String[] exceptions) {
+ annotate();
+ final MethodVisitor originalMethod = super.visitMethod(access, name, desc, signature, exceptions);
+ final Method m = new Method(name, desc);
+
+ return new GeneratorAdapter(Opcodes.ASM4, originalMethod, access, name, desc) {
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ if (Type.getType(Privileged.class).getDescriptor().equals(desc)) {
+ final AccessLevel localAccessLevel = AccessLevel.of(access);
+ if (accessLevel.compareTo(localAccessLevel) > 0) {
+ throw new RuntimeException(new IllegalAccessException("Method " + className + "#" + m
+ + " must have maximum access level '" + accessLevel + "' but is defined wider ('"
+ + localAccessLevel + "')"));
+ }
+ if (AccessLevel.PACKAGE.compareTo(accessLevel) > 0) {
+ privilizer().warn("Possible security leak: granting privileges to %s method %s.%s",
+ localAccessLevel, className, m);
+ }
+ privilegedMethods.put(m, privilizer().generateName(name));
+ }
+ return super.visitAnnotation(desc, visible);
+ }
+
+ @Override
+ public void visitCode() {
+ super.visitCode();
+ if (!privilegedMethods.containsKey(m)) {
+ return;
+ }
+ final String impl = privilegedMethods.get(m);
+ final boolean instanceMethod = !Modifier.isStatic(access);
+
+ if (policy.isConditional()) {
+ // test, loading boolean
+ if (policy == Policy.ON_INIT) {
+ getStatic(target, privilizer().generateName("hasSecurityManager"), Type.BOOLEAN_TYPE);
+ } else if (policy == Policy.DYNAMIC) {
+ checkSecurityManager(this);
+ }
+ final Label doPrivileged = new Label();
+
+ // if true, goto doPrivileged:
+ ifZCmp(NE, doPrivileged);
+
+ final Method implMethod = new Method(impl, desc);
+ if (instanceMethod) {
+ loadThis();
+ loadArgs();
+ invokeVirtual(target, implMethod);
+ } else {
+ loadArgs();
+ invokeStatic(target, implMethod);
+ }
+ returnValue();
+ mark(doPrivileged);
+ }
+
+ // generate action:
+ final Type[] ctorArgs;
+ if (instanceMethod) {
+ ctorArgs = ArrayUtils.add(m.getArgumentTypes(), 0, target);
+ } else {
+ ctorArgs = m.getArgumentTypes();
+ }
+ final Type actionType = new ActionGenerator(access, m, exceptions, PrivilizingVisitor.this).build();
+ newInstance(actionType);
+ dup();
+ if (instanceMethod) {
+ loadThis();
+ }
+ loadArgs();
+ invokeConstructor(actionType, new Method("<init>", Type.VOID_TYPE, ctorArgs));
+
+ final boolean exc = ArrayUtils.isNotEmpty(exceptions);
+ // mark try if needed
+ final Label privTry = exc ? mark() : null;
+
+ // execute action
+ final Type arg =
+ exc ? Type.getType(PrivilegedExceptionAction.class) : Type.getType(PrivilegedAction.class);
+ final Method doPrivileged = new Method("doPrivileged", Type.getType(Object.class), new Type[] { arg });
+ invokeStatic(Type.getType(AccessController.class), doPrivileged);
+
+ unbox(m.getReturnType());
+ returnValue();
+
+ if (exc) {
+ final Type caught = Type.getType(PrivilegedActionException.class);
+ // end try
+ final Label privCatch = mark();
+ // catch
+ catchException(privTry, privCatch, caught);
+ // unwrap
+ invokeVirtual(caught, new Method("getException", Type.getType(Exception.class),
+ Privilizer.EMPTY_TYPE_ARRAY));
+ // throw
+ throwException();
+ }
+
+ // end original method
+ endMethod();
+
+ // substitute an impl visitor and continue
+ mv = cv.visitMethod(AccessLevel.PRIVATE.merge(access), impl, desc, signature, exceptions);
+ mv.visitCode();
+ }
+ };
+
+ }
+
+ public void visitEnd() {
+ annotate();
+ if (privilizer().policy == Policy.ON_INIT) {
+ final String fieldName = privilizer().generateName("hasSecurityManager");
+
+ visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, fieldName,
+ Type.BOOLEAN_TYPE.getDescriptor(), null, null).visitEnd();
+
+ final GeneratorAdapter mg =
+ new GeneratorAdapter(Opcodes.ACC_STATIC, new Method("<clinit>", "()V"), null,
+ Privilizer.EMPTY_TYPE_ARRAY, this);
+ checkSecurityManager(mg);
+ mg.putStatic(target, fieldName, Type.BOOLEAN_TYPE);
+ mg.returnValue();
+ mg.endMethod();
+
+ super.visitEnd();
+ }
+ }
+
+ /**
+ * Generates the instructions to push onto the stack whether there is a security manager available
+ *
+ * @param mg
+ */
+ private static void checkSecurityManager(GeneratorAdapter mg) {
+ final Label setFalse = new Label();
+ final Label done = new Label();
+ mg.invokeStatic(Type.getType(System.class),
+ new Method("getSecurityManager", Type.getType(SecurityManager.class), Privilizer.EMPTY_TYPE_ARRAY));
+ mg.ifNull(setFalse);
+ mg.push(true);
+ mg.goTo(done);
+ mg.mark(setFalse);
+ mg.push(false);
+ mg.mark(done);
+ }
+}
\ No newline at end of file
Propchange: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/java/org/apache/commons/weaver/privilizer/asm/PrivilizingVisitor.java
------------------------------------------------------------------------------
svn:executable = *
Modified: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Cleaner
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Cleaner?rev=1508483&r1=1508482&r2=1508483&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Cleaner (original)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Cleaner Tue Jul 30 15:18:01 2013
@@ -15,5 +15,5 @@
# specific language governing permissions and limitations
# under the License.
-# this class gets picked up by the WeaveProcessor
+# this class gets picked up by the CleanProcessor
org.apache.commons.weaver.privilizer.PrivilizerCleaner
Modified: commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Weaver
URL: http://svn.apache.org/viewvc/commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Weaver?rev=1508483&r1=1508482&r2=1508483&view=diff
==============================================================================
--- commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Weaver (original)
+++ commons/sandbox/weaver/branches/priv-asm/modules/privilizer/weaver/src/main/resources/META-INF/services/org.apache.commons.weaver.spi.Weaver Tue Jul 30 15:18:01 2013
@@ -16,4 +16,4 @@
# under the License.
# this class gets picked up by the WeaveProcessor
-org.apache.commons.weaver.privilizer.PrivilizerWeaver
+org.apache.commons.weaver.privilizer.asm.PrivilizerWeaver