//* Licensed Materials - Property of * //* IBM * //* Miracle A/S * //* Alexandra Instituttet A/S * //* Microsoft * //* * //* eu.abc4trust.pabce.1.34 * //* * //* (C) Copyright IBM Corp. 2014. All Rights Reserved. * //* (C) Copyright Miracle A/S, Denmark. 2014. All Rights Reserved. * //* (C) Copyright Alexandra Instituttet A/S, Denmark. 2014. All * //* Rights Reserved. * //* (C) Copyright Microsoft Corp. 2014. All Rights Reserved. * //* US Government Users Restricted Rights - Use, duplication or * //* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. * //* * //* This file is 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 eu.abc4trust.abce.integrationtests; import static eu.abc4trust.abce.internal.revocation.RevocationConstants.REVOCATION_HANDLE_STR; import static org.junit.Assert.assertNotNull; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import javax.xml.bind.JAXBException; import org.junit.Test; import org.xml.sax.SAXException; import com.google.inject.Injector; import com.ibm.zurich.idmix.abc4trust.facades.InspectorParametersFacade; import com.ibm.zurich.idmix.abc4trust.facades.IssuerParametersFacade; import com.ibm.zurich.idmx.device.ExternalSecretsManagerImpl; import com.ibm.zurich.idmx.exception.ConfigurationException; import com.ibm.zurich.idmx.interfaces.util.Pair; import eu.abc4trust.TestConfiguration; import eu.abc4trust.abce.external.inspector.InspectorAbcEngine; import eu.abc4trust.abce.external.issuer.IssuerAbcEngine; import eu.abc4trust.abce.internal.issuer.tokenManagerIssuer.TokenManagerIssuer; import eu.abc4trust.abce.internal.user.credentialManager.CredentialManager; import eu.abc4trust.abce.internal.user.credentialManager.CredentialManagerException; import eu.abc4trust.abce.testharness.IssuanceHelper; import eu.abc4trust.cryptoEngine.CryptoEngineException; import eu.abc4trust.cryptoEngine.user.CryptoEngineUser; import eu.abc4trust.keyManager.KeyManager; import eu.abc4trust.keyManager.KeyManagerException; import eu.abc4trust.util.CryptoUriUtil; import eu.abc4trust.xml.Attribute; import eu.abc4trust.xml.CredentialInToken; import eu.abc4trust.xml.CredentialSpecification; import eu.abc4trust.xml.FriendlyDescription; import eu.abc4trust.xml.InspectorPublicKey; import eu.abc4trust.xml.IssuancePolicy; import eu.abc4trust.xml.IssuerParameters; import eu.abc4trust.xml.PresentationPolicyAlternatives; import eu.abc4trust.xml.PresentationToken; import eu.abc4trust.xml.PseudonymWithMetadata; import eu.abc4trust.xml.Secret; import eu.abc4trust.xml.SystemParameters; import eu.abc4trust.xml.util.XmlUtils; /** * Patras scenario. */ public class PatrasPilotTest { private static final String USERNAME = "defaultUser"; private static final String PRESENTATION_POLICY_PATRAS_UNIVERSITY_LOGIN = "/eu/abc4trust/sampleXml/patras/presentationPolicyPatrasUniversityLogin.xml"; private static final String CREDENTIAL_SPECIFICATION_PATRAS_UNIVERSITY = "/eu/abc4trust/sampleXml/patras/credentialSpecificationPatrasUniversity.xml"; private static final String ISSUANCE_POLICY_PATRAS_UNIVERSITY = "/eu/abc4trust/sampleXml/patras/issuancePolicyPatrasUniversity.xml"; private static final String CREDENTIAL_SPECIFICATION_PATRAS_COURSE = "/eu/abc4trust/sampleXml/patras/credentialSpecificationPatrasCourse.xml"; private static final String ISSUANCE_POLICY_PATRAS_COURSE = "/eu/abc4trust/sampleXml/patras/issuancePolicyPatrasCourse.xml"; private static final String PRESENTATION_POLICY_PATRAS_COURSE_EVALUATION = "/eu/abc4trust/sampleXml/patras/presentationPolicyPatrasCourseEvaluation.xml"; private static final String PRESENTATION_POLICY_PATRAS_TOMBOLA = "/eu/abc4trust/sampleXml/patras/presentationPolicyPatrasTombola.xml"; private static final String ISSUANCE_POLICY_PATRAS_TOMBOLA = "/eu/abc4trust/sampleXml/patras/issuancePolicyPatrasTombola.xml"; private static final String CREDENTIAL_SPECIFICATION_PATRAS_TOMBOLA = "/eu/abc4trust/sampleXml/patras/credentialSpecificationPatrasTombola.xml"; private Random rand = new Random(1235); // TODO: Backup and restore of attendance credentials. private static final String COURSE_UID = "23330E"; private static final String NAME = "John"; private static final String LASTNAME = "Doe"; private static final String UNIVERSITYNAME = "Patras"; private static final String DEPARTMENTNAME = "CS"; private static final int MATRICULATIONNUMBER = 1235332; @Test(timeout = TestConfiguration.TEST_TIMEOUT) public void patrasPilotIdemixTest() throws Exception { URI cl_technology = Helper.getSignatureTechnologyURI("cl"); int keyLength = 1024; Entities entities = new Entities(); entities.addEntity("UNIVERSITY", cl_technology, false); entities.addEntity("COURSE", cl_technology, true); entities.addEntity("USER"); entities.addEntity("VERIFIER"); entities.addEntity("INSPECTOR"); entities.addEntity("TOMBOLA", cl_technology, true); patrasPilotScenario(keyLength, entities); } @Test(timeout = TestConfiguration.TEST_TIMEOUT) public void patraPilotUProveTest() throws Exception { URI uprove_technology = Helper.getSignatureTechnologyURI("brands"); int keyLength = 1024; Entities entities = new Entities(); entities.addEntity("UNIVERSITY", uprove_technology, false); entities.addEntity("COURSE", uprove_technology, true); entities.addEntity("USER"); entities.addEntity("VERIFIER"); entities.addEntity("INSPECTOR"); entities.addEntity("TOMBOLA", uprove_technology, true); patrasPilotScenario(keyLength, entities); } @Test(timeout = TestConfiguration.TEST_TIMEOUT) public void patraPilotCombinedTestSameTechnology() throws Exception { URI uprove_technology = Helper.getSignatureTechnologyURI("brands"); URI cl_technology = Helper.getSignatureTechnologyURI("cl"); int keyLength = 1024; Entities entities = new Entities(); entities.addEntity("UNIVERSITY", cl_technology, false); entities.addEntity("COURSE", uprove_technology, true); entities.addEntity("USER"); entities.addEntity("VERIFIER"); entities.addEntity("INSPECTOR"); entities.addEntity("TOMBOLA", cl_technology, false); patrasPilotScenario(keyLength, entities); } @Test(timeout = TestConfiguration.TEST_TIMEOUT) public void patraPilotCombinedTestDifferentTechnology() throws Exception { URI uprove_technology = Helper.getSignatureTechnologyURI("brands"); URI cl_technology = Helper.getSignatureTechnologyURI("cl"); int keyLength = 1024; Entities entities = new Entities(); entities.addEntity("UNIVERSITY", uprove_technology, false); entities.addEntity("COURSE", cl_technology, true); entities.addEntity("USER"); entities.addEntity("VERIFIER"); entities.addEntity("INSPECTOR"); entities.addEntity("TOMBOLA", cl_technology, false); patrasPilotScenario(keyLength, entities); } private void patrasPilotScenario(int keyLength, Entities entities) throws KeyManagerException, CryptoEngineException, UnsupportedEncodingException, JAXBException, SAXException, URISyntaxException, ConfigurationException, CredentialManagerException, IOException, Exception, eu.abc4trust.abce.internal.inspector.credentialManager.CredentialManagerException { // Setup system by generating entities and system parameters Collection<Injector> injectors = createEntities(entities); SystemParameters systemParameters = Entities.setupSystemParameters(entities, keyLength); List<Object> parametersList = new ArrayList<Object>(); // Setup university issuer URI credentialTechnology = entities.getTechnology("UNIVERSITY"); URI issuerParametersUID = getIssuanceParametersUIDFromIssuancePolicy(ISSUANCE_POLICY_PATRAS_UNIVERSITY); URI revocationAuthorityUID = new URI("revocationUID1"); parametersList.add(setupIssuer(entities.getInjector("UNIVERSITY"), systemParameters, credentialTechnology, issuerParametersUID, revocationAuthorityUID, 10)); // Setup course credential issuer credentialTechnology = entities.getTechnology("COURSE"); issuerParametersUID = getIssuanceParametersUIDFromIssuancePolicy(ISSUANCE_POLICY_PATRAS_COURSE); revocationAuthorityUID = new URI("revocationUID2"); parametersList.add(setupIssuer(entities.getInjector("COURSE"), systemParameters, credentialTechnology, issuerParametersUID, revocationAuthorityUID, 10)); // Setup tombola credential issuer if (entities.contains("TOMBOLA")) { credentialTechnology = entities.getTechnology("TOMBOLA"); issuerParametersUID = getIssuanceParametersUIDFromIssuancePolicy(ISSUANCE_POLICY_PATRAS_TOMBOLA); revocationAuthorityUID = new URI("revocationUID3"); parametersList.add(setupIssuer(entities.getInjector("TOMBOLA"), systemParameters, credentialTechnology, issuerParametersUID, revocationAuthorityUID, 10)); } // Store all issuer parameters to all key managers entities.storePublicParametersToKeyManagers(parametersList); // Store all credential specifications to all key managers storeCredentialSpecificationToKeyManagers(injectors, CREDENTIAL_SPECIFICATION_PATRAS_UNIVERSITY); storeCredentialSpecificationToKeyManagers(injectors, CREDENTIAL_SPECIFICATION_PATRAS_COURSE); if (entities.contains("TOMBOLA")) { storeCredentialSpecificationToKeyManagers(injectors, CREDENTIAL_SPECIFICATION_PATRAS_TOMBOLA); } // Setup user (generate secret and pseudonym) PseudonymWithMetadata pwm = setupUser(entities.getInjector("USER"), systemParameters, parametersList); // This is a hack since the TokenManagerIssuer does not allow us to add a pseudonym. TokenManagerIssuer universityTokenStorageManager = entities.getInjector("UNIVERSITY").getInstance(TokenManagerIssuer.class); universityTokenStorageManager.addPeudonymForTest(pwm.getPseudonym().getPseudonymValue()); TokenManagerIssuer courseTokenStorageManager = entities.getInjector("COURSE").getInstance(TokenManagerIssuer.class); courseTokenStorageManager.addPeudonymForTest(pwm.getPseudonym().getPseudonymValue()); IssuanceHelper issuanceHelper = new IssuanceHelper(); // Step 1. Login with pseudonym. System.out.println(">> Login with pseudonym."); this.loginWithPseudonym(entities.getInjector("UNIVERSITY"), entities.getInjector("USER"), issuanceHelper); // Step 1. Get university credential. System.out.println(">> Get university credential."); this.issueAndStoreUniversityCredential(entities.getInjector("UNIVERSITY"), entities.getInjector("USER"), issuanceHelper); // Step 2. Get course credential. System.out.println(">> Get course credential."); this.issueAndStoreCourseCredential(entities.getInjector("COURSE"), entities.getInjector("USER"), issuanceHelper); // Verify against course evaluation using the course credential. System.out.println(">> Verify."); PresentationToken pt = this.logIntoCourseEvaluation(issuanceHelper, entities.getInjector("VERIFIER"), entities.getInjector("USER")); assertNotNull(pt); // Issue tombola credential if (entities.contains("TOMBOLA")) { Map<String, Object> atts = new HashMap<String, Object>(); issuanceHelper.issueCredential(USERNAME, entities.getInjector("TOMBOLA"), entities.getInjector("USER"), CREDENTIAL_SPECIFICATION_PATRAS_TOMBOLA, ISSUANCE_POLICY_PATRAS_TOMBOLA, atts); // Inspect the tombola credential if (entities.contains("INSPECTOR")) { InspectorAbcEngine inspectorEngine = entities.getInjector("INSPECTOR").getInstance(InspectorAbcEngine.class); URI inspectionTechnology = CryptoUriUtil.getIdemixMechanism(); URI inspectorPublicKeyUid = URI.create("urn:patras:inspector:tombola"); List<FriendlyDescription> friendlyDescription = Collections.emptyList(); InspectorPublicKey inspectorPublicKey = inspectorEngine.setupInspectorPublicKey(systemParameters, inspectionTechnology, inspectorPublicKeyUid, friendlyDescription); parametersList.add(inspectorPublicKey); // store inspector parameters to key managers (all the other parameters will be stored // again/overwritten) System.out.println("inspectorPublicKey : " + inspectorPublicKey.getPublicKeyUID()); entities.storePublicParametersToKeyManagers(parametersList); // create presentation policy Pair<PresentationToken, PresentationPolicyAlternatives> p = issuanceHelper.createPresentationToken(USERNAME, entities.getInjector("USER"), PRESENTATION_POLICY_PATRAS_TOMBOLA, null, null); // verify.. issuanceHelper.verify(entities.getInjector("INSPECTOR"), p.second, p.first); // inspect.. List<Attribute> inspectedAttributes = inspectorEngine.inspect(p.first); System.out.println("inspectedAttributes"); for (Attribute a : inspectedAttributes) { System.out.println(" a " + a.getAttributeUID() + " : " + a.getAttributeValue()); } } } } private Collection<Injector> createEntities(Entities entities) { // Assert that required entities are present assert (entities.contains("UNIVERSITY")); assert (entities.contains("COURSE")); assert (entities.contains("USER")); assert (entities.contains("VERIFIER")); entities.initInjectors(null); return entities.getInjectors(); } /* * NOTE: This does normally not need to be done. Rather, the issuer parameters UID are taken from * the issuer parameters and fed into the issuance policy. */ private URI getIssuanceParametersUIDFromIssuancePolicy(String pathToIssuancePolicy) throws UnsupportedEncodingException, JAXBException, SAXException { // Load issuance policy IssuancePolicy issuancePolicy = (IssuancePolicy) XmlUtils.getObjectFromXML( this.getClass().getResourceAsStream(pathToIssuancePolicy), true); // Get issuer parameters UID from credential template return issuancePolicy.getCredentialTemplate().getIssuerParametersUID(); } private IssuerParameters setupIssuer(Injector issuerInjector, SystemParameters systemParameters, URI credentialTechnology, URI issuanceParametersUID, URI revocationId, int maximalNumberOfAttributes) throws CryptoEngineException { // Generate issuer parameters. IssuerAbcEngine issuerEngine = issuerInjector.getInstance(IssuerAbcEngine.class); IssuerParameters issuerParameters = issuerEngine.setupIssuerParameters(systemParameters, maximalNumberOfAttributes, credentialTechnology, issuanceParametersUID, revocationId, null); return issuerParameters; } private PseudonymWithMetadata setupUser(Injector userInjector, SystemParameters systemParameters, List<Object> parametersList) throws UnsupportedEncodingException, JAXBException, SAXException, ConfigurationException, CredentialManagerException { URI secretUid = URI.create("secret-patras-test"); Secret s = ExternalSecretsManagerImpl.generateSecret(systemParameters, BigInteger.valueOf(123456), secretUid); CredentialManager userCredentialManager = userInjector.getInstance(CredentialManager.class); userCredentialManager.storeSecret(USERNAME, s); CryptoEngineUser ce = userInjector.getInstance(CryptoEngineUser.class); // Create a pseudonym PseudonymWithMetadata pwm = this.createPseudonym(secretUid, ce, systemParameters); // Store it in the user credential manager. userCredentialManager.storePseudonym(USERNAME, pwm); return pwm; } private void storePublicParametersToKeyManagers(Collection<Injector> injectors, List<Object> publicParameters) throws KeyManagerException, ConfigurationException { // Iterate over all key managers for (Injector injector : injectors) { KeyManager keyManager = injector.getInstance(KeyManager.class); // Iterate over all parameters for (Object parameters : publicParameters) { // Check for issuer parameters if (IssuerParameters.class.isAssignableFrom(parameters.getClass())) { IssuerParametersFacade ipWrapper = new IssuerParametersFacade((IssuerParameters) parameters); keyManager.storeIssuerParameters(ipWrapper.getIssuerParametersId(), ipWrapper.getIssuerParameters()); } // Check for inspector parameters else if (InspectorPublicKey.class.isAssignableFrom(parameters.getClass())) { InspectorParametersFacade ipWrapper = new InspectorParametersFacade((InspectorPublicKey) parameters); keyManager.storeInspectorPublicKey(ipWrapper.getInspectorId(), ipWrapper.getInspectorParameters()); // userKeyManager.storeInspectorPublicKey(inspectorPublicKeyUid, inspectorPublicKey); // inspectorKeyManager.storeInspectorPublicKey(inspectorPublicKeyUid, inspectorPublicKey); } } } } private void storeCredentialSpecificationToKeyManagers(Collection<Injector> injectors, String pathToCredentialSpecification) throws KeyManagerException, UnsupportedEncodingException, JAXBException, SAXException { // Load credential specifications. CredentialSpecification universityCredSpec = (CredentialSpecification) XmlUtils.getObjectFromXML( this.getClass().getResourceAsStream(pathToCredentialSpecification), true); // Store credential specifications. URI universitySpecificationUID = universityCredSpec.getSpecificationUID(); for (Injector injector : injectors) { KeyManager keyManager = injector.getInstance(KeyManager.class); keyManager.storeCredentialSpecification(universitySpecificationUID, universityCredSpec); } } private void loginWithPseudonym(Injector universityInjector, Injector userInjector, IssuanceHelper issuanceHelper) throws Exception { PresentationToken t = this.loginWithPseudonym(issuanceHelper, universityInjector, userInjector); assertNotNull(t); } private PresentationToken loginWithPseudonym(IssuanceHelper issuanceHelper, Injector universityInjector, Injector userInjector) throws Exception { System.out.println("test, logingwithPseudonym, pre token generation"); Pair<PresentationToken, PresentationPolicyAlternatives> p = issuanceHelper.createPresentationToken(USERNAME, userInjector, PRESENTATION_POLICY_PATRAS_UNIVERSITY_LOGIN, null, null); System.out.println("test, logingwithPseudonym, now we verify"); return issuanceHelper.verify(universityInjector, p.second, p.first); } private void issueAndStoreUniversityCredential(Injector issuerInjector, Injector userInjector, IssuanceHelper issuanceHelper) throws Exception { Map<String, Object> atts = this.populateUniveristyAttributes(); issuanceHelper.issueCredential(USERNAME, issuerInjector, userInjector, CREDENTIAL_SPECIFICATION_PATRAS_UNIVERSITY, ISSUANCE_POLICY_PATRAS_UNIVERSITY, atts, null); } private void issueAndStoreCourseCredential(Injector issuerInjector, Injector userInjector, IssuanceHelper issuanceHelper) throws Exception { Map<String, Object> atts = this.populateCourseAttributes(); issuanceHelper.issueCredential(USERNAME, issuerInjector, userInjector, CREDENTIAL_SPECIFICATION_PATRAS_COURSE, ISSUANCE_POLICY_PATRAS_COURSE, atts, null); } private PresentationToken logIntoCourseEvaluation(IssuanceHelper issuanceHelper, Injector verifierInjector, Injector userInjector) throws Exception { /* * Verify for poll. The user must have: 1) A non-revoked university credential 2) A course * credential with the same matriculation number as the university credential 3) A certain * number of attendance credentials, which must be higher than a certain threshold 4) All * attendance credentials must have the same matriculation number as the university credential * 5) All attendance credentials must have a unique UID. */ return this.login(issuanceHelper, verifierInjector, userInjector); } private PresentationToken login(IssuanceHelper issuanceHelper, Injector verifierInjector, Injector userInjector) throws Exception { Pair<PresentationToken, PresentationPolicyAlternatives> p = issuanceHelper.createPresentationToken(USERNAME, userInjector, PRESENTATION_POLICY_PATRAS_COURSE_EVALUATION, null, null); // Store all required cred specs in the verifier key manager. KeyManager hotelKeyManager = verifierInjector.getInstance(KeyManager.class); KeyManager userKeyManager = userInjector.getInstance(KeyManager.class); PresentationToken pt = p.first; assertNotNull(pt); for (CredentialInToken cit : pt.getPresentationTokenDescription().getCredential()) { hotelKeyManager.storeCredentialSpecification(cit.getCredentialSpecUID(), userKeyManager.getCredentialSpecification(cit.getCredentialSpecUID())); } return issuanceHelper.verify(verifierInjector, p.second, p.first); } private PseudonymWithMetadata createPseudonym(URI secretUid, CryptoEngineUser cryptoEngineUser, SystemParameters systemParameters) { String scope = "urn:patras:registration"; PseudonymWithMetadata pwm; try { pwm = cryptoEngineUser.createPseudonym(USERNAME, URI.create("patrasdemo-idemix-uri"), scope, true, secretUid); } catch (CryptoEngineException e) { throw new RuntimeException(e); } return pwm; } private Map<String, Object> populateCourseAttributes() { Map<String, Object> att = new HashMap<String, Object>(); att.put("urn:patras:credspec:credCourse:courseid", COURSE_UID); att.put(REVOCATION_HANDLE_STR, URI.create("urn:patras:revocation:handle2")); return att; } private Map<String, Object> populateUniveristyAttributes() { Map<String, Object> att = new HashMap<String, Object>(); att.put("urn:patras:credspec:credUniv:firstname", NAME); att.put("urn:patras:credspec:credUniv:lastname", LASTNAME); att.put(REVOCATION_HANDLE_STR, URI.create("urn:patras:revocation:handle1")); att.put("urn:patras:credspec:credUniv:university", UNIVERSITYNAME); att.put("urn:patras:credspec:credUniv:department", DEPARTMENTNAME); att.put("urn:patras:credspec:credUniv:matriculationnr", MATRICULATIONNUMBER); return att; } }