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);
+ }
+ }
+ }
+
}
+
diff --git a/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java b/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java
index 30d143c..fee1ae9 100644
--- a/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java
+++ b/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java
@@ -74,6 +74,4 @@
* @return Map of list of permissions sorted by permission type
*/
Map<Integer, List<Permission>> getPrintableRequestedPermissions(ApplicationId appId);
-
-
}
diff --git a/core/security/src/main/java/org/onosproject/security/impl/DefaultPolicyBuilder.java b/core/security/src/main/java/org/onosproject/security/impl/DefaultPolicyBuilder.java
index b043765..1fbb7c8 100644
--- a/core/security/src/main/java/org/onosproject/security/impl/DefaultPolicyBuilder.java
+++ b/core/security/src/main/java/org/onosproject/security/impl/DefaultPolicyBuilder.java
@@ -54,11 +54,12 @@
import org.onosproject.security.SecurityAdminService;
import org.onosproject.store.service.StorageAdminService;
import org.onosproject.store.service.StorageService;
-import org.osgi.framework.BundlePermission;
-import org.osgi.framework.CapabilityPermission;
import org.osgi.framework.ServicePermission;
-import org.osgi.framework.PackagePermission;
+import org.osgi.framework.AdminPermission;
import org.osgi.framework.AdaptPermission;
+import org.osgi.framework.CapabilityPermission;
+import org.osgi.framework.BundlePermission;
+import org.osgi.framework.PackagePermission;
import org.osgi.service.cm.ConfigurationPermission;
import javax.net.ssl.SSLPermission;
@@ -68,6 +69,7 @@
import javax.sound.sampled.AudioPermission;
import java.io.FilePermission;
import java.io.SerializablePermission;
+import java.lang.reflect.ReflectPermission;
import java.net.NetPermission;
import java.net.SocketPermission;
import java.security.Permissions;
@@ -159,6 +161,7 @@
permSet.add(new PackagePermission("*", PackagePermission.IMPORT));
permSet.add(new AdaptPermission("*", AdaptPermission.ADAPT));
permSet.add(new ConfigurationPermission("*", ConfigurationPermission.CONFIGURE));
+ permSet.add(new AdminPermission("*", AdminPermission.METADATA));
return permSet;
}
@@ -359,6 +362,12 @@
} else if (permission instanceof ServicePermission) {
return new org.onosproject.security.Permission(
ServicePermission.class.getName(), permission.getName(), permission.getActions());
+ } else if (permission instanceof AdminPermission) {
+ return new org.onosproject.security.Permission(
+ AdminPermission.class.getName(), permission.getName(), permission.getActions());
+ } else if (permission instanceof ConfigurationPermission) {
+ return new org.onosproject.security.Permission(
+ ConfigurationPermission.class.getName(), permission.getName(), permission.getActions());
}
return null;
}
@@ -416,10 +425,16 @@
return new PackagePermission(name, actions);
} else if (ServicePermission.class.getName().equals(classname)) {
return new ServicePermission(name, actions);
+ } else if (AdminPermission.class.getName().equals(classname)) {
+ return new AdminPermission(name, actions);
+ } else if (ConfigurationPermission.class.getName().equals(classname)) {
+ return new ConfigurationPermission(name, actions);
+ } else if (ReflectPermission.class.getName().equals(classname)) {
+ return new ReflectPermission(name, actions);
}
//AllPermission, SecurityPermission, UnresolvedPermission
- //AWTPermission, AdminPermission(osgi), ReflectPermission not allowed
+ //AWTPermission, ReflectPermission not allowed
return null;
}
@@ -444,5 +459,4 @@
}
return permissions;
}
-}
-
+}
\ No newline at end of file
diff --git a/core/security/src/main/java/org/onosproject/security/impl/SecurityModeManager.java b/core/security/src/main/java/org/onosproject/security/impl/SecurityModeManager.java
index 325f49b..f928dd6 100644
--- a/core/security/src/main/java/org/onosproject/security/impl/SecurityModeManager.java
+++ b/core/security/src/main/java/org/onosproject/security/impl/SecurityModeManager.java
@@ -92,16 +92,12 @@
private PermissionAdmin permissionAdmin = getPermissionAdmin();
-
@Activate
public void activate() {
eventDispatcher.addSink(SecurityModeEvent.class, listenerRegistry);
- // add Listeners
logReaderService.addLogListener(securityLogListener);
- store.setDelegate(delegate);
-
if (System.getSecurityManager() == null) {
log.warn("J2EE security manager is disabled.");
deactivate();
@@ -112,6 +108,7 @@
deactivate();
return;
}
+ store.setDelegate(delegate);
log.info("Security-Mode Started");
}
@@ -302,4 +299,6 @@
return FrameworkUtil.getBundle(this.getClass()).getBundleContext();
}
+
+
}
\ No newline at end of file
diff --git a/core/security/src/main/java/org/onosproject/security/store/DistributedSecurityModeStore.java b/core/security/src/main/java/org/onosproject/security/store/DistributedSecurityModeStore.java
index 925298c..b880ffd 100644
--- a/core/security/src/main/java/org/onosproject/security/store/DistributedSecurityModeStore.java
+++ b/core/security/src/main/java/org/onosproject/security/store/DistributedSecurityModeStore.java
@@ -303,14 +303,4 @@
}
return locations;
}
-
- @Override
- public void setDelegate(SecurityModeStoreDelegate delegate) {
- super.setDelegate(delegate);
- }
-
- @Override
- public void unsetDelegate(SecurityModeStoreDelegate delegate) {
- super.setDelegate(delegate);
- }
}
diff --git a/core/security/src/main/java/org/onosproject/security/store/SecurityModeStore.java b/core/security/src/main/java/org/onosproject/security/store/SecurityModeStore.java
index 7e6b653..e69971c 100644
--- a/core/security/src/main/java/org/onosproject/security/store/SecurityModeStore.java
+++ b/core/security/src/main/java/org/onosproject/security/store/SecurityModeStore.java
@@ -101,4 +101,5 @@
* @param permissionSet array of PermissionInfo
*/
void acceptPolicy(ApplicationId appId, Set<Permission> permissionSet);
+
}
\ No newline at end of file
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index 67b2a85..69c6484 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -186,6 +186,7 @@
import org.onosproject.net.resource.link.MplsLabel;
import org.onosproject.net.resource.link.MplsLabelResourceAllocation;
import org.onosproject.net.resource.link.MplsLabelResourceRequest;
+import org.onosproject.security.Permission;
import org.onosproject.store.Timestamp;
import org.onosproject.store.service.MapEvent;
import org.onosproject.store.service.SetEvent;
@@ -286,6 +287,7 @@
ApplicationState.class,
ApplicationRole.class,
DefaultApplication.class,
+ Permission.class,
Device.Type.class,
Port.Type.class,
ChassisId.class,