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 4b80dfcdc9..788fbcde69 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) () -> { + 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 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 30d143c0ca..fee1ae9476 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 @@ public interface SecurityAdminService { * @return Map of list of permissions sorted by permission type */ Map> 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 b043765a57..1fbb7c8c3e 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.net.topology.TopologyService; 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.security.auth.kerberos.DelegationPermission; 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 @@ public final class DefaultPolicyBuilder { 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 @@ public final class DefaultPolicyBuilder { } 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 @@ public final class DefaultPolicyBuilder { 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 @@ public final class DefaultPolicyBuilder { } 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 325f49bee9..f928dd6e2e 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 @@ public class SecurityModeManager implements SecurityAdminService { 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 @@ public class SecurityModeManager implements SecurityAdminService { deactivate(); return; } + store.setDelegate(delegate); log.info("Security-Mode Started"); } @@ -302,4 +299,6 @@ public class SecurityModeManager implements SecurityAdminService { 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 925298c852..b880ffd936 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 @@ public class DistributedSecurityModeStore } 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 7e6b65334d..e69971cc2b 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 @@ public interface SecurityModeStore extends Store 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 67b2a8555b..69c6484d93 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.LinkResourceRequest; 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 @@ public final class KryoNamespaces { ApplicationState.class, ApplicationRole.class, DefaultApplication.class, + Permission.class, Device.Type.class, Port.Type.class, ChassisId.class,