mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-05 12:16:13 +02:00
added OAuth2 authentication for REST protocol
Change-Id: I3b8f3943ea043587730870a0b861760a4d6f3aa7
This commit is contained in:
parent
28d4657304
commit
02ffa7120d
9
lib/BUCK
9
lib/BUCK
@ -547,6 +547,15 @@ remote_jar (
|
||||
visibility = [ 'PUBLIC' ],
|
||||
)
|
||||
|
||||
remote_jar (
|
||||
name = 'jersey-security',
|
||||
out = 'oauth2-client-2.25.1.jar',
|
||||
url = 'mvn:org.glassfish.jersey.security:oauth2-client:jar:2.25.1',
|
||||
sha1 = '5081be1cdc45a48ebeada89157cab4711f7bad1b',
|
||||
maven_coords = 'org.glassfish.jersey.security:oauth2-client:jar:NON-OSGI:2.25.1',
|
||||
visibility = [ 'PUBLIC' ],
|
||||
)
|
||||
|
||||
remote_jar (
|
||||
name = 'jersey-common',
|
||||
out = 'jersey-common-2.25.1.jar',
|
||||
|
||||
@ -155,6 +155,7 @@
|
||||
"javax.inject": "mvn:org.glassfish.hk2.external:javax.inject:2.5.0-b32",
|
||||
"javax.ws.rs-api": "mvn:javax.ws.rs:javax.ws.rs-api:2.1",
|
||||
"jersey-client": "mvn:org.glassfish.jersey.core:jersey-client:2.25.1",
|
||||
"jersey-security": "mvn:org.glassfish.jersey.security:oauth2-client:jar:2.25.1",
|
||||
"jersey-common": "mvn:org.glassfish.jersey.core:jersey-common:2.25.1",
|
||||
"jersey-container-jetty-http": "mvn:org.glassfish.jersey.containers:jersey-container-jetty-http:2.25.1",
|
||||
"jersey-container-servlet": "mvn:org.glassfish.jersey.containers:jersey-container-servlet:2.25.1",
|
||||
|
||||
@ -223,6 +223,13 @@
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>${jersey.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.security</groupId>
|
||||
<artifactId>oauth2-client</artifactId>
|
||||
<version>${jersey.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.containers</groupId>
|
||||
<artifactId>jersey-container-servlet</artifactId>
|
||||
|
||||
@ -3,6 +3,7 @@ COMPILE_DEPS = [
|
||||
'//utils/rest:onlab-rest',
|
||||
'//lib:CORE_DEPS',
|
||||
'//lib:jersey-client',
|
||||
'//lib:jersey-security',
|
||||
'//lib:jersey-common',
|
||||
'//lib:httpclient-osgi',
|
||||
'//lib:httpcore-osgi',
|
||||
|
||||
@ -35,6 +35,12 @@
|
||||
<groupId>org.glassfish.jersey.core</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.security</groupId>
|
||||
<artifactId>oauth2-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient-osgi</artifactId>
|
||||
@ -43,7 +49,6 @@
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
||||
@ -25,10 +25,12 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
|
||||
import org.glassfish.jersey.client.oauth2.OAuth2ClientSupport;
|
||||
import org.onlab.packet.IpAddress;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.protocol.http.HttpSBController;
|
||||
import org.onosproject.protocol.rest.RestSBDevice;
|
||||
import org.onosproject.protocol.rest.RestSBDevice.AuthenticationScheme;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -55,6 +57,8 @@ import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* The implementation of HttpSBController.
|
||||
*/
|
||||
@ -102,11 +106,7 @@ public class HttpSBControllerImpl implements HttpSBController {
|
||||
public void addDevice(RestSBDevice device) {
|
||||
if (!deviceMap.containsKey(device.deviceId())) {
|
||||
Client client = ignoreSslClient();
|
||||
if (device.username() != null) {
|
||||
String username = device.username();
|
||||
String password = device.password() == null ? "" : device.password();
|
||||
authenticate(client, username, password);
|
||||
}
|
||||
authenticate(client, device);
|
||||
clientMap.put(device.deviceId(), client);
|
||||
deviceMap.put(device.deviceId(), device);
|
||||
} else {
|
||||
@ -283,8 +283,23 @@ public class HttpSBControllerImpl implements HttpSBController {
|
||||
}
|
||||
}
|
||||
|
||||
private void authenticate(Client client, String username, String password) {
|
||||
client.register(HttpAuthenticationFeature.basic(username, password));
|
||||
private void authenticate(Client client, RestSBDevice device) {
|
||||
AuthenticationScheme authScheme = device.authentication();
|
||||
if (authScheme == AuthenticationScheme.NO_AUTHENTICATION) {
|
||||
log.debug("{} scheme is specified, ignoring authentication", authScheme);
|
||||
return;
|
||||
} else if (authScheme == AuthenticationScheme.OAUTH2) {
|
||||
String token = checkNotNull(device.token());
|
||||
client.register(OAuth2ClientSupport.feature(token));
|
||||
} else if (authScheme == AuthenticationScheme.BASIC) {
|
||||
String username = device.username();
|
||||
String password = device.password() == null ? "" : device.password();
|
||||
client.register(HttpAuthenticationFeature.basic(username, password));
|
||||
} else {
|
||||
// TODO: Add support for other authentication schemes here.
|
||||
throw new IllegalArgumentException(String.format("Unsupported authentication scheme: %s",
|
||||
authScheme.name()));
|
||||
}
|
||||
}
|
||||
|
||||
protected WebTarget getWebTarget(DeviceId device, String request) {
|
||||
@ -343,12 +358,15 @@ public class HttpSBControllerImpl implements HttpSBController {
|
||||
try {
|
||||
sslcontext = SSLContext.getInstance("TLS");
|
||||
sslcontext.init(null, new TrustManager[]{new X509TrustManager() {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
@ -41,6 +41,8 @@ public class DefaultRestSBDevice implements RestSBDevice {
|
||||
private String protocol;
|
||||
private String url;
|
||||
private boolean isProxy;
|
||||
private AuthenticationScheme authenticationScheme;
|
||||
private String token;
|
||||
private final Optional<String> testUrl;
|
||||
private final Optional<String> manufacturer;
|
||||
private final Optional<String> hwVersion;
|
||||
@ -48,13 +50,13 @@ public class DefaultRestSBDevice implements RestSBDevice {
|
||||
|
||||
public DefaultRestSBDevice(IpAddress ip, int port, String name, String password,
|
||||
String protocol, String url, boolean isActive) {
|
||||
this(ip, port, name, password, protocol, url, isActive, "", "", "", "");
|
||||
this(ip, port, name, password, protocol, url, isActive, "", "", "", "", AuthenticationScheme.BASIC, "");
|
||||
}
|
||||
|
||||
public DefaultRestSBDevice(IpAddress ip, int port, String name, String password,
|
||||
String protocol, String url, boolean isActive, String testUrl, String manufacturer,
|
||||
String hwVersion,
|
||||
String swVersion) {
|
||||
String hwVersion, String swVersion, AuthenticationScheme authenticationScheme,
|
||||
String token) {
|
||||
Preconditions.checkNotNull(ip, "IP address cannot be null");
|
||||
Preconditions.checkArgument(port > 0, "Port address cannot be negative");
|
||||
Preconditions.checkNotNull(protocol, "protocol address cannot be null");
|
||||
@ -65,6 +67,8 @@ public class DefaultRestSBDevice implements RestSBDevice {
|
||||
this.isActive = isActive;
|
||||
this.protocol = protocol;
|
||||
this.url = StringUtils.isEmpty(url) ? null : url;
|
||||
this.authenticationScheme = authenticationScheme;
|
||||
this.token = token;
|
||||
this.manufacturer = StringUtils.isEmpty(manufacturer) ?
|
||||
Optional.empty() : Optional.ofNullable(manufacturer);
|
||||
this.hwVersion = StringUtils.isEmpty(hwVersion) ?
|
||||
@ -158,6 +162,16 @@ public class DefaultRestSBDevice implements RestSBDevice {
|
||||
return swVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationScheme authentication() {
|
||||
return authenticationScheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String token() {
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
@ -168,6 +182,8 @@ public class DefaultRestSBDevice implements RestSBDevice {
|
||||
.add("username", username)
|
||||
.add("port", port)
|
||||
.add("ip", ip)
|
||||
.add("authentication", authenticationScheme.name())
|
||||
.add("token", token)
|
||||
.add("manufacturer", manufacturer.orElse(null))
|
||||
.add("hwVersion", hwVersion.orElse(null))
|
||||
.add("swVersion", swVersion.orElse(null))
|
||||
|
||||
@ -25,6 +25,16 @@ import java.util.Optional;
|
||||
* Represents an abstraction of a Rest Device in ONOS.
|
||||
*/
|
||||
public interface RestSBDevice {
|
||||
/**
|
||||
* REST Authentication schemes.
|
||||
*/
|
||||
public enum AuthenticationScheme {
|
||||
NO_AUTHENTICATION,
|
||||
BASIC,
|
||||
OAUTH,
|
||||
OAUTH2,
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ip of this device.
|
||||
*
|
||||
@ -39,6 +49,20 @@ public interface RestSBDevice {
|
||||
*/
|
||||
int port();
|
||||
|
||||
/**
|
||||
* The authentication scheme of rest device.
|
||||
*
|
||||
* @return authentication
|
||||
*/
|
||||
AuthenticationScheme authentication();
|
||||
|
||||
/**
|
||||
* The access token of rest device if authentication is OAuth2.
|
||||
*
|
||||
* @return token
|
||||
*/
|
||||
String token();
|
||||
|
||||
/**
|
||||
* Returns the username of this device.
|
||||
*
|
||||
@ -91,6 +115,7 @@ public interface RestSBDevice {
|
||||
/**
|
||||
* Returns the proxy state of this device
|
||||
* (if true, the device is proxying multiple ONOS devices).
|
||||
*
|
||||
* @return proxy state
|
||||
*/
|
||||
boolean isProxy();
|
||||
@ -122,4 +147,5 @@ public interface RestSBDevice {
|
||||
* @return the software version.
|
||||
*/
|
||||
Optional<String> swVersion();
|
||||
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ BUNDLES = [
|
||||
'//protocols/rest/api:onos-protocols-rest-api',
|
||||
'//protocols/rest/ctl:onos-protocols-rest-ctl',
|
||||
'//lib:jersey-client',
|
||||
'//lib:jersey-security',
|
||||
'//lib:commons-io',
|
||||
'//lib:httpclient-osgi',
|
||||
'//lib:httpcore-osgi',
|
||||
|
||||
@ -21,6 +21,7 @@ import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.onlab.packet.IpAddress;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.config.Config;
|
||||
import org.onosproject.protocol.rest.RestSBDevice.AuthenticationScheme;
|
||||
|
||||
/**
|
||||
* Configuration to push devices to the REST provider.
|
||||
@ -38,11 +39,14 @@ public class RestDeviceConfig extends Config<DeviceId> {
|
||||
private static final String MANUFACTURER = "manufacturer";
|
||||
private static final String HWVERSION = "hwVersion";
|
||||
private static final String SWVERSION = "swVersion";
|
||||
private static final String AUTHENTICATION_SCHEME = "authenticationScheme";
|
||||
private static final String TOKEN = "token";
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return hasOnlyFields(IP, PORT, USERNAME, PASSWORD, PROTOCOL, URL,
|
||||
TESTURL, MANUFACTURER, HWVERSION, SWVERSION) &&
|
||||
TESTURL, MANUFACTURER, HWVERSION, SWVERSION, AUTHENTICATION_SCHEME,
|
||||
TOKEN) &&
|
||||
ip() != null;
|
||||
}
|
||||
|
||||
@ -136,6 +140,31 @@ public class RestDeviceConfig extends Config<DeviceId> {
|
||||
return get(SWVERSION, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the authentication type of the REST device.
|
||||
* Default is 'basic' if username is defined, else default is no_authentication.
|
||||
*
|
||||
* @return authentication
|
||||
*/
|
||||
public AuthenticationScheme authenticationScheme() {
|
||||
// hack for backward compatibility
|
||||
if (!hasField(AUTHENTICATION_SCHEME)) {
|
||||
if (hasField(USERNAME)) {
|
||||
return AuthenticationScheme.BASIC;
|
||||
}
|
||||
}
|
||||
return AuthenticationScheme.valueOf(get(AUTHENTICATION_SCHEME, "NO_AUTHENTICATION").toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the token of the REST device.
|
||||
*
|
||||
* @return token
|
||||
*/
|
||||
public String token() {
|
||||
return get(TOKEN, "");
|
||||
}
|
||||
|
||||
private Pair<String, Integer> extractIpPort() {
|
||||
String info = subject.toString();
|
||||
if (info.startsWith(RestDeviceProvider.REST)) {
|
||||
|
||||
@ -28,8 +28,6 @@ import org.onlab.util.SharedScheduledExecutorService;
|
||||
import org.onlab.util.SharedScheduledExecutors;
|
||||
import org.onosproject.core.ApplicationId;
|
||||
import org.onosproject.core.CoreService;
|
||||
import org.onosproject.net.behaviour.PortAdmin;
|
||||
import org.onosproject.net.config.ConfigException;
|
||||
import org.onosproject.net.AnnotationKeys;
|
||||
import org.onosproject.net.DefaultAnnotations;
|
||||
import org.onosproject.net.Device;
|
||||
@ -38,7 +36,9 @@ import org.onosproject.net.MastershipRole;
|
||||
import org.onosproject.net.PortNumber;
|
||||
import org.onosproject.net.SparseAnnotations;
|
||||
import org.onosproject.net.behaviour.DevicesDiscovery;
|
||||
import org.onosproject.net.behaviour.PortAdmin;
|
||||
import org.onosproject.net.behaviour.PortDiscovery;
|
||||
import org.onosproject.net.config.ConfigException;
|
||||
import org.onosproject.net.config.ConfigFactory;
|
||||
import org.onosproject.net.config.NetworkConfigEvent;
|
||||
import org.onosproject.net.config.NetworkConfigListener;
|
||||
@ -73,6 +73,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -81,7 +82,6 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.onlab.util.Tools.groupedThreads;
|
||||
@ -354,22 +354,25 @@ public class RestDeviceProvider extends AbstractProvider
|
||||
Set<DeviceId> deviceSubjects =
|
||||
cfgService.getSubjects(DeviceId.class, RestDeviceConfig.class);
|
||||
connectDevices(deviceSubjects.stream()
|
||||
.filter(deviceId -> deviceService.getDevice(deviceId) == null)
|
||||
.map(deviceId -> {
|
||||
RestDeviceConfig config =
|
||||
cfgService.getConfig(deviceId, RestDeviceConfig.class);
|
||||
return new DefaultRestSBDevice(config.ip(),
|
||||
config.port(),
|
||||
config.username(),
|
||||
config.password(),
|
||||
config.protocol(),
|
||||
config.url(),
|
||||
false,
|
||||
config.testUrl(),
|
||||
config.manufacturer(),
|
||||
config.hwVersion(),
|
||||
config.swVersion());
|
||||
}).collect(Collectors.toSet()));
|
||||
.filter(deviceId -> deviceService.getDevice(deviceId) == null)
|
||||
.map(deviceId -> {
|
||||
RestDeviceConfig config =
|
||||
cfgService.getConfig(deviceId, RestDeviceConfig.class);
|
||||
return new DefaultRestSBDevice(config.ip(),
|
||||
config.port(),
|
||||
config.username(),
|
||||
config.password(),
|
||||
config.protocol(),
|
||||
config.url(),
|
||||
false,
|
||||
config.testUrl(),
|
||||
config.manufacturer(),
|
||||
config.hwVersion(),
|
||||
config.swVersion(),
|
||||
config.authenticationScheme(),
|
||||
config.token()
|
||||
);
|
||||
}).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
//Old method to register devices provided via net-cfg under apps/rest/ tree
|
||||
|
||||
@ -21,15 +21,17 @@ import com.google.common.annotations.Beta;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.onlab.packet.IpAddress;
|
||||
import org.onosproject.core.ApplicationId;
|
||||
import org.onosproject.net.config.ConfigException;
|
||||
import org.onosproject.net.config.Config;
|
||||
import org.onosproject.net.config.ConfigException;
|
||||
import org.onosproject.protocol.rest.DefaultRestSBDevice;
|
||||
import org.onosproject.protocol.rest.RestSBDevice;
|
||||
import org.onosproject.protocol.rest.RestSBDevice.AuthenticationScheme;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Configuration for RestSB provider.
|
||||
*
|
||||
* @deprecated 1.10.0 Kingfisher. Please Use RestDeviceConfig
|
||||
*/
|
||||
@Deprecated
|
||||
@ -48,6 +50,8 @@ public class RestProviderConfig extends Config<ApplicationId> {
|
||||
private static final String MANUFACTURER = "manufacturer";
|
||||
private static final String HWVERSION = "hwVersion";
|
||||
private static final String SWVERSION = "swVersion";
|
||||
private static final String AUTHENTICATION_SCHEME = "authenticationScheme";
|
||||
private static final String TOKEN = "token";
|
||||
|
||||
public Set<RestSBDevice> getDevicesAddresses() throws ConfigException {
|
||||
Set<RestSBDevice> devicesAddresses = Sets.newHashSet();
|
||||
@ -65,11 +69,14 @@ public class RestProviderConfig extends Config<ApplicationId> {
|
||||
String manufacturer = node.path(MANUFACTURER).asText();
|
||||
String hwVersion = node.path(HWVERSION).asText();
|
||||
String swVersion = node.path(SWVERSION).asText();
|
||||
AuthenticationScheme authenticationScheme = AuthenticationScheme.valueOf(node.path(
|
||||
AUTHENTICATION_SCHEME).asText().toUpperCase());
|
||||
String token = node.path(TOKEN).asText();
|
||||
|
||||
devicesAddresses.add(new DefaultRestSBDevice(ipAddr, port, username,
|
||||
password, protocol,
|
||||
url, false, testUrl, manufacturer,
|
||||
hwVersion, swVersion));
|
||||
password, protocol,
|
||||
url, false, testUrl, manufacturer,
|
||||
hwVersion, swVersion, authenticationScheme, token));
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConfigException(CONFIG_VALUE_ERROR, e);
|
||||
|
||||
@ -10,6 +10,7 @@ COMPILE_DEPS = [
|
||||
TEST_DEPS = [
|
||||
'//lib:TEST_REST',
|
||||
'//lib:minimal-json',
|
||||
'//lib:jersey-security'
|
||||
]
|
||||
|
||||
osgi_jar_with_tests (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user