Skip to content

Commit

Permalink
#322 : avoid duplicate PSK identity in bsserver-demo
Browse files Browse the repository at this point in the history
  • Loading branch information
sbernard31 committed Feb 7, 2020
1 parent f9e0627 commit e2872d2
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 8 deletions.
Expand Up @@ -34,16 +34,18 @@
import org.slf4j.LoggerFactory;

/**
* A {@link BootstrapSecurityStore} which use a {@link BootstrapConfigStore} to device credentials.
* A {@link BootstrapSecurityStore} which uses a {@link BootstrapConfigStore} to device credentials.
* <p>
* Generally, a {@link BootstrapSecurityStore} contains information about how a device should connect to server (using
* psk, rpk or x509 ). And a {@link BootstrapConfigStore} contains configuration which should be written on device
* during bootstrap session.
* <p>
* This {@link BootstrapSecurityStore} will search in {@link BootstrapConfigStore} to find security info.
* <p>
*
* WARNING : This store is not production ready.
* {@link #getByIdentity(String)} could have some performance issue and strange behavior if you have several config with
* same identity. (which is possible if you are using same identity for several bootstrap server)
* <p>
* <strong>WARNING : This store is not production ready.</strong>
*/
public class BootstrapConfigSecurityStore implements BootstrapSecurityStore {

Expand All @@ -61,8 +63,11 @@ public BootstrapConfigSecurityStore(EditableBootstrapConfigStore bootstrapConfig
@Override
public SecurityInfo getByIdentity(String identity) {
byte[] identityBytes = identity.getBytes(StandardCharsets.UTF_8);

// Acceptable for a demo but iterate over all the store to get PSK is not really acceptable for a production
// server.
// This could behave strangely if there is several config using same identity but with different bootstrap
// server.
for (Map.Entry<String, BootstrapConfig> e : bootstrapConfigStore.getAll().entrySet()) {
BootstrapConfig bsConfig = e.getValue();
if (bsConfig.security != null) {
Expand Down
Expand Up @@ -138,7 +138,7 @@ protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws

String endpoint = path[0];

if (bsStore.remove(endpoint) == null) {
if (bsStore.remove(endpoint) != null) {
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
} else {
sendError(resp, HttpServletResponse.SC_NOT_FOUND, "no config for " + endpoint);
Expand Down
Expand Up @@ -19,39 +19,121 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.leshan.SecurityMode;
import org.eclipse.leshan.core.request.Identity;
import org.eclipse.leshan.server.bootstrap.BootstrapConfig.ServerSecurity;

/**
* Simple bootstrap store implementation storing bootstrap configuration information in memory.
*/
public class InMemoryBootstrapConfigStore implements EditableBootstrapConfigStore {

protected final ConfigurationChecker configChecker = new ConfigurationChecker();
protected final Map<String, BootstrapConfig> bootstrapByEndpoint = new ConcurrentHashMap<>();

protected final Map<String /* endpoint */, BootstrapConfig> bootstrapByEndpoint = new ConcurrentHashMap<>();
protected final ConcurrentHashMap<PskByServer, BootstrapConfig> bootstrapByPskId = new ConcurrentHashMap<>();

@Override
public BootstrapConfig get(String endpoint, Identity deviceIdentity, BootstrapSession session) {
return bootstrapByEndpoint.get(endpoint);
}

@Override
public void add(String endpoint, BootstrapConfig config) throws InvalidConfigurationException {
public synchronized void add(String endpoint, BootstrapConfig config) throws InvalidConfigurationException {
checkConfig(endpoint, config);

// Check PSK identity uniqueness for bootstrap server:
PskByServer pskToAdd = getBootstrapPskIdentity(config);
if (pskToAdd != null) {
BootstrapConfig existingConfig = bootstrapByPskId.get(pskToAdd);
if (existingConfig != null) {
// check if this config will be replace by the new one.
BootstrapConfig previousConfig = bootstrapByEndpoint.get(endpoint);
if (previousConfig != existingConfig) {
throw new InvalidConfigurationException(
"Psk identity [%s] already used for this bootstrap server [%s]", pskToAdd.identity,
pskToAdd.serverUrl);
}
}
}
// TODO we should probably also check lwm2m server

bootstrapByEndpoint.put(endpoint, config);
if (pskToAdd != null) {
bootstrapByPskId.put(pskToAdd, config);
}
}

protected void checkConfig(String endpoint, BootstrapConfig config) throws InvalidConfigurationException {
configChecker.verify(config);
}

@Override
public BootstrapConfig remove(String enpoint) {
return bootstrapByEndpoint.remove(enpoint);
public synchronized BootstrapConfig remove(String enpoint) {
BootstrapConfig bootstrapConfig = bootstrapByEndpoint.remove(enpoint);
if (bootstrapConfig != null) {
PskByServer pskIdentity = getBootstrapPskIdentity(bootstrapConfig);
if (pskIdentity != null) {
bootstrapByPskId.remove(pskIdentity, bootstrapConfig);
}
}
return bootstrapConfig;
}

protected PskByServer getBootstrapPskIdentity(BootstrapConfig config) {
for (ServerSecurity security : config.security.values()) {
if (security.bootstrapServer) {
if (security.securityMode == SecurityMode.PSK) {
return new PskByServer(security.uri, new String(security.publicKeyOrId));
}
}
}
return null;
}

@Override
public Map<String, BootstrapConfig> getAll() {
return Collections.unmodifiableMap(bootstrapByEndpoint);
}

protected static class PskByServer {
public String serverUrl;
public String identity;

public PskByServer(String serverUrl, String identity) {
this.serverUrl = serverUrl;
this.identity = identity;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((identity == null) ? 0 : identity.hashCode());
result = prime * result + ((serverUrl == null) ? 0 : serverUrl.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PskByServer other = (PskByServer) obj;
if (identity == null) {
if (other.identity != null)
return false;
} else if (!identity.equals(other.identity))
return false;
if (serverUrl == null) {
if (other.serverUrl != null)
return false;
} else if (!serverUrl.equals(other.serverUrl))
return false;
return true;
}
}
}

0 comments on commit e2872d2

Please sign in to comment.