I want B to be run only by the private
method A#getSensitiveData()
that uses or does some processing on sensitive data (example: cryptographic keys, national id, whatever).
public final class A{
private transient final B sensitiveHolder; //set at Constructor
public A(B sensitiveHolder){
this.sensitiveHolder = sensitiveHolder;
}
private final byte[] getSensitiveData(){
return sensitiveHolder.getSensitiveData();
}
}
public final class B{
private transient final byte[] sensitiveData;//encrypt and set at Constructor
public final byte[] getSensitiveData(){
//check if it is run by A#getSensitiveData(); if it is, decrypt by DEK and give plaintext.
}
}
Please take into account that the code would be obfuscated, so please refrain from putting in any package names as String
.
What must I write with SecurityManager#checkPrivilege()
and AccessController.doPrivileged()
before I can achieve such an effect?
EDIT: Obviously this is different because the so called "answer" does not contain any CODE. WORKING CODE is worth infinitely more than "oh, just do this and that".
You could do something like this:
private boolean verify(final StackTraceElement e[]) {
boolean doNext = false;
for (final StackTraceElement s : e) {
if (doNext && s.getClassName().equals("A") && s.getMethodName().equals("getSensitiveData"))
return true;
doNext = s.getMethodName().equals("getStackTrace");
}
return false;
}
And to call the method:
public final byte[] getSensitiveData(StackTraceElement e[]){
if (verify(e)) {
// Do something good
}
}
In your A
class call your B
class like this:
return sensitiveHolder.getSensitiveData(Thread.currentThread().getStackTrace());
I don't know if this is what you need or it is near that. You could play around the values in the equals
section of the if
. I got and modified the example from this site.
If you're able to use JDK 9+, which introduces StackWalker
, this sort of thing might work for you. This technique seems to supersede use of sun.reflect.Reflection#getCallerClass(int)
. (I hope you weren't counting on a SecurityManager-related answer.)
package asdf;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;
public class Asdf {
@Test
public void what() {
get();
}
void get() {
StackWalker.StackFrame stackFrame =
StackWalker.getInstance(EnumSet.of(StackWalker.Option.RETAIN_CLASS_REFERENCE))
.walk(stream -> {
List<StackWalker.StackFrame> stackFrames = stream.collect(Collectors.toList());
return stackFrames.get(1);
});
Assertions.assertEquals(Asdf.class, stackFrame.getDeclaringClass());
Assertions.assertEquals("what", stackFrame.getMethodName());
Assertions.assertEquals(0, stackFrame.getMethodType().parameterCount());
// now do caller-sensitive stuff
}
}