/**
* Copyright (c) Istituto Nazionale di Fisica Nucleare, 2006-2014.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.italiangrid.voms.test.mt;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.junit.Assert;
import org.italiangrid.voms.VOMSAttribute;
import org.italiangrid.voms.VOMSValidators;
import org.italiangrid.voms.ac.VOMSACValidator;
import org.italiangrid.voms.store.UpdatingVOMSTrustStore;
import org.italiangrid.voms.store.impl.DefaultUpdatingVOMSTrustStore;
import org.italiangrid.voms.test.utils.VOMSAA;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import eu.emi.security.authn.x509.NamespaceCheckingMode;
import eu.emi.security.authn.x509.X509CertChainValidatorExt;
import eu.emi.security.authn.x509.impl.OpensslCertChainValidator;
import eu.emi.security.authn.x509.impl.PEMCredential;
import eu.emi.security.authn.x509.proxy.ProxyCertificate;
public class TestConcurrentValidation {
static X509CertChainValidatorExt sharedCertificateValidator;
static UpdatingVOMSTrustStore sharedVOMSTrustStore;
static final String trustAnchorsDir = "src/test/resources/trust-anchors";
static final long trustAnchorsRefreshInterval = TimeUnit.SECONDS.toMillis(15);
static final String vomsTrustStoreDir = "src/test/resources/vomsdir";
static final long trustStoreRefreshInterval = TimeUnit.SECONDS.toMillis(5);
static final int numHolderCredentials = 5;
static PEMCredential[] holderCerts;
static VOMSAA testVO_1, testVO_2;
static final String aaCert = "src/test/resources/certs/test_host_cnaf_infn_it.cert.pem";
static final String aaKey = "src/test/resources/certs/test_host_cnaf_infn_it.key.pem";
static final String aaCert2 = "src/test/resources/certs/wilco_cnaf_infn_it.cert.pem";
static final String aaKey2 = "src/test/resources/certs/wilco_cnaf_infn_it.key.pem";
static final long NUM_ITERATIONS = 10;
static final int NUM_WORKERS = 10;
static final CyclicBarrier barrier = new CyclicBarrier(NUM_WORKERS + 1);
static final ExecutorService pool = Executors.newCachedThreadPool();
static final String[][] fqans = { { "/test.vo" }, { "/test.vo.2" } };
static VOMSACValidator sharedValidator;
static List<ProxyCertificate> testProxies;
static final Random r = new Random();
static void loadHolderCredentials() throws KeyStoreException,
CertificateException, FileNotFoundException, IOException {
holderCerts = new PEMCredential[numHolderCredentials];
for (int i = 0; i < numHolderCredentials; i++) {
String baseFileName = String.format("src/test/resources/certs/test%d", i);
holderCerts[i] = new PEMCredential(new FileInputStream(baseFileName
+ ".key.pem"), new FileInputStream(baseFileName + ".cert.pem"),
"pass".toCharArray());
}
}
static void initVOs() throws KeyStoreException, CertificateException,
FileNotFoundException, IOException {
PEMCredential aaCred1 = new PEMCredential(new FileInputStream(aaKey),
new FileInputStream(aaCert), (char[]) null);
PEMCredential aaCred2 = new PEMCredential(new FileInputStream(aaKey2),
new FileInputStream(aaCert2), (char[]) null);
testVO_1 = new VOMSAA(aaCred1, "test.vo", "test-host.cnaf.infn.it", 15000);
testVO_2 = new VOMSAA(aaCred2, "test.vo.2", "wilco.cnaf.infn.it", 15001);
}
static void initVOMSProxies() throws InvalidKeyException,
CertificateParsingException, SignatureException, NoSuchAlgorithmException,
IOException {
testProxies = new ArrayList<ProxyCertificate>();
for (int i = 0; i < numHolderCredentials; i++)
for (int j = 0; j < 2; j++) {
VOMSAA vo = (j == 0 ? testVO_1 : testVO_2);
PEMCredential cert = holderCerts[i];
ProxyCertificate proxy = vo.createVOMSProxy(cert,
Arrays.asList(fqans[j]));
testProxies.add(proxy);
}
}
static X509Certificate[] getRandomProxy() {
int randomIndex = r.nextInt(testProxies.size());
return testProxies.get(randomIndex).getCertificateChain();
}
@BeforeClass
public static void setup() throws KeyStoreException, CertificateException,
FileNotFoundException, IOException, InvalidKeyException,
SignatureException, NoSuchAlgorithmException {
sharedVOMSTrustStore = new DefaultUpdatingVOMSTrustStore(
Arrays.asList(vomsTrustStoreDir), trustStoreRefreshInterval);
sharedCertificateValidator = new OpensslCertChainValidator(trustAnchorsDir,
NamespaceCheckingMode.EUGRIDPMA_AND_GLOBUS, trustAnchorsRefreshInterval);
loadHolderCredentials();
initVOs();
initVOMSProxies();
sharedValidator = VOMSValidators.newValidator(sharedVOMSTrustStore,
sharedCertificateValidator);
System.out.println("Setup done.");
}
@AfterClass
public static void tearDown() {
}
@Test
public void test() throws InterruptedException, BrokenBarrierException {
long start = System.currentTimeMillis();
System.out.format("Workers: %d. Iterations: %d\n", NUM_WORKERS,
NUM_ITERATIONS);
for (int i = 0; i < NUM_WORKERS; i++)
pool.execute(new ValidatorWorker());
barrier.await();
barrier.await();
pool.shutdown();
sharedVOMSTrustStore.cancel();
sharedCertificateValidator.dispose();
long duration = System.currentTimeMillis() - start;
System.out
.format(
"Done. Test duration: %d milliseconds. Avg validation duration: %d milliseconds.\n",
duration, duration / (NUM_WORKERS * NUM_ITERATIONS));
}
class ValidatorWorker implements Runnable {
private volatile boolean shutdownRequested = false;
private long iterations = 0;
public void run() {
try {
barrier.await();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (BrokenBarrierException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while (true) {
if (iterations++ > NUM_ITERATIONS)
break;
if (shutdownRequested)
return;
VOMSACValidator validator = getValidator();
try {
X509Certificate[] chain = getRandomProxy();
List<VOMSAttribute> attrs = validator.validate(chain);
Assert.assertEquals(1, attrs.size());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
try {
barrier.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized void shutdown() {
shutdownRequested = true;
}
}
static X509Certificate[] buildProxy(int credentialIndex, int voIndex)
throws InvalidKeyException, CertificateParsingException,
SignatureException, NoSuchAlgorithmException, IOException {
VOMSAA vo = (voIndex == 0 ? testVO_1 : testVO_2);
PEMCredential cert = holderCerts[credentialIndex];
ProxyCertificate proxy = vo.createVOMSProxy(cert,
Arrays.asList(fqans[voIndex]));
return proxy.getCertificateChain();
}
static VOMSACValidator getValidator() {
return sharedValidator;
}
}