I have a peculiar requirement where I need ensure that only a particular method from one class is allowed to call a public (non-static) method from a second class. Inheritance cannot be used.
One option is to use StackTrace as follows:
ClassA.java
package org.rnd.stack;
public class ClassA {
public void methodA() throws IllegalAccessException {
Exception fake = new Exception("FAKE-IGNORE");
StackTraceElement[] stack = fake.getStackTrace();
StackTraceElement st = stack[1];
if ("org.rnd.stack.ClassB".equals(st.getClassName())
&& "methodB".equals(st.getMethodName())) {
System.out.println("You are allowed to call");
} else {
throw new IllegalAccessException("You are not allowed to call");
}
}
}
ClassB.java
package org.rnd.stack;
public class ClassB {
public void methodB() throws IllegalAccessException {
new ClassA().methodA();
}
public void illegalMethod() throws IllegalAccessException {
new ClassA().methodA();
}
public static void main(String[] args) {
try {
new ClassB().methodB();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Now the above solution works fine, but due to quality control in code audit I need to come up with another (or rather) better solution. Is there a better way to achieve this?
The right thing to do would be to revisit your requirement. A method that can only be called by certain other code paths is not compatible with public. The general best practice is to use package-private to prevent external callers, and accept that any code in the package could call the method, but won't because you or your team is auditing it.
Method visibility is ultimately not a secure solution to preventing execution; someone has your .class files and the ability to execute them on a machine, they can do just about anything they want. You shouldn't spend too much time trying to lock down method calls. Instead, document the intent of the method clearly (e.g. "Helper function for methodB(), please do not use elsewhere.") and trust the people developing with you know what they're doing. You can even give the method a clear name, like dangerousMethodBForInternalUseOnly() if you really want to beat people over the head about it.
You may also be interested in dependency-injection, which is a design pattern that uses the type system to protect (not prevent) people from executing dangerous code. Here's a couple of talks on Guice, a popular DI framework, that goes into more detail about the concept:
Google I/O 2009 - Big Modular Java with Guice
Java on Guice: Dependency Injection, the Java Way
All of that said, as an academic exercise here's one option for restricting method invocation to a fixed number of codepaths - rely on a shared secret. Add an Object secret field to your locked-down method, and cause the method to fail if the passed secret does not match a hard-coded value (private static final Object SECRET = new Object()). You can then use other mechanisms to share the secret only to code paths you allow (e.g. have a static initializer in your locked-down class publish it to classes you explicitly trust).
Obviously this can still be worked-around by a malicious developer, and it's pretty gross, but it would provide some sort of locking behavior assuming you can trust your locked-down class won't be changed without your knowledge.
A way to improve you method is that you don't need to create an exception to get the stacktrace, you can use the thread methods.
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
Also maybe you want to use the class instead of handwriting the package. For example:
if (ClassB.class.getName().equals(st.getClassName())
&& "methodB".equals(st.getMethodName())) {
System.out.println("You are allowed to call");
} else {
throw new IllegalAccessException("You are not allowed to call");
}
Apart from that I don't know how you can do it better without changing your logic or using inheritance.
Pass caller as an argument and check if the caller is instanceof required class - multithreaded solution, cannot bypass by reflecion.
Get thread stack dump and check top entry - weird, heavy but possible
Create proxy - but that will be overheaded variation of solution 1.
You may be able to satisfy this requirement by using the class Class method getEnclosingMethod(). This is how it works (docs here):
If this Class object represents a local or anonymous class within a method, returns a Method object representing the immediately enclosing method of the underlying class.
The signature for methodA() should be changed to accept a Class object as parameter.
public void methodA(Class c) { }
The legal method from ClassB should create an anonymous class object, and pass its class as argument to methodA().
public void methodB() throws IllegalAccessException, NoSuchMethodException {
new ClassA().methodA(new Object(){}.getClass());
}
Then methodA() should check if the class enclosing method is indeed methodB() from ClassB.
public void methodA(Class c) throws IllegalAccessException, NoSuchMethodException {
if (c.getEnclosingMethod().equals(ClassB.class.getMethod("methodB"))) {
System.out.println("You are allowed to call");
} else {
throw new IllegalAccessException("You are not allowed to call");
}
}
Disadvantages:
You must instantiate a new object every time you call methodB(). This may get expensive depending on how many times you do it. Instead, you could create a local class inside methodB() so there is no object creation overhead:
public void methodB() throws IllegalAccessException, NoSuchMethodException {
class Local {};
new ClassA().methodA(Local.class);
}
You need to handle NoSuchMethodException and change the code if methodB() name changes;
Someone with access to the code could still modify methodB() to return the anonymous object class to another method, and use it to call methodA() from there. So this is not a perfect solution, but may be enough for your use case.
Related
I have been working on a small logging/debug library for my Java projects. I know there are many good ones already out there but I want to learn from doing one myself.
One method I want to have as part of this library is the ability to find out which method you are in at any one time, similar to __func__ in C++. Most of the time it'd be fine to just use the StackTrace to find this, since you often don't need more than the name (and/or declaring class) of the method, but I want to have the ability to get the method as an instance of the java.lang.reflect.Method
The easiest way of doing this is by simply doing
Method currentMethod = new Object() {}.getClass().getEnclosingMethod();
which will work just fine, but I can't figure out a way to do the same without creating that 'new Object() {}' within the method itself. Ideally I'd prefer if I could make a simple
Method currentMethod = _method();
to get the same result but with my current approach it'd just get me the Method-instance of _method itself.
Is there any known method to achieve this? If there isn't that's fine, but it'd be nice to have one.
EDIT: A lot of suggestions I receive, such as this post, provide mostly answers that provide you with the NAME of the method. It would be possible to use that (and the Class info gained in the same way) to find the Method, but only if the class in question has only one method with that name. Methods with the same name but different arguments cannot be identified with this!
This can be done using a StackWalker (since Java 9). It does not directly
provide a Method but enough information to create one.
Here the basic idea, can be improved (e.g. better Exception(s)):
import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.lang.reflect.Method;
public class MethodFinder {
public static Method method() {
return StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE).walk(stream ->
stream
.filter(MethodFinder::notThisClass)
.findFirst()
.map(MethodFinder::frameToMethod))
.orElseThrow();
}
private static boolean notThisClass(StackFrame frame) {
return frame.getDeclaringClass() != MethodFinder.class;
}
private static Method frameToMethod(StackFrame frame) {
var cl = frame.getDeclaringClass();
try {
return cl.getDeclaredMethod(frame.getMethodName(), frame.getMethodType().parameterArray());
} catch (NoSuchMethodException | SecurityException ex) {
throw new RuntimeException(ex);
}
}
}
To be used like Method myself = MethodFinder.method().
Let's say I've an implementation of fund transfer. Now I want to add authentication functionality which should be done before fund transfer (considering we are already receiving username and password in existing request). Which pattern should we use and how we can achieve this without modifying calling class and existing implementation?
What I can think of at this moment is using decorator pattern after extending implementation class, but I believe still we will be required to modify the calling class.
Please find existing Interface and classes.
package sb.test.demo.fundtransfer;
public interface FundTransferService {
public boolean makeTransfer(TransferRequest request) throws Exception;
}
package sb.test.demo.fundtransfer;
public class FundTransferServiceImpl implements FundTransferService {
#Override
public boolean makeTransfer(TransferRequest request) throws Exception {
//Dummy Code
System.out.println("TransferDone");
return true;
}
}
package sb.test.demo.fundtransfer;
public class TestTransfer {
public static void main(String[] args) throws Exception {
TransferRequest request = new TransferRequest();
request.setSourceAccount(123456);
request.setDestinationAccount(654321);
request.setTranserAmount(1000);
request.setUserName("user1");
request.setPassword("pass1");
FundTransferService fts = new FundTransferServiceImpl();
fts.makeTransfer(request);
}
}
Now, I want want extend FundTransferServiceImpl to createFundTransferServiceNEWImpl which will add authentication.
package sb.test.demo.fundtransfer;
public class FundTransferServiceNEWImpl extends FundTransferServiceImpl {
#Override
public boolean makeTransfer(TransferRequest request) throws Exception {
//Dummy Code
System.out.println("Authenticating..");
super.makeTransfer(request);
System.out.println("TransferDone from NEW..");
return true;
}
}
Now, without changing TestTransfer.java and FundTransferServiceImpl.java how can I invoke makeTransfer of FundTransferServiceNEWImpl to add authentication? Or, is there any other way to achieve the same?
Please can anyone help me on this?
Thanks in advance!
you can make "FundTransferServiceNEWImpl" also implement the interface "FundTransferService" and provide the implementation that you wish in this only, if this was what you asked for!!
Now, without changing TestTransfer.java and FundTransferServiceImpl.java how can I invoke makeTransfer of FundTransferServiceNEWImpl to add authentication?
You can't without changing the bytecode of either TestTransfer (the caller) or FundTransferServiceImpl (the callee).
There are two ways to change the bytecode.
You can
edit the source file and compile
edit the bytecode before the class is loaded
Edit the source file
I would suggest to edit the TestTransfer class. The problematic line is
FundTransferService fts = new FundTransferServiceImpl();
because this line introduces the dependency from TestTransfer to FundTransferServiceImpl.
I would also suggest to implement the decorator by composition and not inheritence. E.g.
public class AuthenticationFundTransferServiceWrapper implements FundTransferService {
private FundTransferService fundTransferService;
public AuthenticationFundTransferServiceWrapper(FundTransferService fundTransferService){
this.fundTransferService = fundTransferService;
}
public boolean makeTransfer(TransferRequest request) throws Exception {
//Dummy Code
System.out.println("Authenticating..");
fundTransferService.makeTransfer(request);
System.out.println("TransferDone from NEW..");
return true;
}
}
The advantage is that the AuthenticationFundTransferServiceWrapper does only depend on the interface FundTransferService and not the implementation. This reduces dependencies and makes the class more flexible.
Editing the byte code
Editing the bytecode before the class is loaded is possible.
Take a look at
AOP (aspect oriented programming)
AspectJ
ASM (bytecode manipulation)
cglib
So you've identified decorator pattern and this answer implemented decorator correctly, but as this is a SOLID principles question I'm going to point out the flaw in that option.
To see the flaw in either inheritance or decorator, consider what happens when the authorization fails. If it throws a new exception type, that is a Liskov Substitution Principle Violation. If it changes the behavior by silently not transferring the funds, that is also an LSP violation. If you're going to rely on the boolean returned, you're not going to get a useful failure message back to the user or system admin.
As I see it, there is no way the client code can avoid knowing that the new implementation is checking authorized as it needs to handle either a new exception, or different return values.
Given that, I would recommend you add a new class, like this:
public final class TransactionAuthorizationService {
private final FundTransferService fundTransferService;
public AuthenticationFundTransferServiceWrapper(FundTransferService fundTransferService){
this.fundTransferService = fundTransferService;
}
public boolean authorizeAndMakeAndTransfer(TransferRequest request) throws Exception {
//Dummy Code
System.out.println("Authenticating..");
fundTransferService.makeTransfer(request);
System.out.println("TransferDone from NEW..");
return true;
}
}
Advantages:
Where before client code dealt with the interface FundTransferService you would have no idea until runtime which implementation they had and whether they would be authorizing transactions, now the client code now deals with the TransactionAuthorizationService and they call authorizeAndMakeAndTransfer so it is very clear.
As our new class is not implementing an existing interface, there is no Liskov Substitution Violation and is free to return different values or throw different exceptions.
Other tips:
Stop decorating methods with throw alls: throws Exception
Don't use InterfaceImpl as class names, look for what makes them concrete over the abstract interface.
Q1 : (removed)
Q2 : try-with-resource to create own resource implement AutoCloseable interface and override close() method.
From javadoc
Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.
So, here I created a simple program MyAuto.java
class Demo implements AutoCloseable {
public void show() {
System.out.println("show");
}
public void close() {
System.out.println("close from demo");
}
}
class MyAuto {
public static void main(String[] args) {
try(Demo d = new Demo()) {
int x = 10/0;
d.show();
}catch(ArithmeticException e) {
System.out.println(e);
}
}
}
This program runs fine. :) and giving output
close from demo : as expected, no matters exception occurs, d will be closed.
But my question is I didn't write any code that close this resource, I simply put a print statement. What here actually closing a resource mean ? Assigning null to reference variable of resource or anything else ?
Or JVM runs any other method after running close() behind the scene.
And finally the most important question..
Q3 : In the above scenario if I add my own interface AutoCloseable
interface AutoCloseable {
void close() throws Exception;
}
It gives compile time error on compiling MyAuto.java
error: incompatible types: try-with-resources not applicable to variable type
try(Demo d = new Demo()) {
^
(Demo cannot be converted to AutoCloseable).
So, please give me answer why it's happening. Why can't we create and use our own Interfaces instead of provided by java. What is difference between my interface and the one predefined, although both are same.
What is difference between my interface and the one predefined, although both are same.
They're not the same. Not by a long shot.
The AutoCloseable required for try-with-resources is java.lang.AutoCloseable. Your custom AutoCloseable doesn't come from that package, so Java isn't going to respect it.
Above all, introducing that would not be the best approach, since it'll only lead to confusing semantics and a bad experience later down the road, even if you elected to have your interface extend java.lang.AutoCloseable for whatever reason.
In the same vein...
...I didn't write any code that close this resource, I simply put a print statement. What here actually closing a resource mean ? Assigning null to reference variable of resource or anything else ? Or JVM runs any other method after running close() behind the scene.
The interface can't enforce anything like that. All it can do is provide a mechanism that, if well-implemented, will behave as you expect.
I have the next class within SDK23 which should support playDtmfTone() :
import android.telecom.Call;
public class myDtmf {
public void myPlayDtmfTone() {
Call mytone = new Call(); // error here for Call()
mytone.playDtmfTone('0');
}
}
The Call() in the line 'Call mytone = new Call()' shows the error:
Call() is not public in android.telecom.Call, Cannot be accessed from outside package.
How can I make Call() public or make it accessible ?
Thank you very much.
In this specific case, referring to the Javadoc of Call:
[Call] Represents an ongoing phone call that the in-call app should present to the user.
So it doesn't really make sense to "create" an instance of it, since that requires you actually to create an actual phone call to some endpoint.
In general, if a method is not accessible outside the package, you aren't supposed to access it - it is not part of the API that the class developer has provided. There are ways to access it - specifically, reflection - but this is hacky and it is massively unlikely to be the way that you are meant to use the class.
The class may provide you with some other means to create an instance, like a static factory method (or an external factory) - but, for the reasons outlined above, that doesn't make sense in this case either.
Suppose we a have class named DynamicClass:
public class DynamicClass {
public void get(String input) {
System.out.println(input);
}
}
Now, imagine the following instantiating of DynamicClass:
DynamicClass clazz = new DynamicClass();
clazz.getName();
clazz.getOther();
Of course, the calling of getName and getOther methods throws MethodNotFoundException exception. However, I'm curious, is there any way to catch the MethodNotFoundException exception inside the DynamicClass class, i.e. the calling of get("Name") and get("Other") rather than throwing the MethodNotFoundException exception due to the calling of getName() and getOther()?
Nice curiosity.
I am afraid, there is no other way than using try catch in Java, but if Java was a OTF(on the fly) compiler and the exception mechanism actually use a (if-responds_to?) method which expected to be declared on the top of the hierarchal pyramid of Class inheritance for example Object in Java that would be possible to override that method on your DynamicClass.
However Java doesn't use the above mechanism to control the if responds_to? and the messages which are sent to an object(class) are tested somewhere else in compiler but not as a method that you can override.
I know a language called (Magik) that has the above mechanism which is very nice and it is an OTF compiler.
the Object class in Magik has a method with name does_not_responds_to() and whenever a message is sent to an object it is tested against the class states and behaviors and finally raise or better to say run does_not_responds_to() method in case the method name(message) is invalid.
It is a very neat solution to implement the does_not_responds_to? method in the class (DynamicClass) to handle the exception before it raises. however after 10 years of experiance with Magik, never needed to do so.
Sorry, My English is not good, I hope I could explain the issue.
Why not?
try{
clazz.getName();
clazz.getOther();
}catch(MethodNotFoundException e){
clazz.get("Name")
}
But actually do not think that it is good idea...
With reference to this answer, it's possible to catch all uncaught Exceptions in Java:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread thread, Throwable throwable) {
// TODO
}
});