Java SecurityManager - how to ensure a method is run only by another method?

Java SecurityManager - how to ensure a method is run only by another method?



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).


private


A#getSensitiveData()


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.


String



What must I write with SecurityManager#checkPrivilege() and AccessController.doPrivileged() before I can achieve such an effect?


SecurityManager#checkPrivilege()


AccessController.doPrivileged()



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".





For a working answer with code that solves the question of how B.getSensitiveData can check and limit who is calling it, see stackoverflow.com/a/41420960/14955 It does not use a SecurityManager, though.
– Thilo
May 19 at 1:30


B.getSensitiveData




2 Answers
2



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:


A


B


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.


equals


if



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.)


StackWalker


sun.reflect.Reflection#getCallerClass(int)


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







By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.