Changhoon Yoon
Committed by Gerrit Code Review

ONOS-1858, ONOS-1857, ONOS-1860, ONOS-1862, ONOS-1898 : SM-ONOS

Change-Id: I206e72521cf663466bfcc612e1896bb22d87da06
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.cli.security;
18 +
19 +import org.apache.karaf.shell.console.completer.StringsCompleter;
20 +import org.onosproject.app.ApplicationService;
21 +import org.onosproject.cli.AbstractCompleter;
22 +import org.onosproject.core.Application;
23 +
24 +import java.util.Iterator;
25 +import java.util.List;
26 +import java.util.SortedSet;
27 +
28 +import static org.onosproject.cli.AbstractShellCommand.get;
29 +
30 +/**
31 + * Application name completer for permission command.
32 + */
33 +public class PermissionApplicationNameCompleter extends AbstractCompleter {
34 + @Override
35 + public int complete(String buffer, int cursor, List<String> candidates) {
36 + // Delegate string completer
37 + StringsCompleter delegate = new StringsCompleter();
38 +
39 + // Fetch our service and feed it's offerings to the string completer
40 + ApplicationService service = get(ApplicationService.class);
41 + Iterator<Application> it = service.getApplications().iterator();
42 + SortedSet<String> strings = delegate.getStrings();
43 + while (it.hasNext()) {
44 + Application app = it.next();
45 + strings.add(app.id().name());
46 + }
47 +
48 + // Now let the completer do the work for figuring out what to offer.
49 + return delegate.complete(buffer, cursor, candidates);
50 + }
51 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.cli.security;
18 +
19 +import com.google.common.collect.ImmutableSet;
20 +import com.google.common.collect.Sets;
21 +import org.apache.karaf.shell.commands.Argument;
22 +import org.apache.karaf.shell.commands.Command;
23 +import org.onosproject.app.ApplicationAdminService;
24 +import org.onosproject.cli.AbstractShellCommand;
25 +import org.onosproject.core.Application;
26 +import org.onosproject.core.ApplicationId;
27 +import org.onosproject.core.Permission;
28 +
29 +import java.util.Set;
30 +import java.util.stream.Collectors;
31 +
32 +/**
33 + * Manages application permissions.
34 + */
35 +@Command(scope = "onos", name = "perm",
36 + description = "Manages application permissions")
37 +public class PermissionCommand extends AbstractShellCommand {
38 +
39 + static final String ADD = "add";
40 + static final String REMOVE = "remove";
41 + static final String LIST = "list";
42 + static final String CLEAR = "clear";
43 +
44 +
45 + @Argument(index = 0, name = "command",
46 + description = "Command name (add|remove)",
47 + required = true, multiValued = false)
48 + String command = null;
49 +
50 + @Argument(index = 1, name = "name", description = "Application name",
51 + required = true, multiValued = false)
52 + String name = null;
53 +
54 + @Argument(index = 2, name = "permissions", description = "List of permissions",
55 + required = false, multiValued = true)
56 + String[] permissions = null;
57 +
58 + @Override
59 + protected void execute() {
60 + ApplicationAdminService applicationAdminService = get(ApplicationAdminService.class);
61 + Set<Permission> newPermSet = Sets.newHashSet();
62 + if (command.equals(ADD)) {
63 + ApplicationId appId = applicationAdminService.getId(name);
64 + if (appId == null) {
65 + print("No such application: %s", name);
66 + return;
67 + }
68 + Application app = applicationAdminService.getApplication(appId);
69 +
70 + for (String perm : permissions) {
71 + try {
72 + Permission permission = Permission.valueOf(perm);
73 + newPermSet.add(permission);
74 + } catch (IllegalArgumentException e) {
75 + print("%s is not a valid permission.", perm);
76 + return;
77 + }
78 +
79 + }
80 + Set<Permission> oldPermSet = applicationAdminService.getPermissions(appId);
81 + if (oldPermSet != null) {
82 + newPermSet.addAll(oldPermSet);
83 + } else {
84 + newPermSet.addAll(app.permissions());
85 + }
86 + applicationAdminService.setPermissions(appId, ImmutableSet.copyOf(newPermSet));
87 +
88 + } else if (command.equals(REMOVE)) {
89 + ApplicationId appId = applicationAdminService.getId(name);
90 + Application app = applicationAdminService.getApplication(appId);
91 + if (appId == null) {
92 + print("No such application: %s", name);
93 + return;
94 + }
95 + Set<Permission> oldPermSet = applicationAdminService.getPermissions(appId);
96 + if (oldPermSet == null) {
97 + oldPermSet = app.permissions();
98 + }
99 + Set<String> clearPermSet = Sets.newHashSet(permissions);
100 + newPermSet.addAll(oldPermSet.stream().filter(
101 + perm -> !clearPermSet.contains(perm.name().toUpperCase())).collect(Collectors.toList()));
102 + applicationAdminService.setPermissions(appId, ImmutableSet.copyOf(newPermSet));
103 + } else if (command.equals(CLEAR)) {
104 + ApplicationId appId = applicationAdminService.getId(name);
105 + if (appId == null) {
106 + print("No such application: %s", name);
107 + return;
108 + }
109 + applicationAdminService.setPermissions(appId, ImmutableSet.of());
110 + print("Cleared the permission list of %s.", appId.name());
111 + } else if (command.equals(LIST)) {
112 + ApplicationId appId = applicationAdminService.getId(name);
113 + if (appId == null) {
114 + print("No such application: %s", name);
115 + return;
116 + }
117 + Application app = applicationAdminService.getApplication(appId);
118 + Set<Permission> userPermissions = applicationAdminService.getPermissions(appId);
119 + Set<Permission> defaultPermissions = app.permissions();
120 + print("Application Role");
121 + print("\trole=%s", app.role().name());
122 +
123 + if (defaultPermissions != null) {
124 + if (!defaultPermissions.isEmpty()) {
125 + print("Default permissions (specified in app.xml)");
126 + for (Permission perm : defaultPermissions) {
127 + print("\tpermission=%s", perm.name());
128 + }
129 + } else {
130 + print("(No default permissions specified in app.xml)");
131 + }
132 + }
133 + if (userPermissions != null) {
134 + if (!userPermissions.isEmpty()) {
135 + print("User permissions");
136 + for (Permission perm : userPermissions) {
137 + print("\tpermission=%s", perm.name());
138 + }
139 + } else {
140 + print("(User has removed all the permissions");
141 + }
142 + }
143 +
144 + }
145 + }
146 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.cli.security;
18 +
19 +import com.google.common.collect.ImmutableList;
20 +import org.onosproject.cli.AbstractChoicesCompleter;
21 +
22 +import java.util.List;
23 +
24 +import static org.onosproject.cli.security.PermissionCommand.*;
25 +/**
26 + * Permission command completer.
27 + */
28 +public class PermissionCommandCompleter extends AbstractChoicesCompleter {
29 + @Override
30 + protected List<String> choices() {
31 + return ImmutableList.of(ADD, REMOVE, CLEAR, LIST);
32 + }
33 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.cli.security;
18 +
19 +import org.apache.karaf.shell.console.completer.ArgumentCompleter;
20 +import org.onosproject.cli.AbstractChoicesCompleter;
21 +import org.onosproject.core.Permission;
22 +
23 +import java.util.ArrayList;
24 +import java.util.List;
25 +
26 +/**
27 + * Permission Name Completer.
28 + */
29 +public class PermissionNameCompleter extends AbstractChoicesCompleter {
30 + @Override
31 + protected List<String> choices() {
32 + List<String> permNames = new ArrayList<>();
33 +
34 + ArgumentCompleter.ArgumentList list = getArgumentList();
35 + String cmd = list.getArguments()[1];
36 + if (cmd.equals("add") || cmd.equals("remove")) {
37 + for (Permission perm : Permission.values()) {
38 + permNames.add(perm.name());
39 + }
40 + }
41 + return permNames;
42 + }
43 +
44 +
45 +}
...@@ -21,6 +21,15 @@ ...@@ -21,6 +21,15 @@
21 </command> 21 </command>
22 22
23 <command> 23 <command>
24 + <action class="org.onosproject.cli.security.PermissionCommand"/>
25 + <completers>
26 + <ref component-id="permCommandCompleter"/>
27 + <ref component-id="permAppNameCompleter"/>
28 + <ref component-id="permNameCompleter"/>
29 + </completers>
30 + </command>
31 +
32 + <command>
24 <action class="org.onosproject.cli.app.ApplicationsListCommand"/> 33 <action class="org.onosproject.cli.app.ApplicationsListCommand"/>
25 </command> 34 </command>
26 35
...@@ -360,6 +369,9 @@ ...@@ -360,6 +369,9 @@
360 </command> 369 </command>
361 </command-bundle> 370 </command-bundle>
362 371
372 + <bean id="permAppNameCompleter" class="org.onosproject.cli.security.PermissionApplicationNameCompleter"/>
373 + <bean id="permCommandCompleter" class="org.onosproject.cli.security.PermissionCommandCompleter"/>
374 + <bean id="permNameCompleter" class="org.onosproject.cli.security.PermissionNameCompleter"/>
363 <bean id="appCommandCompleter" class="org.onosproject.cli.app.ApplicationCommandCompleter"/> 375 <bean id="appCommandCompleter" class="org.onosproject.cli.app.ApplicationCommandCompleter"/>
364 <bean id="appNameCompleter" class="org.onosproject.cli.app.ApplicationNameCompleter"/> 376 <bean id="appNameCompleter" class="org.onosproject.cli.app.ApplicationNameCompleter"/>
365 <bean id="allAppNameCompleter" class="org.onosproject.cli.app.AllApplicationNamesCompleter"/> 377 <bean id="allAppNameCompleter" class="org.onosproject.cli.app.AllApplicationNamesCompleter"/>
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
36 <module>common</module> 36 <module>common</module>
37 <module>net</module> 37 <module>net</module>
38 <module>store</module> 38 <module>store</module>
39 + <module>security</module>
39 </modules> 40 </modules>
40 41
41 <dependencies> 42 <dependencies>
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +
18 +<project xmlns="http://maven.apache.org/POM/4.0.0"
19 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21 + <parent>
22 + <artifactId>onos-security</artifactId>
23 + <groupId>org.onosproject</groupId>
24 + <version>1.2.0-SNAPSHOT</version>
25 + <relativePath>../pom.xml</relativePath>
26 + </parent>
27 + <modelVersion>4.0.0</modelVersion>
28 + <packaging>bundle</packaging>
29 +
30 + <artifactId>onos-security-impl</artifactId>
31 +
32 + <dependencies>
33 + <dependency>
34 + <groupId>org.osgi</groupId>
35 + <artifactId>org.osgi.core</artifactId>
36 + </dependency>
37 + <dependency>
38 + <groupId>org.osgi</groupId>
39 + <artifactId>org.osgi.compendium</artifactId>
40 + </dependency>
41 + <dependency>
42 + <groupId>org.apache.felix</groupId>
43 + <artifactId>org.apache.felix.scr.annotations</artifactId>
44 + </dependency>
45 + <dependency>
46 + <groupId>org.onosproject</groupId>
47 + <artifactId>onos-api</artifactId>
48 + </dependency>
49 + <dependency>
50 + <groupId>org.onosproject</groupId>
51 + <artifactId>onos-security-util</artifactId>
52 + <version>${project.version}</version>
53 + </dependency>
54 + <dependency>
55 + <groupId>org.apache.karaf.features</groupId>
56 + <artifactId>org.apache.karaf.features.core</artifactId>
57 + </dependency>
58 + </dependencies>
59 +
60 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +package org.onosproject.security.impl;
2 +
3 +
4 +import com.google.common.collect.ImmutableSet;
5 +import com.google.common.collect.Sets;
6 +import org.apache.commons.collections.FastHashMap;
7 +import org.onosproject.core.Permission;
8 +import org.onosproject.security.util.AppPermission;
9 +import org.osgi.service.permissionadmin.PermissionInfo;
10 +
11 +import org.onosproject.app.ApplicationAdminService;
12 +import org.onosproject.app.ApplicationService;
13 +import org.onosproject.cfg.ComponentConfigService;
14 +import org.onosproject.cluster.ClusterAdminService;
15 +import org.onosproject.cluster.ClusterService;
16 +import org.onosproject.core.CoreService;
17 +import org.onosproject.cluster.LeadershipService;
18 +import org.onosproject.mastership.MastershipAdminService;
19 +import org.onosproject.mastership.MastershipService;
20 +import org.onosproject.net.device.DeviceAdminService;
21 +import org.onosproject.net.device.DeviceService;
22 +import org.onosproject.net.device.DeviceClockService;
23 +import org.onosproject.net.driver.DriverAdminService;
24 +import org.onosproject.net.driver.DriverService;
25 +import org.onosproject.net.flow.FlowRuleService;
26 +import org.onosproject.net.flowobjective.FlowObjectiveService;
27 +import org.onosproject.net.group.GroupService;
28 +import org.onosproject.net.host.HostAdminService;
29 +import org.onosproject.net.host.HostService;
30 +import org.onosproject.net.host.HostClockService;
31 +import org.onosproject.net.intent.IntentService;
32 +import org.onosproject.net.intent.IntentExtensionService;
33 +import org.onosproject.net.intent.IntentClockService;
34 +import org.onosproject.net.intent.PartitionService;
35 +import org.onosproject.net.link.LinkAdminService;
36 +import org.onosproject.net.link.LinkService;
37 +import org.onosproject.net.packet.PacketService;
38 +import org.onosproject.net.proxyarp.ProxyArpService;
39 +import org.onosproject.net.resource.LabelResourceAdminService;
40 +import org.onosproject.net.resource.LinkResourceService;
41 +import org.onosproject.net.resource.LabelResourceService;
42 +import org.onosproject.net.statistic.StatisticService;
43 +import org.onosproject.net.topology.PathService;
44 +import org.onosproject.net.topology.TopologyService;
45 +import org.onosproject.net.tunnel.TunnelAdminService;
46 +import org.onosproject.net.tunnel.TunnelService;
47 +import org.onosproject.store.service.StorageAdminService;
48 +import org.onosproject.store.service.StorageService;
49 +import org.osgi.framework.ServicePermission;
50 +import org.osgi.framework.PackagePermission;
51 +import org.osgi.framework.AdaptPermission;
52 +
53 +
54 +import java.util.Collections;
55 +import java.util.HashMap;
56 +import java.util.Set;
57 +import java.util.stream.Collectors;
58 +
59 +public final class PolicyBuilder {
60 +
61 + private PolicyBuilder(){
62 + }
63 +
64 + public static PermissionInfo[] getApplicationPermissions(HashMap<Permission, Set<String>> serviceDirectory,
65 + Set<Permission> permissions) {
66 + Set<PermissionInfo> permSet = Sets.newHashSet();
67 + Collections.addAll(permSet, getDefaultPerms());
68 + for (Permission perm : permissions) {
69 + permSet.add(new PermissionInfo(AppPermission.class.getName(), perm.name(), ""));
70 + permSet.addAll(serviceDirectory.get(perm).stream().map(service -> new PermissionInfo(
71 + ServicePermission.class.getName(), service, ServicePermission.GET)).collect(Collectors.toList()));
72 + }
73 + PermissionInfo[] permissionInfos = new PermissionInfo[permSet.size()];
74 + return permSet.toArray(permissionInfos);
75 + }
76 +
77 + public static PermissionInfo[] getAdminApplicationPermissions(HashMap<Permission, Set<String>> serviceDirectory) {
78 + Set<PermissionInfo> permSet = Sets.newHashSet();
79 + Collections.addAll(permSet, getDefaultPerms());
80 + Collections.addAll(permSet, getAdminDefaultPerms());
81 + permSet.addAll(serviceDirectory.keySet().stream().map(perm ->
82 + new PermissionInfo(AppPermission.class.getName(), perm.name(), "")).collect(Collectors.toList()));
83 + PermissionInfo[] permissionInfos = new PermissionInfo[permSet.size()];
84 + return permSet.toArray(permissionInfos);
85 + }
86 +
87 + public static PermissionInfo[] getDefaultPerms() {
88 + return new PermissionInfo[]{
89 + new PermissionInfo(PackagePermission.class.getName(), "*", PackagePermission.EXPORTONLY),
90 + new PermissionInfo(PackagePermission.class.getName(), "*", PackagePermission.IMPORT),
91 + new PermissionInfo(AdaptPermission.class.getName(), "*", AdaptPermission.ADAPT),
92 + };
93 + }
94 + public static PermissionInfo[] getAdminDefaultPerms() {
95 + return new PermissionInfo[]{
96 + new PermissionInfo(ServicePermission.class.getName(),
97 + ApplicationAdminService.class.getName(), ServicePermission.GET),
98 + new PermissionInfo(ServicePermission.class.getName(),
99 + ClusterAdminService.class.getName(), ServicePermission.GET),
100 + new PermissionInfo(ServicePermission.class.getName(),
101 + MastershipAdminService.class.getName(), ServicePermission.GET),
102 + new PermissionInfo(ServicePermission.class.getName(),
103 + DeviceAdminService.class.getName(), ServicePermission.GET),
104 + new PermissionInfo(ServicePermission.class.getName(),
105 + HostAdminService.class.getName(), ServicePermission.GET),
106 + new PermissionInfo(ServicePermission.class.getName(),
107 + LinkAdminService.class.getName(), ServicePermission.GET),
108 + new PermissionInfo(ServicePermission.class.getName(),
109 + DriverAdminService.class.getName(), ServicePermission.GET),
110 + new PermissionInfo(ServicePermission.class.getName(),
111 + StorageAdminService.class.getName(), ServicePermission.GET),
112 + new PermissionInfo(ServicePermission.class.getName(),
113 + LabelResourceAdminService.class.getName(), ServicePermission.GET),
114 + new PermissionInfo(ServicePermission.class.getName(),
115 + TunnelAdminService.class.getName(), ServicePermission.GET),
116 + new PermissionInfo(ServicePermission.class.getName(),
117 + ApplicationService.class.getName(), ServicePermission.GET),
118 + new PermissionInfo(ServicePermission.class.getName(),
119 + ComponentConfigService.class.getName(), ServicePermission.GET),
120 + new PermissionInfo(ServicePermission.class.getName(),
121 + CoreService.class.getName(), ServicePermission.GET),
122 + new PermissionInfo(ServicePermission.class.getName(),
123 + ClusterService.class.getName(), ServicePermission.GET),
124 + new PermissionInfo(ServicePermission.class.getName(),
125 + LeadershipService.class.getName(), ServicePermission.GET),
126 + new PermissionInfo(ServicePermission.class.getName(),
127 + MastershipService.class.getName(), ServicePermission.GET),
128 + new PermissionInfo(ServicePermission.class.getName(),
129 + DeviceService.class.getName(), ServicePermission.GET),
130 + new PermissionInfo(ServicePermission.class.getName(),
131 + DeviceClockService.class.getName(), ServicePermission.GET),
132 + new PermissionInfo(ServicePermission.class.getName(),
133 + DriverService.class.getName(), ServicePermission.GET),
134 + new PermissionInfo(ServicePermission.class.getName(),
135 + FlowRuleService.class.getName(), ServicePermission.GET),
136 + new PermissionInfo(ServicePermission.class.getName(),
137 + FlowObjectiveService.class.getName(), ServicePermission.GET),
138 + new PermissionInfo(ServicePermission.class.getName(),
139 + GroupService.class.getName(), ServicePermission.GET),
140 + new PermissionInfo(ServicePermission.class.getName(),
141 + HostService.class.getName(), ServicePermission.GET),
142 + new PermissionInfo(ServicePermission.class.getName(),
143 + HostClockService.class.getName(), ServicePermission.GET),
144 + new PermissionInfo(ServicePermission.class.getName(),
145 + IntentService.class.getName(), ServicePermission.GET),
146 + new PermissionInfo(ServicePermission.class.getName(),
147 + IntentClockService.class.getName(), ServicePermission.GET),
148 + new PermissionInfo(ServicePermission.class.getName(),
149 + IntentExtensionService.class.getName(), ServicePermission.GET),
150 + new PermissionInfo(ServicePermission.class.getName(),
151 + PartitionService.class.getName(), ServicePermission.GET),
152 + new PermissionInfo(ServicePermission.class.getName(),
153 + LinkService.class.getName(), ServicePermission.GET),
154 + new PermissionInfo(ServicePermission.class.getName(),
155 + LinkResourceService.class.getName(), ServicePermission.GET),
156 + new PermissionInfo(ServicePermission.class.getName(),
157 + LabelResourceService.class.getName(), ServicePermission.GET),
158 + new PermissionInfo(ServicePermission.class.getName(),
159 + PacketService.class.getName(), ServicePermission.GET),
160 + new PermissionInfo(ServicePermission.class.getName(),
161 + ProxyArpService.class.getName(), ServicePermission.GET),
162 + new PermissionInfo(ServicePermission.class.getName(),
163 + StatisticService.class.getName(), ServicePermission.GET),
164 + new PermissionInfo(ServicePermission.class.getName(),
165 + PathService.class.getName(), ServicePermission.GET),
166 + new PermissionInfo(ServicePermission.class.getName(),
167 + TopologyService.class.getName(), ServicePermission.GET),
168 + new PermissionInfo(ServicePermission.class.getName(),
169 + TunnelService.class.getName(), ServicePermission.GET),
170 + new PermissionInfo(ServicePermission.class.getName(),
171 + StorageService.class.getName(), ServicePermission.GET),
172 + };
173 + }
174 +
175 +
176 + public static HashMap<Permission, Set<String>> getServiceDirectory() {
177 +
178 + HashMap<Permission, Set<String>> serviceDirectory = new FastHashMap();
179 +
180 + serviceDirectory.put(Permission.APP_READ, ImmutableSet.of(
181 + ApplicationService.class.getName(), CoreService.class.getName()));
182 + serviceDirectory.put(Permission.APP_EVENT, ImmutableSet.of(
183 + ApplicationService.class.getName(), CoreService.class.getName()));
184 + serviceDirectory.put(Permission.CONFIG_READ, ImmutableSet.of(
185 + ComponentConfigService.class.getName()));
186 + serviceDirectory.put(Permission.CONFIG_WRITE, ImmutableSet.of(
187 + ComponentConfigService.class.getName()));
188 + serviceDirectory.put(Permission.CLUSTER_READ, ImmutableSet.of(
189 + ClusterService.class.getName(), LeadershipService.class.getName(),
190 + MastershipService.class.getName()));
191 + serviceDirectory.put(Permission.CLUSTER_WRITE, ImmutableSet.of(
192 + LeadershipService.class.getName(), MastershipService.class.getName()));
193 + serviceDirectory.put(Permission.CLUSTER_EVENT, ImmutableSet.of(
194 + ClusterService.class.getName(), LeadershipService.class.getName(),
195 + MastershipService.class.getName()));
196 + serviceDirectory.put(Permission.DEVICE_READ, ImmutableSet.of(
197 + DeviceService.class.getName(), DeviceClockService.class.getName()));
198 + serviceDirectory.put(Permission.DEVICE_EVENT, ImmutableSet.of(
199 + DeviceService.class.getName()));
200 + serviceDirectory.put(Permission.DRIVER_READ, ImmutableSet.of(
201 + DriverService.class.getName()));
202 + serviceDirectory.put(Permission.DRIVER_WRITE, ImmutableSet.of(
203 + DriverService.class.getName()));
204 + serviceDirectory.put(Permission.FLOWRULE_READ, ImmutableSet.of(
205 + FlowRuleService.class.getName()));
206 + serviceDirectory.put(Permission.FLOWRULE_WRITE, ImmutableSet.of(
207 + FlowRuleService.class.getName(), FlowObjectiveService.class.getName()));
208 + serviceDirectory.put(Permission.FLOWRULE_EVENT, ImmutableSet.of(
209 + FlowRuleService.class.getName()));
210 + serviceDirectory.put(Permission.GROUP_READ, ImmutableSet.of(
211 + GroupService.class.getName()));
212 + serviceDirectory.put(Permission.GROUP_WRITE, ImmutableSet.of(
213 + GroupService.class.getName()));
214 + serviceDirectory.put(Permission.GROUP_EVENT, ImmutableSet.of(
215 + GroupService.class.getName()));
216 + serviceDirectory.put(Permission.HOST_READ, ImmutableSet.of(
217 + HostService.class.getName(), HostClockService.class.getName()));
218 + serviceDirectory.put(Permission.HOST_WRITE, ImmutableSet.of(
219 + HostService.class.getName()));
220 + serviceDirectory.put(Permission.HOST_EVENT, ImmutableSet.of(
221 + HostService.class.getName()));
222 + serviceDirectory.put(Permission.INTENT_READ, ImmutableSet.of(
223 + IntentService.class.getName(), PartitionService.class.getName(),
224 + IntentClockService.class.getName()));
225 + serviceDirectory.put(Permission.INTENT_WRITE, ImmutableSet.of(
226 + IntentService.class.getName()));
227 + serviceDirectory.put(Permission.INTENT_EVENT, ImmutableSet.of(
228 + IntentService.class.getName()));
229 + serviceDirectory.put(Permission.LINK_READ, ImmutableSet.of(
230 + LinkService.class.getName(), LinkResourceService.class.getName(),
231 + LabelResourceService.class.getName()));
232 + serviceDirectory.put(Permission.LINK_WRITE, ImmutableSet.of(
233 + LinkResourceService.class.getName(), LabelResourceService.class.getName()));
234 + serviceDirectory.put(Permission.LINK_EVENT, ImmutableSet.of(
235 + LinkService.class.getName(), LinkResourceService.class.getName(),
236 + LabelResourceService.class.getName()));
237 + serviceDirectory.put(Permission.PACKET_READ, ImmutableSet.of(
238 + PacketService.class.getName(), ProxyArpService.class.getName()));
239 + serviceDirectory.put(Permission.PACKET_WRITE, ImmutableSet.of(
240 + PacketService.class.getName(), ProxyArpService.class.getName()));
241 + serviceDirectory.put(Permission.PACKET_EVENT, ImmutableSet.of(
242 + PacketService.class.getName()));
243 + serviceDirectory.put(Permission.STATISTIC_READ, ImmutableSet.of(
244 + StatisticService.class.getName()));
245 + serviceDirectory.put(Permission.TOPOLOGY_READ, ImmutableSet.of(
246 + TopologyService.class.getName(), PathService.class.getName()));
247 + serviceDirectory.put(Permission.TOPOLOGY_EVENT, ImmutableSet.of(
248 + TopologyService.class.getName()));
249 + serviceDirectory.put(Permission.TUNNEL_READ, ImmutableSet.of(
250 + TunnelService.class.getName()));
251 + serviceDirectory.put(Permission.TUNNEL_WRITE, ImmutableSet.of(
252 + TunnelService.class.getName()));
253 + serviceDirectory.put(Permission.TUNNEL_EVENT, ImmutableSet.of(
254 + TunnelService.class.getName()));
255 + serviceDirectory.put(Permission.STORAGE_WRITE, ImmutableSet.of(
256 + StorageService.class.getName()));
257 +
258 + return serviceDirectory;
259 + }
260 +}
261 +
262 +
263 +// public static PermissionInfo[] getNonAdminPerms() {
264 +// return new PermissionInfo[]{
265 +// new PermissionInfo(PackagePermission.class.getName(), "*", PackagePermission.EXPORTONLY),
266 +// new PermissionInfo(PackagePermission.class.getName(), "*", PackagePermission.IMPORT),
267 +// new PermissionInfo(AdaptPermission.class.getName(), "*", AdaptPermission.ADAPT),
268 +// new PermissionInfo(ServicePermission.class.getName(),
269 +// ApplicationService.class.getName(), ServicePermission.GET),
270 +// new PermissionInfo(ServicePermission.class.getName(),
271 +// ComponentConfigService.class.getName(), ServicePermission.GET),
272 +// new PermissionInfo(ServicePermission.class.getName(),
273 +// CoreService.class.getName(), ServicePermission.GET),
274 +// new PermissionInfo(ServicePermission.class.getName(),
275 +// ClusterService.class.getName(), ServicePermission.GET),
276 +// new PermissionInfo(ServicePermission.class.getName(),
277 +// LeadershipService.class.getName(), ServicePermission.GET),
278 +// new PermissionInfo(ServicePermission.class.getName(),
279 +// MastershipService.class.getName(), ServicePermission.GET),
280 +// new PermissionInfo(ServicePermission.class.getName(),
281 +// DeviceService.class.getName(), ServicePermission.GET),
282 +// new PermissionInfo(ServicePermission.class.getName(),
283 +// DeviceClockService.class.getName(), ServicePermission.GET),
284 +// new PermissionInfo(ServicePermission.class.getName(),
285 +// DriverService.class.getName(), ServicePermission.GET),
286 +// new PermissionInfo(ServicePermission.class.getName(),
287 +// FlowRuleService.class.getName(), ServicePermission.GET),
288 +// new PermissionInfo(ServicePermission.class.getName(),
289 +// FlowObjectiveService.class.getName(), ServicePermission.GET),
290 +// new PermissionInfo(ServicePermission.class.getName(),
291 +// GroupService.class.getName(), ServicePermission.GET),
292 +// new PermissionInfo(ServicePermission.class.getName(),
293 +// HostService.class.getName(), ServicePermission.GET),
294 +// new PermissionInfo(ServicePermission.class.getName(),
295 +// HostClockService.class.getName(), ServicePermission.GET),
296 +// new PermissionInfo(ServicePermission.class.getName(),
297 +// IntentService.class.getName(), ServicePermission.GET),
298 +// new PermissionInfo(ServicePermission.class.getName(),
299 +// IntentClockService.class.getName(), ServicePermission.GET),
300 +// new PermissionInfo(ServicePermission.class.getName(),
301 +// IntentExtensionService.class.getName(), ServicePermission.GET),
302 +// new PermissionInfo(ServicePermission.class.getName(),
303 +// PartitionService.class.getName(), ServicePermission.GET),
304 +// new PermissionInfo(ServicePermission.class.getName(),
305 +// LinkService.class.getName(), ServicePermission.GET),
306 +// new PermissionInfo(ServicePermission.class.getName(),
307 +// LinkResourceService.class.getName(), ServicePermission.GET),
308 +// new PermissionInfo(ServicePermission.class.getName(),
309 +// LabelResourceService.class.getName(), ServicePermission.GET),
310 +// new PermissionInfo(ServicePermission.class.getName(),
311 +// PacketService.class.getName(), ServicePermission.GET),
312 +// new PermissionInfo(ServicePermission.class.getName(),
313 +// ProxyArpService.class.getName(), ServicePermission.GET),
314 +// new PermissionInfo(ServicePermission.class.getName(),
315 +// StatisticService.class.getName(), ServicePermission.GET),
316 +// new PermissionInfo(ServicePermission.class.getName(),
317 +// PathService.class.getName(), ServicePermission.GET),
318 +// new PermissionInfo(ServicePermission.class.getName(),
319 +// TopologyService.class.getName(), ServicePermission.GET),
320 +// new PermissionInfo(ServicePermission.class.getName(),
321 +// TunnelService.class.getName(), ServicePermission.GET),
322 +// new PermissionInfo(ServicePermission.class.getName(),
323 +// StorageService.class.getName(), ServicePermission.GET),
324 +// };
325 +// }
...\ No newline at end of file ...\ No newline at end of file
1 +package org.onosproject.security.impl;
2 +
3 +import org.apache.commons.collections.FastHashMap;
4 +import org.apache.felix.scr.annotations.Component;
5 +import org.apache.felix.scr.annotations.Reference;
6 +import org.apache.felix.scr.annotations.ReferenceCardinality;
7 +import org.apache.felix.scr.annotations.Activate;
8 +import org.apache.felix.scr.annotations.Deactivate;
9 +import org.apache.karaf.features.BundleInfo;
10 +import org.apache.karaf.features.Feature;
11 +import org.apache.karaf.features.FeaturesService;
12 +
13 +import org.onosproject.app.ApplicationAdminService;
14 +import org.onosproject.app.ApplicationEvent;
15 +import org.onosproject.app.ApplicationListener;
16 +import org.onosproject.app.ApplicationState;
17 +import org.onosproject.core.Application;
18 +import org.onosproject.core.ApplicationId;
19 +import org.onosproject.core.Permission;
20 +import org.onosproject.security.util.AppPermission;
21 +import org.osgi.framework.Bundle;
22 +import org.osgi.framework.BundleContext;
23 +import org.osgi.framework.BundleEvent;
24 +import org.osgi.framework.BundleListener;
25 +import org.osgi.framework.FrameworkUtil;
26 +import org.osgi.framework.PackagePermission;
27 +import org.osgi.framework.ServicePermission;
28 +import org.osgi.service.log.LogEntry;
29 +import org.osgi.service.log.LogListener;
30 +import org.osgi.service.log.LogReaderService;
31 +import org.osgi.service.permissionadmin.PermissionInfo;
32 +
33 +import java.security.AccessControlException;
34 +import java.security.AllPermission;
35 +import java.util.ArrayList;
36 +import java.util.HashMap;
37 +import java.util.List;
38 +import java.util.Set;
39 +import java.util.stream.Collectors;
40 +
41 +import org.osgi.service.permissionadmin.PermissionAdmin;
42 +import org.slf4j.Logger;
43 +
44 +import static org.slf4j.LoggerFactory.getLogger;
45 +
46 +/**
47 + * Security-Mode ONOS management implementation.
48 + */
49 +
50 +//TODO : implement a dedicated distributed store for SM-ONOS
51 +
52 +@Component(immediate = true)
53 +public class SecurityModeManager {
54 +
55 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
56 + protected ApplicationAdminService appAdminService;
57 +
58 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 + protected FeaturesService featuresService;
60 +
61 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 + protected LogReaderService logReaderService;
63 +
64 + private final Logger log = getLogger(getClass());
65 +
66 + private SecurityBundleListener securityBundleListener = new SecurityBundleListener();
67 +
68 + private SecurityApplicationListener securityApplicationListener = new SecurityApplicationListener();
69 +
70 + private SecurityLogListener securityLogListener = new SecurityLogListener();
71 +
72 + private Bundle bundle = null;
73 +
74 + private BundleContext bundleContext = null;
75 +
76 + private PermissionAdmin permissionAdmin = null;
77 +
78 + private HashMap<String, ApplicationId> appTracker = null;
79 +
80 + private HashMap<Permission, Set<String>> serviceDirectory = null;
81 +
82 +
83 + @Activate
84 + public void activate() {
85 + if (System.getSecurityManager() == null) {
86 + log.warn("J2EE security manager is disabled.");
87 + deactivate();
88 + return;
89 + }
90 + bundle = FrameworkUtil.getBundle(this.getClass());
91 + bundleContext = bundle.getBundleContext();
92 +
93 + bundleContext.addBundleListener(securityBundleListener);
94 + appAdminService.addListener(securityApplicationListener);
95 + logReaderService.addLogListener(securityLogListener);
96 + appTracker = new FastHashMap();
97 +
98 + permissionAdmin = getPermissionAdmin(bundleContext);
99 + if (permissionAdmin == null) {
100 + log.warn("Permission Admin not found.");
101 + this.deactivate();
102 + return;
103 + }
104 +
105 + serviceDirectory = PolicyBuilder.getServiceDirectory();
106 +
107 + PermissionInfo[] allPerm = {
108 + new PermissionInfo(AllPermission.class.getName(), "", ""), };
109 +
110 + permissionAdmin.setPermissions(bundle.getLocation(), allPerm);
111 + log.warn("Security-Mode Started");
112 +
113 + }
114 +
115 +
116 + @Deactivate
117 + public void deactivate() {
118 + bundleContext.removeBundleListener(securityBundleListener);
119 + appAdminService.removeListener(securityApplicationListener);
120 + logReaderService.removeLogListener(securityLogListener);
121 + log.info("Stopped");
122 +
123 + }
124 +
125 + private class SecurityApplicationListener implements ApplicationListener {
126 +
127 + @Override
128 + public void event(ApplicationEvent event) {
129 + //App needs to be restarted
130 + if (event.type() == ApplicationEvent.Type.APP_PERMISSIONS_CHANGED) {
131 + if (appAdminService.getState(event.subject().id()) == ApplicationState.ACTIVE) {
132 + appAdminService.deactivate(event.subject().id());
133 + print("Permissions updated (%s). Deactivating...",
134 + event.subject().id().name());
135 + }
136 + }
137 + }
138 + }
139 +
140 + private class SecurityBundleListener implements BundleListener {
141 +
142 + @Override
143 + public void bundleChanged(BundleEvent event) {
144 + switch (event.getType()) {
145 + case BundleEvent.INSTALLED:
146 + setPermissions(event);
147 + break;
148 + case BundleEvent.UNINSTALLED:
149 + clearPermissions(event);
150 + break;
151 + default:
152 + break;
153 + }
154 + }
155 + }
156 +
157 + private void clearPermissions(BundleEvent bundleEvent) {
158 + if (appTracker.containsKey(bundleEvent.getBundle().getLocation())) {
159 + permissionAdmin.setPermissions(bundleEvent.getBundle().getLocation(), new PermissionInfo[]{});
160 + appTracker.remove(bundleEvent.getBundle().getLocation());
161 + }
162 + }
163 +
164 + // find the location of the installed bundle and enforce policy
165 + private void setPermissions(BundleEvent bundleEvent) {
166 + for (Application app : appAdminService.getApplications()) {
167 + if (getBundleLocations(app).contains(bundleEvent.getBundle().getLocation())) {
168 + String location = bundleEvent.getBundle().getLocation();
169 +
170 + Set<org.onosproject.core.Permission> permissions =
171 + appAdminService.getPermissions(app.id());
172 +
173 + //Permissions granted by user overrides the permissions specified in App.Xml file
174 + if (permissions == null) {
175 + permissions = app.permissions();
176 + }
177 +
178 + if (permissions.isEmpty()) {
179 + print("Application %s has not been granted any permission.", app.id().name());
180 + }
181 +
182 + PermissionInfo[] perms = null;
183 +
184 + switch (app.role()) {
185 + case ADMIN:
186 + perms = PolicyBuilder.getAdminApplicationPermissions(serviceDirectory);
187 + break;
188 + case REGULAR:
189 + perms = PolicyBuilder.getApplicationPermissions(serviceDirectory, permissions);
190 + break;
191 + case UNSPECIFIED:
192 + default:
193 + //no role has been assigned.
194 + perms = PolicyBuilder.getDefaultPerms();
195 + log.warn("Application %s has no role assigned.", app.id().name());
196 + break;
197 + }
198 + permissionAdmin.setPermissions(location, perms);
199 + appTracker.put(location, app.id());
200 + break;
201 + }
202 + }
203 + }
204 +
205 + //TODO: dispatch security policy violation event via distributed store
206 + //immediately notify and deactivate the application upon policy violation
207 + private class SecurityLogListener implements LogListener {
208 + @Override
209 + public void logged(LogEntry entry) {
210 + if (entry != null) {
211 + if (entry.getException() != null) {
212 + ApplicationId applicationId = appTracker.get(entry.getBundle().getLocation());
213 + if (applicationId != null) {
214 + if (appAdminService.getState(applicationId).equals(ApplicationState.ACTIVE)) {
215 + if (entry.getException() instanceof AccessControlException) {
216 + java.security.Permission permission =
217 + ((AccessControlException) entry.getException()).getPermission();
218 + handleException(applicationId.name(), permission);
219 + appAdminService.deactivate(applicationId);
220 + }
221 + }
222 + }
223 + }
224 + }
225 + }
226 + }
227 +
228 + private void handleException(String name, java.security.Permission perm) {
229 + if (perm instanceof ServicePermission || perm instanceof PackagePermission) {
230 + print("%s has attempted to %s %s.", name, perm.getActions(), perm.getName());
231 + } else if (perm instanceof AppPermission) {
232 + print("%s has attempted to call an NB API that requires %s permission.",
233 + name, perm.getName().toUpperCase());
234 + } else {
235 + print("%s has attempted to perform an action that requires %s", name, perm.toString());
236 + }
237 + print("POLICY VIOLATION: Deactivating %s.", name);
238 +
239 + }
240 + private void print(String format, Object... args) {
241 + System.out.println(String.format("SM-ONOS: " + format, args));
242 + log.warn(String.format(format, args));
243 + }
244 +
245 + private List<String> getBundleLocations(Application app) {
246 + List<String> locations = new ArrayList();
247 + for (String name : app.features()) {
248 + try {
249 + Feature feature = featuresService.getFeature(name);
250 + locations.addAll(
251 + feature.getBundles().stream().map(BundleInfo::getLocation).collect(Collectors.toList()));
252 + } catch (Exception e) {
253 + return locations;
254 + }
255 + }
256 + return locations;
257 + }
258 +
259 + private PermissionAdmin getPermissionAdmin(BundleContext context) {
260 + return (PermissionAdmin) context.getService(context.getServiceReference(PermissionAdmin.class.getName()));
261 + }
262 +
263 +}
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 + <modelVersion>4.0.0</modelVersion>
6 +
7 + <parent>
8 + <artifactId>onos-core</artifactId>
9 + <groupId>org.onosproject</groupId>
10 + <version>1.2.0-SNAPSHOT</version>
11 + <relativePath>../pom.xml</relativePath>
12 + </parent>
13 +
14 + <artifactId>onos-security</artifactId>
15 + <packaging>pom</packaging>
16 + <modules>
17 + <module>util</module>
18 + <module>impl</module>
19 + </modules>
20 +
21 +</project>
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 + <modelVersion>4.0.0</modelVersion>
6 +
7 + <parent>
8 + <artifactId>onos-security</artifactId>
9 + <groupId>org.onosproject</groupId>
10 + <version>1.2.0-SNAPSHOT</version>
11 + </parent>
12 +
13 + <artifactId>onos-security-util</artifactId>
14 + <packaging>bundle</packaging>
15 +
16 +</project>
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.security.util;
18 +
19 +/**
20 + * Checks if the caller has the required permission to call each API.
21 + */
22 +public final class AppGuard {
23 +
24 + private AppGuard() {
25 + }
26 +
27 + public static boolean check(String perm) {
28 + SecurityManager sm = System.getSecurityManager();
29 + if (sm != null) {
30 + System.getSecurityManager().checkPermission(new AppPermission(perm));
31 + }
32 + return true;
33 + }
34 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.security.util;
18 +
19 +import java.security.BasicPermission;
20 +
21 +/**
22 + * Implementation of API access permission.
23 + */
24 +public class AppPermission extends BasicPermission {
25 +
26 + public AppPermission(String name) {
27 + super(name.toUpperCase(), "");
28 + }
29 +
30 + public AppPermission(String name, String actions) {
31 + super(name.toUpperCase(), actions);
32 + }
33 +
34 +}
...@@ -123,6 +123,13 @@ ...@@ -123,6 +123,13 @@
123 <bundle>mvn:org.onosproject/onos-cli/@ONOS-VERSION</bundle> 123 <bundle>mvn:org.onosproject/onos-cli/@ONOS-VERSION</bundle>
124 </feature> 124 </feature>
125 125
126 + <feature name="onos-security" version="@FEATURE-VERSION"
127 + description="Security-Mode ONOS">
128 + <!--<bundle>mvn:org.onosproject/onos-security-felix/2.2.0-ONOS</bundle>-->
129 + <bundle>mvn:org.onosproject/onos-security-impl/@ONOS-VERSION</bundle>
130 + <bundle>mvn:org.onosproject/onos-security-util/@ONOS-VERSION</bundle>
131 + </feature>
132 +
126 <!-- Deprecated! For standalone testing only. --> 133 <!-- Deprecated! For standalone testing only. -->
127 <feature name="onos-core-trivial" version="@FEATURE-VERSION" 134 <feature name="onos-core-trivial" version="@FEATURE-VERSION"
128 description="ONOS trivial core components"> 135 description="ONOS trivial core components">
......