Committed by
Gerrit Code Review
ONOS-3810 augmenting Rest southbound protocol and provider for https and password based auth
Change-Id: I3e5f07ba6a751bc8a7637373c037a1910181f9ab
Showing
9 changed files
with
250 additions
and
52 deletions
| ... | @@ -54,14 +54,20 @@ public class PortDiscoveryCienaWaveserverImpl extends AbstractHandlerBehaviour | ... | @@ -54,14 +54,20 @@ public class PortDiscoveryCienaWaveserverImpl extends AbstractHandlerBehaviour |
| 54 | private static final String NAME = "name"; | 54 | private static final String NAME = "name"; |
| 55 | private static final String ADMIN_STATE = "admin-state"; | 55 | private static final String ADMIN_STATE = "admin-state"; |
| 56 | 56 | ||
| 57 | - private static final ArrayList<String> LINESIDE = Lists.newArrayList( | 57 | + private static final ArrayList<String> LINESIDE_PORT_ID = Lists.newArrayList( |
| 58 | - "1.1", "1.2", "12.1", "12.2"); | 58 | + "4", "48"); |
| 59 | 59 | ||
| 60 | private static final String GENERAL_PORT_REQUEST = | 60 | private static final String GENERAL_PORT_REQUEST = |
| 61 | - "yang-api/datastore/ws-ports?config=true&format=xml&depth=unbounded"; | 61 | + "ws-ports?config=true&format=xml&depth=unbounded"; |
| 62 | - private static final String SPECIFIC_PORT_PATH = "yang-api/datastore/ws-ptps/ptp/"; | 62 | + private static final String SPECIFIC_PORT_PATH = "ws-ptps/ptp/"; |
| 63 | private static final String SPECIFIC_PORT_CONFIG = | 63 | private static final String SPECIFIC_PORT_CONFIG = |
| 64 | "/ptp-config?config=true&format=xml&depth=unbounded"; | 64 | "/ptp-config?config=true&format=xml&depth=unbounded"; |
| 65 | + //HTTP strings | ||
| 66 | +// private static final String GENERAL_PORT_REQUEST = | ||
| 67 | +// "/yang-api/datastore/ws-ports?config=true&format=xml&depth=unbounded"; | ||
| 68 | +// private static final String SPECIFIC_PORT_PATH = "/yang-api/datastore/ws-ptps/ptp/"; | ||
| 69 | +// private static final String SPECIFIC_PORT_CONFIG = | ||
| 70 | +// "/ptp-config?config=true&format=xml&depth=unbounded"; | ||
| 65 | 71 | ||
| 66 | 72 | ||
| 67 | @Override | 73 | @Override |
| ... | @@ -76,24 +82,35 @@ public class PortDiscoveryCienaWaveserverImpl extends AbstractHandlerBehaviour | ... | @@ -76,24 +82,35 @@ public class PortDiscoveryCienaWaveserverImpl extends AbstractHandlerBehaviour |
| 76 | loadXml(controller.get(deviceId, GENERAL_PORT_REQUEST, XML)); | 82 | loadXml(controller.get(deviceId, GENERAL_PORT_REQUEST, XML)); |
| 77 | List<HierarchicalConfiguration> portsConfig = | 83 | List<HierarchicalConfiguration> portsConfig = |
| 78 | XmlConfigParser.parseWaveServerCienaPorts(config); | 84 | XmlConfigParser.parseWaveServerCienaPorts(config); |
| 79 | - | ||
| 80 | portsConfig.stream().forEach(sub -> { | 85 | portsConfig.stream().forEach(sub -> { |
| 86 | + String portId = sub.getString(PORT_ID); | ||
| 81 | String name = sub.getString(NAME); | 87 | String name = sub.getString(NAME); |
| 82 | SparseAnnotations annotations = DefaultAnnotations.builder() | 88 | SparseAnnotations annotations = DefaultAnnotations.builder() |
| 83 | - .set(AnnotationKeys.NAME, String.valueOf(name)).build(); | 89 | + .set(AnnotationKeys.NAME, name).build(); |
| 84 | - if (LINESIDE.contains(name)) { | 90 | + if (LINESIDE_PORT_ID.contains(portId)) { |
| 85 | - String wsportInfoRequest = SPECIFIC_PORT_PATH + sub.getLong(PORT_ID) + | 91 | + String wsportInfoRequest = SPECIFIC_PORT_PATH + portId + |
| 86 | SPECIFIC_PORT_CONFIG; | 92 | SPECIFIC_PORT_CONFIG; |
| 87 | ports.add(XmlConfigParser.parseWaveServerCienaOchPorts( | 93 | ports.add(XmlConfigParser.parseWaveServerCienaOchPorts( |
| 88 | sub.getLong(PORT_ID), | 94 | sub.getLong(PORT_ID), |
| 89 | - toGbps(Long.parseLong(sub.getString(SPEED).replace(GBPS, EMPTY_STRING))), | 95 | + toGbps(Long.parseLong(sub.getString(SPEED).replace(GBPS, EMPTY_STRING) |
| 96 | + .replace(" ", EMPTY_STRING))), | ||
| 90 | XmlConfigParser.loadXml(controller.get(deviceId, wsportInfoRequest, XML)), | 97 | XmlConfigParser.loadXml(controller.get(deviceId, wsportInfoRequest, XML)), |
| 91 | annotations)); | 98 | annotations)); |
| 92 | - } else { | 99 | + //adding corresponding opposite side port |
| 100 | + ports.add(XmlConfigParser.parseWaveServerCienaOchPorts( | ||
| 101 | + sub.getLong(PORT_ID) + 1, | ||
| 102 | + toGbps(Long.parseLong(sub.getString(SPEED).replace(GBPS, EMPTY_STRING) | ||
| 103 | + .replace(" ", EMPTY_STRING))), | ||
| 104 | + XmlConfigParser.loadXml(controller.get(deviceId, wsportInfoRequest, XML)), | ||
| 105 | + DefaultAnnotations.builder() | ||
| 106 | + .set(AnnotationKeys.NAME, name.replace(".1", ".2")) | ||
| 107 | + .build())); | ||
| 108 | + } else if (!portId.equals("5") && !portId.equals("49")) { | ||
| 93 | //FIXME change when all optical types have two way information methods, see jira tickets | 109 | //FIXME change when all optical types have two way information methods, see jira tickets |
| 94 | final int speed100GbpsinMbps = 100000; | 110 | final int speed100GbpsinMbps = 100000; |
| 95 | CltSignalType cltType = toGbps(Long.parseLong( | 111 | CltSignalType cltType = toGbps(Long.parseLong( |
| 96 | - sub.getString(SPEED).replace(GBPS, EMPTY_STRING))) == speed100GbpsinMbps ? | 112 | + sub.getString(SPEED).replace(GBPS, EMPTY_STRING) |
| 113 | + .replace(" ", EMPTY_STRING))) == speed100GbpsinMbps ? | ||
| 97 | CltSignalType.CLT_100GBE : null; | 114 | CltSignalType.CLT_100GBE : null; |
| 98 | ports.add(new OduCltPortDescription(PortNumber.portNumber(sub.getLong(PORT_ID)), | 115 | ports.add(new OduCltPortDescription(PortNumber.portNumber(sub.getLong(PORT_ID)), |
| 99 | sub.getString(ADMIN_STATE).equals(ENABLED), | 116 | sub.getString(ADMIN_STATE).equals(ENABLED), |
| ... | @@ -107,5 +124,6 @@ public class PortDiscoveryCienaWaveserverImpl extends AbstractHandlerBehaviour | ... | @@ -107,5 +124,6 @@ public class PortDiscoveryCienaWaveserverImpl extends AbstractHandlerBehaviour |
| 107 | private long toGbps(long speed) { | 124 | private long toGbps(long speed) { |
| 108 | return speed * 1000; | 125 | return speed * 1000; |
| 109 | } | 126 | } |
| 127 | + | ||
| 110 | } | 128 | } |
| 111 | 129 | ... | ... |
| ... | @@ -16,7 +16,9 @@ | ... | @@ -16,7 +16,9 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.protocol.rest; | 17 | package org.onosproject.protocol.rest; |
| 18 | 18 | ||
| 19 | +import com.google.common.base.MoreObjects; | ||
| 19 | import com.google.common.base.Preconditions; | 20 | import com.google.common.base.Preconditions; |
| 21 | +import org.apache.commons.lang3.StringUtils; | ||
| 20 | import org.onlab.packet.IpAddress; | 22 | import org.onlab.packet.IpAddress; |
| 21 | import org.onosproject.net.DeviceId; | 23 | import org.onosproject.net.DeviceId; |
| 22 | 24 | ||
| ... | @@ -34,18 +36,20 @@ public class DefaultRestSBDevice implements RestSBDevice { | ... | @@ -34,18 +36,20 @@ public class DefaultRestSBDevice implements RestSBDevice { |
| 34 | private final String password; | 36 | private final String password; |
| 35 | private boolean isActive; | 37 | private boolean isActive; |
| 36 | private String protocol; | 38 | private String protocol; |
| 39 | + private String url; | ||
| 37 | 40 | ||
| 38 | public DefaultRestSBDevice(IpAddress ip, int port, String name, String password, | 41 | public DefaultRestSBDevice(IpAddress ip, int port, String name, String password, |
| 39 | - String protocol, boolean isActive) { | 42 | + String protocol, String url, boolean isActive) { |
| 40 | Preconditions.checkNotNull(ip, "IP address cannot be null"); | 43 | Preconditions.checkNotNull(ip, "IP address cannot be null"); |
| 41 | Preconditions.checkArgument(port > 0, "Port address cannot be negative"); | 44 | Preconditions.checkArgument(port > 0, "Port address cannot be negative"); |
| 42 | Preconditions.checkNotNull(protocol, "protocol address cannot be null"); | 45 | Preconditions.checkNotNull(protocol, "protocol address cannot be null"); |
| 43 | this.ip = ip; | 46 | this.ip = ip; |
| 44 | this.port = port; | 47 | this.port = port; |
| 45 | this.name = name; | 48 | this.name = name; |
| 46 | - this.password = password; | 49 | + this.password = StringUtils.isEmpty(password) ? null : password; |
| 47 | this.isActive = isActive; | 50 | this.isActive = isActive; |
| 48 | this.protocol = protocol; | 51 | this.protocol = protocol; |
| 52 | + this.url = StringUtils.isEmpty(url) ? null : url; | ||
| 49 | } | 53 | } |
| 50 | 54 | ||
| 51 | @Override | 55 | @Override |
| ... | @@ -89,6 +93,22 @@ public class DefaultRestSBDevice implements RestSBDevice { | ... | @@ -89,6 +93,22 @@ public class DefaultRestSBDevice implements RestSBDevice { |
| 89 | } | 93 | } |
| 90 | 94 | ||
| 91 | @Override | 95 | @Override |
| 96 | + public String url() { | ||
| 97 | + return url; | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + @Override | ||
| 101 | + public String toString() { | ||
| 102 | + return MoreObjects.toStringHelper(this) | ||
| 103 | + .add("url", url) | ||
| 104 | + .add("protocol", protocol) | ||
| 105 | + .add("name", name) | ||
| 106 | + .add("port", port) | ||
| 107 | + .add("ip", ip) | ||
| 108 | + .toString(); | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + @Override | ||
| 92 | public boolean equals(Object obj) { | 112 | public boolean equals(Object obj) { |
| 93 | if (obj == this) { | 113 | if (obj == this) { |
| 94 | return true; | 114 | return true; | ... | ... |
| ... | @@ -79,4 +79,10 @@ public interface RestSBDevice { | ... | @@ -79,4 +79,10 @@ public interface RestSBDevice { |
| 79 | */ | 79 | */ |
| 80 | String protocol(); | 80 | String protocol(); |
| 81 | 81 | ||
| 82 | + /** | ||
| 83 | + * Returns the url for the REST requests, to be used instead of IP and PORT. | ||
| 84 | + * | ||
| 85 | + * @return url | ||
| 86 | + */ | ||
| 87 | + String url(); | ||
| 82 | } | 88 | } | ... | ... |
| ... | @@ -16,17 +16,22 @@ | ... | @@ -16,17 +16,22 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.protocol.rest.ctl; | 17 | package org.onosproject.protocol.rest.ctl; |
| 18 | 18 | ||
| 19 | +import com.google.common.collect.ImmutableMap; | ||
| 19 | import com.sun.jersey.api.client.Client; | 20 | import com.sun.jersey.api.client.Client; |
| 20 | import com.sun.jersey.api.client.ClientResponse; | 21 | import com.sun.jersey.api.client.ClientResponse; |
| 21 | import com.sun.jersey.api.client.WebResource; | 22 | import com.sun.jersey.api.client.WebResource; |
| 23 | +import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; | ||
| 22 | import org.apache.commons.io.IOUtils; | 24 | import org.apache.commons.io.IOUtils; |
| 23 | import org.apache.felix.scr.annotations.Activate; | 25 | import org.apache.felix.scr.annotations.Activate; |
| 24 | import org.apache.felix.scr.annotations.Component; | 26 | import org.apache.felix.scr.annotations.Component; |
| 25 | import org.apache.felix.scr.annotations.Deactivate; | 27 | import org.apache.felix.scr.annotations.Deactivate; |
| 26 | import org.apache.felix.scr.annotations.Service; | 28 | import org.apache.felix.scr.annotations.Service; |
| 27 | import org.apache.http.client.methods.HttpPatch; | 29 | import org.apache.http.client.methods.HttpPatch; |
| 30 | +import org.apache.http.conn.ssl.AllowAllHostnameVerifier; | ||
| 28 | import org.apache.http.entity.StringEntity; | 31 | import org.apache.http.entity.StringEntity; |
| 32 | +import org.apache.http.impl.client.CloseableHttpClient; | ||
| 29 | import org.apache.http.impl.client.HttpClients; | 33 | import org.apache.http.impl.client.HttpClients; |
| 34 | +import org.apache.http.ssl.SSLContextBuilder; | ||
| 30 | import org.onlab.packet.IpAddress; | 35 | import org.onlab.packet.IpAddress; |
| 31 | import org.onosproject.net.DeviceId; | 36 | import org.onosproject.net.DeviceId; |
| 32 | import org.onosproject.protocol.rest.RestSBController; | 37 | import org.onosproject.protocol.rest.RestSBController; |
| ... | @@ -40,6 +45,10 @@ import java.io.ByteArrayInputStream; | ... | @@ -40,6 +45,10 @@ import java.io.ByteArrayInputStream; |
| 40 | import java.io.IOException; | 45 | import java.io.IOException; |
| 41 | import java.io.InputStream; | 46 | import java.io.InputStream; |
| 42 | import java.nio.charset.StandardCharsets; | 47 | import java.nio.charset.StandardCharsets; |
| 48 | +import java.security.KeyManagementException; | ||
| 49 | +import java.security.KeyStoreException; | ||
| 50 | +import java.security.NoSuchAlgorithmException; | ||
| 51 | +import java.util.Base64; | ||
| 43 | import java.util.Map; | 52 | import java.util.Map; |
| 44 | import java.util.concurrent.ConcurrentHashMap; | 53 | import java.util.concurrent.ConcurrentHashMap; |
| 45 | 54 | ||
| ... | @@ -59,7 +68,9 @@ public class RestSBControllerImpl implements RestSBController { | ... | @@ -59,7 +68,9 @@ public class RestSBControllerImpl implements RestSBController { |
| 59 | private static final int STATUS_OK = Response.Status.OK.getStatusCode(); | 68 | private static final int STATUS_OK = Response.Status.OK.getStatusCode(); |
| 60 | private static final int STATUS_CREATED = Response.Status.CREATED.getStatusCode(); | 69 | private static final int STATUS_CREATED = Response.Status.CREATED.getStatusCode(); |
| 61 | private static final int STATUS_ACCEPTED = Response.Status.ACCEPTED.getStatusCode(); | 70 | private static final int STATUS_ACCEPTED = Response.Status.ACCEPTED.getStatusCode(); |
| 62 | - private static final String SLASH = "/"; | 71 | + private static final String HTTPS = "https"; |
| 72 | + private static final String AUTHORIZATION_PROPERTY = "authorization"; | ||
| 73 | + private static final String BASIC_AUTH_PREFIX = "Basic "; | ||
| 63 | 74 | ||
| 64 | private final Map<DeviceId, RestSBDevice> deviceMap = new ConcurrentHashMap<>(); | 75 | private final Map<DeviceId, RestSBDevice> deviceMap = new ConcurrentHashMap<>(); |
| 65 | Client client; | 76 | Client client; |
| ... | @@ -78,7 +89,7 @@ public class RestSBControllerImpl implements RestSBController { | ... | @@ -78,7 +89,7 @@ public class RestSBControllerImpl implements RestSBController { |
| 78 | 89 | ||
| 79 | @Override | 90 | @Override |
| 80 | public Map<DeviceId, RestSBDevice> getDevices() { | 91 | public Map<DeviceId, RestSBDevice> getDevices() { |
| 81 | - return deviceMap; | 92 | + return ImmutableMap.copyOf(deviceMap); |
| 82 | } | 93 | } |
| 83 | 94 | ||
| 84 | @Override | 95 | @Override |
| ... | @@ -88,13 +99,8 @@ public class RestSBControllerImpl implements RestSBController { | ... | @@ -88,13 +99,8 @@ public class RestSBControllerImpl implements RestSBController { |
| 88 | 99 | ||
| 89 | @Override | 100 | @Override |
| 90 | public RestSBDevice getDevice(IpAddress ip, int port) { | 101 | public RestSBDevice getDevice(IpAddress ip, int port) { |
| 91 | - for (RestSBDevice device : deviceMap.values()) { | 102 | + return deviceMap.values().stream().filter(v -> v.ip().equals(ip) |
| 92 | - if (device.ip().equals(ip) && | 103 | + && v.port() == port).findFirst().get(); |
| 93 | - device.port() == port) { | ||
| 94 | - return device; | ||
| 95 | - } | ||
| 96 | - } | ||
| 97 | - return null; | ||
| 98 | } | 104 | } |
| 99 | 105 | ||
| 100 | @Override | 106 | @Override |
| ... | @@ -162,32 +168,44 @@ public class RestSBControllerImpl implements RestSBController { | ... | @@ -162,32 +168,44 @@ public class RestSBControllerImpl implements RestSBController { |
| 162 | throw new IllegalArgumentException("Unsupported media type " + mediaType); | 168 | throw new IllegalArgumentException("Unsupported media type " + mediaType); |
| 163 | 169 | ||
| 164 | } | 170 | } |
| 165 | - return new ByteArrayInputStream(webResource.accept(type).get(ClientResponse.class) | 171 | + |
| 166 | - .getEntity(String.class) | 172 | + ClientResponse s = webResource.accept(type).get(ClientResponse.class); |
| 167 | - .getBytes(StandardCharsets.UTF_8)); | 173 | + if (checkReply(s)) { |
| 174 | + return new ByteArrayInputStream(s.getEntity(String.class) | ||
| 175 | + .getBytes(StandardCharsets.UTF_8)); | ||
| 176 | + } | ||
| 177 | + return null; | ||
| 168 | } | 178 | } |
| 169 | 179 | ||
| 170 | @Override | 180 | @Override |
| 171 | public boolean patch(DeviceId device, String request, InputStream payload, String mediaType) { | 181 | public boolean patch(DeviceId device, String request, InputStream payload, String mediaType) { |
| 172 | - String url = deviceMap.get(device).protocol() + COLON + | ||
| 173 | - DOUBLESLASH + | ||
| 174 | - deviceMap.get(device).ip().toString() + | ||
| 175 | - COLON + deviceMap.get(device).port() + | ||
| 176 | - SLASH + request; | ||
| 177 | try { | 182 | try { |
| 178 | - HttpPatch httprequest = new HttpPatch(url); | 183 | + log.debug("Url request {} ", getUrlString(device, request)); |
| 184 | + HttpPatch httprequest = new HttpPatch(getUrlString(device, request)); | ||
| 185 | + if (deviceMap.get(device).password() != null) { | ||
| 186 | + String userPassword = deviceMap.get(device).name() + COLON + deviceMap.get(device).password(); | ||
| 187 | + String base64string = Base64.getEncoder().encodeToString(userPassword.getBytes(StandardCharsets.UTF_8)); | ||
| 188 | + httprequest.addHeader(AUTHORIZATION_PROPERTY, BASIC_AUTH_PREFIX + base64string); | ||
| 189 | + } | ||
| 179 | if (payload != null) { | 190 | if (payload != null) { |
| 180 | StringEntity input = new StringEntity(IOUtils.toString(payload, StandardCharsets.UTF_8)); | 191 | StringEntity input = new StringEntity(IOUtils.toString(payload, StandardCharsets.UTF_8)); |
| 181 | input.setContentType(mediaType); | 192 | input.setContentType(mediaType); |
| 182 | httprequest.setEntity(input); | 193 | httprequest.setEntity(input); |
| 183 | } | 194 | } |
| 184 | - int responseStatusCode = HttpClients.createDefault().execute(httprequest) | 195 | + CloseableHttpClient httpClient; |
| 196 | + if (deviceMap.containsKey(device) && deviceMap.get(device).protocol().equals(HTTPS)) { | ||
| 197 | + httpClient = getApacheSslBypassClient(); | ||
| 198 | + } else { | ||
| 199 | + httpClient = HttpClients.createDefault(); | ||
| 200 | + } | ||
| 201 | + int responseStatusCode = httpClient | ||
| 202 | + .execute(httprequest) | ||
| 185 | .getStatusLine() | 203 | .getStatusLine() |
| 186 | .getStatusCode(); | 204 | .getStatusCode(); |
| 187 | return checkStatusCode(responseStatusCode); | 205 | return checkStatusCode(responseStatusCode); |
| 188 | - } catch (IOException e) { | 206 | + } catch (IOException | NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { |
| 189 | - log.error("Cannot do PATCH {} request on device {} because can't read payload", | 207 | + log.error("Cannot do PATCH {} request on device {}", |
| 190 | - request, device); | 208 | + request, device, e); |
| 191 | } | 209 | } |
| 192 | return false; | 210 | return false; |
| 193 | } | 211 | } |
| ... | @@ -212,11 +230,35 @@ public class RestSBControllerImpl implements RestSBController { | ... | @@ -212,11 +230,35 @@ public class RestSBControllerImpl implements RestSBController { |
| 212 | } | 230 | } |
| 213 | 231 | ||
| 214 | private WebResource getWebResource(DeviceId device, String request) { | 232 | private WebResource getWebResource(DeviceId device, String request) { |
| 215 | - return Client.create().resource(deviceMap.get(device).protocol() + COLON + | 233 | + log.debug("Sending request to URL {} ", getUrlString(device, request)); |
| 216 | - DOUBLESLASH + | 234 | + WebResource webResource = client.resource(getUrlString(device, request)); |
| 217 | - deviceMap.get(device).ip().toString() + | 235 | + if (deviceMap.containsKey(device) && deviceMap.get(device).password() != null) { |
| 218 | - COLON + deviceMap.get(device).port() + | 236 | + client.addFilter(new HTTPBasicAuthFilter(deviceMap.get(device).name(), |
| 219 | - SLASH + request); | 237 | + deviceMap.get(device).password())); |
| 238 | + } | ||
| 239 | + return webResource; | ||
| 240 | + } | ||
| 241 | + | ||
| 242 | + //FIXME security issue: this trusts every SSL certificate, even if is self-signed. Also deprecated methods. | ||
| 243 | + private CloseableHttpClient getApacheSslBypassClient() throws NoSuchAlgorithmException, | ||
| 244 | + KeyManagementException, KeyStoreException { | ||
| 245 | + return HttpClients.custom(). | ||
| 246 | + setHostnameVerifier(new AllowAllHostnameVerifier()). | ||
| 247 | + setSslcontext(new SSLContextBuilder() | ||
| 248 | + .loadTrustMaterial(null, (arg0, arg1) -> true) | ||
| 249 | + .build()).build(); | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + private String getUrlString(DeviceId device, String request) { | ||
| 253 | + if (deviceMap.get(device).url() != null) { | ||
| 254 | + return deviceMap.get(device).protocol() + COLON + DOUBLESLASH | ||
| 255 | + + deviceMap.get(device).url() + request; | ||
| 256 | + } else { | ||
| 257 | + return deviceMap.get(device).protocol() + COLON + | ||
| 258 | + DOUBLESLASH + | ||
| 259 | + deviceMap.get(device).ip().toString() + | ||
| 260 | + COLON + deviceMap.get(device).port() + request; | ||
| 261 | + } | ||
| 220 | } | 262 | } |
| 221 | 263 | ||
| 222 | private boolean checkReply(ClientResponse response) { | 264 | private boolean checkReply(ClientResponse response) { |
| ... | @@ -233,7 +275,7 @@ public class RestSBControllerImpl implements RestSBController { | ... | @@ -233,7 +275,7 @@ public class RestSBControllerImpl implements RestSBController { |
| 233 | statusCode == STATUS_ACCEPTED) { | 275 | statusCode == STATUS_ACCEPTED) { |
| 234 | return true; | 276 | return true; |
| 235 | } else { | 277 | } else { |
| 236 | - log.error("Failed request: HTTP error code : " | 278 | + log.error("Failed request, HTTP error code : " |
| 237 | + statusCode); | 279 | + statusCode); |
| 238 | return false; | 280 | return false; |
| 239 | } | 281 | } | ... | ... |
| ... | @@ -39,8 +39,8 @@ public class RestSBControllerImplTest { | ... | @@ -39,8 +39,8 @@ public class RestSBControllerImplTest { |
| 39 | public void setUp() { | 39 | public void setUp() { |
| 40 | controller = new RestSBControllerImpl(); | 40 | controller = new RestSBControllerImpl(); |
| 41 | controller.activate(); | 41 | controller.activate(); |
| 42 | - device1 = new DefaultRestSBDevice(IpAddress.valueOf("127.0.0.1"), 8080, "foo", "bar", "http", true); | 42 | + device1 = new DefaultRestSBDevice(IpAddress.valueOf("127.0.0.1"), 8080, "foo", "bar", "http", null, true); |
| 43 | - device2 = new DefaultRestSBDevice(IpAddress.valueOf("127.0.0.2"), 8080, "foo1", "bar2", "http", true); | 43 | + device2 = new DefaultRestSBDevice(IpAddress.valueOf("127.0.0.2"), 8080, "foo1", "bar2", "http", null, true); |
| 44 | controller.addDevice(device1); | 44 | controller.addDevice(device1); |
| 45 | } | 45 | } |
| 46 | 46 | ... | ... |
| ... | @@ -49,9 +49,14 @@ import org.onosproject.protocol.rest.RestSBController; | ... | @@ -49,9 +49,14 @@ import org.onosproject.protocol.rest.RestSBController; |
| 49 | import org.onosproject.protocol.rest.RestSBDevice; | 49 | import org.onosproject.protocol.rest.RestSBDevice; |
| 50 | import org.slf4j.Logger; | 50 | import org.slf4j.Logger; |
| 51 | 51 | ||
| 52 | +import javax.net.ssl.HttpsURLConnection; | ||
| 52 | import java.io.IOException; | 53 | import java.io.IOException; |
| 53 | import java.net.HttpURLConnection; | 54 | import java.net.HttpURLConnection; |
| 54 | import java.net.URL; | 55 | import java.net.URL; |
| 56 | +import java.nio.charset.StandardCharsets; | ||
| 57 | +import java.security.KeyManagementException; | ||
| 58 | +import java.security.NoSuchAlgorithmException; | ||
| 59 | +import java.util.Base64; | ||
| 55 | import java.util.HashSet; | 60 | import java.util.HashSet; |
| 56 | import java.util.Set; | 61 | import java.util.Set; |
| 57 | 62 | ||
| ... | @@ -71,6 +76,10 @@ public class RestDeviceProvider extends AbstractProvider | ... | @@ -71,6 +76,10 @@ public class RestDeviceProvider extends AbstractProvider |
| 71 | private static final String PROVIDER = "org.onosproject.provider.rest.device"; | 76 | private static final String PROVIDER = "org.onosproject.provider.rest.device"; |
| 72 | private static final String IPADDRESS = "ipaddress"; | 77 | private static final String IPADDRESS = "ipaddress"; |
| 73 | private static final int TEST_CONNECT_TIMEOUT = 1000; | 78 | private static final int TEST_CONNECT_TIMEOUT = 1000; |
| 79 | + private static final String HTTPS = "https"; | ||
| 80 | + private static final String AUTHORIZATION_PROPERTY = "authorization"; | ||
| 81 | + private static final String BASIC_AUTH_PREFIX = "Basic "; | ||
| 82 | + private static final String URL_SEPARATOR = "://"; | ||
| 74 | private final Logger log = getLogger(getClass()); | 83 | private final Logger log = getLogger(getClass()); |
| 75 | 84 | ||
| 76 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 85 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| ... | @@ -202,7 +211,7 @@ public class RestDeviceProvider extends AbstractProvider | ... | @@ -202,7 +211,7 @@ public class RestDeviceProvider extends AbstractProvider |
| 202 | } catch (ConfigException e) { | 211 | } catch (ConfigException e) { |
| 203 | log.error("Configuration error {}", e); | 212 | log.error("Configuration error {}", e); |
| 204 | } | 213 | } |
| 205 | - log.info("REST Devices {}", controller.getDevices()); | 214 | + log.debug("REST Devices {}", controller.getDevices()); |
| 206 | controller.getDevices().keySet().forEach(deviceId -> { | 215 | controller.getDevices().keySet().forEach(deviceId -> { |
| 207 | DriverHandler h = driverService.createHandler(deviceId); | 216 | DriverHandler h = driverService.createHandler(deviceId); |
| 208 | PortDiscovery portConfig = h.behaviour(PortDiscovery.class); | 217 | PortDiscovery portConfig = h.behaviour(PortDiscovery.class); |
| ... | @@ -216,14 +225,39 @@ public class RestDeviceProvider extends AbstractProvider | ... | @@ -216,14 +225,39 @@ public class RestDeviceProvider extends AbstractProvider |
| 216 | 225 | ||
| 217 | private boolean testDeviceConnection(RestSBDevice device) { | 226 | private boolean testDeviceConnection(RestSBDevice device) { |
| 218 | try { | 227 | try { |
| 219 | - URL url = new URL(device.protocol(), device.ip().toString(), device.port(), "/"); | 228 | + URL url; |
| 220 | - HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); | 229 | + if (device.url() == null) { |
| 230 | + url = new URL(device.protocol(), device.ip().toString(), device.port(), ""); | ||
| 231 | + } else { | ||
| 232 | + url = new URL(device.protocol() + URL_SEPARATOR + device.url()); | ||
| 233 | + } | ||
| 234 | + HttpURLConnection urlConn; | ||
| 235 | + if (device.protocol().equals(HTTPS)) { | ||
| 236 | + //FIXME this method provides no security accepting all SSL certs. | ||
| 237 | + RestDeviceProviderUtilities.enableSslCert(); | ||
| 238 | + | ||
| 239 | + urlConn = (HttpsURLConnection) url.openConnection(); | ||
| 240 | + } else { | ||
| 241 | + urlConn = (HttpURLConnection) url.openConnection(); | ||
| 242 | + } | ||
| 243 | + if (device.password() != null) { | ||
| 244 | + String userPassword = device.name() + ":" + device.password(); | ||
| 245 | + String basicAuth = Base64.getEncoder() | ||
| 246 | + .encodeToString(userPassword.getBytes(StandardCharsets.UTF_8)); | ||
| 247 | + urlConn.setRequestProperty(AUTHORIZATION_PROPERTY, BASIC_AUTH_PREFIX + basicAuth); | ||
| 248 | + } | ||
| 221 | urlConn.setConnectTimeout(TEST_CONNECT_TIMEOUT); | 249 | urlConn.setConnectTimeout(TEST_CONNECT_TIMEOUT); |
| 222 | - boolean open = urlConn.getResponseCode() == (HttpURLConnection.HTTP_OK); | 250 | + boolean open = urlConn.getResponseCode() == (HttpsURLConnection.HTTP_OK); |
| 251 | + if (!open) { | ||
| 252 | + log.error("Device {} not accessibile, response code {} ", device, | ||
| 253 | + urlConn.getResponseCode()); | ||
| 254 | + } | ||
| 223 | urlConn.disconnect(); | 255 | urlConn.disconnect(); |
| 224 | return open; | 256 | return open; |
| 225 | - } catch (IOException e) { | 257 | + |
| 226 | - log.error("Device {} not reachable, error creating HTTP connection", device, e); | 258 | + } catch (IOException | NoSuchAlgorithmException | KeyManagementException e) { |
| 259 | + log.error("Device {} not reachable, error creating {} connection", device, | ||
| 260 | + device.protocol(), e); | ||
| 227 | } | 261 | } |
| 228 | return false; | 262 | return false; |
| 229 | } | 263 | } | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2016 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.provider.rest.device.impl; | ||
| 18 | + | ||
| 19 | +import javax.net.ssl.HttpsURLConnection; | ||
| 20 | +import javax.net.ssl.KeyManager; | ||
| 21 | +import javax.net.ssl.SSLContext; | ||
| 22 | +import javax.net.ssl.TrustManager; | ||
| 23 | +import javax.net.ssl.X509TrustManager; | ||
| 24 | +import java.security.KeyManagementException; | ||
| 25 | +import java.security.NoSuchAlgorithmException; | ||
| 26 | +import java.security.SecureRandom; | ||
| 27 | +import java.security.cert.CertificateException; | ||
| 28 | +import java.security.cert.X509Certificate; | ||
| 29 | + | ||
| 30 | +/** | ||
| 31 | + * Utilities class for RestDevice provider. | ||
| 32 | + */ | ||
| 33 | +final class RestDeviceProviderUtilities { | ||
| 34 | + | ||
| 35 | + private static final String TLS = "TLS"; | ||
| 36 | + | ||
| 37 | + //disable construction. | ||
| 38 | + private RestDeviceProviderUtilities(){} | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * Method that bypasses every SSL certificate verification and accepts every | ||
| 42 | + * connection with any SSL protected device that ONOS has an interaction with. | ||
| 43 | + * Needs addressing for secutirty purposes. | ||
| 44 | + * | ||
| 45 | + * @throws NoSuchAlgorithmException | ||
| 46 | + * @throws KeyManagementException | ||
| 47 | + */ | ||
| 48 | + //FIXME redo for security purposes. | ||
| 49 | + protected static void enableSslCert() throws NoSuchAlgorithmException, KeyManagementException { | ||
| 50 | + SSLContext ctx = SSLContext.getInstance(TLS); | ||
| 51 | + ctx.init(new KeyManager[0], new TrustManager[]{new DefaultTrustManager()}, new SecureRandom()); | ||
| 52 | + SSLContext.setDefault(ctx); | ||
| 53 | + HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> { | ||
| 54 | + //FIXME better way to do this. | ||
| 55 | + return true; | ||
| 56 | + }); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + //FIXME this accepts every connection | ||
| 60 | + private static class DefaultTrustManager implements X509TrustManager { | ||
| 61 | + | ||
| 62 | + @Override | ||
| 63 | + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + @Override | ||
| 67 | + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + @Override | ||
| 71 | + public X509Certificate[] getAcceptedIssuers() { | ||
| 72 | + return null; | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | +} |
| ... | @@ -42,6 +42,7 @@ public class RestProviderConfig extends Config<ApplicationId> { | ... | @@ -42,6 +42,7 @@ public class RestProviderConfig extends Config<ApplicationId> { |
| 42 | private static final String NAME = "name"; | 42 | private static final String NAME = "name"; |
| 43 | private static final String PASSWORD = "password"; | 43 | private static final String PASSWORD = "password"; |
| 44 | private static final String PROTOCOL = "protocol"; | 44 | private static final String PROTOCOL = "protocol"; |
| 45 | + private static final String URL = "url"; | ||
| 45 | 46 | ||
| 46 | public Set<RestSBDevice> getDevicesAddresses() throws ConfigException { | 47 | public Set<RestSBDevice> getDevicesAddresses() throws ConfigException { |
| 47 | Set<RestSBDevice> devicesAddresses = Sets.newHashSet(); | 48 | Set<RestSBDevice> devicesAddresses = Sets.newHashSet(); |
| ... | @@ -54,8 +55,10 @@ public class RestProviderConfig extends Config<ApplicationId> { | ... | @@ -54,8 +55,10 @@ public class RestProviderConfig extends Config<ApplicationId> { |
| 54 | String name = node.path(NAME).asText(); | 55 | String name = node.path(NAME).asText(); |
| 55 | String password = node.path(PASSWORD).asText(); | 56 | String password = node.path(PASSWORD).asText(); |
| 56 | String protocol = node.path(PROTOCOL).asText(); | 57 | String protocol = node.path(PROTOCOL).asText(); |
| 58 | + String url = node.path(URL).asText(); | ||
| 57 | devicesAddresses.add(new DefaultRestSBDevice(ipAddr, port, name, | 59 | devicesAddresses.add(new DefaultRestSBDevice(ipAddr, port, name, |
| 58 | - password, protocol, false)); | 60 | + password, protocol, |
| 61 | + url, false)); | ||
| 59 | 62 | ||
| 60 | } | 63 | } |
| 61 | } catch (IllegalArgumentException e) { | 64 | } catch (IllegalArgumentException e) { | ... | ... |
| ... | @@ -9,8 +9,8 @@ | ... | @@ -9,8 +9,8 @@ |
| 9 | "apps": { | 9 | "apps": { |
| 10 | "org.onosproject.restsb": { | 10 | "org.onosproject.restsb": { |
| 11 | "restDevices": [{ | 11 | "restDevices": [{ |
| 12 | - "name": "local", | 12 | + "name": "dev", |
| 13 | - "password": "local", | 13 | + "password": "", |
| 14 | "ip": "127.0.0.1", | 14 | "ip": "127.0.0.1", |
| 15 | "port": 8080, | 15 | "port": 8080, |
| 16 | "protocol": "http" | 16 | "protocol": "http" | ... | ... |
-
Please register or login to post a comment