Changhoon Yoon
Committed by Gerrit Code Review

ONOS-1896 Modify Application Subsystem to support Security-Mode ONOS

Change-Id: Ie3686e0d5071f9f6e946bc48ed7562bb2f5ec413
......@@ -15,6 +15,7 @@
*/
package org.onosproject.app;
import org.onosproject.core.ApplicationRole;
import org.onosproject.core.Permission;
import org.onosproject.core.Version;
......@@ -57,6 +58,13 @@ public interface ApplicationDescription {
String origin();
/**
* Returns the role of the application.
*
* @return application role
*/
ApplicationRole role();
/**
* Returns the permissions requested by the application.
*
* @return requested permissions
......
......@@ -15,6 +15,7 @@
*/
package org.onosproject.app;
import org.onosproject.core.ApplicationRole;
import org.onosproject.core.Permission;
import org.onosproject.core.Version;
......@@ -36,6 +37,7 @@ public class DefaultApplicationDescription implements ApplicationDescription {
private final Version version;
private final String description;
private final String origin;
private final ApplicationRole role;
private final Set<Permission> permissions;
private final Optional<URI> featuresRepo;
private final List<String> features;
......@@ -47,18 +49,20 @@ public class DefaultApplicationDescription implements ApplicationDescription {
* @param version application version
* @param description application description
* @param origin origin company
* @param role application role
* @param permissions requested permissions
* @param featuresRepo optional features repo URI
* @param features application features
*/
public DefaultApplicationDescription(String name, Version version,
String description, String origin,
Set<Permission> permissions,
ApplicationRole role, Set<Permission> permissions,
URI featuresRepo, List<String> features) {
this.name = checkNotNull(name, "Name cannot be null");
this.version = checkNotNull(version, "Version cannot be null");
this.description = checkNotNull(description, "Description cannot be null");
this.origin = checkNotNull(origin, "Origin cannot be null");
this.role = checkNotNull(role, "Role cannot be null");
this.permissions = checkNotNull(permissions, "Permissions cannot be null");
this.featuresRepo = Optional.ofNullable(featuresRepo);
this.features = checkNotNull(features, "Features cannot be null");
......@@ -86,6 +90,11 @@ public class DefaultApplicationDescription implements ApplicationDescription {
}
@Override
public ApplicationRole role() {
return role;
}
@Override
public Set<Permission> permissions() {
return permissions;
}
......@@ -107,6 +116,7 @@ public class DefaultApplicationDescription implements ApplicationDescription {
.add("version", version)
.add("description", description)
.add("origin", origin)
.add("role", role)
.add("permissions", permissions)
.add("featuresRepo", featuresRepo)
.add("features", features)
......
......@@ -54,6 +54,13 @@ public interface Application {
String origin();
/**
* Returns the role of the application.
*
* @return application role
*/
ApplicationRole role();
/**
* Returns the permissions requested by the application.
*
* @return requested permissions
......
/*
* Copyright 2015 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.core;
public enum ApplicationRole {
/**
* Indicates that an application has an ADMIN role.
*/
ADMIN,
/**
* Indicates that an application has a REGULAR role.
*/
REGULAR,
/**
* Indicates that an application role has not been specified.
*/
UNSPECIFIED,
/**
* More useful roles may be defined.
*/
}
......@@ -16,10 +16,10 @@
package org.onosproject.core;
import java.net.URI;
import java.util.Set;
import java.util.Optional;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
......@@ -34,6 +34,7 @@ public class DefaultApplication implements Application {
private final Version version;
private final String description;
private final String origin;
private final ApplicationRole role;
private final Set<Permission> permissions;
private final Optional<URI> featuresRepo;
private final List<String> features;
......@@ -45,18 +46,20 @@ public class DefaultApplication implements Application {
* @param version application version
* @param description application description
* @param origin origin company
* @param role application role
* @param permissions requested permissions
* @param featuresRepo optional features repo URI
* @param features application features
*/
public DefaultApplication(ApplicationId appId, Version version,
String description, String origin,
Set<Permission> permissions,
ApplicationRole role, Set<Permission> permissions,
Optional<URI> featuresRepo, List<String> features) {
this.appId = checkNotNull(appId, "ID cannot be null");
this.version = checkNotNull(version, "Version cannot be null");
this.description = checkNotNull(description, "Description cannot be null");
this.origin = checkNotNull(origin, "Origin cannot be null");
this.role = checkNotNull(role, "Role cannot be null");
this.permissions = checkNotNull(permissions, "Permissions cannot be null");
this.featuresRepo = checkNotNull(featuresRepo, "Features repo cannot be null");
this.features = checkNotNull(features, "Features cannot be null");
......@@ -84,6 +87,11 @@ public class DefaultApplication implements Application {
}
@Override
public ApplicationRole role() {
return role;
}
@Override
public Set<Permission> permissions() {
return permissions;
}
......@@ -100,7 +108,7 @@ public class DefaultApplication implements Application {
@Override
public int hashCode() {
return Objects.hash(appId, version, description, origin, permissions,
return Objects.hash(appId, version, description, origin, role, permissions,
featuresRepo, features);
}
......@@ -117,6 +125,7 @@ public class DefaultApplication implements Application {
Objects.equals(this.version, other.version) &&
Objects.equals(this.description, other.description) &&
Objects.equals(this.origin, other.origin) &&
Objects.equals(this.role, other.role) &&
Objects.equals(this.permissions, other.permissions) &&
Objects.equals(this.featuresRepo, other.featuresRepo) &&
Objects.equals(this.features, other.features);
......@@ -129,6 +138,7 @@ public class DefaultApplication implements Application {
.add("version", version)
.add("description", description)
.add("origin", origin)
.add("role", role)
.add("permissions", permissions)
.add("featuresRepo", featuresRepo)
.add("features", features)
......
/*
* Copyright 2015 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.core;
import java.security.BasicPermission;
/**
* Default implementation of ONOS application permissions for API-level access control.
*/
public class DefaultPermission extends BasicPermission implements Permission {
public enum Type {
APP_READ,
APP_EVENT,
CONFIG_READ,
CONFIG_WRITE,
CLUSTER_READ,
CLUSTER_WRITE,
CLUSTER_EVENT,
DEVICE_READ,
DEVICE_EVENT,
DRIVER_READ,
DRIVER_WRITE,
FLOWRULE_READ,
FLOWRULE_WRITE,
FLOWRULE_EVENT,
GROUP_READ,
GROUP_WRITE,
GROUP_EVENT,
HOST_READ,
HOST_WRITE,
HOST_EVENT,
INTENT_READ,
INTENT_WRITE,
INTENT_EVENT,
LINK_READ,
LINK_WRITE,
LINK_EVENT,
PACKET_READ,
PACKET_WRITE,
PACKET_EVENT,
STATISTIC_READ,
TOPOLOGY_READ,
TOPOLOGY_EVENT,
TUNNEL_READ,
TUNNEL_WRITE,
TUNNEL_EVENT,
STORAGE_WRITE
}
/**
* Creates a new DefaultPermission.
* @param name name of the permission
* @param actions optional action field
*/
public DefaultPermission(String name, String actions) {
super(name, actions);
}
/**
* Creates a new DefaultPermission.
* @param name name of the permission
*/
public DefaultPermission(String name) {
super(name, "");
}
public DefaultPermission(Type permtype) {
super(permtype.name(), "");
}
@Override
public String name() {
return super.getName();
}
@Override
public String actions() {
return super.getActions();
}
}
......@@ -19,5 +19,16 @@ package org.onosproject.core;
* Representation of an application permission.
*/
public interface Permission {
// TODO: to be fleshed out
/**
* Returns the name of the permission.
* @return a string value
*/
String name();
/**
* Returns the actions string of the permission if specified.
* @return a string value
*/
String actions();
}
......
......@@ -32,7 +32,7 @@ import static org.onosproject.core.DefaultApplicationTest.APP_ID;
public class ApplicationEventTest extends AbstractEventTest {
private Application createApp() {
return new DefaultApplication(APP_ID, VER, DESC, ORIGIN,
return new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE,
PERMS, Optional.of(FURL), FEATURES);
}
......
......@@ -18,6 +18,8 @@ package org.onosproject.app;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.Test;
import org.onosproject.core.ApplicationRole;
import org.onosproject.core.DefaultPermission;
import org.onosproject.core.Permission;
import org.onosproject.core.Version;
......@@ -27,6 +29,9 @@ import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.onosproject.core.DefaultPermission.Type.FLOWRULE_WRITE;
import static org.onosproject.core.DefaultPermission.Type.FLOWRULE_READ;
/**
* Basic tests of the default app description.
......@@ -37,7 +42,9 @@ public class DefaultApplicationDescriptionTest {
public static final Version VER = Version.version(1, 2, "a", null);
public static final String DESC = "Awesome application from Circus";
public static final String ORIGIN = "Circus";
public static final Set<Permission> PERMS = ImmutableSet.of();
public static final ApplicationRole ROLE = ApplicationRole.ADMIN;
public static final Set<Permission> PERMS = ImmutableSet.of(new DefaultPermission(FLOWRULE_WRITE),
new DefaultPermission(FLOWRULE_READ));
public static final URI FURL = URI.create("mvn:org.foo-features/1.2a/xml/features");
public static final List<String> FEATURES = ImmutableList.of("foo", "bar");
......@@ -45,11 +52,12 @@ public class DefaultApplicationDescriptionTest {
public void basics() {
ApplicationDescription app =
new DefaultApplicationDescription(APP_NAME, VER, DESC, ORIGIN,
PERMS, FURL, FEATURES);
ROLE, PERMS, FURL, FEATURES);
assertEquals("incorrect id", APP_NAME, app.name());
assertEquals("incorrect version", VER, app.version());
assertEquals("incorrect description", DESC, app.description());
assertEquals("incorrect origin", ORIGIN, app.origin());
assertEquals("incorect role", ROLE, app.role());
assertEquals("incorrect permissions", PERMS, app.permissions());
assertEquals("incorrect features repo", FURL, app.featuresRepo().get());
assertEquals("incorrect features", FEATURES, app.features());
......
......@@ -33,12 +33,13 @@ public class DefaultApplicationTest {
@Test
public void basics() {
Application app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN,
Application app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE,
PERMS, Optional.of(FURL), FEATURES);
assertEquals("incorrect id", APP_ID, app.id());
assertEquals("incorrect version", VER, app.version());
assertEquals("incorrect description", DESC, app.description());
assertEquals("incorrect origin", ORIGIN, app.origin());
assertEquals("incorrect role", ROLE, app.role());
assertEquals("incorrect permissions", PERMS, app.permissions());
assertEquals("incorrect features repo", FURL, app.featuresRepo().get());
assertEquals("incorrect features", FEATURES, app.features());
......@@ -47,13 +48,13 @@ public class DefaultApplicationTest {
@Test
public void testEquality() {
Application a1 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN,
Application a1 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE,
PERMS, Optional.of(FURL), FEATURES);
Application a2 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN,
Application a2 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE,
PERMS, Optional.of(FURL), FEATURES);
Application a3 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN,
Application a3 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE,
PERMS, Optional.empty(), FEATURES);
Application a4 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN + "asd",
Application a4 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN + "asd", ROLE,
PERMS, Optional.of(FURL), FEATURES);
new EqualsTester().addEqualityGroup(a1, a2)
.addEqualityGroup(a3).addEqualityGroup(a4).testEquals();
......
......@@ -27,6 +27,8 @@ import org.onosproject.app.ApplicationEvent;
import org.onosproject.app.ApplicationException;
import org.onosproject.app.ApplicationStoreDelegate;
import org.onosproject.app.DefaultApplicationDescription;
import org.onosproject.core.ApplicationRole;
import org.onosproject.core.DefaultPermission;
import org.onosproject.core.Permission;
import org.onosproject.core.Version;
import org.onosproject.store.AbstractStore;
......@@ -42,7 +44,9 @@ import java.io.InputStream;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.NoSuchFileException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
......@@ -74,6 +78,9 @@ public class ApplicationArchive
private static final String FEATURES = "[@features]";
private static final String DESCRIPTION = "description";
private static final String ROLE = "security.role";
private static final String PERMISSIONS = "security.permissions.permission";
private static final String OAR = ".oar";
private static final String APP_XML = "app.xml";
private static final String M2_PREFIX = "m2";
......@@ -267,12 +274,13 @@ public class ApplicationArchive
Version version = Version.version(cfg.getString(VERSION));
String desc = cfg.getString(DESCRIPTION);
String origin = cfg.getString(ORIGIN);
Set<Permission> perms = ImmutableSet.of();
ApplicationRole role = getRole(cfg.getString(ROLE));
Set<Permission> perms = getPermissions(cfg);
String featRepo = cfg.getString(FEATURES_REPO);
URI featuresRepo = featRepo != null ? URI.create(featRepo) : null;
List<String> features = ImmutableList.copyOf(cfg.getStringArray(FEATURES));
return new DefaultApplicationDescription(name, version, desc, origin,
return new DefaultApplicationDescription(name, version, desc, origin, role,
perms, featuresRepo, features);
}
......@@ -368,4 +376,34 @@ public class ApplicationArchive
return new File(new File(appsDir, appName), fileName);
}
// Returns the set of Permissions specified in the app.xml file
private ImmutableSet<Permission> getPermissions(XMLConfiguration cfg) {
List<Permission> perms = new ArrayList();
for (Object o : cfg.getList(PERMISSIONS)) {
DefaultPermission perm = null;
if (o != null) {
String permStr = (String) o;
perm = new DefaultPermission(permStr);
}
if (perm != null) {
perms.add(perm);
}
}
return ImmutableSet.copyOf(perms);
}
// Returns application role type
public ApplicationRole getRole(String value) {
if (value == null) {
return ApplicationRole.UNSPECIFIED;
} else {
try {
return ApplicationRole.valueOf(value.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException e) {
log.debug("Unknown role value: %s", value);
return ApplicationRole.UNSPECIFIED;
}
}
}
}
......
......@@ -56,6 +56,7 @@ public class ApplicationArchiveTest {
assertEquals("incorrect name", APP_NAME, app.name());
assertEquals("incorrect version", VER, app.version());
assertEquals("incorrect origin", ORIGIN, app.origin());
assertEquals("incorrect role", ROLE, app.role());
assertEquals("incorrect description", DESC, app.description());
assertEquals("incorrect features URI", FURL, app.featuresRepo().get());
......
......@@ -18,4 +18,11 @@
featuresRepo="mvn:org.foo-features/1.2a/xml/features"
features="foo,bar">
<description>Awesome application from Circus, Inc.</description>
<security>
<role>ADMIN</role>
<permissions>
<permission>FLOWRULE_WRITE</permission>
<permission>FLOWRULE_READ</permission>
</permissions>
</security>
</app>
......
......@@ -127,7 +127,7 @@ public class ApplicationManagerTest {
@Override
public Application create(InputStream appDescStream) {
app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, PERMS,
app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, PERMS,
Optional.of(FURL), FEATURES);
state = INSTALLED;
delegate.notify(new ApplicationEvent(APP_INSTALLED, app));
......
......@@ -431,7 +431,7 @@ public class GossipApplicationStore extends ApplicationArchive
private Application registerApp(ApplicationDescription appDesc) {
ApplicationId appId = idStore.registerApplication(appDesc.name());
return new DefaultApplication(appId, appDesc.version(), appDesc.description(),
appDesc.origin(), appDesc.permissions(),
appDesc.origin(), appDesc.role(), appDesc.permissions(),
appDesc.featuresRepo(), appDesc.features());
}
}
......
......@@ -74,7 +74,7 @@ public class SimpleApplicationStore extends ApplicationArchive implements Applic
DefaultApplication app =
new DefaultApplication(appId, appDesc.version(),
appDesc.description(), appDesc.origin(),
appDesc.permissions(),
appDesc.role(), appDesc.permissions(),
appDesc.featuresRepo(), appDesc.features());
apps.put(appId, app);
states.put(appId, isActive(name) ? INSTALLED : ACTIVE);
......@@ -116,7 +116,7 @@ public class SimpleApplicationStore extends ApplicationArchive implements Applic
ApplicationId appId = idStore.registerApplication(appDesc.name());
DefaultApplication app =
new DefaultApplication(appId, appDesc.version(), appDesc.description(),
appDesc.origin(), appDesc.permissions(),
appDesc.origin(), appDesc.role(), appDesc.permissions(),
appDesc.featuresRepo(), appDesc.features());
apps.put(appId, app);
states.put(appId, INSTALLED);
......
......@@ -24,12 +24,18 @@ import org.onosproject.app.ApplicationStoreDelegate;
import org.onosproject.common.app.ApplicationArchive;
import org.onosproject.core.Application;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.Permission;
import org.onosproject.core.DefaultPermission;
import org.onosproject.core.ApplicationIdStoreAdapter;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.core.Permission;
import static org.onosproject.core.DefaultPermission.Type.FLOWRULE_WRITE;
import static org.junit.Assert.assertEquals;
import static org.onosproject.app.ApplicationEvent.Type.*;
import static org.onosproject.app.ApplicationEvent.Type.APP_INSTALLED;
import static org.onosproject.app.ApplicationEvent.Type.APP_DEACTIVATED;
import static org.onosproject.app.ApplicationEvent.Type.APP_ACTIVATED;
import static org.onosproject.app.ApplicationEvent.Type.APP_UNINSTALLED;
import static org.onosproject.app.ApplicationEvent.Type.APP_PERMISSIONS_CHANGED;
import static org.onosproject.app.ApplicationState.ACTIVE;
import static org.onosproject.app.ApplicationState.INSTALLED;
......@@ -100,8 +106,7 @@ public class SimpleApplicationStoreTest {
@Test
public void permissions() {
Application app = createTestApp();
ImmutableSet<Permission> permissions = ImmutableSet.of(new Permission() {
});
ImmutableSet<Permission> permissions = ImmutableSet.of(new DefaultPermission(FLOWRULE_WRITE));
store.setPermissions(app.id(), permissions);
assertEquals("incorrect app perms", 1, store.getPermissions(app.id()).size());
assertEquals("incorrect app state", INSTALLED, store.getState(app.id()));
......
......@@ -37,6 +37,7 @@ import org.onosproject.codec.impl.CodecManager;
import org.onosproject.codec.impl.MockCodecContext;
import org.onosproject.core.Application;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.ApplicationRole;
import org.onosproject.core.DefaultApplication;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.core.Version;
......@@ -83,19 +84,19 @@ public class ApplicationsResourceTest extends ResourceTest {
private Application app1 =
new DefaultApplication(id1, VER,
"app1", "origin1", ImmutableSet.of(), Optional.of(FURL),
"app1", "origin1", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL),
ImmutableList.of("My Feature"));
private Application app2 =
new DefaultApplication(id2, VER,
"app2", "origin2", ImmutableSet.of(), Optional.of(FURL),
"app2", "origin2", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL),
ImmutableList.of("My Feature"));
private Application app3 =
new DefaultApplication(id3, VER,
"app3", "origin3", ImmutableSet.of(), Optional.of(FURL),
"app3", "origin3", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL),
ImmutableList.of("My Feature"));
private Application app4 =
new DefaultApplication(id4, VER,
"app4", "origin4", ImmutableSet.of(), Optional.of(FURL),
"app4", "origin4", ApplicationRole.ADMIN, ImmutableSet.of(), Optional.of(FURL),
ImmutableList.of("My Feature"));
/**
......