Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Datamanager #326

Merged
merged 21 commits into from
Jul 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ public class CommonConstants {
public static final String CBOR = "CBOR";
public static final String HTTP_SECURE_JSON = HTTP + "-SECURE-" + JSON;
public static final String HTTP_INSECURE_JSON = HTTP + "-INSECURE-" + JSON;
public static final String WS_SECURE_JSON = WS + "-SECURE-" + JSON;
public static final String WS_INSECURE_JSON = WS + "-INSECURE-" + JSON;
public static final String UNKNOWN_ORIGIN = "<unknown>";

public static final String SERVICE_REGISTRY_ADDRESS = "sr_address";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import org.springframework.util.Assert;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;
import org.springframework.http.server.ServletServerHttpRequest;

@Component
public class SecurityUtilities {
Expand Down Expand Up @@ -109,6 +110,14 @@ public static String getCertificateCNFromRequest(final HttpServletRequest reques
return null;
}

//-------------------------------------------------------------------------------------------------
public static String getCertificateCNFromServerRequest(final ServletServerHttpRequest request) {
Assert.notNull(request, "request must not be null");
final HttpServletRequest servletRequest = request.getServletRequest();

return getCertificateCNFromRequest(servletRequest);
}

//-------------------------------------------------------------------------------------------------
private static String getCommonNameFromCloudCertificate(final Principal principal) {
Assert.notNull(principal, "Principal must not be null");
Expand Down
1 change: 1 addition & 0 deletions datamanager/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<includes>
<include>application.properties</include>
<include>log4j2.xml</include>
<include>accesslist.acl</include>
</includes>
</resource>
</resources>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Contributors:
* {Lulea University of Technology} - implementation
* Arrowhead Consortia - conceptualization
* Arrowhead Consortia - conceptualization
********************************************************************************/
package eu.arrowhead.core.datamanager;

Expand Down Expand Up @@ -59,6 +59,7 @@
import eu.arrowhead.common.exception.DataNotFoundException;
import eu.arrowhead.common.exception.InvalidParameterException;
import eu.arrowhead.core.datamanager.database.service.DataManagerDBService;
import eu.arrowhead.core.datamanager.service.DataManagerDriver;
import eu.arrowhead.core.datamanager.service.ProxyService;
import eu.arrowhead.core.datamanager.service.ProxyElement;
import eu.arrowhead.core.datamanager.service.HistorianService;
Expand Down Expand Up @@ -90,12 +91,15 @@ public class DataManagerController {
@Autowired
private HistorianService historianService;

@Autowired
private DataManagerDriver dataManagerDriver;

@Autowired
private DataManagerDBService dataManagerDBService;

//=================================================================================================
// methods

//-------------------------------------------------------------------------------------------------
@ApiOperation(value = "Return an echo message with the purpose of testing the core service availability", response = String.class, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT })
@ApiResponses (value = {
Expand Down Expand Up @@ -167,9 +171,9 @@ public class DataManagerController {
@RequestParam MultiValueMap<String, String> params
) {

if(Utilities.isEmpty(systemName) || Utilities.isEmpty(serviceName)) {
throw new InvalidParameterException(OP_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, CommonConstants.OP_DATAMANAGER_HISTORIAN);
}
if(Utilities.isEmpty(systemName) || Utilities.isEmpty(serviceName)) {
throw new InvalidParameterException(OP_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, CommonConstants.OP_DATAMANAGER_HISTORIAN);
}
logger.debug("historianServiceGet for {}/{}", systemName, serviceName);

double from=-1, to=-1;
Expand Down Expand Up @@ -256,7 +260,7 @@ public class DataManagerController {
}
logger.debug("historianServicePut for {}/{}", systemName, serviceName);

validateSenMLMessage(systemName, serviceName, message);
dataManagerDriver.validateSenMLMessage(systemName, serviceName, message);

historianService.createEndpoint(systemName, serviceName);

Expand All @@ -265,7 +269,7 @@ public class DataManagerController {
head.setBt((double)System.currentTimeMillis() / 1000);
}

validateSenMLContent(message);
dataManagerDriver.validateSenMLContent(message);

final boolean statusCode = historianService.updateEndpoint(systemName, serviceName, message);
if (!statusCode) {
Expand Down Expand Up @@ -362,14 +366,14 @@ public class DataManagerController {
}
logger.debug("proxyServicePut for {}/{}", systemName, serviceName);

validateSenMLMessage(systemName, serviceName, message);
dataManagerDriver.validateSenMLMessage(systemName, serviceName, message);

SenML head = message.firstElement();
if(head.getBt() == null) {
head.setBt((double)System.currentTimeMillis() / 1000);
}

validateSenMLContent(message);
dataManagerDriver.validateSenMLContent(message);

final ProxyElement pe = proxyService.getEndpointFromService(systemName, serviceName);
if (pe == null) {
Expand All @@ -388,82 +392,4 @@ public class DataManagerController {
//=================================================================================================
// assistant methods


//=================================================================================================
private void validateSenMLMessage(String systemName, String serviceName, Vector<SenML> message) {
try {
Assert.notNull(systemName, "systemName is null.");
Assert.notNull(serviceName, "serviceName is null.");
Assert.notNull(message, "message is null.");
Assert.isTrue(!message.isEmpty(), "message is empty");

SenML head = (SenML)message.get(0);
Assert.notNull(head.getBn(), "bn is null.");
} catch(Exception e){
throw new BadPayloadException("Missing mandatory field");
}
}

//-------------------------------------------------------------------------------------------------
public void validateSenMLContent(final Vector<SenML> message) {
try {

/* check that bn, bt and bu are included only once, and in the first object */
Iterator<SenML> entry = message.iterator();
int bnc=0, btc=0, buc=0;
while (entry.hasNext()) {
SenML element = entry.next();
if (element.getBn() != null) {
bnc++;
}
if (element.getBt() != null) {
btc++;
}
if (element.getBu() != null) {
buc++;
}
}

/* bu can only exist once. bt can only exist one, bu can exist 0 or 1 times */
Assert.isTrue(!(bnc != 1 || btc != 1 || buc > 1), "invalid bn/bt/bu");

/* bn must exist in [0] */
SenML element = (SenML)message.get(0);
Assert.notNull(element.getBn(), "bn is missing");

/* bt must exist in [0] */
Assert.notNull(element.getBt(), "bt is missing");

/* bt cannot be negative */
Assert.isTrue(element.getBt() >= 0.0, "a negative base time is not allowed");

/* bu must exist in [0], if it exists */
Assert.isTrue(!(element.getBu() == null && buc == 1), "invalid use of bu");

/* check that v, bv, sv, etc are included only once per object */
entry = message.iterator();
while (entry.hasNext()) {
element = (SenML)entry.next();

int valueCount = 0;
if (element.getV() != null) {
valueCount++;
}
if (element.getVs() != null) {
valueCount++;
}
if (element.getVd() != null) {
valueCount++;
}
if (element.getVb() != null) {
valueCount++;
}

Assert.isTrue(!(valueCount > 1 && element.getS() == null), "too many value tags");
}
} catch(Exception e) {
throw new BadPayloadException("Illegal request");
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/********************************************************************************
* Copyright (c) 2021 {Lulea University of Technology}
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* {Lulea University of Technology} - implementation
* Arrowhead Consortia - conceptualization
********************************************************************************/
package eu.arrowhead.core.datamanager;

import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import eu.arrowhead.common.SecurityUtilities;
import eu.arrowhead.common.CommonConstants;
import eu.arrowhead.core.datamanager.HistorianWSHandler;
import eu.arrowhead.core.datamanager.security.DatamanagerACLFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;


@Configuration
@EnableWebSocket
public class DataManagerWSConfig implements WebSocketConfigurer {

private final Logger logger = LogManager.getLogger(DataManagerWSConfig.class);

@Value("${server.ssl.enabled}")
private boolean sslEnabled;

@Value("${websockets.enabled}")
private boolean websocketsEnabled;

@Autowired
HistorianWSHandler historianWSHandler;

@Autowired
DatamanagerACLFilter dmACLFilter;

@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
if (websocketsEnabled) {
logger.info("WebSocket support enabled");
webSocketHandlerRegistry.addHandler(historianWSHandler, CommonConstants.DATAMANAGER_URI + CommonConstants.OP_DATAMANAGER_HISTORIAN + "/ws/*/*").addInterceptors(auctionInterceptor());
} else {
logger.info("WebSocket support disabled");
}
}

@Bean
public HandshakeInterceptor auctionInterceptor() {
return new HandshakeInterceptor() {
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {

String path = request.getURI().getPath();
final String serviceId = path.substring(path.lastIndexOf('/') + 1);
path = path.substring(0, path.lastIndexOf('/'));
final String systemId = path.substring(path.lastIndexOf('/') + 1);
String CN = null;

// if running in secure mode, check authorization (ACL)
if(sslEnabled) {
if (request instanceof org.springframework.http.server.ServletServerHttpRequest) {
CN = SecurityUtilities.getCertificateCNFromServerRequest((ServletServerHttpRequest)request);
if(CN == null) {
logger.info("No valid client certificate found");
return false;
}
attributes.put("CN", CN);
} else {
return false;
}
}

// Add to the websocket session
attributes.put("systemId", systemId);
attributes.put("serviceId", serviceId);

return true;
}

public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
// tbd
}

};
}
}

Loading