Synchronize reads and writes in Spiffe SVID Manager

Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>
This commit is contained in:
Max Lambrecht 2018-08-17 10:11:07 -03:00
parent 0a2fc88078
commit fdff8485cf
4 changed files with 55 additions and 21 deletions

View File

@ -69,7 +69,7 @@ public final class X509SVIDFetcher implements Fetcher<List<X509SVID>> {
StreamObserver<X509SVIDResponse> observer = new StreamObserver<X509SVIDResponse>() { StreamObserver<X509SVIDResponse> observer = new StreamObserver<X509SVIDResponse>() {
@Override @Override
public void onNext(X509SVIDResponse value) { public void onNext(X509SVIDResponse value) {
LOGGER.log(Level.INFO, "New SVID received "); LOGGER.log(Level.FINE, "New SVID received ");
listener.accept(value.getSvidsList()); listener.accept(value.getSvidsList());
retryHandler.reset(); retryHandler.reset();
} }

View File

@ -0,0 +1,31 @@
package spiffe.provider;
import java.util.concurrent.locks.StampedLock;
import java.util.function.Supplier;
public class FunctionalReadWriteLock {
private final StampedLock lock;
public FunctionalReadWriteLock() {
this.lock = new StampedLock();
}
public <T> T read(Supplier<T> supplier) {
long stamp = lock.readLock();
try {
return supplier.get();
} finally {
lock.unlockRead(stamp);
}
}
public void write(Runnable runnable) {
long stamp = lock.writeLock();
try {
runnable.run();
} finally {
lock.unlockWrite(stamp);
}
}
}

View File

@ -8,7 +8,6 @@ import java.security.PrivateKey;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import static java.util.Collections.EMPTY_SET; import static java.util.Collections.EMPTY_SET;
@ -26,8 +25,16 @@ class SpiffeIdManager {
return INSTANCE; return INSTANCE;
} }
/**
* The Spiffe SVID handled by this manager
*/
private SpiffeSVID spiffeSVID; private SpiffeSVID spiffeSVID;
/**
* Used to synchronize spiffeSVID writes and reads
*/
private final FunctionalReadWriteLock guard;
/** /**
* Private Constructor * Private Constructor
* *
@ -35,33 +42,30 @@ class SpiffeIdManager {
* *
*/ */
private SpiffeIdManager() { private SpiffeIdManager() {
Consumer<List<X509SVID>> certificateUpdater = certs -> { guard = new FunctionalReadWriteLock();
X509SVID svid = certs.get(0);
spiffeSVID = new SpiffeSVID(svid);
};
Fetcher<List<X509SVID>> svidFetcher = new X509SVIDFetcher(); Fetcher<List<X509SVID>> svidFetcher = new X509SVIDFetcher();
svidFetcher.registerListener(certificateUpdater); svidFetcher.registerListener(this::updateSVID);
}
/**
* Method used as callback that gets executed whenever an SVID update is pushed by the Workload API
* Uses a write lock to synchronize access to spiffeSVID
*/
private void updateSVID(List<X509SVID> certs) {
X509SVID svid = certs.get(0);
guard.write(() -> spiffeSVID = new SpiffeSVID(svid));
} }
X509Certificate getCertificate() { X509Certificate getCertificate() {
if (spiffeSVID != null) { return guard.read(() -> spiffeSVID != null ? spiffeSVID.getCertificate() : null);
return spiffeSVID.getCertificate();
}
return null;
} }
PrivateKey getPrivateKey() { PrivateKey getPrivateKey() {
if (spiffeSVID != null) { return guard.read(() -> spiffeSVID != null ? spiffeSVID.getPrivateKey() : null);
return spiffeSVID.getPrivateKey();
}
return null;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Set<X509Certificate> getTrustedCerts() { Set<X509Certificate> getTrustedCerts() {
if (spiffeSVID != null) { return guard.read(() -> spiffeSVID != null ? spiffeSVID.getBundle() : EMPTY_SET);
return spiffeSVID.getBundle();
}
return EMPTY_SET;
} }
} }

View File

@ -15,7 +15,6 @@ import static spiffe.provider.CertificateUtils.validate;
*/ */
public class SpiffeTrustManager extends X509ExtendedTrustManager { public class SpiffeTrustManager extends X509ExtendedTrustManager {
private final SpiffeIdManager spiffeIdManager; private final SpiffeIdManager spiffeIdManager;
SpiffeTrustManager() { SpiffeTrustManager() {
@ -85,7 +84,7 @@ public class SpiffeTrustManager extends X509ExtendedTrustManager {
* *
* @param chain an array of X509Certificate that contains the Peer's SVID to be validated * @param chain an array of X509Certificate that contains the Peer's SVID to be validated
* @throws CertificateException when either the Peer's certificate doesn't chain to any Trusted CA * @throws CertificateException when either the Peer's certificate doesn't chain to any Trusted CA
* or the SPIFFE ID is not authorized. *
*/ */
private void checkPeer(X509Certificate[] chain) throws CertificateException { private void checkPeer(X509Certificate[] chain) throws CertificateException {
validate(chain, spiffeIdManager.getTrustedCerts()); validate(chain, spiffeIdManager.getTrustedCerts());