org.eclipse.leshan.server.cluster.RedisSecurityStore Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2016 Sierra Wireless and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Sierra Wireless - initial API and implementation
*******************************************************************************/
package org.eclipse.leshan.server.cluster;
import java.util.Collection;
import java.util.LinkedList;
import org.eclipse.leshan.server.cluster.serialization.SecurityInfoSerDes;
import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.eclipse.leshan.server.security.SecurityStore;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import redis.clients.util.Pool;
/**
* A {@link SecurityStore} implementation based on Redis.
*
* Security info are stored using the endpoint as primary key and a secondary index is created for psk-identity lookup.
*/
public class RedisSecurityStore implements EditableSecurityStore {
private static final String SEC_EP = "SEC#EP#";
private static final String PSKID_SEC = "PSKID#SEC";
private final Pool pool;
public RedisSecurityStore(Pool pool) {
this.pool = pool;
}
@Override
public SecurityInfo getByEndpoint(String endpoint) {
try (Jedis j = pool.getResource()) {
byte[] data = j.get((SEC_EP + endpoint).getBytes());
if (data == null) {
return null;
} else {
return deserialize(data);
}
}
}
@Override
public SecurityInfo getByIdentity(String identity) {
try (Jedis j = pool.getResource()) {
String ep = j.hget(PSKID_SEC, identity);
if (ep == null) {
return null;
} else {
byte[] data = j.get((SEC_EP + ep).getBytes());
if (data == null) {
return null;
} else {
return deserialize(data);
}
}
}
}
@Override
public Collection getAll() {
try (Jedis j = pool.getResource()) {
ScanParams params = new ScanParams().match(SEC_EP + "*").count(100);
Collection list = new LinkedList<>();
String cursor = "0";
do {
ScanResult res = j.scan(cursor.getBytes(), params);
for (byte[] key : res.getResult()) {
byte[] element = j.get(key);
list.add(deserialize(element));
}
cursor = res.getStringCursor();
} while (!"0".equals(cursor));
return list;
}
}
@Override
public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException {
byte[] data = serialize(info);
try (Jedis j = pool.getResource()) {
if (info.getIdentity() != null) {
// populate the secondary index (security info by PSK id)
String oldEndpoint = j.hget(PSKID_SEC, info.getIdentity());
if (oldEndpoint != null && !oldEndpoint.equals(info.getEndpoint())) {
throw new NonUniqueSecurityInfoException("PSK Identity " + info.getIdentity() + " is already used");
}
j.hset(PSKID_SEC.getBytes(), info.getIdentity().getBytes(), info.getEndpoint().getBytes());
}
byte[] previousData = j.getSet((SEC_EP + info.getEndpoint()).getBytes(), data);
SecurityInfo previous = previousData == null ? null : deserialize(previousData);
String previousIdentity = previous == null ? null : previous.getIdentity();
if (previousIdentity != null && !previousIdentity.equals(info.getIdentity())) {
j.hdel(PSKID_SEC, previousIdentity);
}
return previous;
}
}
@Override
public SecurityInfo remove(String endpoint) {
try (Jedis j = pool.getResource()) {
byte[] data = j.get((SEC_EP + endpoint).getBytes());
if (data != null) {
SecurityInfo info = deserialize(data);
if (info.getIdentity() != null) {
j.hdel(PSKID_SEC.getBytes(), info.getIdentity().getBytes());
}
j.del((SEC_EP + endpoint).getBytes());
return info;
}
}
return null;
}
private byte[] serialize(SecurityInfo secInfo) {
return SecurityInfoSerDes.serialize(secInfo);
}
private SecurityInfo deserialize(byte[] data) {
return SecurityInfoSerDes.deserialize(data);
}
}