I'm not that good in Java but I have my webApplication running on a Wildfly.
I have 3 threads who just call a function that insert logs in in and the function saves the logs to a Database and after that every thread sends a time how long did it takes to do this.
They send the data to another programm I wrote what has 3 threads to call one of the 3 server threads.
So now I try to do some ByteCode Manipulation every thread on the server saves the datetime call the log function waits 1 second and returns then the time they needed.
1 Thread write something in an logfile before or after they waitet 1 second.
But this part where they wait a second and call the log function I want that to inject to every 3 threads with Bytecode manipulation.
public class MyTransformer implements ClassFileTransformer {
#Override
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
return transformClass(redefiningClass, bytes);
}
private byte[] transformClass(Class classToTransform, byte[] b) {
ClassPool pool = ClassPool.getDefault();
CtClass cl = null;
try {
cl = pool.get("de.soptim.ws.MyApplication");
} catch (javassist.NotFoundException e) {
e.printStackTrace();
}
try {
assert cl != null;
CtMethod[] methods = cl.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].isEmpty() == false) {
changeMethod(methods[i]);
}
}
b = cl.toBytecode();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cl != null) {
cl.detach();
}
}
return b;
}
private void changeMethod(CtMethod method) throws NotFoundException, CannotCompileException {
if (method.hasAnnotation(Loggable.class)) {
method.insertBefore("threadLogger.info(\"ADDED THIS FROM BYTECODE !!!\");");
method.insertAfter("threadLogger.info(\"ADDED THIS FROM BYTECODE !!!\");");
}
}}
Thats my transformer class it should increase the Code my Methods need it checks what Method has an #Loggable annotation an then adds the code into it("at the moment it's just some log statments for checking if it works")
My biggest problem is now that I don't know how to call my agent ... I googled hwo to call an agent at runtime with agentmain() but I think I dind't really understood how it works.
Agent Class
public class LogAgent {
public static void agentmain(String agentArgs, Instrumentation inst) {
System.out.println("Starting the agent");
inst.addTransformer(new MyTransformer());
}}
Hope you understand My problem :) I and if you answere pleas try to stay noob friendly :D.
you don't call your agent explicitly, you should specify additional argument to your JVM :
java -javaagent:jarpath[=options]
where jarpath is a path to jar containing your agent. JVM will invoke premain method before main method of java program.
And transform method will be called before classloading by JVM (you don't call it explicitly).
Last remark : you should implement premain method, not agentmain.
agentmain is used during attaching to running vm, while premain is used when you start JVM with -javaagent method.
And make sure that your jar have valid manifest, as described : https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html
I haven't using javaassit so I cannot say that your code is valid, but instrumenting webapp server like Wildfly is much harder than normal java app (mostly due to classloaders visibility and hierarchy).
See also :
http://www.tomsquest.com/blog/2014/01/intro-java-agent-and-bytecode-manipulation/
Tutorials about javaagents
Related
I've read CDI 2.0 specification (JSR 365) and found out the existence of the #Observes(during=AFTER_SUCCESS) annotation, but it actually requires a custom event to be defined in order to work.
This is what i've got:
//simple """transactional""" file system manager using command pattern
#Transactional(value = Transactional.TxType.REQUIRED)
#TransactionScoped
#Stateful
public class TransactionalFileSystemManager implements SessionSynchronization {
private final Deque<Command> commands = new ArrayDeque<>();
public void createFile(InputStream content, Path path, String name) throws IOException {
CreateFile command = CreateFile.execute(content, path, name);
commands.addLast(command);
}
public void deleteFile(Path path) throws IOException {
DeleteFile command = DeleteFile.execute(path);
commands.addLast(command);
}
private void commit() throws IOException{
for(Command c : commands){
c.confirm();
}
}
private void rollback() throws IOException{
Iterator<Command> it = commands.descendingIterator();
while (it.hasNext()) {
Command c = it.next();
c.undo();
}
}
#Override
public void afterBegin() throws EJBException{
}
#Override
public void beforeCompletion() throws EJBException{
}
#Override
public void afterCompletion(boolean commitSucceeded) throws EJBException{
if(commitSucceeded){
try {
commit();
} catch (IOException e) {
throw new EJBException(e);
}
}
else {
try {
rollback();
} catch (IOException e) {
throw new EJBException(e);
}
}
}
}
However, I want to adopt a CDI-only solution so I need to remove anything EJB related (including the SessionSynchronization interface). How can i achieve the same result using CDI?
First the facts: the authoritative source for this topic is the Java Transaction API (JTA) specification. Search for it online, I got this.
Then the bad news: In order to truly participate in a JTA transaction, you either have to implement a connector according to the Java Connector Architecture (JCA) specification or a XAResource according to JTA. Never done any of them, I am afraid both are going to be hard. Nevertheless, if you search, you may find an existing implementation of a File System Connector.
Your code above will never accomplish true 2-phase commit because, if your code fails, the transaction is already committed, so the application state is inconsistent. Or, there is a small time window when the real transaction is committed but the file system change have not beed executed, again the state is inconsistent.
Some workarounds I can think of, none of which solves the consistency problem:
Persist the File System commands in a database. This ensures that they are enqueued transactionally. A scheduled job wakes up and actually tries to execute the queued FS commands.
Register a Synchronization with the current Transaction, fire an appropriate event from there. Your TransactionalFileSystemManager observes this event, no during attribute needed I guess.
Its is my first time implementing a java agent and im trying to learn something about bytecode instrumentation. After reading several introductions and tutorials i coded a small Application with two classes (Summer and Application). Now i want to run a java agent via premain method to show the execution path using the following code:
public class TestJavaAgent {
public static void premain(String agentArgument,
Instrumentation instrumentation){
instrumentation.addTransformer(new ClassFileTransformer() {
#Override
public byte[] transform(ClassLoader classLoader, String s, Class<?> aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
ClassPool cp = ClassPool.getDefault();
try {
CtClass cc = cp.get("Summer");
CtMethod methods [] = cc.getMethods();
for( CtMethod method : methods){
System.out.println("Entering "+method.getName());
method.addLocalVariable("elapsedTime", CtClass.longType);
method.insertBefore("elapsedTime = System.currentTimeMillis();");
method.insertAfter("{elapsedTime = System.currentTimeMillis() - elapsedTime;"
+ "System.out.println(\"Method Executed in ms: \" + elapsedTime);}");
}
return cc.toBytecode();
} catch (Exception ex) {
return bytes;
}
}
});
}
}
I started the Agent via java -javaagent{Agent JAR} -jar {Application Jar} but it did not print anything of the inserted messages. After debugging the code i realized everything after "ClassPool.getDefault()" will not be reached but i dont know why. Can someone help me?
The transformer is supposed to transform the class being passed as parameter, not some arbitrary class you like. And after registration, it will be called for all classes that are loaded, including the classes you are using yourself (ClassPool at first). So you are creating a circular dependency.
You have to check the class name argument and wait until your method has been called for the class you want to transform. For all other classes, just return null.
public class TestJavaAgent {
public static void premain(String agentArgument, Instrumentation instrumentation) {
instrumentation.addTransformer(new ClassFileTransformer() {
#Override
public byte[] transform(ClassLoader classLoader,
String className, Class<?> aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
if(!className.equals("Summer")) return null;
ClassPool cp = ClassPool.getDefault();
try {
// use the class bytes your received as parameter
cp.insertClassPath(new ByteArrayClassPath(className, bytes));
CtClass cc = cp.get("Summer");
CtMethod[] methods = cc.getMethods();
for( CtMethod method : methods){
System.out.println("Entering "+method.getName());
method.addLocalVariable("elapsedTime", CtClass.longType);
method.insertBefore("elapsedTime = System.currentTimeMillis();");
method.insertAfter("{elapsedTime = System.currentTimeMillis() - elapsedTime;"
+ "System.out.println(\"Method Executed in ms: \" + elapsedTime);}");
}
return cc.toBytecode();
} catch (Exception ex) {
return null;
}
}
});
}
}
Note that returning null is preferred to returning the original array if you didn’t change anything as then the JVM can immediately recognize that you didn’t change anything, without looking into the array contents.
How can I securely execute some user supplied JS code using Java8 Nashorn?
The script extends some computations for some servlet based reports. The app has many different (untrusted) users. The scripts should only be able to access a Java Object and those returned by the defined members. By default the scripts could instantiate any class using Class.forName() (using .getClass() of my supplied object). Is there any way to prohibit access to any java class not explicitly specified by me?
I asked this question on the Nashorn mailing list a while back:
Are there any recommendations for the best way to
restrict the classes that Nashorn scripts can create to a whitelist?
Or is the approach the same as any JSR223 engine (custom classloader
on the ScriptEngineManager constructor)?
And got this answer from one of the Nashorn devs:
Hi,
Nashorn already filters classes - only public classes of non-sensitive packages (packages listed in package.access security
property aka 'sensitive'). Package access check is done from a
no-permissions context. i.e., whatever package that can be accessed
from a no-permissions class are only allowed.
Nashorn filters Java reflective and jsr292 access - unless script has RuntimePermission("nashorn.JavaReflection"), the script wont be
able to do reflection.
The above two require running with SecurityManager enabled. Under no security manager, the above filtering won't apply.
You could remove global Java.type function and Packages object (+ com,edu,java,javafx,javax,org,JavaImporter) in global scope and/or
replace those with whatever filtering functions that you implement.
Because, these are the only entry points to Java access from script,
customizing these functions => filtering Java access from scripts.
There is an undocumented option (right now used only to run test262 tests) "--no-java" of nashorn shell that does the above for you. i.e.,
Nashorn won't initialize Java hooks in global scope.
JSR223 does not provide any standards based hook to pass a custom class loader. This may have to be addressed in a (possible) future
update of jsr223.
Hope this helps,
-Sundar
Added in 1.8u40, you can use the ClassFilter to restrict what classes the engine can use.
Here is an example from the Oracle documentation:
import javax.script.ScriptEngine;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
public class MyClassFilterTest {
class MyCF implements ClassFilter {
#Override
public boolean exposeToScripts(String s) {
if (s.compareTo("java.io.File") == 0) return false;
return true;
}
}
public void testClassFilter() {
final String script =
"print(java.lang.System.getProperty(\"java.home\"));" +
"print(\"Create file variable\");" +
"var File = Java.type(\"java.io.File\");";
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine(
new MyClassFilterTest.MyCF());
try {
engine.eval(script);
} catch (Exception e) {
System.out.println("Exception caught: " + e.toString());
}
}
public static void main(String[] args) {
MyClassFilterTest myApp = new MyClassFilterTest();
myApp.testClassFilter();
}
}
This example prints the following:
C:\Java\jre8
Create file variable
Exception caught: java.lang.RuntimeException: java.lang.ClassNotFoundException:
java.io.File
I've researched ways of allowing users to write a simple script in a sandbox that is allowed access to some basic objects provided by my application (in the same way Google Apps Script works). My conclusion was that this is easier/better documented with Rhino than with Nashorn. You can:
Define a class-shutter to avoid access to other classes: http://codeutopia.net/blog/2009/01/02/sandboxing-rhino-in-java/
Limit the number of instructions to avoid endess-loops with observeInstructionCount: http://www-archive.mozilla.org/rhino/apidocs/org/mozilla/javascript/ContextFactory.html
However be warned that with untrusted users this is not enough, because they can still (by accident or on purpose) allocate a hugh amount of memory, causing your JVM to throw an OutOfMemoryError. I have not found a safe solution to this last point yet.
You can quite easily create a ClassFilter which allows fine-grained control of which Java classes are available in JavaScript.
Following the example from the Oracle Nashorn Docs:
class MyCF implements ClassFilter {
#Override
public boolean exposeToScripts(String s) {
if (s.compareTo("java.io.File") == 0) return false;
return true;
}
}
I have wrapped this an a few other measures in a small library today: Nashorn Sandbox (on GitHub). Enjoy!
So far as I can tell, you can't sandbox Nashorn. An untrusted user can execute the "Additional Nashorn Built-In Functions" listed here:
https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/shell.html
which include "quit()". I tested it; it exits the JVM entirely.
(As an aside, in my setup the global objects, $ENV, $ARG, did not work, which is good.)
If I'm wrong about this, someone please leave a comment.
The best way to secure a JS execution in Nashorn is to enable the SecurityManager and let Nashorn deny the critical operations.
In addition you can create a monitoring class that check the script execution time and memory in order to avoid infinite loops and outOfMemory.
In case you run it in a restricted environment without possibility to setup the SecurityManager, you can think to use the Nashorn ClassFilter to deny all/partial access to the Java classes. In addition to that you must overwrite all the critical JS functions (like quit() etc.).
Have a look at this function that manage all this aspects (except memory management):
public static Object javascriptSafeEval(HashMap<String, Object> parameters, String algorithm, boolean enableSecurityManager, boolean disableCriticalJSFunctions, boolean disableLoadJSFunctions, boolean defaultDenyJavaClasses, List<String> javaClassesExceptionList, int maxAllowedExecTimeInSeconds) throws Exception {
System.setProperty("java.net.useSystemProxies", "true");
Policy originalPolicy = null;
if(enableSecurityManager) {
ProtectionDomain currentProtectionDomain = this.getClass().getProtectionDomain();
originalPolicy = Policy.getPolicy();
final Policy orinalPolicyFinal = originalPolicy;
Policy.setPolicy(new Policy() {
#Override
public boolean implies(ProtectionDomain domain, Permission permission) {
if(domain.equals(currentProtectionDomain))
return true;
return orinalPolicyFinal.implies(domain, permission);
}
});
}
try {
SecurityManager originalSecurityManager = null;
if(enableSecurityManager) {
originalSecurityManager = System.getSecurityManager();
System.setSecurityManager(new SecurityManager() {
//allow only the opening of a socket connection (required by the JS function load())
#Override
public void checkConnect(String host, int port, Object context) {}
#Override
public void checkConnect(String host, int port) {}
});
}
try {
ScriptEngine engineReflex = null;
try{
Class<?> nashornScriptEngineFactoryClass = Class.forName("jdk.nashorn.api.scripting.NashornScriptEngineFactory");
Class<?> classFilterClass = Class.forName("jdk.nashorn.api.scripting.ClassFilter");
engineReflex = (ScriptEngine)nashornScriptEngineFactoryClass.getDeclaredMethod("getScriptEngine", new Class[]{Class.forName("jdk.nashorn.api.scripting.ClassFilter")}).invoke(nashornScriptEngineFactoryClass.newInstance(), Proxy.newProxyInstance(classFilterClass.getClassLoader(), new Class[]{classFilterClass}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("exposeToScripts")) {
if(javaClassesExceptionList != null && javaClassesExceptionList.contains(args[0]))
return defaultDenyJavaClasses;
return !defaultDenyJavaClasses;
}
throw new RuntimeException("no method found");
}
}));
/*
engine = new jdk.nashorn.api.scripting.NashornScriptEngineFactory().getScriptEngine(new jdk.nashorn.api.scripting.ClassFilter() {
#Override
public boolean exposeToScripts(String arg0) {
...
}
});
*/
}catch(Exception ex) {
throw new Exception("Impossible to initialize the Nashorn Engine: " + ex.getMessage());
}
final ScriptEngine engine = engineReflex;
if(parameters != null)
for(Entry<String, Object> entry : parameters.entrySet())
engine.put(entry.getKey(), entry.getValue());
if(disableCriticalJSFunctions)
engine.eval("quit=function(){throw 'quit() not allowed';};exit=function(){throw 'exit() not allowed';};print=function(){throw 'print() not allowed';};echo=function(){throw 'echo() not allowed';};readFully=function(){throw 'readFully() not allowed';};readLine=function(){throw 'readLine() not allowed';};$ARG=null;$ENV=null;$EXEC=null;$OPTIONS=null;$OUT=null;$ERR=null;$EXIT=null;");
if(disableLoadJSFunctions)
engine.eval("load=function(){throw 'load() not allowed';};loadWithNewGlobal=function(){throw 'loadWithNewGlobal() not allowed';};");
//nashorn-polyfill.js
engine.eval("var global=this;var window=this;var process={env:{}};var console={};console.debug=print;console.log=print;console.warn=print;console.error=print;");
class ScriptMonitor{
public Object scriptResult = null;
private boolean stop = false;
Object lock = new Object();
#SuppressWarnings("deprecation")
public void startAndWait(Thread threadToMonitor, int secondsToWait) {
threadToMonitor.start();
synchronized (lock) {
if(!stop) {
try {
if(secondsToWait<1)
lock.wait();
else
lock.wait(1000*secondsToWait);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
if(!stop) {
threadToMonitor.interrupt();
threadToMonitor.stop();
throw new RuntimeException("Javascript forced to termination: Execution time bigger then " + secondsToWait + " seconds");
}
}
public void stop() {
synchronized (lock) {
stop = true;
lock.notifyAll();
}
}
}
final ScriptMonitor scriptMonitor = new ScriptMonitor();
scriptMonitor.startAndWait(new Thread(new Runnable() {
#Override
public void run() {
try {
scriptMonitor.scriptResult = engine.eval(algorithm);
} catch (ScriptException e) {
throw new RuntimeException(e);
} finally {
scriptMonitor.stop();
}
}
}), maxAllowedExecTimeInSeconds);
Object ret = scriptMonitor.scriptResult;
return ret;
} finally {
if(enableSecurityManager)
System.setSecurityManager(originalSecurityManager);
}
} finally {
if(enableSecurityManager)
Policy.setPolicy(originalPolicy);
}
}
The function currently use the deprecated Thread stop(). An improvement can be execute the JS not in a Thread but in a separate Process.
PS: here Nashorn is loaded through reflexion but the equivalent Java code is also provided in the comments
I'd say overriding the supplied class's classloader is easiest way to control access to classes.
(Disclaimer: I'm not really familiar with newer Java, so this answer may be old-school/obsolete)
An external sandbox library can be used if you don't want to implement your own ClassLoader & SecurityManager (that's the only way of sandboxing for now).
I've tried "The Java Sandbox" (http://blog.datenwerke.net/p/the-java-sandbox.html) although it's a bit rough around the edges, but it works.
Without the use of Security Manager it is not possible to securely execute JavaScript on Nashorn.
In all releases of Oracle Hotspot that included Nashorn one can write JavaScript that will execute any Java/JavaScript code on this JVM.
As of January 2019, Oracle Security Team insist that use of Security Manager is mandatory.
One of the problems is already discussed in https://github.com/javadelight/delight-nashorn-sandbox/issues/73
in my application the follwoing code is used. Can some one give a detailed explanation for the code that is highlighted?
I understood that in first highlighted block java reflection is used in invoking the method handle_validation..but need the detailed explanation.
Then in second highlighted block RemoteException is thrown..
My exact question is why they used reflection to call EngineHandlerIF and then why they are using RMI in this EngineHandlerIF to invoke the definition of method in EngineHandler?
private static EngineHandlerIF init() {
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] { "validation.xml" });
String[] beans = ctx.getBeanDefinitionNames();
for (String string : beans) {
logger.info(string);
}
EngineHandlerIF engine = (EngineHandlerIF) ctx.getBean("engine");
return engine;
}
private Object callEngineMethod(MiddlewareMessage mmsg) {
Object resultObj;
try {
**String methodName = "handle_validation";
Method method = EngineHandlerIF.class.getDeclaredMethod(methodName, MiddlewareMessage.class);
method.setAccessible(true);
resultObj = method.invoke(engine, new Object[] { mmsg });**
} catch (Exception e) {
logger.error("sendMessage Exception: ", e);
return new Boolean(false);
}
return resultObj;
}
EngineHandlerIF:
----------------
**public abstract String handle_validation(MiddlewareMessage mmsg) throws RemoteException;**
EngineHandler:
--------------
public String handle_validation(MiddlewareMessage mmsg) throws Exception {
//some code
}
I understood that in first highlighted block java reflection is used
in invoking the method handle_validation..but need the detailed
explanation.
That's pretty much it. The only other bit is the
method.setAccessible(true);
which makes the method accessible to the caller (e.g. from private to public), thus allowing you to call it. However the above method does appear to be public already. Perhaps this is some legacy following a refactor ?
Note that this isn't RMI (remote method invocation), but rather reflection. The only RMI I can see here is the handle_validation() method possibly throwing a RemoteException.
Maybe someone had just discovered the hammer of a reflection so everything, including method that were already public, started looking like a nut.
It is garbage: throw it away. Just call the method directly.
I'm having some hard time with Java classloaders, maybe somebody could shed some light on this. I have extracted the essence of the problem to the follwing:
There are three classes - ClassLoaderTest, LoadedClass and LoadedClassDep. They are all on different paths.
ClassLoaderTest instantiates a new URLClassLoader - myClassLoader, priming it with the paths to the remaining two classes and it's own classloader (i.e. the application classloader) as parent. It then uses Class.forName("com.example.LoadedClass", true, myClassLoader) to load the LoadedClass through reflection. The LoadedClass imports the LoadedClassDep. If I run the above, using:
java -cp /path/to/the/ClassLoaderTest ClassLoaderTest "/path/to/LoadedClass" "/path/to/LoadedClassDep"
and using the command line arguments to prime the URLClassLoader everything works fine. Using static initialisers I confirm that the two classes are loaded with an instance of a URLClassLoader.
HOWEVER, and this is the problem, if I do:
java -cp /path/to/the/ClassLoaderTest:/path/to/the/LoadedClass ClassLoaderTest "/path/to/LoadedClassDep"
this fails to load the LoadedClassDep (ClassNotFoundException). The LoadedClass is loaded correctly, but with sun.misc.Launcher$AppClassLoader, not the URLClassLoader!
It would appear that since the application classloader is capable of loading the LoadedClass it also attempts to load the LoadedClassDep, disregarding the URLClassLoader.
Here's the full source code:
package example.bc;
public class ClassloaderTest {
public static void main(String[] args) {
new ClassloaderTest().run(args);
}
private void run(String[] args) {
URLClassLoader myClasLoader = initClassLoader(args);
try {
Class<?> cls = Class.forName("com.example.bc.LoadedClass", true, myClasLoader);
Object obj = cls.newInstance();
cls.getMethod("call").invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
private URLClassLoader initClassLoader(String[] args) {
URL[] urls = new URL[args.length];
try {
for (int i = 0; i < args.length; i++) {
urls[i] = new File(args[i]).toURI().toURL();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return new URLClassLoader(urls, getClass().getClassLoader());
}
}
package com.example.bc;
import com.bc.LoadedClassDep;
public class LoadedClass {
static {
System.out.println("LoadedClass " + LoadedClass.class.getClassLoader().getClass());
}
public void call() {
new LoadedClassDep();
}
}
package com.bc;
public class LoadedClassDep {
static {
System.out.println("LoadedClassDep " + LoadedClassDep.class.getClassLoader().getClass());
}
}
I hope I made this clear enough. My issue is, I only know the path to ClassLoadeTest at compile time, I have to use strings at runtime for the other paths. So, any ideas how to make the second scenario work?
I'd expect the application classloader to load LoadedClass in the second case, since classloaders delegate to their parent initially - this is the standard behaviour. In the second case, LoadedClass is on the parent's classpath, so it loads the class instead of giving up and letting the URLClassLoader try.
The application classloader then attempts to load the LoadedClassDep because it is imported and referenced directly in LoadedClass:
public void call() {
new LoadedClassDep();
}
If you need to load these classes dynamically and independently at runtime, you can't have direct references between them in this way.
It is also possible to change the order in which classloaders are tried - see Java classloaders: why search the parent classloader first? for some discussion of this.