/core/src/main/java/org/infinispan/security/Security.java

https://github.com/an1310/infinispan · Java · 200 lines · 148 code · 19 blank · 33 comment · 28 complexity · 6be5c207a072b928ee3fe476ae338650 MD5 · raw file

  1. package org.infinispan.security;
  2. import java.security.AccessControlContext;
  3. import java.security.AccessControlException;
  4. import java.security.AccessController;
  5. import java.security.Principal;
  6. import java.security.PrivilegedAction;
  7. import java.security.PrivilegedActionException;
  8. import java.security.PrivilegedExceptionAction;
  9. import java.security.acl.Group;
  10. import java.util.Stack;
  11. import javax.security.auth.Subject;
  12. import sun.reflect.Reflection;
  13. /**
  14. * Security. A simple class to implement caller privileges without a security manager and a
  15. * much faster implementations of the {@link Subject#doAs(Subject, PrivilegedAction)} and
  16. * {@link Subject#doAs(Subject, PrivilegedExceptionAction)} when interaction with the
  17. * {@link AccessControlContext} is not needed.
  18. *
  19. * N.B. this uses the caller's {@link Package}, this can easily be subverted by placing the
  20. * calling code within the org.infinispan hierarchy. However for most purposes this is ok.
  21. *
  22. * @author Tristan Tarrant
  23. * @since 7.0
  24. */
  25. @SuppressWarnings({ "restriction", "deprecation" })
  26. public final class Security {
  27. private static final boolean hasGetCallerClass;
  28. private static final int callerOffset;
  29. private static final LocalSecurityManager SECURITY_MANAGER;
  30. static {
  31. boolean result = false;
  32. int offset = 0;
  33. try {
  34. result = Reflection.getCallerClass(1) == Security.class || Reflection.getCallerClass(2) == Security.class;
  35. offset = Reflection.getCallerClass(1) == Reflection.class ? 2 : 1;
  36. } catch (Throwable ignored) {
  37. }
  38. hasGetCallerClass = result;
  39. callerOffset = offset;
  40. if (!hasGetCallerClass) {
  41. SECURITY_MANAGER = new LocalSecurityManager();
  42. } else {
  43. SECURITY_MANAGER = null;
  44. }
  45. }
  46. private static class LocalSecurityManager extends SecurityManager {
  47. public Class<?>[] getClasses() {
  48. return this.getClassContext();
  49. }
  50. }
  51. private static final ThreadLocal<Boolean> PRIVILEGED = new ThreadLocal<Boolean>() {
  52. @Override
  53. protected Boolean initialValue() {
  54. return Boolean.FALSE;
  55. }
  56. };
  57. private static final ThreadLocal<Stack<Subject>> SUBJECT = new ThreadLocal<Stack<Subject>>();
  58. private static boolean isTrustedClass(Class<?> klass) {
  59. // TODO: implement a better way
  60. return klass.getPackage().getName().startsWith("org.infinispan.");
  61. }
  62. public static <T> T doPrivileged(PrivilegedAction<T> action) {
  63. if (!isPrivileged() && isTrustedClass(getCallerClass(2))) {
  64. try {
  65. PRIVILEGED.set(true);
  66. return action.run();
  67. } finally {
  68. PRIVILEGED.remove();
  69. }
  70. } else {
  71. return action.run();
  72. }
  73. }
  74. public static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
  75. if (!isPrivileged() && isTrustedClass(getCallerClass(2))) {
  76. try {
  77. PRIVILEGED.set(true);
  78. return action.run();
  79. } catch (Exception e) {
  80. throw new PrivilegedActionException(e);
  81. } finally {
  82. PRIVILEGED.remove();
  83. }
  84. } else {
  85. try {
  86. return action.run();
  87. } catch (Exception e) {
  88. throw new PrivilegedActionException(e);
  89. }
  90. }
  91. }
  92. /**
  93. * A "lightweight" implementation of {@link Subject#doAs(Subject, PrivilegedAction)} which uses a ThreadLocal
  94. * {@link Subject} instead of modifying the current {@link AccessControlContext}.
  95. *
  96. * @see Subject#doAs(Subject, PrivilegedAction)
  97. */
  98. public static <T> T doAs(final Subject subject, final java.security.PrivilegedAction<T> action) {
  99. Stack<Subject> stack = SUBJECT.get();
  100. if (stack == null) {
  101. stack = new Stack<Subject>();
  102. SUBJECT.set(stack);
  103. }
  104. stack.push(subject);
  105. try {
  106. return action.run();
  107. } finally {
  108. stack.pop();
  109. if (stack.isEmpty()) {
  110. SUBJECT.remove();
  111. }
  112. }
  113. }
  114. /**
  115. * A "lightweight" implementation of {@link Subject#doAs(Subject, PrivilegedExceptionAction)} which uses a ThreadLocal
  116. * {@link Subject} instead of modifying the current {@link AccessControlContext}.
  117. *
  118. * @see Subject#doAs(Subject, PrivilegedExceptionAction)
  119. */
  120. public static <T> T doAs(final Subject subject,
  121. final java.security.PrivilegedExceptionAction<T> action)
  122. throws java.security.PrivilegedActionException {
  123. Stack<Subject> stack = SUBJECT.get();
  124. if (stack == null) {
  125. stack = new Stack<Subject>();
  126. SUBJECT.set(stack);
  127. }
  128. stack.push(subject);
  129. try {
  130. return action.run();
  131. } catch (Exception e) {
  132. throw new PrivilegedActionException(e);
  133. } finally {
  134. stack.pop();
  135. if (stack.isEmpty()) {
  136. SUBJECT.remove();
  137. }
  138. }
  139. }
  140. public static void checkPermission(CachePermission permission) throws AccessControlException {
  141. if (!isPrivileged()) {
  142. throw new AccessControlException("Call from unprivileged code", permission);
  143. }
  144. }
  145. public static boolean isPrivileged() {
  146. return PRIVILEGED.get();
  147. }
  148. /**
  149. * If using {@link Security#doAs(Subject, PrivilegedAction)} or
  150. * {@link Security#doAs(Subject, PrivilegedExceptionAction)}, returns the {@link Subject} associated with the current thread
  151. * otherwise it returns the {@link Subject} associated with the current {@link AccessControlContext}
  152. */
  153. public static Subject getSubject() {
  154. if (SUBJECT.get() != null) {
  155. return SUBJECT.get().peek();
  156. } else {
  157. AccessControlContext acc = AccessController.getContext();
  158. return Subject.getSubject(acc);
  159. }
  160. }
  161. /**
  162. * Returns the first principal of a subject which is not of type {@link java.security.acl.Group}
  163. */
  164. public static Principal getSubjectUserPrincipal(Subject s) {
  165. if (s != null) {
  166. for (Principal p : s.getPrincipals()) {
  167. if (!(p instanceof Group)) {
  168. return p;
  169. }
  170. }
  171. }
  172. return null;
  173. }
  174. static Class<?> getCallerClass(int n) {
  175. if (hasGetCallerClass) {
  176. return Reflection.getCallerClass(n + callerOffset);
  177. } else {
  178. return SECURITY_MANAGER.getClasses()[n + callerOffset];
  179. }
  180. }
  181. }