| /* |
| * Copyright 2015-present Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| 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. |
| * |
| * Note: Activating Security-Mode ONOS has significant performance implications in Drake. |
| * See the wiki for instructions on how to activate it. |
| */ |
| |
| @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); |
| logReaderService.addLogListener(securityLogListener); |
| |
| if (System.getSecurityManager() == null) { |
| log.warn("J2EE security manager is disabled."); |
| deactivate(); |
| return; |
| } |
| if (permissionAdmin == null) { |
| log.warn("Permission Admin not found."); |
| deactivate(); |
| return; |
| } |
| store.setDelegate(delegate); |
| |
| 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(); |
| |
| } |
| |
| |
| } |