/** * Licensed to the Austrian Association for Software Tool Integration (AASTI) * under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright * ownership. The AASTI licenses this file to you 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 test; import java.io.IOException; import java.io.InputStream; import java.security.PublicKey; import java.util.UUID; import javax.crypto.SecretKey; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.IOUtils; import org.openengsb.core.api.model.BeanDescription; import org.openengsb.core.api.remote.MethodCall; import org.openengsb.core.api.remote.MethodCallMessage; import org.openengsb.core.api.remote.MethodResult; import org.openengsb.core.api.remote.MethodResultMessage; import org.openengsb.core.api.security.DecryptionException; import org.openengsb.core.api.security.EncryptionException; import org.openengsb.core.api.security.model.EncryptedMessage; import org.openengsb.core.util.CipherUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.SessionCallback; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableMap; /** * Setup to run this app: + Start OpenEngSB + install the jms-feature: * features:install openengsb-ports-jms + copy example+example+testlog.connector * to the openengsb/config-directory + copy openengsb/etc/keys/public.key.data * to src/main/resources */ public final class SecureSampleApp { private static final Logger LOGGER = LoggerFactory.getLogger(SecureSampleApp.class); private static final ObjectMapper MAPPER = new ObjectMapper(); private static final String URL = "tcp://127.0.0.1:6549"; private static JmsTemplate template; private static void init() throws JMSException { ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(URL); template = new JmsTemplate(cf); } private static MethodResult call(MethodCall call, String username, Object credentails) throws IOException, JMSException, InterruptedException, ClassNotFoundException, EncryptionException, DecryptionException { MethodCallMessage methodCallRequest = new MethodCallMessage(call); SecretKey sessionKey = CipherUtils.generateKey("AES", 128); String requestString = marshalRequest(methodCallRequest, sessionKey, username, credentails); String resultString = sendMessage(requestString); return convertStringToResult(resultString, sessionKey); } private static String sendMessage(final String encryptedMessage) { return template.execute(new SessionCallback<String>() { @Override public String doInJms(Session session) throws JMSException { TextMessage message = session.createTextMessage(encryptedMessage); Queue outQueue = session.createQueue("receive"); Destination inDest = session.createTemporaryQueue(); String correlationID = UUID.randomUUID().toString(); message.setJMSReplyTo(inDest); message.setJMSCorrelationID(correlationID); MessageProducer producer = session.createProducer(outQueue); producer.send(outQueue, message); return ((TextMessage) session.createConsumer(inDest).receive(10000)).getText(); } }, true); } private static String marshalRequest(MethodCallMessage methodCallRequest, SecretKey sessionKey, String username, Object credentials) throws IOException, EncryptionException { byte[] requestString = marshalSecureRequest(methodCallRequest, username, credentials); EncryptedMessage encryptedMessage = encryptMessage(sessionKey, requestString); return MAPPER.writeValueAsString(encryptedMessage); } private static EncryptedMessage encryptMessage(SecretKey sessionKey, byte[] requestString) throws IOException, EncryptionException { PublicKey publicKey = readPublicKey(); byte[] encryptedContent = CipherUtils.encrypt(requestString, sessionKey); byte[] encryptedKey = CipherUtils.encrypt(sessionKey.getEncoded(), publicKey); EncryptedMessage encryptedMessage = new EncryptedMessage(encryptedContent, encryptedKey); return encryptedMessage; } private static PublicKey readPublicKey() throws IOException { InputStream publicKeyResource = ClassLoader.getSystemResourceAsStream("public.key.data"); byte[] publicKeyData = IOUtils.toByteArray(publicKeyResource); PublicKey publicKey = CipherUtils.deserializePublicKey(publicKeyData, "RSA"); return publicKey; } private static byte[] marshalSecureRequest(MethodCallMessage methodCallRequest, String username, Object credentials) throws IOException { BeanDescription credentialsBean = BeanDescription.fromObject(credentials); methodCallRequest.setPrincipal(username); methodCallRequest.setCredentials(credentialsBean); return MAPPER.writeValueAsBytes(methodCallRequest); } private static MethodResult convertStringToResult(String resultString, SecretKey sessionKey) throws IOException, ClassNotFoundException, DecryptionException { MethodResultMessage resultMessage = decryptResponse(resultString, sessionKey); return convertResult(resultMessage); } private static MethodResult convertResult(MethodResultMessage resultMessage) throws ClassNotFoundException { MethodResult result = resultMessage.getResult(); Class<?> clazz = Class.forName(result.getClassName()); Object resultValue = MAPPER.convertValue(result.getArg(), clazz); result.setArg(resultValue); return result; } private static MethodResultMessage decryptResponse(String resultString, SecretKey sessionKey) throws DecryptionException, IOException { byte[] decryptedContent; try { decryptedContent = CipherUtils.decrypt(Base64.decodeBase64(resultString), sessionKey); } catch (DecryptionException e) { System.err.println(resultString); throw e; } MethodResultMessage resultMessage = MAPPER.readValue(decryptedContent, MethodResultMessage.class); return resultMessage; } /** * Small-test client that can be used for sending jms-messages to a running * openengsb */ public static void main(String[] args) throws Exception { LOGGER.info("initializing"); init(); LOGGER.info("initialized"); MethodCall methodCall = new MethodCall("doSomething", new Object[] { "Hello World!" }, ImmutableMap.of( "serviceId", "example+example+testlog", "contextId", "foo")); LOGGER.info("calling method"); MethodResult methodResult = call(methodCall, "admin", "password"); System.out.println(methodResult); } private SecureSampleApp() { } }