diff --git a/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/LeshanServer.java b/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/LeshanServer.java index d9a31460f4..2654e27ef6 100644 --- a/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/LeshanServer.java +++ b/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/LeshanServer.java @@ -163,7 +163,7 @@ public LeshanServer(LwM2mServerEndpointsProvider endpointsProvider, Registration presenceService = createPresenceService(registrationService, awakeTimeProvider, updateRegistrationOnNotification); } - this.sendService = createSendHandler(registrationStore, updateRegistrationOnSend); + this.sendService = createSendHandler(registrationStore, authorizer, updateRegistrationOnSend); // create endpoints ServerEndpointToolbox toolbox = new ServerEndpointToolbox(decoder, encoder, linkParser, @@ -202,8 +202,9 @@ protected PresenceServiceImpl createPresenceService(RegistrationService registra return presenceService; } - protected SendHandler createSendHandler(RegistrationStore registrationStore, boolean updateRegistrationOnSend) { - return new SendHandler(registrationStore, updateRegistrationOnSend); + protected SendHandler createSendHandler(RegistrationStore registrationStore, Authorizer authorizer, + boolean updateRegistrationOnSend) { + return new SendHandler(registrationStore, authorizer, updateRegistrationOnSend); } protected UplinkDeviceManagementRequestReceiver createRequestReceiver(RegistrationHandler registrationHandler, diff --git a/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/security/DefaultAuthorizer.java b/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/security/DefaultAuthorizer.java index 6d434cacb8..60c056ae0c 100644 --- a/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/security/DefaultAuthorizer.java +++ b/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/security/DefaultAuthorizer.java @@ -17,7 +17,9 @@ import org.eclipse.leshan.core.endpoint.EndpointUri; import org.eclipse.leshan.core.peer.LwM2mPeer; +import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; +import org.eclipse.leshan.core.request.UpdateRequest; import org.eclipse.leshan.core.request.UplinkRequest; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.servers.security.Authorization; @@ -72,15 +74,30 @@ protected boolean checkEndpointUri(UplinkRequest request, Registration regist protected Authorization checkIdentity(UplinkRequest request, Registration registration, LwM2mPeer sender, EndpointUri endpointUri) { - // do we have security information for this client? - SecurityInfo expectedSecurityInfo = null; - if (securityStore != null) - expectedSecurityInfo = securityStore.getByEndpoint(registration.getEndpoint()); - if (securityChecker.checkSecurityInfo(registration.getEndpoint(), sender, expectedSecurityInfo)) { - return Authorization.approved(); + if (request instanceof RegisterRequest || request instanceof UpdateRequest + || request instanceof DeregisterRequest) { + + // For Register, Update, DeregisterRequest we check in security store + + // do we have security information for this client? + SecurityInfo expectedSecurityInfo = null; + if (securityStore != null) + expectedSecurityInfo = securityStore.getByEndpoint(registration.getEndpoint()); + + if (securityChecker.checkSecurityInfo(registration.getEndpoint(), sender, expectedSecurityInfo)) { + return Authorization.approved(); + } else { + return Authorization.declined(); + } } else { - return Authorization.declined(); + + // for other we just check this is same identity + if (registration.getClientTransportData().getIdentity().equals(sender.getIdentity())) { + return Authorization.approved(); + } else { + return Authorization.declined(); + } } } } diff --git a/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/send/SendHandler.java b/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/send/SendHandler.java index 278308352c..7a58800d99 100644 --- a/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/send/SendHandler.java +++ b/leshan-lwm2m-server/src/main/java/org/eclipse/leshan/server/send/SendHandler.java @@ -19,12 +19,14 @@ import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; +import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.endpoint.EndpointUri; import org.eclipse.leshan.core.node.LwM2mNode; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.TimestampedLwM2mNodes; import org.eclipse.leshan.core.peer.LwM2mPeer; import org.eclipse.leshan.core.request.SendRequest; +import org.eclipse.leshan.core.request.UpdateRequest; import org.eclipse.leshan.core.request.exception.InvalidRequestException; import org.eclipse.leshan.core.response.SendResponse; import org.eclipse.leshan.core.response.SendableResponse; @@ -32,6 +34,8 @@ import org.eclipse.leshan.server.registration.RegistrationStore; import org.eclipse.leshan.server.registration.RegistrationUpdate; import org.eclipse.leshan.server.registration.UpdatedRegistration; +import org.eclipse.leshan.server.security.Authorizer; +import org.eclipse.leshan.servers.security.Authorization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,12 +49,14 @@ public class SendHandler implements SendService { private final Logger LOG = LoggerFactory.getLogger(SendHandler.class); private final RegistrationStore registrationStore; + private final Authorizer authorizer; private final boolean updateRegistrationOnSend; private final List listeners = new CopyOnWriteArrayList<>();; - public SendHandler(RegistrationStore registrationStore, boolean updateRegistrationOnSend) { + public SendHandler(RegistrationStore registrationStore, Authorizer authorizer, boolean updateRegistrationOnSend) { this.registrationStore = registrationStore; + this.authorizer = authorizer; this.updateRegistrationOnSend = updateRegistrationOnSend; } @@ -67,47 +73,69 @@ public void removeListener(SendListener listener) { public SendableResponse handleSend(LwM2mPeer sender, Registration registration, final SendRequest request, EndpointUri serverEndpointUri) { - // try to update registration if needed + // Try to update registration if needed final Registration updatedRegistration; try { - updatedRegistration = updateRegistration(sender, registration); + updatedRegistration = updateRegistration(sender, registration, request, serverEndpointUri); + if (updatedRegistration == null) { + return errorReponse(updatedRegistration, ResponseCode.BAD_REQUEST, "not authorized", null); + } } catch (Exception e) { - String errMsg = "unable to update registration"; - SendableResponse response = new SendableResponse<>(SendResponse.internalServerError(errMsg), - new Runnable() { - @Override - public void run() { - onError(registration, errMsg, e); - } - }); - return response; + return errorReponse(registration, ResponseCode.INTERNAL_SERVER_ERROR, "unable to update registration", e); + } + + // Check if send request is allowed + Authorization authorized = authorizer.isAuthorized(request, registration, sender, serverEndpointUri); + if (authorized.isDeclined()) { + return errorReponse(updatedRegistration, ResponseCode.BAD_REQUEST, "not authorized", null); } - // Send Response to send request on success + // Validate and create Send Response final SendResponse sendResponse = validateSendRequest(updatedRegistration, request); - SendableResponse response = new SendableResponse<>(sendResponse, new Runnable() { - - @Override - public void run() { - if (sendResponse.isSuccess()) { - fireDataReceived(updatedRegistration, request.getTimestampedNodes(), request); - } else { - onError(updatedRegistration, String.format("Invalid Send Request, server returns %s %s", // - sendResponse.getCode().getName(), // - sendResponse.getErrorMessage() != null ? "because" + sendResponse.getErrorMessage() : ""), - new InvalidRequestException( - sendResponse.getErrorMessage() != null ? sendResponse.getErrorMessage() - : "unknown reason")); - } - } - }); + SendableResponse response; + if (sendResponse.isSuccess()) { + response = new SendableResponse<>(sendResponse, new Runnable() { + @Override + public void run() { + if (sendResponse.isSuccess()) { + fireDataReceived(updatedRegistration, request.getTimestampedNodes(), request); + } + } + }); + } else { + response = errorReponse(updatedRegistration, // + sendResponse.getCode(), // + String.format("Invalid Send Request, server returns %s %s", // + sendResponse.getCode().getName(), // + sendResponse.getErrorMessage() != null ? "because" + sendResponse.getErrorMessage() : ""), // + new InvalidRequestException(sendResponse.getErrorMessage() != null ? sendResponse.getErrorMessage() + : "unknown reason")); + } return response; } - private Registration updateRegistration(LwM2mPeer sender, final Registration registration) { + /** + * Update registration if needed and allowed by authorizer. + * + * Note that updating registration on send is out of specification and could be a problem for interoperability. + * + * @return the registration or the updated registration or null if not allowed to update. + */ + protected Registration updateRegistration(LwM2mPeer sender, final Registration registration, + final SendRequest request, EndpointUri endpointUri) { if (updateRegistrationOnSend) { + + // check if update is allowed + Authorization authorized = authorizer.isAuthorized( + new UpdateRequest(registration.getId(), null, null, null, null, null), registration, sender, + endpointUri); + if (authorized.isDeclined()) { + return null; + } + + // update registration RegistrationUpdate regUpdate = new RegistrationUpdate(registration.getId(), sender, null, null, null, null, null, null, null, null, null, null); UpdatedRegistration updatedRegistration = registrationStore.updateRegistration(regUpdate); @@ -156,4 +184,17 @@ protected SendResponse validateSendRequest(Registration registration, SendReques } return SendResponse.success(); } + + protected SendableResponse errorReponse(Registration registration, ResponseCode code, + String errorMessage, Exception e) { + + SendableResponse response = new SendableResponse<>(new SendResponse(code, errorMessage), + new Runnable() { + @Override + public void run() { + onError(registration, errorMessage, e); + } + }); + return response; + } }