//* Licensed Materials - Property of *
//* IBM *
//* Miracle A/S *
//* Alexandra Instituttet A/S *
//* *
//* 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. *
//* 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.assertEquals;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.logging.Logger;
import javax.xml.bind.JAXBException;
import org.junit.Test;
import org.xml.sax.SAXException;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.ibm.zurich.idmx.interfaces.util.Pair;
import eu.abc4trust.abce.external.inspector.InspectorAbcEngine;
import eu.abc4trust.abce.external.issuer.IssuerAbcEngine;
import eu.abc4trust.abce.external.revocation.RevocationAbcEngine;
import eu.abc4trust.abce.external.verifier.VerifierAbcEngine;
import eu.abc4trust.abce.testharness.IntegrationModuleFactory;
import eu.abc4trust.abce.testharness.IssuanceHelper;
import eu.abc4trust.cryptoEngine.CryptoEngineException;
import eu.abc4trust.cryptoEngine.inspector.CryptoEngineInspector;
import eu.abc4trust.cryptoEngine.util.SystemParametersUtil;
import eu.abc4trust.guice.ProductionModuleFactory.CryptoEngine;
import eu.abc4trust.keyManager.KeyManager;
import eu.abc4trust.keyManager.KeyManagerException;
import eu.abc4trust.revocationProxy.revauth.RevocationProxyAuthority;
import eu.abc4trust.util.CryptoUriUtil;
import eu.abc4trust.xml.Attribute;
import eu.abc4trust.xml.CredentialDescription;
import eu.abc4trust.xml.CredentialSpecification;
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.Reference;
import eu.abc4trust.xml.RevocationAuthorityParameters;
import eu.abc4trust.xml.RevocationInformation;
import eu.abc4trust.xml.SystemParameters;
import eu.abc4trust.xml.VerifierParameters;
import eu.abc4trust.xml.util.XmlUtils;
public class HotelBookingTest {
private static final String USERNAME = "defaultUser";
private static final String PRESENTATION_POLICY_ALTERNATIVES_HOTEL = "/eu/abc4trust/sampleXml/presentationPolicies/presentationPolicyAlternativesHotelBooking.xml";
private static final String ISSUANCE_POLICY_REVOCABLE_CREDIT_CARD = "/eu/abc4trust/sampleXml/issuance/issuancePolicyRevocableCreditCard.xml";
private static final String ISSUANCE_POLICY_PASSPORT = "/eu/abc4trust/sampleXml/issuance/issuancePolicyPassport.xml";
private static final String ISSUANCE_POLICY_STUDENT_CARD = "/eu/abc4trust/sampleXml/issuance/issuancePolicyStudentCard.xml";
private static final String CREDENTIAL_SPECIFICATION_REVOCABLE_CREDITCARD = "/eu/abc4trust/sampleXml/credspecs/credentialSpecificationRevocableCreditcard.xml";
private static final String CREDENTIAL_SPECIFICATION_PASSPORT = "/eu/abc4trust/sampleXml/credspecs/credentialSpecificationPassport.xml";
private static final String CREDENTIAL_SPECIFICATION_STUDENT_CARD = "/eu/abc4trust/sampleXml/credspecs/credentialSpecificationStudentCardForHotelBooking.xml";
private static final URI STATUS = URI.create("#status");
private static final int SECURITY_CODE = 42;
private static final int CARD_NUMBER = 555;
private static final String SWISS_EXPRESS = "SwissExpress";
private static final String NAME = "John";
private static final String LASTNAME = "Doe";
private static final URI revParamsUid = IntegrationTestUtil.REVOCATION_PARAMETERS_UID;
private static final URI INSPECTOR_URI = URI.create("http://thebestbank.com/inspector/pub_key_v1");
private static final Logger logger = Logger
.getLogger(HotelBookingTest.class.getCanonicalName());
private static URI revocationTechnology = null;
@Test
public void hotelBookingTestIdemix() throws Exception{
revocationTechnology = Helper.getRevocationTechnologyURI("cl");
URI cl_technology = Helper.getSignatureTechnologyURI("cl");
int keyLength = 1024;
Entities entities = new Entities();
entities.addEntity("CREDITCARD", cl_technology, true);
entities.addEntity("STUDENTCARD", cl_technology, false);
entities.addEntity("PASSPORT", cl_technology, false);
entities.addEntity("USER");
entities.addEntity("VERIFIER");
entities.addEntity("INSPECTOR");
runHotelBookingScenario(keyLength, entities);
}
@Test
public void hotelBookingTestUProve() throws Exception{
revocationTechnology = Helper.getRevocationTechnologyURI("cl");
URI brands_technology = Helper.getSignatureTechnologyURI("brands");
int keyLength = 1024;
Entities entities = new Entities();
entities.addEntity("CREDITCARD", brands_technology, true);
entities.addEntity("STUDENTCARD", brands_technology, false);
entities.addEntity("PASSPORT", brands_technology, false);
entities.addEntity("USER");
entities.addEntity("VERIFIER");
entities.addEntity("INSPECTOR");
runHotelBookingScenario(keyLength, entities);
}
@Test
public void hotelBookingTestWithBridging() throws Exception{
revocationTechnology = Helper.getRevocationTechnologyURI("cl");
URI cl_technology = Helper.getSignatureTechnologyURI("cl");
URI brands_technology = Helper.getSignatureTechnologyURI("brands");
int keyLength = 1024;
Entities entities = new Entities();
entities.addEntity("CREDITCARD", cl_technology, true);
entities.addEntity("STUDENTCARD", brands_technology, false);
entities.addEntity("PASSPORT", cl_technology, false);
entities.addEntity("USER");
entities.addEntity("VERIFIER");
entities.addEntity("INSPECTOR");
runHotelBookingScenario(keyLength, entities);
}
private void runHotelBookingScenario(int keyLength, Entities entities) throws Exception{
Injector revocationInjector = setupRevocationInjector(keyLength);
RevocationProxyAuthority revocationProxyAuthority = revocationInjector
.getInstance(RevocationProxyAuthority.class);
RevocationAuthorityParameters revocationAuthorityParameters =
setupRevocationAuthorityParameters(keyLength, revocationInjector);
// Setup system by generating entities and system parameters
Collection<Injector> injectors = createEntities(entities, revocationProxyAuthority);
SystemParameters systemParameters = Entities.setupSystemParameters(entities, keyLength);
List<Object> parametersList = new ArrayList<Object>();
// Setup creditcard issuer
URI credentialTechnology = entities.getTechnology("CREDITCARD");
URI issuerParametersUID =
getIssuanceParametersUIDFromIssuancePolicy(ISSUANCE_POLICY_REVOCABLE_CREDIT_CARD);
parametersList.add(setupIssuer(entities.getInjector("CREDITCARD"), systemParameters,
credentialTechnology, issuerParametersUID, revParamsUid, 10));
// Setup creditcard issuer
credentialTechnology = entities.getTechnology("STUDENTCARD");
issuerParametersUID =
getIssuanceParametersUIDFromIssuancePolicy(ISSUANCE_POLICY_STUDENT_CARD);
parametersList.add(setupIssuer(entities.getInjector("STUDENTCARD"), systemParameters,
credentialTechnology, issuerParametersUID, null, 10));
// Setup creditcard issuer
credentialTechnology = entities.getTechnology("PASSPORT");
issuerParametersUID =
getIssuanceParametersUIDFromIssuancePolicy(ISSUANCE_POLICY_PASSPORT);
parametersList.add(setupIssuer(entities.getInjector("PASSPORT"), systemParameters,
credentialTechnology, issuerParametersUID, null, 10));
// Parameters for verifier parameters
credentialTechnology = Helper.getSignatureTechnologyURI("cl");
issuerParametersUID = URI.create("vp:rangeProof");
parametersList.add(setupIssuer(entities.getInjector("STUDENTCARD"), systemParameters,
credentialTechnology, issuerParametersUID, null, 0));
// setup inspector public key.
InspectorAbcEngine inspectorEngine =
entities.getInjector("INSPECTOR").getInstance(InspectorAbcEngine.class);
InspectorPublicKey inspectorPubKey =
inspectorEngine.setupInspectorPublicKey(systemParameters,
CryptoUriUtil.getIdemixMechanism(),
HotelBookingTest.INSPECTOR_URI,
null);
parametersList.add(inspectorPubKey);
// Store all issuer parameters to all key managers
entities.storePublicParametersToKeyManagers(parametersList);
//store credentialSpecifications
storeCredentialSpecificationToKeyManagers(injectors, CREDENTIAL_SPECIFICATION_REVOCABLE_CREDITCARD);
storeCredentialSpecificationToKeyManagers(injectors, CREDENTIAL_SPECIFICATION_STUDENT_CARD);
storeCredentialSpecificationToKeyManagers(injectors, CREDENTIAL_SPECIFICATION_PASSPORT);
addRevocationToIssuers(entities, revocationAuthorityParameters);
Injector governmentInjector = entities.getInjector("PASSPORT");
Injector userInjector = entities.getInjector("USER");
Injector studentInjector = entities.getInjector("STUDENTCARD");
Injector bankInjector = entities.getInjector("CREDITCARD");
Injector hotelInjector = entities.getInjector("VERIFIER");
Injector inspectorInjector = entities.getInjector("INSPECTOR");
IssuanceHelper issuanceHelper = new IssuanceHelper();
VerifierParameters verifierParameter = entities.getInjector("USER").getInstance(VerifierAbcEngine.class).createVerifierParameters(systemParameters);
// Step 1. Get passport.
logger.info("Get passport.");
URI passportCredentialUID = this.issueAndStorePassport(governmentInjector, userInjector,
issuanceHelper, verifierParameter).getCredentialUID();
// Step 2. Get student id.
logger.info("Get student id.");
URI studentcardCredentialUID = this.issueAndStoreStudentId(studentInjector, userInjector,
issuanceHelper, verifierParameter).getCredentialUID();
// Step 3. Get credit card using id and student card
logger.info("Get credit card.");
this.issueAndStoreCreditCard(bankInjector, userInjector,
issuanceHelper, verifierParameter);
// Step 4a. Book a hotel room using passport and credit card. This uses
// the first alternative of the presentation policy.
logger.info("Verify.");
PresentationToken pt = this.bookHotelRoomUsingPassportAndCreditcard(
issuanceHelper, hotelInjector, userInjector, revParamsUid, verifierParameter, passportCredentialUID);
// Step 4b. Book a hotel room using passport and credit card. This uses
// the second alternative of the presentation policy.
pt = this.bookHotelRoomUsingStudentcardPassportAndCreditcard(
hotelInjector, userInjector, issuanceHelper, revParamsUid, verifierParameter, studentcardCredentialUID);
// Step 5. Inspect credit card data because of no-show.
if (inspectorInjector != null) {
this.inspectCreditCard(bankInjector, inspectorInjector, pt);
}
// Step 4c. Booking a hotel room using passport and credit card fails
// because customer is blacklisted by hotel.
// Not implemented yet.
//this.failBookingHotelRoomUsingPassportAndCreditcard(hotelInjector,
// userInjector, issuanceHelper, verifierParameter);
}
private Injector setupRevocationInjector(int keyLength) throws Exception{
// Generate revocation parameters.
Injector revocationInjector = Guice
.createInjector(IntegrationModuleFactory.newModule(new Random(1231),
CryptoEngine.IDEMIX));
KeyManager revocationKeyManager = revocationInjector.getInstance(KeyManager.class);
SystemParameters systemParameters = null;
if(keyLength == 1024){
systemParameters = SystemParametersUtil.getDefaultSystemParameters_1024();
}else{
systemParameters = SystemParametersUtil.getDefaultSystemParameters_2048();
}
revocationKeyManager.storeSystemParameters(systemParameters);
return revocationInjector;
}
private RevocationAuthorityParameters setupRevocationAuthorityParameters(int keyLength,
Injector revocationInjector)
throws Exception{
RevocationAbcEngine revocationEngine = revocationInjector.getInstance(RevocationAbcEngine.class);
URI revParamsUid = IntegrationTestUtil.REVOCATION_PARAMETERS_UID;
Reference revocationInfoReference = new Reference();
revocationInfoReference.setReferenceType(URI.create("https"));
revocationInfoReference.getReferences().add(URI.create("https://example.org"));
Reference nonRevocationEvidenceReference = new Reference();
nonRevocationEvidenceReference.setReferenceType(URI.create("https"));
nonRevocationEvidenceReference.getReferences().add(URI.create("https://example.org"));
Reference nonRrevocationUpdateReference = new Reference();
nonRrevocationUpdateReference.setReferenceType(URI.create("https"));
nonRrevocationUpdateReference.getReferences().add(
URI.create("https://example.org"));
RevocationAuthorityParameters revocationAuthorityParameters = revocationEngine
.setupRevocationAuthorityParameters(keyLength,
revocationTechnology, revParamsUid, revocationInfoReference,
nonRevocationEvidenceReference, nonRrevocationUpdateReference);
return revocationAuthorityParameters;
}
private void addRevocationToIssuers(Entities entities, RevocationAuthorityParameters revAuthParams)
throws KeyManagerException{
for(Injector injector: entities.getInjectors()){
KeyManager keyManager = injector.getInstance(KeyManager.class);
keyManager.storeRevocationAuthorityParameters(IntegrationTestUtil.REVOCATION_PARAMETERS_UID, revAuthParams);
}
}
private Collection<Injector> createEntities(Entities entities, RevocationProxyAuthority revProxy) {
// Assert that required entities are present
assert (entities.contains("CREDITCARD"));
assert (entities.contains("STUDENTCARD"));
assert (entities.contains("PASSPORT"));
assert (entities.contains("USER"));
assert (entities.contains("VERIFIER"));
assert (entities.contains("INSPECTOR"));
assert (!entities.contains("REVOCATION")); //do not contain revocation - should be separate
entities.initInjectors(revProxy);
return entities.getInjectors();
}
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 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 CredentialDescription issueAndStorePassport(Injector governmentInjector,
Injector userInjector, IssuanceHelper issuanceHelper, VerifierParameters verifierParameter)
throws Exception {
Map<String, Object> passportAtts = this.populatePassportAttributes();
return issuanceHelper.issueCredential(USERNAME, governmentInjector, userInjector,
CREDENTIAL_SPECIFICATION_PASSPORT, ISSUANCE_POLICY_PASSPORT,
passportAtts, verifierParameter);
}
private Map<String, Object> populatePassportAttributes() {
Map<String, Object> att = new HashMap<String, Object>();
att.put("Name", NAME);
att.put("LastName", LASTNAME);
att.put(REVOCATION_HANDLE_STR,
"http://admin.ch/passport/revocation/parameters");
att.put("PassportNumber", 895749);
att.put("Issued", "2012-02-06Z");
att.put("Expires", "2022-02-06Z");
att.put("IssuedBy", "admin.ch");
return att;
}
private CredentialDescription issueAndStoreStudentId(Injector univsersityInjector,
Injector userInjector, IssuanceHelper issuanceHelper, VerifierParameters verifierParameter)
throws Exception {
Map<String, Object> atts = this
.populateStudentIdIssuerAttributes();
return issuanceHelper.issueCredential(USERNAME, univsersityInjector, userInjector,
CREDENTIAL_SPECIFICATION_STUDENT_CARD,
ISSUANCE_POLICY_STUDENT_CARD, atts, verifierParameter);
}
private Map<String, Object> populateStudentIdIssuerAttributes() {
Map<String, Object> atts = new HashMap<String, Object>();
atts.put("Name", NAME);
atts.put("LastName", LASTNAME);
atts.put(REVOCATION_HANDLE_STR,
"http://admin.ch/passport/revocation/parameters");
atts.put("StudentNumber", 345);
atts.put("Issued", "2012-02-02Z");
atts.put("Expires", "2022-02-02Z");
atts.put("IssuedBy", "ethz.ch");
return atts;
}
private void issueAndStoreCreditCard(Injector bankInjector,
Injector userInjector, IssuanceHelper issuanceHelper, VerifierParameters verifierParameter)
throws Exception {
Map<String, Object> atts = this.populateCreditCardIssuerAttributes();
issuanceHelper.issueCredential(USERNAME, bankInjector, userInjector,
CREDENTIAL_SPECIFICATION_REVOCABLE_CREDITCARD,
ISSUANCE_POLICY_REVOCABLE_CREDIT_CARD, atts, verifierParameter);
}
private Map<String, Object> populateCreditCardIssuerAttributes()
throws Exception {
Map<String, Object> atts = new HashMap<String, Object>();
atts.put(REVOCATION_HANDLE_STR,
new BigInteger("123123123"));
atts.put("CardType", SWISS_EXPRESS);
atts.put("Status", STATUS);
atts.put("SecurityCode", SECURITY_CODE);
atts.put("CardNumber", CARD_NUMBER);
return atts;
}
private PresentationToken bookHotelRoomUsingPassportAndCreditcard(
IssuanceHelper issuanceHelper, Injector hotelInjector,
Injector userInjector, URI revParamsUid, VerifierParameters verifierParameter,
URI passportCredentialUID) throws Exception {
// find passport credential uid and use that instead of presentationTokenChoice
return this.bookHotel(issuanceHelper, hotelInjector, userInjector,
passportCredentialUID, revParamsUid, verifierParameter);
}
private PresentationToken bookHotelRoomUsingStudentcardPassportAndCreditcard(
Injector hotelInjector, Injector userInjector,
IssuanceHelper issuanceHelper, URI revParamsUid, VerifierParameters verifierParameter,
URI studentcardCredentialUID) throws Exception {
return this.bookHotel(issuanceHelper, hotelInjector, userInjector,
studentcardCredentialUID, revParamsUid, verifierParameter);
}
private PresentationToken bookHotel(IssuanceHelper issuanceHelper,
Injector hotelInjector, Injector userInjector,
final URI credentialChoice,
URI revParamsUid, VerifierParameters verifierParameter)
throws Exception {
List<URI> chosenInspectors = new LinkedList<URI>();
chosenInspectors.add(HotelBookingTest.INSPECTOR_URI);
VerifierAbcEngine hotelEngine = hotelInjector
.getInstance(VerifierAbcEngine.class);
RevocationInformation revocationInformation = null;
if (revParamsUid != null) {
try {
revocationInformation = hotelEngine
.getLatestRevocationInformation(revParamsUid);
} catch (CryptoEngineException ex) {
revocationInformation = null;
}
}
Pair<PresentationToken, PresentationPolicyAlternatives> p = issuanceHelper
.createSpecificPresentationToken(USERNAME, userInjector,
PRESENTATION_POLICY_ALTERNATIVES_HOTEL, credentialChoice,
revocationInformation, verifierParameter);
return issuanceHelper.verify(hotelInjector, p.second, p.first);
}
private void failBookingHotelRoomUsingPassportAndCreditcard(
Injector hotelInjector, Injector userInjector,
IssuanceHelper issuanceHelper, VerifierParameters verifierParameter) throws Exception {
// TODO(enr): Fix this
org.junit.Assert.fail();
/*
int presentationTokenChoice = 0;
int pseudonymChoice = 1;
Pair<PresentationToken, PresentationPolicyAlternatives> p = issuanceHelper
.createPresentationToken(USERNAME, userInjector, userInjector,
PRESENTATION_POLICY_ALTERNATIVES_HOTEL,
new IdentitySelectionPrinter(
new PolicySelector(presentationTokenChoice,
pseudonymChoice)));
PresentationToken pt = p.first();
// TODO: Verifier driven revocation is not yet implemented.
// The user should not be able to create a presentation token as
// his passport number is on the Hotel blacklist.
// assertNull(pt);
assertNotNull(pt);
*/
}
private void inspectCreditCard(Injector bankInjector,
Injector inspectorInjector,
PresentationToken pt) throws Exception {
CryptoEngineInspector engine = inspectorInjector.getInstance(CryptoEngineInspector.class);
List<Attribute> attributes = engine.inspect(pt);
assertEquals(1, attributes.size());
Attribute attribute = attributes.get(0);
assertEquals(URI.create("CardNumber"), attribute
.getAttributeDescription().getType());
assertEquals(BigInteger.valueOf(555), attribute.getAttributeValue());
}
}