diff --git a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/gui/MessageBean.java b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/gui/MessageBean.java index 053bed57d98acf7a1a348a4a3b8f26070b89e839..8560473281dd005668fd33a117071c143fb38f2d 100644 --- a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/gui/MessageBean.java +++ b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/gui/MessageBean.java @@ -30,6 +30,7 @@ import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; import org.apache.commons.httpclient.methods.multipart.PartSource; import org.apache.commons.lang.StringEscapeUtils; +import org.apache.log4j.Logger; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; @@ -42,6 +43,8 @@ import org.jboss.seam.international.StatusMessage; @Scope(ScopeType.PAGE) public class MessageBean { + private static final Logger log = Logger.getLogger(MessageBean.class); + @In private EntityManager entityManager; @@ -227,7 +230,6 @@ public class MessageBean { e.printStackTrace(); } // redirect the user to the good page - boolean fail = false; if (status == HttpStatus.SC_OK) { try { String key = filePost.getResponseBodyAsString(); @@ -238,11 +240,8 @@ public class MessageBean { response.sendRedirect(url); } catch (IOException e) { - fail = true; - e.printStackTrace(); + log.error(e); } - } else { - fail = true; } } } diff --git a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/HL7EventListener.java b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/HL7EventListener.java index 305812993b560e9e5c19f7064ef2f4b9f06f854b..4e2a1f2988de4718edadae4ab6b97ab1727c5dce 100644 --- a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/HL7EventListener.java +++ b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/HL7EventListener.java @@ -17,7 +17,7 @@ public class HL7EventListener extends SameEventListener<String> { requestChannelId, responseChannelId, side); hl7message.setMessageReceivedAsString(message); - messageListener.processMessageSimple(hl7message); + messageListener.processMessage(hl7message); } } } diff --git a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/MessageListener.java b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/MessageListener.java index 9ddb816203527fc6c8ce539caa6e1468d44757aa..328ccafa225d4e6e5fca00408d08c854e7751b88 100644 --- a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/MessageListener.java +++ b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/MessageListener.java @@ -6,7 +6,7 @@ import net.ihe.gazelle.proxy.model.message.AbstractMessage; public interface MessageListener { - void processMessageSimple(AbstractMessage abstractMessage); + void processMessage(AbstractMessage abstractMessage); EntityManager getEntityManager(); diff --git a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/MessageListenerSaveAbstract.java b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/MessageListenerSaveAbstract.java index 42d4ad1e580474eda3e5411eb032bee054fcd5a7..88f2f4947edba65205d0e821e14fc47bde76167a 100644 --- a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/MessageListenerSaveAbstract.java +++ b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/MessageListenerSaveAbstract.java @@ -6,8 +6,6 @@ import net.ihe.gazelle.proxy.model.message.AbstractMessage; public abstract class MessageListenerSaveAbstract implements MessageListener { - private static org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(MessageListenerSaveAbstract.class); - @Override public void processMessage(EntityManager em, AbstractMessage abstractMessage) { if (abstractMessage.getId() == null) { @@ -18,38 +16,10 @@ public abstract class MessageListenerSaveAbstract implements MessageListener { } @Override - public void processMessageSimple(AbstractMessage abstractMessage) { + public void processMessage(AbstractMessage abstractMessage) { EntityManager em = getEntityManager(); processMessage(em, abstractMessage); releaseEntityManager(em); } - /* - public void processMessage(EntityManager em, AbstractMessage abstractMessage) { - if (em == null || abstractMessage == null) { - log.fatal("entityManager null or abstractMessage null"); - return null; - } - AbstractMessage messageToReturn = null; - synchronized (em) { - - boolean transactionWasActive = false; - - EntityTransaction transaction = em.getTransaction(); - synchronized (transaction) { - if (!transaction.isActive()) { - transaction.begin(); - } else - transactionWasActive = true; - em.persist(abstractMessage); - messageToReturn = em.merge(abstractMessage); - - if (!transactionWasActive) { - transaction.commit(); - } - } - } - return messageToReturn; - } - */ } diff --git a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/RawEventListener.java b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/RawEventListener.java index 8cf79ee776fd58efd7e1821fe93bb485bc6aa6a1..16aaad566db2868be140356136d1760522d5c206 100644 --- a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/RawEventListener.java +++ b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/RawEventListener.java @@ -17,7 +17,7 @@ public class RawEventListener extends SameEventListener<byte[]> { requestChannelId, responseChannelId, side); rawmessage.setMessageReceived(message); - messageListener.processMessageSimple(rawmessage); + messageListener.processMessage(rawmessage); } } diff --git a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/SyslogEventListener.java b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/SyslogEventListener.java index 6ec184548075ac31e74d438e30ccedda75c3fc9e..8953d8555c1ffcc0fffc7684bbd44f537cc891eb 100644 --- a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/SyslogEventListener.java +++ b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/listeners/SyslogEventListener.java @@ -1,23 +1,35 @@ package net.ihe.gazelle.proxy.listeners; +import net.ihe.gazelle.proxy.model.message.RawMessage; import net.ihe.gazelle.proxy.model.message.SyslogMessage; import net.ihe.gazelle.proxy.netty.channel.ProxySide; +import net.ihe.gazelle.proxy.netty.protocols.syslog.SyslogData; -public class SyslogEventListener extends SameEventListener<String> { +public class SyslogEventListener extends GazelleProxyEventListener<SyslogData, byte[]> { public SyslogEventListener(MessageListener messageListener) { super(messageListener); } - protected void saveMessage(String message, String requesterIp, int requesterPort, int proxyPort, - String responderIp, int responderPort, int requestChannelId, int responseChannelId, ProxySide side) { - // Messages are coming from different threads! + @Override + public void onRequest(SyslogData request, String requesterIp, int requesterPort, int proxyProviderPort, + String responderIp, int responderPort, int providerChannelId, int consumerChannelId) { synchronized (this) { - SyslogMessage syslogMessage = new SyslogMessage(requesterIp, requesterPort, proxyPort, responderIp, - responderPort, requestChannelId, responseChannelId, side); - syslogMessage.setMessageReceivedAsString(message); - messageListener.processMessageSimple(syslogMessage); + SyslogMessage syslogMessage = new SyslogMessage(requesterIp, requesterPort, proxyProviderPort, responderIp, + responderPort, providerChannelId, consumerChannelId, request); + messageListener.processMessage(syslogMessage); } } + @Override + public void onResponse(byte[] response, String requesterIp, int requesterPort, int proxyProviderPort, + String responderIp, int responderPort, int providerChannelId, int consumerChannelId) { + // Messages are coming from different threads! + synchronized (this) { + RawMessage rawmessage = new RawMessage(requesterIp, requesterPort, proxyProviderPort, responderIp, + responderPort, providerChannelId, consumerChannelId, ProxySide.RESPONSE); + rawmessage.setMessageReceived(response); + messageListener.processMessage(rawmessage); + } + } } diff --git a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/model/message/SyslogMessage.java b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/model/message/SyslogMessage.java index d2766ff263d205c71877e969f78db7b726c5f6c1..069b5bbea027be22b34cd27c58a88f90425ad620 100644 --- a/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/model/message/SyslogMessage.java +++ b/gazelle-proxy-jar/src/main/java/net/ihe/gazelle/proxy/model/message/SyslogMessage.java @@ -19,6 +19,7 @@ import javax.persistence.Entity; import net.ihe.gazelle.proxy.netty.ChannelType; import net.ihe.gazelle.proxy.netty.channel.ProxySide; +import net.ihe.gazelle.proxy.netty.protocols.syslog.SyslogData; import org.jboss.seam.annotations.Name; @@ -28,17 +29,107 @@ public class SyslogMessage extends AbstractMessage implements java.io.Serializab private static final long serialVersionUID = -2767782636271713844L; + private Integer facility; + + private String hostName; + + private Integer severity; + + private String timestamp; + + private String tag; + + private String appName; + + private String messageId; + + private String procId; + public SyslogMessage() { super(); + setProxySide(ProxySide.REQUEST); } public SyslogMessage(String fromIP, Integer localPort, Integer proxyPort, String toIP, Integer remotePort, - Integer requestChannelId, Integer responseChannelId, ProxySide proxySide) { - super(fromIP, localPort, proxyPort, toIP, remotePort, requestChannelId, responseChannelId, proxySide); + Integer requestChannelId, Integer responseChannelId, SyslogData request) { + super(fromIP, localPort, proxyPort, toIP, remotePort, requestChannelId, responseChannelId, ProxySide.REQUEST); + this.facility = request.getFacility(); + this.hostName = request.getHostName(); + this.severity = request.getSeverity(); + this.timestamp = request.getTimestamp(); + this.tag = request.getTag(); + this.appName = request.getAppName(); + this.messageId = request.getMessageId(); + this.procId = request.getProcId(); + setMessageReceivedAsString(request.getMessage()); } public ChannelType getChannelType() { return ChannelType.SYSLOG; } + public Integer getFacility() { + return facility; + } + + public void setFacility(Integer facility) { + this.facility = facility; + } + + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } + + public Integer getSeverity() { + return severity; + } + + public void setSeverity(Integer severity) { + this.severity = severity; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getMessageId() { + return messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getProcId() { + return procId; + } + + public void setProcId(String procId) { + this.procId = procId; + } + } diff --git a/gazelle-proxy-netty/pom.xml b/gazelle-proxy-netty/pom.xml index 11fabe65d026abfcf33b9a21069f93640a212f76..d3fbc91e64f8fc4f6434edc8bdb1f7ee577ae39f 100644 --- a/gazelle-proxy-netty/pom.xml +++ b/gazelle-proxy-netty/pom.xml @@ -1,4 +1,5 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>net.ihe.gazelle.proxy</groupId> @@ -37,6 +38,17 @@ <artifactId>ihej-dicom</artifactId> <version>1.0</version> </dependency> + <dependency> + <groupId>org.openhealthtools.openatna</groupId> + <artifactId>syslog-core</artifactId> + <version>1.2</version> + </dependency> + <dependency> + <groupId>org.openhealthtools.openatna</groupId> + <artifactId>syslog-mina</artifactId> + <version>1.2</version> + <scope>test</scope> + </dependency> <dependency> <groupId>apache-log4j</groupId> <artifactId>log4j</artifactId> diff --git a/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/raw/RawEventListenerSimple.java b/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/raw/RawEventListenerSimple.java new file mode 100644 index 0000000000000000000000000000000000000000..773cf5390e89bb4e0b76dfee05efbba9b3b7a8b8 --- /dev/null +++ b/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/raw/RawEventListenerSimple.java @@ -0,0 +1,23 @@ +package net.ihe.gazelle.proxy.netty.protocols.raw; + +import java.io.PrintStream; + +import net.ihe.gazelle.proxy.netty.ProxyEventListenerToStream; + +public class RawEventListenerSimple extends ProxyEventListenerToStream<byte[], byte[]> { + + public RawEventListenerSimple(PrintStream printStream) { + super(printStream); + } + + @Override + protected String decodeResponse(byte[] response) { + return new String(response); + } + + @Override + protected String decodeRequest(byte[] request) { + return new String(request); + } + +} diff --git a/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/syslog/SyslogData.java b/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/syslog/SyslogData.java new file mode 100644 index 0000000000000000000000000000000000000000..c6392f39c191604a56ebabf465fc194dae3d73ce --- /dev/null +++ b/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/syslog/SyslogData.java @@ -0,0 +1,127 @@ +package net.ihe.gazelle.proxy.netty.protocols.syslog; + +import java.io.ByteArrayOutputStream; + +import org.openhealthtools.openatna.syslog.LogMessage; +import org.openhealthtools.openatna.syslog.SyslogException; +import org.openhealthtools.openatna.syslog.SyslogMessage; +import org.openhealthtools.openatna.syslog.bsd.BsdMessage; +import org.openhealthtools.openatna.syslog.protocol.ProtocolMessage; + +public class SyslogData { + + private int facility; + private String hostName; + private int severity; + private String timestamp; + private String message; + private String tag; + private String appName; + private String messageId; + private String procId; + + public SyslogData(SyslogMessage<?> syslogMessage) { + super(); + + facility = syslogMessage.getFacility(); + hostName = syslogMessage.getHostName(); + severity = syslogMessage.getSeverity(); + timestamp = syslogMessage.getTimestamp(); + + LogMessage<?> logMessage = syslogMessage.getMessage(); + message = null; + if (logMessage != null) { + Object messageObject = logMessage.getMessageObject(); + + if (messageObject instanceof String) { + message = (String) messageObject; + } else { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try { + logMessage.write(bos); + message = new String(bos.toByteArray()); + } catch (SyslogException e) { + message = null; + } + } + } + tag = null; + if (syslogMessage instanceof BsdMessage) { + BsdMessage<?> bsdMessage = (BsdMessage<?>) syslogMessage; + tag = bsdMessage.getTag(); + } + + appName = null; + messageId = null; + procId = null; + if (syslogMessage instanceof ProtocolMessage) { + ProtocolMessage<?> protocolMessage = (ProtocolMessage<?>) syslogMessage; + appName = protocolMessage.getAppName(); + messageId = protocolMessage.getMessageId(); + procId = protocolMessage.getProcId(); + } + + } + + public int getFacility() { + return facility; + } + + public String getHostName() { + return hostName; + } + + public int getSeverity() { + return severity; + } + + public String getTimestamp() { + return timestamp; + } + + public String getMessage() { + return message; + } + + public String getTag() { + return tag; + } + + public String getAppName() { + return appName; + } + + public String getMessageId() { + return messageId; + } + + public String getProcId() { + return procId; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("SyslogData [facility="); + builder.append(facility); + builder.append(", hostName="); + builder.append(hostName); + builder.append(", severity="); + builder.append(severity); + builder.append(", timestamp="); + builder.append(timestamp); + builder.append(", message="); + builder.append(message); + builder.append(", tag="); + builder.append(tag); + builder.append(", appName="); + builder.append(appName); + builder.append(", messageId="); + builder.append(messageId); + builder.append(", procId="); + builder.append(procId); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/syslog/SyslogFrameDecoder.java b/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/syslog/SyslogFrameDecoder.java new file mode 100644 index 0000000000000000000000000000000000000000..d952089d5cbf0f965ad87006f2ca8beafe450684 --- /dev/null +++ b/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/syslog/SyslogFrameDecoder.java @@ -0,0 +1,57 @@ +package net.ihe.gazelle.proxy.netty.protocols.syslog; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.handler.codec.frame.FrameDecoder; +import org.openhealthtools.openatna.syslog.SyslogMessage; +import org.openhealthtools.openatna.syslog.SyslogMessageFactory; + +class SyslogFrameDecoder extends FrameDecoder { + + private static final int STATUS_SIZE = 0; + private static final int STATUS_READ = 1; + private static final int STATUS_END = 2; + + private int status = STATUS_SIZE; + private StringBuffer messageSizeBuffer = new StringBuffer(); + private int messageSize; + private ByteArrayOutputStream currentFrame = null; + + @Override + protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { + while (buffer.readableBytes() > 0) { + byte readByte = buffer.readByte(); + switch (status) { + case STATUS_SIZE: + if (readByte == 32) { + status = STATUS_READ; + messageSize = Integer.parseInt(messageSizeBuffer.toString()); + currentFrame = new ByteArrayOutputStream(); + } else { + char c = (char) readByte; + messageSizeBuffer.append(c); + } + break; + case STATUS_READ: + if (currentFrame.size() == messageSize) { + status = STATUS_END; + byte[] bytes = currentFrame.toByteArray(); + SyslogMessage<?> syslogMessage = SyslogMessageFactory.getFactory().read( + new ByteArrayInputStream(bytes)); + return new SyslogData(syslogMessage); + } + currentFrame.write(readByte); + break; + case STATUS_END: + return null; + default: + break; + } + } + return null; + } +} diff --git a/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/syslog/SyslogProxy.java b/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/syslog/SyslogProxy.java index 72aac403fb62916b442a8ce5969b1069123bedcd..efca84684c81548d3d5f9c3982d644e1bb941595 100644 --- a/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/syslog/SyslogProxy.java +++ b/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/protocols/syslog/SyslogProxy.java @@ -6,16 +6,14 @@ import java.util.List; import net.ihe.gazelle.proxy.netty.ConnectionConfig; import net.ihe.gazelle.proxy.netty.Proxy; import net.ihe.gazelle.proxy.netty.ProxyEventListener; +import net.ihe.gazelle.proxy.netty.channel.ProxyTools; import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandler; -import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; -import org.jboss.netty.util.CharsetUtil; -public class SyslogProxy extends Proxy<String, String> { +public class SyslogProxy extends Proxy<SyslogData, byte[]> { - public SyslogProxy(ProxyEventListener<String, String> proxyEventListener, ConnectionConfig connectionConfig) { + public SyslogProxy(ProxyEventListener<SyslogData, byte[]> proxyEventListener, ConnectionConfig connectionConfig) { super(proxyEventListener, connectionConfig); } @@ -23,32 +21,31 @@ public class SyslogProxy extends Proxy<String, String> { List<ChannelHandler> channels = new ArrayList<ChannelHandler>(); // Decode syslog messages - channels.add(new DelimiterBasedFrameDecoder(1024 * 1024, getSyslogDelimiter())); + channels.add(new SyslogFrameDecoder()); return channels; } - public static ChannelBuffer[] getSyslogDelimiter() { - return new ChannelBuffer[] { ChannelBuffers.wrappedBuffer("auditmessage".getBytes(CharsetUtil.UTF_8)) }; - } - public List<ChannelHandler> getDecodersForResponse() { - return getDecodersForRequest(); + return new ArrayList<ChannelHandler>(); } @Override - public String handleRequest(Object message) { - if (message instanceof ChannelBuffer) { - ChannelBuffer cb = (ChannelBuffer) message; - String result = cb.toString(CharsetUtil.UTF_8); - return result; + public SyslogData handleRequest(Object message) { + if (message instanceof SyslogData) { + SyslogData syslogData = (SyslogData) message; + return syslogData; } return null; } @Override - public String handleResponse(Object message) { - return handleRequest(message); + public byte[] handleResponse(Object message) { + if (message instanceof ChannelBuffer) { + ChannelBuffer cb = (ChannelBuffer) message; + return ProxyTools.getBytes(cb); + } + return null; } } diff --git a/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/tools/SyslogEventListenerSimple.java b/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/tools/SyslogEventListenerSimple.java index 2f8e528e465693dda153149854aaff17ea281d96..8db74ac28172c7342f407a5d412e2a7f07cff1b9 100644 --- a/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/tools/SyslogEventListenerSimple.java +++ b/gazelle-proxy-netty/src/main/java/net/ihe/gazelle/proxy/netty/tools/SyslogEventListenerSimple.java @@ -3,21 +3,22 @@ package net.ihe.gazelle.proxy.netty.tools; import java.io.PrintStream; import net.ihe.gazelle.proxy.netty.ProxyEventListenerToStream; +import net.ihe.gazelle.proxy.netty.protocols.syslog.SyslogData; -public class SyslogEventListenerSimple extends ProxyEventListenerToStream<String, String> { +public class SyslogEventListenerSimple extends ProxyEventListenerToStream<SyslogData, byte[]> { public SyslogEventListenerSimple(PrintStream printStream) { super(printStream); } @Override - protected String decodeResponse(String response) { - return response; + protected String decodeRequest(SyslogData request) { + return request.toString(); } @Override - protected String decodeRequest(String request) { - return request; + protected String decodeResponse(byte[] request) { + return new String(request); } } diff --git a/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/App.java b/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/App.java index 3649b19dde7b3d4ea12a008d5ff96565f21eb297..4eb227a8670cb15bb6feb455b74916f0a8d5722c 100644 --- a/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/App.java +++ b/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/App.java @@ -1,6 +1,12 @@ package net.ihe.gazelle.proxy.netty; +import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; import jp.digitalsensation.ihej.transactionmonitor.dicom.messageexchange.DimseMessage; import net.ihe.gazelle.proxy.netty.basictls.ConnectionConfigSimpleTls; @@ -8,14 +14,29 @@ import net.ihe.gazelle.proxy.netty.basictls.TlsConfig; import net.ihe.gazelle.proxy.netty.basictls.TlsCredentials; import net.ihe.gazelle.proxy.netty.protocols.dicom.DicomProxy; import net.ihe.gazelle.proxy.netty.protocols.http.HttpProxy; +import net.ihe.gazelle.proxy.netty.protocols.raw.RawEventListenerSimple; +import net.ihe.gazelle.proxy.netty.protocols.raw.RawProxy; +import net.ihe.gazelle.proxy.netty.syslog.AuthSSLSocketFactory; +import net.ihe.gazelle.proxy.netty.syslog.KeystoreDetails; import net.ihe.gazelle.proxy.netty.tools.DicomEventListenerSimple; import net.ihe.gazelle.proxy.netty.tools.HttpEventListenerSimple; +import org.openhealthtools.openatna.syslog.Constants; +import org.openhealthtools.openatna.syslog.SyslogException; +import org.openhealthtools.openatna.syslog.SyslogMessage; +import org.openhealthtools.openatna.syslog.message.StringLogMessage; +import org.openhealthtools.openatna.syslog.mina.tls.TlsServer; +import org.openhealthtools.openatna.syslog.protocol.ProtocolMessage; +import org.openhealthtools.openatna.syslog.protocol.SdParam; +import org.openhealthtools.openatna.syslog.protocol.StructuredElement; +import org.openhealthtools.openatna.syslog.transport.SyslogListener; + public class App { public static void main(String[] args) throws Exception { // testHttpsConnection(); - startDicomProxyTLS(10004); + // startDicomProxyTLS(10004); + startSyslogProxyTLS(); /* startHTTPProxyBasic(10000); @@ -45,11 +66,103 @@ public class App { } + private static void startSyslogProxyTLS() { + // Syslog Client -TLS> Proxy1 -> Proxy Web app -> Proxy3 -TLS> Syslog + // Server + + // Starts a Syslog server (8443) + try { + AuthSSLSocketFactory serverSocketFactory = getSyslogServerSocketFactory(); + org.openhealthtools.openatna.syslog.mina.tls.TlsConfig serverConfig = new org.openhealthtools.openatna.syslog.mina.tls.TlsConfig(); + serverConfig.setSSLContext(serverSocketFactory.getSSLContext()); + serverConfig.setHost("localhost"); + serverConfig.setPort(8443); + TlsServer server = new TlsServer(); + server.configure(serverConfig); + server.addSyslogListener(new Listener()); + server.start(); + } catch (IOException e) { + e.printStackTrace(); + } + + RawEventListenerSimple listener = new RawEventListenerSimple(System.out); + + // Starts proxy3 + InputStream clientKeyStoreStream = listener.getClass().getResourceAsStream("/keys/clientKeyStore"); + TlsCredentials clientCredentials = new TlsCredentials(clientKeyStoreStream, "clientStorePass".toCharArray(), + "myClientCert", "password".toCharArray()); + TlsConfig tlsConfigClient = new TlsConfig(null, true, clientCredentials); + ConnectionConfig connectionConfigClient = new ConnectionConfigSimpleTls(8442, "127.0.0.1", 8443, + ChannelType.SYSLOG, tlsConfigClient); + RawProxy proxy3 = new RawProxy(listener, connectionConfigClient); + proxy3.start(); + + // Starts proxy2 + InputStream serverKeyStoreStream = listener.getClass().getResourceAsStream("/keys/serverKeyStore"); + TlsCredentials serverCredentials = new TlsCredentials(serverKeyStoreStream, "serverStorePass".toCharArray(), + "myServerCert", "password".toCharArray()); + TlsConfig tlsConfigServer = new TlsConfig(serverCredentials, false, null); + ConnectionConfig connectionConfigServer = new ConnectionConfigSimpleTls(9443, "127.0.0.1", 10000, + ChannelType.SYSLOG, tlsConfigServer); + RawProxy proxy1 = new RawProxy(listener, connectionConfigServer); + proxy1.start(); + + // Ping! + try { + AuthSSLSocketFactory clientSocketFactory = getSyslogClientSocketFactory(); + + ProtocolMessage sl = new ProtocolMessage(10, 5, "2009-08-14T14:12:23.115Z", "localhost", + new StringLogMessage("<atna></atna>"), "IHE_XDS", "ATNALOG", "1234"); + List<SdParam> params = new ArrayList<SdParam>(); + params.add(new SdParam("param1", "param value\\=1")); + params.add(new SdParam("param2", "param value] 2")); + params.add(new SdParam("param3", "param value 3")); + params.add(new SdParam("param3", "param value 4")); + StructuredElement se = new StructuredElement("exampleSDID@1234", params); + sl.addStructuredElement(se); + + Socket s = clientSocketFactory.createSecureSocket("localhost", 9443); + OutputStream out = s.getOutputStream(); + byte[] bytes = sl.toByteArray(); + for (int i = 0; i < 5; i++) { + // add message length plus space before message + out.write((String.valueOf(bytes.length) + " ").getBytes(Constants.ENC_UTF8)); + out.write(bytes); + out.flush(); + } + out.close(); + s.close(); + } catch (SyslogException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + private static AuthSSLSocketFactory getSyslogServerSocketFactory() throws IOException { + URL u = Thread.currentThread().getContextClassLoader().getResource("keys/serverKeyStore"); + KeystoreDetails key = new KeystoreDetails(u.toString(), "serverStorePass", "myServerCert", "password"); + URL uu = Thread.currentThread().getContextClassLoader().getResource("keys/clientKeyStore"); + KeystoreDetails trust = new KeystoreDetails(uu.toString(), "clientStorePass", "myClientCert"); + AuthSSLSocketFactory f = new AuthSSLSocketFactory(key, trust); + return f; + } + + private static AuthSSLSocketFactory getSyslogClientSocketFactory() throws IOException { + URL u = Thread.currentThread().getContextClassLoader().getResource("keys/serverKeyStore"); + KeystoreDetails trust = new KeystoreDetails(u.toString(), "serverStorePass", "myServerCert"); + URL uu = Thread.currentThread().getContextClassLoader().getResource("keys/clientKeyStore"); + KeystoreDetails key = new KeystoreDetails(uu.toString(), "clientStorePass", "myClientCert", "password"); + AuthSSLSocketFactory f = new AuthSSLSocketFactory(key, trust); + return f; + } + private static void startDicomProxyTLS(int port) { final ProxyEventListener<DimseMessage, DimseMessage> dicomProxyEvent = new DicomEventListenerSimple(System.out); - TlsConfig tlsConfig = new TlsConfig(new TlsCredentials(getStream("/home/glandais/435.p12"), "password".toCharArray()), false, - null); + TlsConfig tlsConfig = new TlsConfig(new TlsCredentials(getStream("/home/glandais/435.p12"), + "password".toCharArray()), false, null); ConnectionConfigSimpleTls connectionConfig = new ConnectionConfigSimpleTls(port, "kujira.irisa.fr", 10002, ChannelType.DICOM, tlsConfig); @@ -61,8 +174,8 @@ public class App { private static void startHTTPProxyTLSServer(int port) { HttpEventListenerSimple eventListener = new HttpEventListenerSimple(System.out); - TlsConfig tlsConfig = new TlsConfig(new TlsCredentials(getStream("/home/glandais/435.p12"), "password".toCharArray()), false, - null); + TlsConfig tlsConfig = new TlsConfig(new TlsCredentials(getStream("/home/glandais/435.p12"), + "password".toCharArray()), false, null); HttpProxy httpProxy = new HttpProxy(eventListener, new ConnectionConfigSimpleTls(port, "www.google.fr", 80, ChannelType.HTTP, tlsConfig)); httpProxy.start(); @@ -95,4 +208,18 @@ public class App { ChannelType.HTTP)); httpProxy.start(); } + + static class Listener implements SyslogListener { + + public void messageArrived(SyslogMessage message) { + System.out.println("serialized message:"); + System.out.println(message.toString()); + System.out.println("application message:"); + System.out.println(message.getMessage().getMessageObject()); + } + + public void exceptionThrown(SyslogException exception) { + exception.printStackTrace(); + } + } } diff --git a/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/AuthSSLSocketFactory.java b/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/AuthSSLSocketFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..01bd93207862383bbeda9920bf7fa54c26f056a8 --- /dev/null +++ b/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/AuthSSLSocketFactory.java @@ -0,0 +1,257 @@ +/** + * Copyright (c) 2009-2011 University of Cardiff and others + * + * 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. + * + * Contributors: + * University of Cardiff - initial API and implementation + * - + */ + +package net.ihe.gazelle.proxy.netty.syslog; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.logging.Logger; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + + +/** + * + */ +public class AuthSSLSocketFactory { + + static Logger log = Logger.getLogger("org.openhealthtools.openatna.syslog.test.tls.ssl.AuthSSLSocketFactory"); + + private KeystoreDetails details = null; + private KeystoreDetails truststore = null; + + private SSLContext sslcontext = null; + private X509TrustManager defaultTrustManager = null; + + public AuthSSLSocketFactory(KeystoreDetails details, KeystoreDetails truststore, X509TrustManager defaultTrustManager) throws IOException { + super(); + + if (details != null) { + this.details = details; + } + if (truststore != null) { + this.truststore = truststore; + } + if (defaultTrustManager == null) { + log.fine(" using sun default trust manager"); + this.defaultTrustManager = KeystoreManager.getDefaultTrustManager(); + } else { + this.defaultTrustManager = defaultTrustManager; + } + } + + public AuthSSLSocketFactory(KeystoreDetails details, KeystoreDetails truststore) throws IOException { + this(details, truststore, null); + } + + public AuthSSLSocketFactory(KeystoreDetails details, X509TrustManager defaultTrustManager) throws IOException { + this(details, null, defaultTrustManager); + } + + public AuthSSLSocketFactory(KeystoreDetails details) throws IOException { + this(details, null, null); + } + + private static KeyStore createKeyStore(KeystoreDetails details) + throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { + if (details.getKeystoreLocation() == null) { + throw new IllegalArgumentException("Keystore location may not be null"); + } + + log.fine("Initializing key store"); + KeyStore keystore = KeyStore.getInstance(details.getKeystoreType()); + InputStream is = null; + try { + is = getKeystoreInputStream(details.getKeystoreLocation()); + if (is == null) { + throw new IOException("Could not open stream to " + details.getKeystoreLocation()); + } + String password = details.getKeystorePassword(); + keystore.load(is, password != null ? password.toCharArray() : null); + } finally { + if (is != null) { + is.close(); + } + } + return keystore; + } + + private static InputStream getKeystoreInputStream(String location) { + try { + File file = new File(location); + if (file.exists()) { + return new FileInputStream(file); + } + } catch (Exception e) { + + } + try { + URL url = new URL(location); + return url.openStream(); + } catch (Exception e) { + + } + log.fine("could not open stream to:" + location); + return null; + } + + private KeyManager[] createKeyManagers(final KeyStore keystore, KeystoreDetails details) + throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { + if (keystore == null) { + throw new IllegalArgumentException("Keystore may not be null"); + } + log.fine("Initializing key manager"); + KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(details.getAlgType()); + String password = details.getKeyPassword(); + kmfactory.init(keystore, (password == null || password.length() == 0) ? details.getKeystorePassword().toCharArray() : password.toCharArray()); + return kmfactory.getKeyManagers(); + + } + + private TrustManager[] createTrustManagers(KeystoreDetails truststore, final KeyStore keystore, X509TrustManager defaultTrustManager) + throws KeyStoreException, NoSuchAlgorithmException { + + if (keystore == null) { + throw new IllegalArgumentException("Keystore may not be null"); + } + TrustManagerFactory tmfactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());//TrustManagerFactory.getInstance(algorithm); + tmfactory.init(keystore); + TrustManager[] trustmanagers = tmfactory.getTrustManagers(); + for (int i = 0; i < trustmanagers.length; i++) { + + if (trustmanagers[i] instanceof X509TrustManager) { + return new TrustManager[]{ + new AuthSSLX509TrustManager((X509TrustManager) trustmanagers[i], defaultTrustManager, truststore.getAuthorizedDNs())}; + } + } + return trustmanagers; + } + + private SSLContext createSSLContext() throws IOException { + try { + KeyManager[] keymanagers = null; + TrustManager[] trustmanagers = null; + if (this.details != null) { + KeyStore keystore = createKeyStore(details); + Enumeration aliases = keystore.aliases(); + while (aliases.hasMoreElements()) { + String alias = (String) aliases.nextElement(); + Certificate[] certs = keystore.getCertificateChain(alias); + if (certs != null) { + log.fine("Certificate chain '" + alias + "':"); + for (int c = 0; c < certs.length; c++) { + if (certs[c] instanceof X509Certificate) { + X509Certificate cert = (X509Certificate) certs[c]; + log.fine(" Certificate " + (c + 1) + ":"); + log.fine(" Subject DN: " + cert.getSubjectDN()); + log.fine(" Signature Algorithm: " + cert.getSigAlgName()); + log.fine(" Valid from: " + cert.getNotBefore()); + log.fine(" Valid until: " + cert.getNotAfter()); + log.fine(" Issuer: " + cert.getIssuerDN()); + } + } + } + + } + keymanagers = createKeyManagers(keystore, details); + } + if (this.truststore != null) { + KeyStore keystore = createKeyStore(truststore); + Enumeration aliases = keystore.aliases(); + while (aliases.hasMoreElements()) { + String alias = (String) aliases.nextElement(); + log.fine("Trusted certificate '" + alias + "':"); + Certificate trustedcert = keystore.getCertificate(alias); + if (trustedcert != null && trustedcert instanceof X509Certificate) { + X509Certificate cert = (X509Certificate) trustedcert; + log.fine(" Subject DN: " + cert.getSubjectDN()); + log.fine(" Signature Algorithm: " + cert.getSigAlgName()); + log.fine(" Valid from: " + cert.getNotBefore()); + log.fine(" Valid until: " + cert.getNotAfter()); + log.fine(" Issuer: " + cert.getIssuerDN()); + } + } + trustmanagers = createTrustManagers(truststore, keystore, defaultTrustManager); + } + if (trustmanagers == null) { + log.fine(" created trustmanagers from the default..."); + trustmanagers = new TrustManager[]{defaultTrustManager}; + } + + SSLContext sslcontext = SSLContext.getInstance("SSL"); + sslcontext.init(keymanagers, trustmanagers, null); + return sslcontext; + } catch (NoSuchAlgorithmException e) { + log.warning(e.getMessage()); + throw new IOException("Unsupported algorithm exception: " + e.getMessage()); + } catch (KeyStoreException e) { + log.warning(e.getMessage()); + throw new IOException("Keystore exception: " + e.getMessage()); + } catch (GeneralSecurityException e) { + log.warning(e.getMessage()); + throw new IOException("Key management exception: " + e.getMessage()); + } catch (IOException e) { + log.warning(e.getMessage()); + throw new IOException("I/O error reading keystore/truststore file: " + e.getMessage()); + } + } + + public SSLContext getSSLContext() throws IOException { + if (this.sslcontext == null) { + this.sslcontext = createSSLContext(); + } + return this.sslcontext; + } + + public Socket createSecureSocket(String host, int port) throws IOException { + return getSSLContext().getSocketFactory().createSocket(host, port); + } + + public ServerSocket createServerSocket(int port) throws IOException { + return getSSLContext().getServerSocketFactory().createServerSocket(port); + } + + public boolean isSecured() { + return true; + } + + +} \ No newline at end of file diff --git a/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/AuthSSLX509TrustManager.java b/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/AuthSSLX509TrustManager.java new file mode 100644 index 0000000000000000000000000000000000000000..a10565691d3929427cd0d04133713b2689542cdc --- /dev/null +++ b/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/AuthSSLX509TrustManager.java @@ -0,0 +1,140 @@ +/** + * Copyright (c) 2009-2011 University of Cardiff and others + * + * 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. + * + * Contributors: + * University of Cardiff - initial API and implementation + * - + */ + +package net.ihe.gazelle.proxy.netty.syslog; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import javax.net.ssl.X509TrustManager; + +/** + * <p> + * <p/> + * </p> + */ + +public class AuthSSLX509TrustManager implements X509TrustManager { + + private X509TrustManager trustManager = null; + private X509TrustManager defaultTrustManager = null; + List<String> authorizedDns = null; + /** + * Log object for this class. + */ + static Logger log = Logger.getLogger("org.openhealthtools.openatna.syslog.test.tls.ssl.AuthSSLX509TrustManager"); + + /** + * Constructor for AuthSSLX509TrustManager. + */ + public AuthSSLX509TrustManager(final X509TrustManager trustManager, final X509TrustManager defaultTrustManager, List<String> authorizedDns) { + super(); + if (trustManager == null) { + throw new IllegalArgumentException("Trust manager may not be null"); + } + this.trustManager = trustManager; + this.defaultTrustManager = defaultTrustManager; + this.authorizedDns = authorizedDns; + if (this.authorizedDns == null) { + this.authorizedDns = new ArrayList<String>(); + } + } + + /** + * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType) + */ + public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException { + if (certificates != null) { + boolean isAuthDN = false; + if (authorizedDns.size() == 0) { + isAuthDN = true; + } + for (int c = 0; c < certificates.length; c++) { + X509Certificate cert = certificates[c]; + if (isAuthDN == false) { + for (String authorizedDn : authorizedDns) { + if (authorizedDn.equals(cert.getSubjectDN())) { + isAuthDN = true; + } + } + } + log.fine(" Client certificate " + (c + 1) + ":"); + log.fine(" Subject DN: " + cert.getSubjectDN()); + log.fine(" Signature Algorithm: " + cert.getSigAlgName()); + log.fine(" Valid from: " + cert.getNotBefore()); + log.fine(" Valid until: " + cert.getNotAfter()); + log.fine(" Issuer: " + cert.getIssuerDN()); + } + if (!isAuthDN) { + throw new CertificateException("Subject DN is not authorized to perform the requested action."); + } + trustManager.checkClientTrusted(certificates, authType); + } + + } + + /** + * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType) + */ + public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException { + if (certificates != null) { + for (int c = 0; c < certificates.length; c++) { + X509Certificate cert = certificates[c]; + log.fine(" Server certificate " + (c + 1) + ":"); + log.fine(" Subject DN: " + cert.getSubjectDN()); + log.fine(" Signature Algorithm: " + cert.getSigAlgName()); + log.fine(" Valid from: " + cert.getNotBefore()); + log.fine(" Valid until: " + cert.getNotAfter()); + log.fine(" Issuer: " + cert.getIssuerDN()); + } + } + + try { + if (defaultTrustManager != null) { + defaultTrustManager.checkServerTrusted(certificates, authType); + } + } catch (CertificateException e) { + trustManager.checkServerTrusted(certificates, authType); + } + } + + /** + * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() + */ + public X509Certificate[] getAcceptedIssuers() { + X509Certificate[] certs = this.trustManager.getAcceptedIssuers(); + + if (defaultTrustManager != null) { + X509Certificate[] suncerts = this.defaultTrustManager.getAcceptedIssuers(); + X509Certificate[] all = new X509Certificate[certs.length + suncerts.length]; + System.arraycopy(certs, 0, all, 0, certs.length); + System.arraycopy(suncerts, 0, all, certs.length, suncerts.length); + certs = all; + } + if (certs == null) { + certs = new X509Certificate[0]; + } + + return certs; + } +} \ No newline at end of file diff --git a/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/KeystoreDetails.java b/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/KeystoreDetails.java new file mode 100644 index 0000000000000000000000000000000000000000..a0a14ce2e5e2c083f60bde9180da6662adeb0376 --- /dev/null +++ b/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/KeystoreDetails.java @@ -0,0 +1,138 @@ +/** + * Copyright (c) 2009-2011 University of Cardiff and others + * + * 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. + * + * Contributors: + * University of Cardiff - initial API and implementation + * - + */ + +package net.ihe.gazelle.proxy.netty.syslog; + +import java.util.ArrayList; +import java.util.List; + + +/** + * interface for classes that can retrieve details required for signing a jar or authetication. + * + * @author Andrew Harrison + * @version $Revision: 72 $ + * @created Mar 16, 2007: 3:13:50 PM + * @date $Date: 2007-03-23 09:52:50 +0000 (Fri, 23 Mar 2007) $ modified by $Author: scmabh $ + * @todo Put your notes here... + */ +public class KeystoreDetails { + + private String keystoreLocation = ""; + private String keystorePassword = ""; + private String alias = ""; + private String keyPassword = null; + private String keystoreType = "JKS"; + private String algType = "SunX509"; + private String authority = ""; + private List<String> authorizedDNs = new ArrayList<String>(); + + /** + * create a KeystoreDetails for accessing a certificate + * + * @param keystoreLocation + * @param keystorePassword + * @param alias + * @param keyPassword + */ + public KeystoreDetails(String keystoreLocation, String keystorePassword, String alias, String keyPassword) { + this.keystoreLocation = keystoreLocation; + this.keystorePassword = keystorePassword; + this.alias = alias; + this.keyPassword = keyPassword; + } + + public KeystoreDetails(String keystoreLocation, String keystorePassword, String alias) { + this.keystoreLocation = keystoreLocation; + this.keystorePassword = keystorePassword; + this.alias = alias; + this.keyPassword = keystorePassword; + } + + /** + * constructor used when loading details from file. + */ + public KeystoreDetails() { + } + + public String getKeystoreLocation() { + return keystoreLocation; + } + + public String getKeystorePassword() { + return keystorePassword; + } + + public String getAlias() { + return alias; + } + + public String getKeyPassword() { + return keyPassword; + } + + public void setKeyPassword(String keyPassword) { + this.keyPassword = keyPassword; + } + + public String getKeystoreType() { + return keystoreType; + } + + public void setKeystoreType(String keystoreType) { + this.keystoreType = keystoreType; + } + + public String getAlgType() { + return algType; + } + + public void setAlgType(String algType) { + this.algType = algType; + } + + /** + * combination of host (domain or IP) and port separated by a colon. + * + * @return + */ + public String getAuthority() { + return authority; + } + + public void setAuthority(String authority) { + this.authority = authority; + } + + public void addAuthorizedDN(String dn) { + if (!authorizedDNs.contains(dn)) { + authorizedDNs.add(dn); + } + } + + public List<String> getAuthorizedDNs() { + return authorizedDNs; + } + + public void setAuthorizedDNs(List<String> authorizedDNs) { + this.authorizedDNs = authorizedDNs; + } + +} diff --git a/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/KeystoreManager.java b/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/KeystoreManager.java new file mode 100644 index 0000000000000000000000000000000000000000..22563e63f31b28265ef68e13a9a64ba6ea470352 --- /dev/null +++ b/gazelle-proxy-netty/src/test/java/net/ihe/gazelle/proxy/netty/syslog/KeystoreManager.java @@ -0,0 +1,430 @@ +/** + * Copyright (c) 2009-2011 University of Cardiff and others + * + * 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. + * + * Contributors: + * University of Cardiff - initial API and implementation + * - + */ + +package net.ihe.gazelle.proxy.netty.syslog; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.cert.CertificateException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Properties; +import java.util.logging.Logger; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +/** + * Class Description Here... + * + * @author Andrew Harrison + * @version $Revision:$ + * @created Nov 20, 2008: 7:58:07 PM + * @date $Date:$ modified by $Author:$ + * @todo Put your notes here... + */ + +public class KeystoreManager { + + static Logger log = Logger.getLogger("org.wspeer.security.KeystoreManager"); + + private static X509TrustManager sunTrustManager = null; + private KeystoreDetails defaultKeyDetails; + private HashMap<String, KeystoreDetails> allKeys = new HashMap<String, KeystoreDetails>(); + private HashMap<String, KeystoreDetails> allStores = new HashMap<String, KeystoreDetails>(); + + private File keysDir; + private File certsDir; + private String home; + + static { + loadDefaultTrustManager(); + } + + private static void loadDefaultTrustManager() { + try { + File certs; + String definedcerts = System.getProperty("javax.net.ssl.trustStore"); + String pass = System.getProperty("javax.net.ssl.trustStorePassword"); + if (definedcerts != null) { + certs = new File(definedcerts); + } else { + String common = System.getProperty("java.home") + + File.separator + + "lib" + + File.separator + + "security" + + File.separator; + String cacerts = common + "cacerts"; + String jssecacerts = common + "jssecacerts"; + certs = new File(jssecacerts); + if (!certs.exists() || certs.length() == 0) { + certs = new File(cacerts); + } + + } + if (pass == null) { + pass = "changeit"; + } + if (certs != null) { + KeyStore ks = KeyStore.getInstance("jks"); + ks.load(new FileInputStream(certs), pass.toCharArray()); + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509", "SunJSSE"); + tmf.init(ks); + TrustManager tms[] = tmf.getTrustManagers(); + for (int i = 0; i < tms.length; i++) { + if (tms[i] instanceof X509TrustManager) { + log.info(" found default trust manager."); + sunTrustManager = (X509TrustManager) tms[i]; + break; + } + } + } + + } catch (KeyStoreException e) { + log.fine("Exception thrown trying to create default trust manager:" + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + log.fine("Exception thrown trying to create default trust manager:" + e.getMessage()); + } catch (CertificateException e) { + log.fine("Exception thrown trying to create default trust manager:" + e.getMessage()); + } catch (NoSuchProviderException e) { + log.fine("Exception thrown trying to create default trust manager:" + e.getMessage()); + } catch (FileNotFoundException e) { + log.fine("Exception thrown trying to create default trust manager:" + e.getMessage()); + } catch (IOException e) { + log.fine("Exception thrown trying to create default trust manager:" + e.getMessage()); + } + } + + public KeystoreManager(String home) { + if (home != null) { + this.home = home; + loadKeys(this.home); + } + } + + private void loadKeys(String home) { + File sec = new File(home); + if (!sec.exists()) { + return; + } + + keysDir = new File(sec, "keys"); + if (!keysDir.exists()) { + keysDir.mkdir(); + } + certsDir = new File(sec, "certs"); + if (!certsDir.exists()) { + certsDir.mkdir(); + } + File[] keyfiles = keysDir.listFiles(); + if (keyfiles != null) { + for (File keyfile : keyfiles) { + try { + KeystoreDetails kd = load(new FileInputStream(keyfile)); + if (kd.getAuthority() != null && kd.getAuthority().trim().equalsIgnoreCase("default")) { + defaultKeyDetails = kd; + } + allKeys.put(keyfile.getName(), kd); + + } catch (IOException e) { + log.info(" exception thrown while loading details from " + keyfile.getAbsolutePath()); + continue; + } + } + } + keyfiles = certsDir.listFiles(); + if (keyfiles != null) { + for (File keyfile : keyfiles) { + try { + KeystoreDetails kd = load(new FileInputStream(keyfile)); + allStores.put(keyfile.getName(), kd); + + } catch (IOException e) { + log.info(" exception thrown while loading details from " + keyfile.getAbsolutePath()); + continue; + } + } + } + } + + public static X509TrustManager getDefaultTrustManager() { + return sunTrustManager; + } + + public void addKeyDetails(String fileName, KeystoreDetails details) throws IOException { + storeAsKey(details, fileName); + allKeys.put(fileName, details); + } + + public void addTrustDetails(String fileName, KeystoreDetails details) throws IOException { + storeAsCert(details, fileName); + allStores.put(fileName, details); + } + + public void deleteKeyDetails(String fileName) { + allKeys.remove(fileName); + deleteKey(fileName); + } + + public void deleteTrustDetails(String fileName) { + allStores.remove(fileName); + deleteCert(fileName); + } + + public KeystoreDetails getKeyDetails(String fileName) { + return allKeys.get(fileName); + } + + public KeystoreDetails getTrustStoreDetails(String fileName) { + return allStores.get(fileName); + } + + public void setDefaultKeystoreDetails(KeystoreDetails details) { + defaultKeyDetails = details; + } + + public KeystoreDetails getDefaultKeyDetails() { + return defaultKeyDetails; + } + + public File getKeysDirectory() { + return keysDir; + } + + public File getCertsDirectory() { + return certsDir; + } + + public KeystoreDetails getKeyFileDetails(String fileName) { + return allKeys.get(fileName); + } + + public KeystoreDetails getStoreFileDetails(String fileName) { + return allStores.get(fileName); + } + + public String[] getKeyfileNames() { + return allKeys.keySet().toArray(new String[allKeys.keySet().size()]); + } + + public String[] getTrustfileNames() { + return allStores.keySet().toArray(new String[allStores.keySet().size()]); + } + + public KeystoreDetails getKeyFileForHost(String host) { + KeystoreDetails def = null; + for (KeystoreDetails keystoreDetails : allKeys.values()) { + System.out.println("KeystoreManager.getKeyFileForHost getting next key authority:" + keystoreDetails.getAuthority()); + String auth = keystoreDetails.getAuthority(); + if (auth != null) { + if (auth.endsWith("*")) { + String s = trimPort(host); + if (s != null) { + log.fine("KeystoreManager.getKeyFileForHost trimmed port:" + s); + String a = getAnyPort(auth); + if (a != null) { + log.fine("KeystoreManager.getKeyFileForHost trimmed auth:" + a); + auth = a; + host = s; + } + } + } + if (auth.equals(host)) { + return keystoreDetails; + } else if (auth.equalsIgnoreCase("default")) { + def = keystoreDetails; + } + } + } + return def; + } + + private static String trimPort(String host) { + int colon = host.indexOf(":"); + if (colon > 0 && colon < host.length() - 1) { + try { + int port = Integer.parseInt(host.substring(colon + 1, host.length()), host.length()); + host = host.substring(0, colon); + log.fine("KeystoreManager.trimPort up to colon:" + host); + log.fine("KeystoreManager.trimPort port:" + port); + + return host; + } catch (NumberFormatException e) { + } + } + return null; + } + + private static String getAnyPort(String auth) { + int star = auth.indexOf("*"); + if (star == auth.length() - 1) { + int colon = auth.indexOf(":"); + if (colon == star - 1) { + auth = auth.substring(0, colon); + return auth; + } + } + return null; + } + + public KeystoreDetails getTrustFileForHost(String host) { + + KeystoreDetails def = null; + for (KeystoreDetails keystoreDetails : allStores.values()) { + String auth = keystoreDetails.getAuthority(); + if (auth != null) { + if (auth.endsWith("*")) { + String s = trimPort(host); + if (s != null) { + String a = getAnyPort(auth); + if (a != null) { + auth = a; + host = s; + } + } + } + if (auth.equals(host)) { + return keystoreDetails; + } else if (auth.equalsIgnoreCase("default")) { + def = keystoreDetails; + } + } + } + return def; + } + + + public KeystoreDetails load(InputStream in) throws IOException { + Properties props = new Properties(); + props.load(in); + String keystoreLocation = props.getProperty("keystoreLocation"); + if (keystoreLocation == null || keystoreLocation.length() == 0) { + throw new IOException("no location defined"); + } + String keystorePassword = props.getProperty("keystorePassword"); + if (keystorePassword == null || keystorePassword.length() == 0) { + throw new IOException("no keystore password defined"); + } + String alias = props.getProperty("alias"); + String keyPassword = props.getProperty("keyPassword"); + if (keyPassword == null || keyPassword.length() == 0) { + keyPassword = keystorePassword; + } + String keystoreType = props.getProperty("keystoreType"); + if (keystoreType == null || keystoreType.length() == 0) { + keystoreType = "JKS"; + } + String algType = props.getProperty("algType"); + if (algType == null || algType.length() == 0) { + algType = "SunX509"; + } + String authority = props.getProperty("authority"); + if (authority == null) { + authority = ""; + } + + String dns = props.getProperty("authorizedDNs"); + List<String> authorizedDNs = new ArrayList<String>(); + if (dns != null && dns.length() > 0) { + String[] dn = dns.split("&"); + for (String s : dn) { + String decoded = URLDecoder.decode(s, "UTF-8"); + if (decoded.length() > 0) { + authorizedDNs.add(decoded); + } + } + } + KeystoreDetails details = new KeystoreDetails(keystoreLocation, keystorePassword, alias, keyPassword); + details.setAlgType(algType); + details.setKeystoreType(keystoreType); + details.setAuthority(authority); + for (String authorizedDN : authorizedDNs) { + details.addAuthorizedDN(authorizedDN); + } + return details; + } + + public void storeAsKey(KeystoreDetails details, String name) throws IOException { + store(details, name, true); + } + + public void storeAsCert(KeystoreDetails details, String name) throws IOException { + store(details, name, false); + } + + public boolean deleteKey(String name) { + return delete(name, true); + } + + public boolean deleteCert(String name) { + return delete(name, false); + } + + private boolean delete(String name, boolean key) { + File f = key ? getKeysDirectory() : getCertsDirectory(); + f = new File(f, name); + return f.delete(); + } + + private void store(KeystoreDetails details, String name, boolean key) throws IOException { + Properties props = new Properties(); + props.setProperty("keystoreLocation", details.getKeystoreLocation()); + props.setProperty("keystorePassword", details.getKeystorePassword()); + props.setProperty("alias", details.getAlias()); + if (details.getKeyPassword() == null) { + details.setKeyPassword(""); + } + props.setProperty("keyPassword", details.getKeyPassword()); + props.setProperty("keystoreType", details.getKeystoreType()); + props.setProperty("algType", details.getAlgType()); + if (details.getAuthority() != null) { + props.setProperty("authority", details.getAuthority()); + } + List<String> authorizedDNs = details.getAuthorizedDNs(); + if (authorizedDNs.size() > 0) { + StringBuilder sb = new StringBuilder(); + for (String dn : authorizedDNs) { + sb.append(URLEncoder.encode(dn, "UTF-8")).append("&"); + } + props.setProperty("authorizedDNs", sb.toString()); + } + File f = key ? getKeysDirectory() : getCertsDirectory(); + f = new File(f, name); + FileOutputStream out = new FileOutputStream(f); + props.store(out, "Details for " + details.getAlias() + " keystore access."); + out.close(); + } + + +} diff --git a/gazelle-proxy-netty/src/test/resources/keys/clientKeyStore b/gazelle-proxy-netty/src/test/resources/keys/clientKeyStore new file mode 100644 index 0000000000000000000000000000000000000000..d5e6c1b6103503afc66add97c9c6cf28eaca9a65 Binary files /dev/null and b/gazelle-proxy-netty/src/test/resources/keys/clientKeyStore differ diff --git a/gazelle-proxy-netty/src/test/resources/keys/serverKeyStore b/gazelle-proxy-netty/src/test/resources/keys/serverKeyStore new file mode 100644 index 0000000000000000000000000000000000000000..db9b60cdde7f88c77584883ffb6210881c3d83b5 Binary files /dev/null and b/gazelle-proxy-netty/src/test/resources/keys/serverKeyStore differ