ONOS-3521: SM-ONOS performance improvement
Change-Id: I8643187f2ceb35f8e0701d9e7ddb10098f05b244
diff --git a/core/api/src/main/java/org/onosproject/security/AppGuard.java b/core/api/src/main/java/org/onosproject/security/AppGuard.java
index 4b80dfc..788fbcd 100644
--- a/core/api/src/main/java/org/onosproject/security/AppGuard.java
+++ b/core/api/src/main/java/org/onosproject/security/AppGuard.java
@@ -16,26 +16,102 @@
package org.onosproject.security;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
import com.google.common.annotations.Beta;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+import java.lang.reflect.Field;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
/**
* Aids SM-ONOS to perform API-level permission checking.
*/
@Beta
public final class AppGuard {
-
private AppGuard() {
}
/**
* Checks if the caller has the required permission only when security-mode is enabled.
+ *
* @param permission permission to be checked
*/
public static void checkPermission(AppPermission.Type permission) {
+
SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- System.getSecurityManager().checkPermission(new AppPermission(permission));
+ if (sm == null) {
+ return;
+ }
+
+ Object result = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
+ int contextHash = 0;
+ AccessControlContext context = AccessController.getContext();
+ Field f = null;
+ try {
+ f = context.getClass().getDeclaredField("context");
+
+ f.setAccessible(true);
+ ProtectionDomain[] domain = (ProtectionDomain[]) f.get(context);
+ for (ProtectionDomain pd : domain) {
+ if (pd.getCodeSource() != null) {
+ contextHash = contextHash ^ pd.getCodeSource().getLocation().hashCode();
+ } else {
+ return null;
+ }
+ }
+ return contextHash;
+ } catch (NoSuchFieldException e) {
+ return null;
+ } catch (IllegalAccessException e) {
+ return null;
+ }
+ });
+
+ if (result == null) {
+ sm.checkPermission(new AppPermission(permission));
+ } else {
+ AppPermission perm = new AppPermission(permission);
+ int hash = ((int) result) ^ perm.hashCode();
+ PermissionCheckCache.getInstance().checkCache(hash, perm);
}
}
+
+
+ private static final class PermissionCheckCache {
+
+ private static final Cache<Integer, Boolean> CACHE = CacheBuilder.newBuilder()
+ .maximumSize(1000)
+ .expireAfterAccess(10, TimeUnit.MINUTES)
+ .build();
+
+ private PermissionCheckCache() {
+ }
+
+ private static class SingletonHelper {
+ private static final PermissionCheckCache INSTANCE = new PermissionCheckCache();
+ }
+
+ public static PermissionCheckCache getInstance() {
+ return SingletonHelper.INSTANCE;
+ }
+
+ public static void checkCache(int key, AppPermission perm) {
+ try {
+ CACHE.get(key, () -> {
+ System.getSecurityManager().checkPermission(perm);
+ return true;
+ });
+ } catch (ExecutionException e) {
+ System.getSecurityManager().checkPermission(perm);
+ }
+ }
+ }
+
}
+