Java tutorial
/******************************************************************************* * Copyright (c) 2011 TXT e-solutions SpA * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * This work was performed within the IoT_at_Work Project * and partially funded by the European Commission's * 7th Framework Programme under the research area ICT-2009.1.3 * Internet of Things and enterprise environments. * * * Authors: * Cristoforo Seccia (TXT e-solutions SpA) * * Contributors: * Domenico Rotondi (TXT e-solutions SpA) *******************************************************************************/ package it.txt.access.capability.demo.soap.server.service.impl; import it.txt.access.capability.commons.schema.util.CapabilitySchemasPrinter; import it.txt.access.capability.commons.schema.validation.CapabilitySchemaValidationHandler; import it.txt.access.capability.commons.schema.validation.CapabilitySchemaValidationHandlerException; import it.txt.access.capability.commons.utils.CalendarUtils; import it.txt.access.capability.commons.utils.ClientServerUtils; import it.txt.access.capability.factory.CapabilitySchemaFactoryException; import it.txt.access.capability.factory.CapabilitySchemaFactory; import it.txt.access.capability.factory.values.X509SubjectInfo; import it.txt.access.capability.demo.schema.CapabilityRequestType; import it.txt.access.capability.demo.schema.CapabilityResponseType; import it.txt.access.capability.demo.soap.server.model.ServiceRequestInfoModel; import it.txt.access.capability.schema.AccessRightType; import it.txt.access.capability.schema.AccessRightsCapabilityType; import it.txt.access.capability.demo.soap.server.model.ServerKeystoreDataModel; import it.txt.access.capability.demo.soap.server.model.ServerResponseInfoModel; import it.txt.access.capability.demo.schema.factory.CapabilityDemoSchemaFactoryException; import it.txt.access.capability.demo.schema.factory.CapabilityDemoSchemaFactory; import it.txt.access.capability.demo.soap.server.service.CapabilityServiceException; import it.txt.access.capability.verifier.CapabilityVerifier; import it.txt.access.capability.verifier.CapabilityVerifierException; import it.txt.access.capability.verifier.VerifiedCapability; import it.txt.access.capability.verifier.security.KeystoreHelper; import it.txt.access.capability.verifier.security.KeystoreSecurityException; import it.txt.access.capability.verifier.security.KeystoreSignature; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.ResourceLoader; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; import org.w3c.dom.Element; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import org.w3c.dom.Document; /** * * @author Cristoforo Seccia (TXT e-solutions SpA) */ public class CapabilityServiceHelper implements ResourceLoaderAware { private static final Logger LOGGER = Logger.getLogger(CapabilityServiceHelper.class.getName()); //Used by the server into the xml response if the specified resource id is not the same as //the one specified in the capability. public static final String RESPONSE_INVALID_RESOURCE_ID = "The Resoure specified in the " + "request do not match the Capability Resource ID."; //Used by the server into the xml response if the specified operation is not contained in //the action rights of the capability. public static final String RESPONSE_INVALID_CAPABILITY_OPERATION = "The Operation specified in the " + "request is not specified in the Capability."; //Used by the server into the xml response if the operation is contained within the capability but //is not contained in the well known crud operation list. public static final String RESPONSE_INVALID_CRUD_OPERATION = "Can not perform the operation " + "specified in the request becouse it is not a standard CRUD operations."; public static final String RESPONSE_OPERATION_RESOURCE_NOT_EXIST = "The operation " + "can not be performed becouse the file do not exist."; //Used by the server after the RESPONSE_CAPABILITY_VALID if the operation Create can not be performed. public static final String RESPONSE_OPERATION_CREATE_ALREADY_EXIST = "The Create operation " + "can not be performed becouse the file already exist."; //Used by the server when creating a new file as specified by the capability request. public static final String OPERATION_CREATE_FILE_CONTENT = "This file was created by the " + "TXT Capability-Based Authorization System in order to perfom the Create operation."; //Used by the server after the RESPONSE_CAPABILITY_VALID if the operation Delete can not be performed. public static final String RESPONSE_OPERATION_DELETE_NOT_PERFORMED = "The Delete operation " + "can not be performed becouse the resource is not a file or is not an empty directory."; public static final String RESPONSE_OPERATION_CREATE_NOT_PERFORMED = "The Create operation " + "can not be performed."; private static KeystoreSignature.CertificateKeyValues CERTIFICATE_KEY_VALUES; private static ServerKeystoreDataModel KEYSTORE_DATA; private static KeystoreSignature KEYSTORE_SIGN; private static ResourceLoader RESOURCE_LOADER; public ServiceRequestInfoModel checkRequestCapability(CapabilityRequestType capabilityRequest) throws CapabilityServiceException { try { Document document = CapabilityDemoSchemaFactory.getCapabilityRequestToDocument(capabilityRequest); return checkRequestCapability(document.getDocumentElement()); } catch (CapabilityDemoSchemaFactoryException ex) { throw new CapabilityServiceException("Error while recovering Request document.", ex); } } public ServiceRequestInfoModel checkRequestCapability(Element capabilityRequest) throws CapabilityServiceException { CapabilitySchemasPrinter.prettyLogDocumentElement(capabilityRequest, "Receives request"); ServiceRequestInfoModel dataModel = new ServiceRequestInfoModel(); X509SubjectInfo requestSubjectInfo = new X509SubjectInfo(); CapabilityRequestType crt; // Check the Capability Request has not been tampered! try { Source source = new DOMSource(capabilityRequest); crt = CapabilityDemoSchemaFactory.getCapabilityRequestFromSource(source); KeystoreSignature signature = new KeystoreSignature(); if (!signature.verifyElementSignature(capabilityRequest, requestSubjectInfo)) { throw new CapabilityServiceException("The Request Document Sign is Invalid"); } } catch (CapabilityDemoSchemaFactoryException ex) { throw new CapabilityServiceException("Error while recovering Request document.", ex); } catch (KeystoreSecurityException ex) { throw new CapabilityServiceException("The Request Document Sign is Invalid.", ex); } //Verify the capability through the CapabilityVerifier AccessRightsCapabilityType capability = crt.getRequestAccessRightsCapability().getAccessRightsCapability(); try { ArrayList<VerifiedCapability> vcs = new ArrayList<VerifiedCapability>(); if (!CapabilityVerifier.accessRightsCapabilityValidityCheck(capability, vcs)) { String message = "Access Rights Capability is well formed but " + "did not pass the validity check."; throw new CapabilityServiceException(message); } } catch (CapabilityVerifierException ex) { throw new CapabilityServiceException(ex.getMessage(), ex); } catch (CapabilitySchemaValidationHandlerException ex) { String errors = CapabilitySchemaValidationHandler.dumpValidationEvents(ex.getValidationEvents()); throw new CapabilityServiceException(errors, ex); } //Check that the signer of the request is the subject of the capability String capabilitySubject = capability.getSubject().getSubjectID().getValue(); capabilitySubject = capabilitySubject.trim().replace(" ", ""); capabilitySubject = capabilitySubject.toUpperCase(); String requestSubject = requestSubjectInfo.getX509SubjectName(); requestSubject = requestSubject.trim().replace(" ", ""); requestSubject = requestSubject.toUpperCase(); if (!requestSubject.contains(capabilitySubject)) { String message = "The Subject used to sign the request is not " + "equal to the subject specified in the Capability."; throw new CapabilityServiceException(message); } //Check thet the request issue time is included in the capability //validation time range. XMLGregorianCalendar requestIssueTime = crt.getRequestIstant(); XMLGregorianCalendar capabilityNotBeforeTime = capability.getValidityCondition().getNotBefore(); XMLGregorianCalendar capabilityNotOrOnAfterTime = capability.getValidityCondition().getNotOnOrAfter(); int checkRequestIssueTimeToNotBeforeTime = CalendarUtils.comapareDataToAnotherDate(requestIssueTime, capabilityNotBeforeTime); int checkRequestIssueTimeToNotOrOnAfterTime = CalendarUtils.comapareDataToAnotherDate(requestIssueTime, capabilityNotOrOnAfterTime); if (checkRequestIssueTimeToNotBeforeTime != CalendarUtils.AFTER_THAN) { String message = "The request issue time is not 'after' " + "the Capability 'not before' time."; throw new CapabilityServiceException(message); } if (checkRequestIssueTimeToNotOrOnAfterTime != CalendarUtils.BEFORE_THAN) { String message = "The request issue time is not 'before' " + "the Capability 'not or on after' time."; throw new CapabilityServiceException(message); } //Everything is fine, now get the model dataModel.setRequestCapability(capability); dataModel.setRequestID(crt.getCapabilityRequestID()); dataModel.setResourceID(crt.getResourceID()); dataModel.setOperation(crt.getOperation()); dataModel.setCapabilityID(capability.getAccessRightsCapabilityID()); dataModel.setSigner(requestSubjectInfo.getX509SubjectName()); dataModel.setSignerKeyIssuer(requestSubjectInfo.getX509IssuerName()); dataModel.setSignerKeyID(requestSubjectInfo.getX509SerialNumber().toString(16)); return dataModel; } public void performRequestOperation(ServiceRequestInfoModel infoModel) throws CapabilityServiceException { File requestFile; //Recover request operation. String operation = infoModel.getOperation(); //Recover request resource. String resourceID = infoModel.getResourceID(); //Recover the file specified by the resource. //Before perfor the operation, check if the request is valid checkRequestOperation(infoModel); try { requestFile = new File(new URI(resourceID)); } catch (Exception ex) { //The Resource is not an URi; LOGGER.log(Level.INFO, ex.getMessage(), ex); requestFile = new File(resourceID); } LOGGER.log(Level.INFO, "The Resource ID Path: {0}", requestFile.getAbsolutePath()); //Check the operation type if (operation.equalsIgnoreCase(ClientServerUtils.OPERATION_UPDATE)) { if (!requestFile.exists()) { //can not perform update operation. throw new CapabilityServiceException(RESPONSE_OPERATION_RESOURCE_NOT_EXIST); } } else if (operation.equalsIgnoreCase(ClientServerUtils.OPERATION_READ)) { if (!requestFile.exists()) { //can not perform read operation. throw new CapabilityServiceException(RESPONSE_OPERATION_RESOURCE_NOT_EXIST); } } else if (operation.equalsIgnoreCase(ClientServerUtils.OPERATION_DELETE)) { if (!requestFile.exists()) { //can not perform delete operation. throw new CapabilityServiceException(RESPONSE_OPERATION_RESOURCE_NOT_EXIST); } else { //can not perform delete operation over directory. if (requestFile.isDirectory()) { throw new CapabilityServiceException(RESPONSE_OPERATION_DELETE_NOT_PERFORMED); } else if (requestFile.isFile()) { if (!requestFile.delete()) { //can not perform delete operation. throw new CapabilityServiceException(RESPONSE_OPERATION_DELETE_NOT_PERFORMED); } } else { //The resourceID is not a file. throw new CapabilityServiceException(RESPONSE_OPERATION_DELETE_NOT_PERFORMED); } } } else if (operation.equalsIgnoreCase(ClientServerUtils.OPERATION_CREATE)) { if (requestFile.exists()) { //can not perform create operation. throw new CapabilityServiceException(RESPONSE_OPERATION_CREATE_ALREADY_EXIST); } else { try { //write something to the created file FileWriter fileWriter = new FileWriter(requestFile.toURI().getPath()); fileWriter.append(OPERATION_CREATE_FILE_CONTENT); fileWriter.close(); } catch (IOException ex) { String response = ""; response += ClientServerUtils.RESPONSE_INTERNAL_ERROR; response += " "; response += RESPONSE_OPERATION_CREATE_NOT_PERFORMED; throw new CapabilityServiceException(response, ex); } } } else { //due the checkRequestValidity this case should not been performed. throw new CapabilityServiceException(ClientServerUtils.RESPONSE_REQUEST_OPERATION_NOT_PERFORMED); } } private void checkRequestOperation(ServiceRequestInfoModel infoModel) throws CapabilityServiceException { AccessRightsCapabilityType capability = infoModel.getRequestCapability(); String capabilityResource = capability.getResourceID(); String requestResource = infoModel.getResourceID(); if (!capabilityResource.equals(requestResource)) { throw new CapabilityServiceException(RESPONSE_INVALID_RESOURCE_ID); } List<AccessRightType> accessRights = capability.getAccessRights().getAccessRight(); String requestOperation = infoModel.getOperation(); boolean requestOperationFound = false; for (AccessRightType accessRightType : accessRights) { String action = accessRightType.getPermittedAction().getValue(); if (action.equalsIgnoreCase(requestOperation)) { requestOperationFound = true; break; } } if (!requestOperationFound) { throw new CapabilityServiceException(RESPONSE_INVALID_CAPABILITY_OPERATION); } boolean crudOperationFound = false; for (String crudOperation : ClientServerUtils.CRUD_LIST) { if (crudOperation.equalsIgnoreCase(requestOperation)) { crudOperationFound = true; break; } } if (!crudOperationFound) { throw new CapabilityServiceException(RESPONSE_INVALID_CRUD_OPERATION); } } public Element createSignedResponse(ServerResponseInfoModel responseInfoModel) throws CapabilityServiceException { try { String responseStatus = responseInfoModel.getResponseStatus(); String requestID = responseInfoModel.getRequestID(); CapabilityResponseType serverCapabilityResponse = CapabilityDemoSchemaFactory .createCapabilityResponse(responseStatus, requestID); Document document = CapabilityDemoSchemaFactory .getFragmentCapabilityResponseToDocument(serverCapabilityResponse); Element serverResponse = document.getDocumentElement(); KEYSTORE_SIGN.signElementObject(serverResponse, CERTIFICATE_KEY_VALUES, "CapabilityResponseID"); return serverResponse; } catch (CapabilityDemoSchemaFactoryException ex) { throw new CapabilityServiceException(ex.getMessage(), ex); } catch (KeystoreSecurityException ex) { throw new CapabilityServiceException(ex.getMessage(), ex); } } @Override public void setResourceLoader(ResourceLoader resourceLoader) { try { KeyStore keyStore = null; RESOURCE_LOADER = resourceLoader; String schemas = RESOURCE_LOADER.getResource("Capability_Schemas").getFile().getPath(); CapabilitySchemaFactory.initCapabilityCreator(schemas); LOGGER.log(Level.INFO, "Capability Creator Initialized successfully."); File keystore = RESOURCE_LOADER.getResource("keystore/capability_keystore.jks").getFile(); LOGGER.log(Level.INFO, "Set Resource Loader: {0}", keystore.getPath()); KEYSTORE_DATA.setKeystorePath(keystore.getPath()); KEYSTORE_DATA.setServerID("demoserver01@acme.com"); KEYSTORE_DATA.setKeystorePsw("sysmgr".toCharArray()); KEYSTORE_DATA.setPrivateKeyPsw("sysmgr".toCharArray()); java.security.cert.X509Certificate x509Certificate = null; try { //Recover the Keystore. keyStore = KeystoreHelper.getKeyStore(KEYSTORE_DATA.getKeystorePath(), KEYSTORE_DATA.getKeystorePsw()); //Recover the certificate from the Keystore x509Certificate = KeystoreHelper.getX509CertificateByIssuer(keyStore, KEYSTORE_DATA.getServerID()); //Check if we have found a certificate with the provided issuer. if (x509Certificate != null) { try { //Recover the alias of the certificate String SERVER_ALIAS = KeystoreHelper.getAlias(keyStore, x509Certificate); //Recover the private key of the. KEYSTORE_SIGN = new KeystoreSignature(); //Recover the server certificate key values CERTIFICATE_KEY_VALUES = KEYSTORE_SIGN.getCertificateKeyValues( KEYSTORE_DATA.getKeystorePath(), KEYSTORE_DATA.getPrivateKeyPsw(), SERVER_ALIAS, KEYSTORE_DATA.getPrivateKeyPsw()); } catch (KeyStoreException ex) { LOGGER.log(Level.SEVERE, "Cannot recover the alias of the certificate: {0}", ex.getMessage()); } catch (KeystoreSecurityException ex) { LOGGER.log(Level.SEVERE, "Error while recovering certificate private key: {0}", ex.getMessage()); } } else { LOGGER.log(Level.SEVERE, "Cannot find a certificate by using."); } } catch (KeystoreSecurityException ex) { LOGGER.log(Level.SEVERE, ex.getMessage()); } catch (GeneralSecurityException ex) { LOGGER.log(Level.SEVERE, "Error while searching for certificate into keystore: {0}", ex.getMessage()); } } catch (CapabilitySchemaFactoryException ex) { LOGGER.log(Level.SEVERE, ex.getMessage(), ex); } catch (IOException ex) { LOGGER.log(Level.SEVERE, ex.getMessage(), ex); } } }