ONOS-1767 SM-ONOS implementation

22a363e ONOS-17767 SM-ONOS impl

Change-Id: Ifca8129f2266bada68af735cf81a1d39f1ec8506
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
new file mode 100644
index 0000000..30b0f8b
--- /dev/null
+++ b/core/security/src/main/java/org/onosproject/security/impl/SecurityModeManager.java
@@ -0,0 +1,289 @@
+package org.onosproject.security.impl;
+
+import com.google.common.collect.Lists;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+
+import org.onosproject.app.ApplicationAdminService;
+import org.onosproject.app.ApplicationState;
+import org.onosproject.core.Application;
+import org.onosproject.core.ApplicationId;
+
+import org.onosproject.event.EventDeliveryService;
+import org.onosproject.event.ListenerRegistry;
+import org.onosproject.security.AppPermission;
+import org.onosproject.security.SecurityAdminService;
+import org.onosproject.security.store.SecurityModeEvent;
+import org.onosproject.security.store.SecurityModeListener;
+import org.onosproject.security.store.SecurityModeStore;
+import org.onosproject.security.store.SecurityModeStoreDelegate;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServicePermission;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogListener;
+import org.osgi.service.log.LogReaderService;
+import org.osgi.service.permissionadmin.PermissionInfo;
+
+import java.security.AccessControlException;
+import java.security.Permission;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.osgi.service.permissionadmin.PermissionAdmin;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+
+
+/**
+ * Security-Mode ONOS management implementation.
+ */
+
+@Component(immediate = true)
+@Service
+public class SecurityModeManager implements SecurityAdminService {
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected SecurityModeStore store;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ApplicationAdminService appAdminService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LogReaderService logReaderService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected EventDeliveryService eventDispatcher;
+
+    private final Logger log = getLogger(getClass());
+
+    protected final ListenerRegistry<SecurityModeEvent, SecurityModeListener>
+            listenerRegistry = new ListenerRegistry<>();
+
+    private final SecurityModeStoreDelegate delegate = new InternalStoreDelegate();
+
+    private SecurityLogListener securityLogListener = new SecurityLogListener();
+
+    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();
+            return;
+        }
+        if (permissionAdmin == null) {
+            log.warn("Permission Admin not found.");
+            deactivate();
+            return;
+        }
+
+        log.info("Security-Mode Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        eventDispatcher.removeSink(SecurityModeEvent.class);
+        logReaderService.removeLogListener(securityLogListener);
+        store.unsetDelegate(delegate);
+        log.info("Stopped");
+
+    }
+
+    @Override
+    public boolean isSecured(ApplicationId appId) {
+        if (store.getState(appId) == null) {
+            store.registerApplication(appId);
+        }
+        return store.isSecured(appId);
+    }
+
+
+    @Override
+    public void review(ApplicationId appId) {
+        if (store.getState(appId) == null) {
+            store.registerApplication(appId);
+        }
+        store.reviewPolicy(appId);
+    }
+
+    @Override
+    public void acceptPolicy(ApplicationId appId) {
+        if (store.getState(appId) == null) {
+            store.registerApplication(appId);
+        }
+        store.acceptPolicy(appId, DefaultPolicyBuilder.convertToOnosPermissions(getMaximumPermissions(appId)));
+    }
+
+    @Override
+    public void register(ApplicationId appId) {
+        store.registerApplication(appId);
+    }
+
+    @Override
+    public Map<Integer, List<Permission>> getPrintableSpecifiedPermissions(ApplicationId appId) {
+        return getPrintablePermissionMap(getMaximumPermissions(appId));
+    }
+
+    @Override
+    public Map<Integer, List<Permission>> getPrintableGrantedPermissions(ApplicationId appId) {
+        return getPrintablePermissionMap(
+                DefaultPolicyBuilder.convertToJavaPermissions(store.getGrantedPermissions(appId)));
+    }
+
+    @Override
+    public Map<Integer, List<Permission>> getPrintableRequestedPermissions(ApplicationId appId) {
+        return getPrintablePermissionMap(
+                DefaultPolicyBuilder.convertToJavaPermissions(store.getRequestedPermissions(appId)));
+    }
+
+    private class SecurityLogListener implements LogListener {
+        @Override
+        public void logged(LogEntry entry) {
+            if (entry.getException() != null &&
+                    entry.getException() instanceof AccessControlException) {
+                String location = entry.getBundle().getLocation();
+                Permission javaPerm =
+                        ((AccessControlException) entry.getException()).getPermission();
+                org.onosproject.security.Permission permission = DefaultPolicyBuilder.getOnosPermission(javaPerm);
+                if (permission == null) {
+                    log.warn("Unsupported permission requested.");
+                    return;
+                }
+                store.getApplicationIds(location).stream().filter(
+                        appId -> store.isSecured(appId) &&
+                                appAdminService.getState(appId) == ApplicationState.ACTIVE).forEach(appId -> {
+                    store.requestPermission(appId, permission);
+                    print("[POLICY VIOLATION] APP: %s / Bundle: %s / Permission: %s ",
+                            appId.name(), location, permission.toString());
+                });
+            }
+        }
+    }
+
+    private class InternalStoreDelegate implements SecurityModeStoreDelegate {
+        @Override
+        public void notify(SecurityModeEvent event) {
+            if (event.type() == SecurityModeEvent.Type.POLICY_ACCEPTED) {
+                setLocalPermissions(event.subject());
+                log.info("{} POLICY ACCEPTED and ENFORCED", event.subject().name());
+            } else if (event.type() == SecurityModeEvent.Type.POLICY_VIOLATED) {
+                log.info("{} POLICY VIOLATED", event.subject().name());
+            } else if (event.type() == SecurityModeEvent.Type.POLICY_REVIEWED) {
+                log.info("{} POLICY REVIEWED", event.subject().name());
+            }
+            eventDispatcher.post(event);
+        }
+    }
+
+    /**
+     * TYPES.
+     * 0 - APP_PERM
+     * 1 - ADMIN SERVICE
+     * 2 - NB_SERVICE
+     * 3 - ETC_SERVICE
+     * 4 - ETC
+     * @param perms
+     */
+    private Map<Integer, List<Permission>> getPrintablePermissionMap(List<Permission> perms) {
+        ConcurrentHashMap<Integer, List<Permission>> sortedMap = new ConcurrentHashMap<>();
+        sortedMap.put(0, new ArrayList());
+        sortedMap.put(1, new ArrayList());
+        sortedMap.put(2, new ArrayList());
+        sortedMap.put(3, new ArrayList());
+        sortedMap.put(4, new ArrayList());
+        for (Permission perm : perms) {
+            if (perm instanceof ServicePermission) {
+                if (DefaultPolicyBuilder.getNBServiceList().contains(perm.getName())) {
+                    if (perm.getName().contains("Admin")) {
+                        sortedMap.get(1).add(perm);
+                    } else {
+                        sortedMap.get(2).add(perm);
+                    }
+                } else {
+                    sortedMap.get(3).add(perm);
+                }
+            } else if (perm instanceof AppPermission) {
+                sortedMap.get(0).add(perm);
+            } else {
+                sortedMap.get(4).add(perm);
+            }
+        }
+        return sortedMap;
+    }
+
+    private void setLocalPermissions(ApplicationId applicationId) {
+        for (String location : store.getBundleLocations(applicationId)) {
+            permissionAdmin.setPermissions(location, permissionsToInfo(store.getGrantedPermissions(applicationId)));
+        }
+    }
+
+    private PermissionInfo[] permissionsToInfo(Set<org.onosproject.security.Permission> permissions) {
+        List<PermissionInfo> result = Lists.newArrayList();
+        for (org.onosproject.security.Permission perm : permissions) {
+            result.add(new PermissionInfo(perm.getClassName(), perm.getName(), perm.getActions()));
+        }
+        PermissionInfo[] permissionInfos = new PermissionInfo[result.size()];
+        return result.toArray(permissionInfos);
+    }
+
+
+
+    private List<Permission> getMaximumPermissions(ApplicationId appId) {
+        Application app = appAdminService.getApplication(appId);
+        if (app == null) {
+            print("Unknown application.");
+            return null;
+        }
+        List<Permission> appPerms;
+        switch (app.role()) {
+            case ADMIN:
+                appPerms = DefaultPolicyBuilder.getAdminApplicationPermissions(app.permissions());
+                break;
+            case USER:
+                appPerms = DefaultPolicyBuilder.getUserApplicationPermissions(app.permissions());
+                break;
+            case UNSPECIFIED:
+            default:
+                appPerms = DefaultPolicyBuilder.getDefaultPerms();
+                break;
+        }
+
+        return appPerms;
+    }
+
+
+    private void print(String format, Object... args) {
+        System.out.println(String.format("SM-ONOS: " + format, args));
+        log.warn(String.format(format, args));
+    }
+
+    private PermissionAdmin getPermissionAdmin() {
+        BundleContext context = getBundleContext();
+        return (PermissionAdmin) context.getService(context.getServiceReference(PermissionAdmin.class.getName()));
+    }
+
+    private BundleContext getBundleContext() {
+        return FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+
+    }
+}
\ No newline at end of file