Merge "Issue #2756 implemented HTTP public key auth scheme" into development

Former-commit-id: 99fd81f105 [formerly 99fd81f105 [formerly 21d22f790f71941797a23926be5ed77c6d72353b]]
Former-commit-id: 869909cc66
Former-commit-id: 19a252d820
This commit is contained in:
Nate Jensen 2014-03-03 09:44:26 -06:00 committed by Gerrit Code Review
commit 76318d62e8
50 changed files with 3216 additions and 274 deletions

View file

@ -19,7 +19,9 @@ Require-Bundle: org.eclipse.core.runtime,
com.raytheon.uf.common.localization,
com.raytheon.uf.viz.core,
com.raytheon.uf.common.time,
com.raytheon.uf.common.util
com.raytheon.uf.common.util,
com.raytheon.uf.common.xmpp,
com.raytheon.uf.common.http
Export-Package: com.raytheon.uf.viz.collaboration.comm,
com.raytheon.uf.viz.collaboration.comm.compression,
com.raytheon.uf.viz.collaboration.comm.identity,
@ -28,6 +30,7 @@ Export-Package: com.raytheon.uf.viz.collaboration.comm,
com.raytheon.uf.viz.collaboration.comm.identity.invite,
com.raytheon.uf.viz.collaboration.comm.identity.roster,
com.raytheon.uf.viz.collaboration.comm.identity.user,
com.raytheon.uf.viz.collaboration.comm.packet,
com.raytheon.uf.viz.collaboration.comm.provider,
com.raytheon.uf.viz.collaboration.comm.provider.event,
com.raytheon.uf.viz.collaboration.comm.provider.info,

View file

@ -17,15 +17,22 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider;
package com.raytheon.uf.viz.collaboration.comm.packet;
import java.util.Arrays;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.util.Base64;
import com.raytheon.uf.common.serialization.SerializationUtil;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.xmpp.PacketConstants;
import com.raytheon.uf.common.xmpp.XmlBuilder;
import com.raytheon.uf.common.xmpp.XmlBuilder.Pair;
import com.raytheon.uf.common.xmpp.ext.BaseExtension;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.provider.CollaborationXmlManager;
import com.raytheon.uf.viz.collaboration.comm.provider.SerializationMode;
/**
* XMPP packet extension for collaboration session data
@ -37,13 +44,14 @@ import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 11, 2013 2562 bclement Initial creation
* Feb 27, 2013 2756 bclement extends BaseExtension
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class SessionPayload implements PacketExtension {
public class SessionPayload extends BaseExtension {
private static final IUFStatusHandler log = UFStatus
.getHandler(SessionPayload.class);
@ -52,8 +60,6 @@ public class SessionPayload implements PacketExtension {
Config, Command, Invitation;
};
public static final String XMLNS = "urn:uf:viz:collaboration";
public static final String ELEMENT_NAME = "SessionData";
public static final String TYPE_ATTRIBUTE = "payloadtype";
@ -75,6 +81,7 @@ public class SessionPayload implements PacketExtension {
* message object
*/
public SessionPayload(PayloadType type, SerializationMode mode, Object data) {
super(ELEMENT_NAME, PacketConstants.COLLAB_XMLNS);
this.payloadType = type;
this.mode = mode;
this.data = data;
@ -106,18 +113,16 @@ public class SessionPayload implements PacketExtension {
*/
public static String createXml(PayloadType type, SerializationMode mode,
Object data) throws CollaborationException {
StringBuilder builder = new StringBuilder();
builder = new StringBuilder();
builder.append("<").append(ELEMENT_NAME).append(" ");
appendAttribute(builder, "xmlns", XMLNS);
appendAttribute(builder, TYPE_ATTRIBUTE, type.name());
appendAttribute(builder, ENCODING_ATTRIBUTE, mode.name());
builder.append(">");
XmlBuilder builder = new XmlBuilder();
Pair typeAttr = new Pair(TYPE_ATTRIBUTE, type.name());
Pair encAttr = new Pair(ENCODING_ATTRIBUTE, mode.name());
builder.startTag(ELEMENT_NAME, PacketConstants.COLLAB_XMLNS,
Arrays.asList(typeAttr, encAttr));
switch (mode) {
case THRIFT:
try {
byte[] arr = SerializationUtil.transformToThrift(data);
builder.append(Base64.encodeBytes(arr));
builder.appendText(Base64.encodeBytes(arr));
} catch (Exception e) {
throw new CollaborationException(
"[THRIFT] Could not serialize object", e);
@ -128,14 +133,14 @@ public class SessionPayload implements PacketExtension {
CollaborationXmlManager jaxb = CollaborationXmlManager
.getInstance();
String xml = jaxb.marshalToFragment(data);
builder.append(xml);
builder.appendText(xml);
} catch (Exception je) {
throw new CollaborationException(
"[JAXB] Could not serialize object", je);
}
break;
case STRING:
builder.append(data.toString());
builder.appendText(data.toString());
break;
case NONE:
throw new CollaborationException("Serialization of "
@ -143,23 +148,10 @@ public class SessionPayload implements PacketExtension {
case ISNULL:
break;
}
builder.append("</").append(ELEMENT_NAME).append(">");
builder.endTag(ELEMENT_NAME);
return builder.toString();
}
/**
* Format XML attribute name/value pair and append to string builder
*
* @param sb
* @param name
* @param value
*/
private static void appendAttribute(StringBuilder sb, String name,
String value) {
sb.append(name).append("='").append(value).append("' ");
}
/**
* @return the payloadType
*/
@ -181,26 +173,6 @@ public class SessionPayload implements PacketExtension {
return data;
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.smack.packet.PacketExtension#getElementName()
*/
@Override
public String getElementName() {
return ELEMENT_NAME;
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.smack.packet.PacketExtension#getNamespace()
*/
@Override
public String getNamespace() {
return XMLNS;
}
/*
* (non-Javadoc)
*
@ -219,5 +191,4 @@ public class SessionPayload implements PacketExtension {
}
}
}

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider;
package com.raytheon.uf.viz.collaboration.comm.packet;
import java.io.IOException;
@ -34,8 +34,11 @@ import com.raytheon.uf.common.serialization.SerializationException;
import com.raytheon.uf.common.serialization.SerializationUtil;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.xmpp.BaseProvider;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.provider.CollaborationXmlManager;
import com.raytheon.uf.viz.collaboration.comm.provider.SerializationMode;
/**
* XMPP packet extension parsing provider for collaboration session data
@ -48,6 +51,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload.PayloadTyp
* ------------ ---------- ----------- --------------------------
* Dec 16, 2013 2562 bclement Initial creation
* Feb 12, 2014 2793 bclement improved error handling
* Feb 27, 2013 2756 bclement extends BaseProvider
*
* </pre>
*
@ -55,98 +59,86 @@ import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload.PayloadTyp
* @version 1.0
*/
public class SessionPayloadProvider implements PacketExtensionProvider {
public class SessionPayloadProvider extends BaseProvider<SessionPayload>
implements PacketExtensionProvider {
private static final IUFStatusHandler log = UFStatus
.getHandler(SessionPayloadProvider.class);
public SessionPayloadProvider() {
super(SessionPayload.ELEMENT_NAME);
}
/* (non-Javadoc)
* @see org.jivesoftware.smack.provider.PacketExtensionProvider#parseExtension(org.xmlpull.v1.XmlPullParser)
/*
* (non-Javadoc)
*
* @see
* org.jivesoftware.smack.provider.PacketExtensionProvider#parseExtension
* (org.xmlpull.v1.XmlPullParser)
*/
@Override
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception {
return parse(parser);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.common.xmpp.BaseProvider#parseInternal(org.xmlpull.v1
* .XmlPullParser)
*/
@Override
protected SessionPayload parseInternal(XmlPullParser parser)
throws XmlPullParserException, IOException {
try {
return parseInternal(parser);
String typeString = parser.getAttributeValue(null,
SessionPayload.TYPE_ATTRIBUTE);
String modeString = parser.getAttributeValue(null,
SessionPayload.ENCODING_ATTRIBUTE);
checkAttribute(SessionPayload.TYPE_ATTRIBUTE, typeString);
checkAttribute(SessionPayload.ENCODING_ATTRIBUTE, modeString);
SerializationMode mode;
try {
mode = SerializationMode.valueOf(modeString);
} catch (IllegalArgumentException e) {
throw new CollaborationException(
"Unsupported payload encoding: " + modeString, e);
}
PayloadType t;
try {
t = PayloadType.valueOf(typeString);
} catch (IllegalArgumentException e) {
throw new CollaborationException(
"Unsupported IQ payload type: " + typeString, e);
}
Object data;
switch (mode) {
case THRIFT:
String text = getText(parser);
data = unmarshalThrift(text);
break;
case JAXB:
data = unmarshalJaxb(parser);
break;
case STRING:
data = getText(parser);
break;
default:
throw new CollaborationException("Could not deserialize object");
}
return new SessionPayload(t, mode, data);
} catch (CollaborationException e) {
// collaboration exceptions are only thrown for problems with our own format
// collaboration exceptions are only thrown for problems with our
// own format
log.error("Unable to parse collaboration packet", e);
return new SessionPayload(PayloadType.Command,
SerializationMode.ISNULL, null);
} finally {
// ensure that we are at the end of the packet so we don't corrupt
// stream
while (!atEndOfPacket(parser)) {
parser.next();
}
}
}
/**
* @param parser
* @return true if parser is at the end tag of the payload packet
* @throws XmlPullParserException
*/
private static boolean atEndOfPacket(XmlPullParser parser)
throws XmlPullParserException {
return parser.getEventType() == XmlPullParser.END_TAG
&& parser.getName().equals(SessionPayload.ELEMENT_NAME);
}
/**
* Parse contents of packet extension from XMPP stream.
*
* @param parser
* @return
* @throws CollaborationException
* when error occurs with collaboration format
* @throws XmlPullParserException
* when error occurs with XMPP stream
* @throws IOException
* when error occurs with XMPP stream
*/
private static PacketExtension parseInternal(XmlPullParser parser)
throws CollaborationException, XmlPullParserException, IOException {
String typeString = parser.getAttributeValue(null,
SessionPayload.TYPE_ATTRIBUTE);
String modeString = parser.getAttributeValue(null,
SessionPayload.ENCODING_ATTRIBUTE);
checkAttribute(SessionPayload.TYPE_ATTRIBUTE, typeString);
checkAttribute(SessionPayload.ENCODING_ATTRIBUTE, modeString);
SerializationMode mode;
try {
mode = SerializationMode.valueOf(modeString);
} catch (IllegalArgumentException e) {
throw new CollaborationException("Unsupported payload encoding: "
+ modeString, e);
}
PayloadType t;
try {
t = PayloadType.valueOf(typeString);
} catch (IllegalArgumentException e) {
throw new CollaborationException("Unsupported IQ payload type: "
+ typeString, e);
}
Object data;
switch (mode) {
case THRIFT:
String text = getText(parser);
data = unmarshalThrift(text);
break;
case JAXB:
data = unmarshalJaxb(parser);
break;
case STRING:
data = getText(parser);
break;
default:
throw new CollaborationException("Could not deserialize object");
}
return new SessionPayload(t, mode, data);
}
/**
* Unmarshal base64 encoded thrift data
*
@ -185,31 +177,6 @@ public class SessionPayloadProvider implements PacketExtensionProvider {
return manager.unmarshalFromXPP(parser);
}
/**
* Get any text elements under current tag
*
* @param parser
* @return
* @throws XmlPullParserException
* @throws IOException
*/
private static String getText(XmlPullParser parser)
throws XmlPullParserException, IOException {
boolean done = false;
StringBuilder payloadText = new StringBuilder();
while (!done) {
if (atEndOfPacket(parser)) {
done = true;
continue;
} else if (parser.getEventType() == XmlPullParser.TEXT) {
payloadText.append(parser.getText());
}
parser.next();
}
return payloadText.toString();
}
/**
* Assert that value is not null or empty
*

View file

@ -43,6 +43,7 @@ import com.raytheon.uf.common.serialization.jaxb.JaxbDummyObject;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.xmpp.PullParserJaxbAdapter;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.core.procedures.ProcedureXmlManager;
import com.raytheon.uf.viz.core.reflect.SubClassLocator;

View file

@ -0,0 +1,223 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
import java.net.URI;
import java.security.GeneralSecurityException;
import java.security.SignatureException;
import org.apache.http.message.AbstractHttpMessage;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.util.SyncPacketSend;
import com.raytheon.uf.common.http.auth.ClientSignatureAuth;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.xmpp.BaseProvider;
import com.raytheon.uf.common.xmpp.iq.AuthInfo;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
/**
* Manages collaboration client's authentication credentials for HTTP data
* server which are stored on the XMPP server
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 24, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class ClientAuthManager {
private static final IUFStatusHandler log = UFStatus
.getHandler(ClientAuthManager.class);
private final XMPPConnection conn;
public static enum State {
PENDING, ENABLED, DISABLED, ERROR
}
private State state = State.PENDING;
private final Object stateMonitor = new Object();
private ClientSignatureAuth sigAuth;
/**
* @param conn
* @throws CollaborationException
*/
public ClientAuthManager(XMPPConnection conn) throws CollaborationException {
this.conn = conn;
if (isEnabledOnServer(conn)) {
createAndRegisterAuth();
} else {
this.sigAuth = null;
this.state = State.DISABLED;
}
}
/**
* @param conn
* @return true if server supports collaboration auth feature
* @throws CollaborationException
*/
public static boolean isEnabledOnServer(XMPPConnection conn)
throws CollaborationException {
try {
return BaseProvider.serverSupportsFeature(conn,
AuthInfo.AUTH_QUERY_XMLNS);
} catch (XMPPException e) {
throw new CollaborationException(
"Unable to query server for supported features", e);
}
}
/**
* Create a new key pair and register key with server
*
* @return
* @throws CollaborationException
*/
private void createAndRegisterAuth() {
Job job = new Job("Creating and registering collaboration credentials") {
@Override
protected IStatus run(IProgressMonitor monitor) {
State authState = State.ERROR;
try {
ClientSignatureAuth auth = new ClientSignatureAuth();
String encodedKey = auth.getEncodedPublicKey();
AuthInfo packet = AuthInfo.createSetPacket(encodedKey,
auth.getKeyAlgorithm());
SyncPacketSend.getReply(conn, packet);
ClientAuthManager.this.sigAuth = auth;
authState = State.ENABLED;
} catch (GeneralSecurityException e) {
log.error("Problem creating public key auth", e);
} catch (XMPPException e) {
log.error("Problem registering public key", e);
} finally {
synchronized (stateMonitor) {
ClientAuthManager.this.state = authState;
stateMonitor.notifyAll();
}
}
return Status.OK_STATUS;
}
};
job.setPriority(Job.SHORT);
job.setSystem(true);
job.schedule();
}
/**
* NOTE: this method will block if auth registration has not yet completed
*
* @return the sigAuth, null if {@link ClientAuthManager#getState()} is
* {@link State#DISABLED}
*/
public ClientSignatureAuth getSigAuth() {
if (state.equals(State.PENDING)) {
waitForInit();
}
return sigAuth;
}
/**
* Add an Auth header to the message using the credential and a signature
* generated from the URI.
*
* @param msg
* @param credential
* @param uri
* @throws CollaborationException
*/
public void signRequest(AbstractHttpMessage msg, String credential, URI uri)
throws CollaborationException {
signRequest(msg, credential, uri, null);
}
/**
* Add an Auth header to the message using the credential and a signature
* generated from the URI and body.
*
* @param msg
* @param credential
* @param uri
* @param body
* @throws CollaborationException
*/
public void signRequest(AbstractHttpMessage msg, String credential,
URI uri, byte[] body) throws CollaborationException {
ClientSignatureAuth sigAuth = getSigAuth();
if (state.equals(State.ENABLED)) {
String sig;
try {
if (body != null) {
sig = sigAuth.sign(uri, body);
} else {
sig = sigAuth.sign(uri);
}
} catch (SignatureException e) {
throw new CollaborationException(
"Problem signing HTTP message", e);
}
String headerValue = ClientSignatureAuth.formatAuthHeader(
credential, sig);
msg.addHeader(ClientSignatureAuth.HTTP_AUTH_HEADER, headerValue);
}
}
/**
* waits thread until state is no longer pending auth registration
*/
private void waitForInit() {
synchronized (stateMonitor) {
if (state.equals(State.PENDING)) {
try {
stateMonitor.wait();
} catch (InterruptedException e) {
log.error("Interrupted waiting for auth", e);
}
}
}
}
/**
* @return the state of the auth registration
*/
public State getState() {
return state;
}
}

View file

@ -48,6 +48,9 @@ import com.google.common.eventbus.EventBus;
import com.google.common.net.HostAndPort;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.xmpp.PacketConstants;
import com.raytheon.uf.common.xmpp.iq.AuthInfo;
import com.raytheon.uf.common.xmpp.iq.AuthInfoProvider;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.IAccountManager;
import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
@ -59,9 +62,9 @@ import com.raytheon.uf.viz.collaboration.comm.identity.event.IVenueInvitationEve
import com.raytheon.uf.viz.collaboration.comm.identity.event.RosterChangeType;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.SharedDisplayVenueInvite;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.VenueInvite;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayloadProvider;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayloadProvider;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.event.RosterChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.event.ServerDisconnectEvent;
@ -114,6 +117,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
* Feb 13, 2014 2751 bclement better types for venueid and invitor
* Feb 18, 2014 2793 bclement improved disconnection notification and handling
* Feb 24, 2014 2632 mpduff Fix roster change type for presence change.
* Feb 28, 2014 2756 bclement added authManager
*
* </pre>
*
@ -125,9 +129,11 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
public class CollaborationConnection implements IEventPublisher {
static {
ProviderManager.getInstance().addExtensionProvider(
SessionPayload.ELEMENT_NAME, SessionPayload.XMLNS,
new SessionPayloadProvider());
ProviderManager pm = ProviderManager.getInstance();
pm.addExtensionProvider(SessionPayload.ELEMENT_NAME,
PacketConstants.COLLAB_XMLNS, new SessionPayloadProvider());
pm.addIQProvider(PacketConstants.QUERY_ELEMENT_NAME,
AuthInfo.AUTH_QUERY_XMLNS, new AuthInfoProvider());
}
private static final transient IUFStatusHandler statusHandler = UFStatus
@ -155,6 +161,8 @@ public class CollaborationConnection implements IEventPublisher {
private XMPPConnection connection;
private final ClientAuthManager authManager;
public static boolean COMPRESS = true;
static {
@ -209,6 +217,8 @@ public class CollaborationConnection implements IEventPublisher {
setupP2PComm();
getPeerToPeerSession();
authManager = new ClientAuthManager(connection);
userPresence = initialPresence;
if (accountManager != null && initialPresence != null) {
accountManager.sendPresence(initialPresence);
@ -632,7 +642,7 @@ public class CollaborationConnection implements IEventPublisher {
if (message != null) {
SessionPayload payload = (SessionPayload) message
.getExtension(SessionPayload.XMLNS);
.getExtension(PacketConstants.COLLAB_XMLNS);
if (payload != null) {
handleCollabInvite(venueId, invitor,
payload);
@ -770,4 +780,11 @@ public class CollaborationConnection implements IEventPublisher {
}
}
/**
* @return the authManager
*/
public ClientAuthManager getAuthManager() {
return authManager;
}
}

View file

@ -29,6 +29,7 @@ import org.jivesoftware.smack.packet.Packet;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.xmpp.PacketConstants;
import com.raytheon.uf.viz.collaboration.comm.Activator;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
@ -36,7 +37,7 @@ import com.raytheon.uf.viz.collaboration.comm.identity.event.IHttpXmppMessage;
import com.raytheon.uf.viz.collaboration.comm.identity.event.IHttpdCollaborationConfigurationEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.event.ITextMessageEvent;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.provider.TextMessage;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.event.ChatMessageEvent;
@ -61,6 +62,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
* Feb 13, 2014 2751 bclement changed IQualifiedID objects to IUser
* Feb 17, 2014 2756 bclement null check for message from field
* moved url validation from regex to java utility
* Feb 24, 2014 2756 bclement moved xmpp objects to new packages
*
* </pre>
*
@ -134,7 +136,7 @@ public class PeerToPeerCommHelper implements PacketListener {
}
} else {
SessionPayload payload = (SessionPayload) msg
.getExtension(SessionPayload.XMLNS);
.getExtension(PacketConstants.COLLAB_XMLNS);
if (payload != null) {
switch (payload.getPayloadType()) {
case Command:

View file

@ -26,6 +26,8 @@ import org.jivesoftware.smackx.pubsub.packet.PubSub;
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
import com.raytheon.uf.common.xmpp.ext.ChangeAffiliationExtension;
/**
* PubSub operations not implemented by the Smack PubSub manager. This includes
* operations to modify ownership of a topic node.

View file

@ -19,11 +19,13 @@
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
import java.net.URI;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.http.client.methods.HttpDelete;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
@ -49,14 +51,17 @@ import org.jivesoftware.smackx.pubsub.listener.ItemEventListener;
import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
import com.google.common.eventbus.EventBus;
import com.raytheon.uf.common.comm.HttpClient;
import com.raytheon.uf.common.comm.HttpClient.HttpClientResponse;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.xmpp.ext.ChangeAffiliationExtension;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.ISession;
import com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.identity.user.SharedDisplayRole;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.event.LeaderChangeEvent;
import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId;
@ -82,6 +87,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
* Feb 18, 2014 2751 bclement implemented room and pubsub ownership transfer
* Feb 19, 2014 2751 bclement added isClosed()
* Feb 24, 2014 2751 bclement added validation for change leader event
* Feb 28, 2014 2756 bclement added cleanUpHttpStorage()
*
* </pre>
*
@ -156,6 +162,7 @@ public class SharedDisplaySession extends VenueSession implements
// before cleanup?
log.info("Deleting old topic: " + aff.getNodeId());
try {
cleanUpHttpStorage(aff.getNodeId());
pubsubMgr.deleteNode(aff.getNodeId());
} catch (XMPPException e) {
log.error(
@ -481,6 +488,7 @@ public class SharedDisplaySession extends VenueSession implements
topic.removeItemDeleteListener(this);
topic.removeItemEventListener(this);
if (hasRole(SharedDisplayRole.SESSION_LEADER)) {
cleanUpHttpStorage(topic.getId());
pubsubMgr.deleteNode(topic.getId());
}
topic = null;
@ -494,6 +502,38 @@ public class SharedDisplaySession extends VenueSession implements
}
}
/**
* Delete session directory on HTTP server. This should only be called if
* this client is the owner of the topic associated with the session and
* only after the session is closed.
*
* TODO this will not be needed if the xmpp server takes care of shared
* display session lifecycle (create, transfer ownership, destroy, etc)
*
* @param sessionid
*/
private void cleanUpHttpStorage(String sessionid) {
try {
String userid = getAccount().getNormalizedId();
String url = PeerToPeerCommHelper.getCollaborationHttpServer();
url += sessionid + "/";
URI uri = new URI(url);
HttpDelete delete = new HttpDelete(uri);
ClientAuthManager authManager = getConnection().getAuthManager();
authManager.signRequest(delete, userid, uri);
HttpClientResponse response = HttpClient.getInstance()
.executeRequest(delete);
if (!response.isSuccess() && !response.isNotExists()) {
throw new CollaborationException("Session deletion failed for "
+ uri + ": " + new String(response.data));
}
} catch (Exception e) {
log.error(
"Problem cleaning up old HTTP storage objects for session: "
+ sessionid, e);
}
}
/*
* (non-Javadoc)
*

View file

@ -52,8 +52,8 @@ import com.raytheon.uf.viz.collaboration.comm.identity.event.ParticipantEventTyp
import com.raytheon.uf.viz.collaboration.comm.identity.info.IVenue;
import com.raytheon.uf.viz.collaboration.comm.identity.invite.VenueInvite;
import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload;
import com.raytheon.uf.viz.collaboration.comm.packet.SessionPayload.PayloadType;
import com.raytheon.uf.viz.collaboration.comm.provider.TextMessage;
import com.raytheon.uf.viz.collaboration.comm.provider.Tools;
import com.raytheon.uf.viz.collaboration.comm.provider.event.UserNicknameChangedEvent;

View file

@ -20,7 +20,8 @@ Require-Bundle: org.eclipse.core.runtime,
com.raytheon.uf.common.time,
com.raytheon.uf.common.geospatial,
com.raytheon.uf.common.util,
com.raytheon.viz.core
com.raytheon.viz.core,
com.raytheon.uf.common.http
Export-Package: com.raytheon.uf.viz.collaboration.display,
com.raytheon.uf.viz.collaboration.display.data,
com.raytheon.uf.viz.collaboration.display.editor,

View file

@ -40,6 +40,7 @@ import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import com.raytheon.uf.common.comm.HttpClient;
import com.raytheon.uf.common.comm.HttpClient.HttpClientResponse;
@ -53,6 +54,7 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.collaboration.comm.compression.CompressionUtil;
import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException;
import com.raytheon.uf.viz.collaboration.comm.identity.ISharedDisplaySession;
import com.raytheon.uf.viz.collaboration.comm.provider.session.ClientAuthManager;
import com.raytheon.uf.viz.collaboration.comm.provider.session.PeerToPeerCommHelper;
import com.raytheon.uf.viz.collaboration.comm.provider.user.VenueParticipant;
import com.raytheon.uf.viz.remote.graphics.Dispatcher;
@ -75,6 +77,8 @@ import com.raytheon.uf.viz.remote.graphics.events.ICreationEvent;
* Feb 17, 2014 2756 bclement added xml parsing for HTTP directory listing
* Feb 24, 2014 2751 bclement added separate paths for each provider under session id
* Feb 25, 2014 2751 bclement fixed provider id path for webDAV
* Feb 28, 2014 2756 bclement added auth, moved response code checks to response object
*
* </pre>
*
* @author mschenke
@ -90,16 +94,18 @@ public class CollaborationObjectEventStorage implements
private static NetworkStatistics stats = com.raytheon.uf.viz.collaboration.comm.Activator
.getDefault().getNetworkStats();
private static final String SLASH = "/";
public static IObjectEventPersistance createPersistanceObject(
ISharedDisplaySession session, Dispatcher dispatcher)
throws CollaborationException {
CollaborationObjectEventStorage persistance = new CollaborationObjectEventStorage(
session, dispatcher.getDispatcherId());
persistance.createFolder(URI.create(persistance.sessionDataURL));
persistance.sessionDataURL += persistance.displayId + "/";
persistance.createFolder(URI.create(persistance.sessionDataURL));
appendProviderIdToPath(persistance);
persistance.createFolder(URI.create(persistance.sessionDataURL));
persistance.sessionDataURL += persistance.displayId + SLASH;
persistance.createFolder(URI.create(persistance.sessionDataURL));
return persistance;
}
@ -112,8 +118,8 @@ public class CollaborationObjectEventStorage implements
private static void appendProviderIdToPath(
CollaborationObjectEventStorage persistance) {
try {
persistance.sessionDataURL += URLEncoder.encode(persistance.providerid,
"UTF-8") + "/";
persistance.sessionDataURL += URLEncoder.encode(
persistance.providerid, HTTP.UTF_8) + SLASH;
} catch (UnsupportedEncodingException e) {
log.warn("URL encoding failed, retrying with default encoding: "
+ e.getLocalizedMessage());
@ -127,8 +133,8 @@ public class CollaborationObjectEventStorage implements
ISharedDisplaySession session, int displayId) {
CollaborationObjectEventStorage persistance = new CollaborationObjectEventStorage(
session, displayId);
persistance.sessionDataURL += persistance.displayId + "/";
appendProviderIdToPath(persistance);
persistance.sessionDataURL += persistance.displayId + SLASH;
return persistance;
}
@ -148,14 +154,17 @@ public class CollaborationObjectEventStorage implements
private final String providerid;
private final ClientAuthManager authManager;
private CollaborationObjectEventStorage(ISharedDisplaySession session,
int displayId) {
this.displayId = displayId;
this.client = HttpClient.getInstance();
this.authManager = session.getConnection().getAuthManager();
VenueParticipant dataProvider = session.getCurrentDataProvider();
this.providerid = dataProvider.getUserid().getNormalizedId();
this.sessionDataURL = PeerToPeerCommHelper.getCollaborationHttpServer();
this.sessionDataURL += session.getSessionId() + "/";
this.sessionDataURL += session.getSessionId() + SLASH;
}
/*
@ -187,10 +196,9 @@ public class CollaborationObjectEventStorage implements
try {
CollaborationHttpPersistedEvent wrapped = new CollaborationHttpPersistedEvent();
String objectPath = event.getObjectId() + "/"
String objectPath = event.getObjectId() + SLASH
+ event.getClass().getName() + ".obj";
String eventObjectURL = sessionDataURL + objectPath;
HttpPut put = new HttpPut(eventObjectURL);
CollaborationHttpPersistedObject persistObject = new CollaborationHttpPersistedObject();
persistObject.persistTime = System.currentTimeMillis();
@ -198,9 +206,9 @@ public class CollaborationObjectEventStorage implements
byte[] toPersist = CompressionUtil.compress(SerializationUtil
.transformToThrift(persistObject));
stats.log(event.getClass().getSimpleName(), toPersist.length, 0);
put.setEntity(new ByteArrayEntity(toPersist));
HttpPut put = createPut(eventObjectURL, toPersist);
HttpClientResponse response = executeRequest(put);
if (isSuccess(response.code) == false) {
if (response.isSuccess() == false) {
throw new CollaborationException(
"Error uploading event object (" + event.getObjectId()
+ ") to server @ " + eventObjectURL + " : "
@ -216,6 +224,35 @@ public class CollaborationObjectEventStorage implements
}
}
/**
* Create http put method object. Adds auth header if needed.
*
* @param url
* @param body
* @return
* @throws CollaborationException
*/
private HttpPut createPut(String url, byte[] body) throws CollaborationException{
URI uri = URI.create(url);
HttpPut put = new HttpPut(uri);
authManager.signRequest(put, providerid, uri, body);
put.setEntity(new ByteArrayEntity(body));
return put;
}
/**
* Create http delete method object. Adds auth header if needed.
*
* @param uri
* @return
* @throws CollaborationException
*/
private HttpDelete createDelete(URI uri) throws CollaborationException {
HttpDelete delete = new HttpDelete(uri);
authManager.signRequest(delete, providerid, uri);
return delete;
}
/*
* (non-Javadoc)
*
@ -273,7 +310,7 @@ public class CollaborationObjectEventStorage implements
String objectPath = event.getResourcePath();
HttpGet get = new HttpGet(sessionDataURL + objectPath);
HttpClientResponse response = executeRequest(get);
if (isSuccess(response.code)) {
if (response.isSuccess()) {
try {
CollaborationHttpPersistedObject dataObject = SerializationUtil
.transformFromThrift(
@ -286,7 +323,7 @@ public class CollaborationObjectEventStorage implements
} catch (SerializationException e) {
throw new CollaborationException(e);
}
} else if (isNotExists(response.code)) {
} else if (response.isNotExists()) {
// Object was deleted
return null;
} else {
@ -310,8 +347,8 @@ public class CollaborationObjectEventStorage implements
get.addHeader(new BasicHeader(ACCEPTS_HEADER, XML_CONTENT_TYPE + ","
+ HTML_CONTENT_TYPE));
HttpClientResponse response = executeRequest(get);
if (isSuccess(response.code) == false) {
if (isNotExists(response.code)) {
if (response.isSuccess() == false) {
if (response.isNotExists()) {
return new AbstractDispatchingObjectEvent[0];
}
throw new CollaborationException("Error retrieving object ("
@ -475,7 +512,7 @@ public class CollaborationObjectEventStorage implements
};
mkcol.setURI(folderPath);
HttpClientResponse rsp = executeRequest(mkcol);
if (isSuccess(rsp.code) == false && isDirExists(rsp.code) == false) {
if (rsp.isSuccess() == false && isDirExists(rsp.code) == false) {
throw new CollaborationException("Folder creation failed for "
+ folderPath + ": " + new String(rsp.data));
}
@ -488,9 +525,9 @@ public class CollaborationObjectEventStorage implements
* @throws CollaborationException
*/
private void deleteResource(URI uri) throws CollaborationException {
HttpClientResponse rsp = executeRequest(new HttpDelete(uri));
HttpClientResponse rsp = executeRequest(createDelete(uri));
// If request was success or resource doesn't exist, we are good
if (isSuccess(rsp.code) == false && isNotExists(rsp.code) == false) {
if (rsp.isSuccess() == false && rsp.isNotExists() == false) {
throw new CollaborationException("Folder creation failed for "
+ uri + ": " + new String(rsp.data));
}
@ -512,22 +549,6 @@ public class CollaborationObjectEventStorage implements
}
}
/**
* @param code
* @return true if code is a 200 level return code
*/
private boolean isSuccess(int code) {
return code >= 200 && code < 300;
}
/**
* @param code
* @return true if resource does not exist on server
*/
private boolean isNotExists(int code) {
return code == 404 || code == 410;
}
/**
* @deprecated this error is related to MKCOL. MKCOL is only required for
* DAV (pre 14.3)

View file

@ -77,8 +77,7 @@
id="org.jivesoftware.smack"
download-size="0"
install-size="0"
version="0.0.0"
unpack="true"/>
version="0.0.0"/>
<plugin
id="org.eclipse.equinox.concurrent"
@ -87,4 +86,18 @@
version="0.0.0"
unpack="false"/>
<plugin
id="com.raytheon.uf.common.xmpp"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="com.raytheon.uf.common.http"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>

View file

@ -107,6 +107,7 @@ import com.raytheon.uf.common.util.ByteArrayOutputStreamPool.ByteArrayOutputStre
* Feb 04, 2014 2704 njensen Better error message with bad address
* Https authentication failures notify handler
* Feb 17, 2014 2756 bclement added content type to response object
* Feb 28, 2014 2756 bclement added isSuccess() and isNotExists() to response
*
* </pre>
*
@ -126,6 +127,20 @@ public class HttpClient {
this.data = data != null ? data : new byte[0];
this.contentType = contentType;
}
/**
* @return true if code is a 200 level return code
*/
public boolean isSuccess() {
return code >= 200 && code < 300;
}
/**
* @return true if resource does not exist on server
*/
public boolean isNotExists() {
return code == 404 || code == 410;
}
}
/**

View file

@ -5,5 +5,8 @@ Bundle-SymbolicName: com.raytheon.uf.common.http
Bundle-Version: 1.14.0
Bundle-Vendor: RAYTHEON
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Export-Package: com.raytheon.uf.common.http
Require-Bundle: org.apache.commons.lang;bundle-version="2.3.0"
Export-Package: com.raytheon.uf.common.http,
com.raytheon.uf.common.http.auth
Require-Bundle: org.apache.commons.lang,
org.apache.http,
org.apache.commons.codec

View file

@ -0,0 +1,149 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.http.auth;
import java.net.URI;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import org.apache.http.HttpHost;
import org.apache.http.client.utils.URIUtils;
/**
* Implements signature authentication for HTTP clients
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 25, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class ClientSignatureAuth extends SignatureAuthScheme {
private final KeyPair keypair;
private final Signature sig;
/**
* Default constructor, creates a new keypair
*
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public ClientSignatureAuth() throws NoSuchAlgorithmException,
InvalidKeyException {
this(generateKeys());
}
/**
* @param keypair
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public ClientSignatureAuth(KeyPair keypair)
throws NoSuchAlgorithmException, InvalidKeyException {
this.keypair = keypair;
this.sig = Signature.getInstance(SIG_ALG);
this.sig.initSign(this.keypair.getPrivate());
}
/**
* Create a base64 encoded signature from URI
*
* @param uri
* @return
* @throws SignatureException
*/
public String sign(URI uri) throws SignatureException {
return sign(uri, null);
}
/**
* Create a base64 encoded signature from URI and body
*
* @param uri
* @param bytes
* @return
* @throws SignatureException
*/
public String sign(URI uri, byte[] bytes) throws SignatureException {
HttpHost host = URIUtils.extractHost(uri);
synchronized (sig) {
sig.update(host.toHostString().getBytes());
sig.update(uri.getPath().getBytes());
if (bytes != null) {
sig.update(bytes);
}
return base64Encode(sig.sign());
}
}
/**
* Generate a new public/private key pair using the default algorithms
*
* @return
* @throws NoSuchAlgorithmException
*/
public static final KeyPair generateKeys() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(KEY_ALG);
SecureRandom random = SecureRandom.getInstance(RANDOM_ALG);
keyGen.initialize(KEY_SIZE, random);
return keyGen.generateKeyPair();
}
/**
* @return the keypair
*/
public KeyPair getKeypair() {
return keypair;
}
/**
* Get the default public key algorithm
*
* @return
*/
public String getKeyAlgorithm() {
return KEY_ALG;
}
/**
* Get the base64 X509 encoded public key
*
* @return
*/
public String getEncodedPublicKey() {
PublicKey pub = keypair.getPublic();
return base64Encode(pub.getEncoded());
}
}

View file

@ -0,0 +1,126 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.http.auth;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
/**
* Implements signature authentication for HTTP servers
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 25, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class ServerSignatureAuth extends SignatureAuthScheme {
private final Map<String, KeyFactory> factoryMap = new HashMap<String, KeyFactory>();
/**
* Get the KeyFactory associated with the provided algorithm, a new factory
* is created and cached if not found
*
* @param keyAlg
* @return
* @throws NoSuchAlgorithmException
*/
public KeyFactory getFactory(String keyAlg) throws NoSuchAlgorithmException {
KeyFactory rval;
synchronized (factoryMap) {
rval = factoryMap.get(keyAlg);
if (rval == null) {
rval = KeyFactory.getInstance(keyAlg);
factoryMap.put(keyAlg, rval);
}
}
return rval;
}
/**
* Decode a base64 X509 encoded public key using the provided algorithm.
*
* @param encodedKey
* @param algorithm
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public PublicKey decodePublicKey(String encodedKey, String algorithm)
throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] bytes = base64Decode(encodedKey);
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(bytes);
KeyFactory factory = getFactory(algorithm);
return factory.generatePublic(pubKeySpec);
}
/**
* @param sig
* @param hostHeader
* host used in request including port
* @param path
* path used in request
* @return true if the signature matches the URI parts provided
* @throws SignatureException
*/
public boolean verify(Signature sig, String hostHeader, String path)
throws SignatureException {
return verify(sig, hostHeader, path, null);
}
/**
* @param sig
* @param hostHeader
* host used in request including port
* @param path
* path used in request
* @param bytes
* body of request
* @return true if the signature matches the URI parts and body provided
* @throws SignatureException
*/
public boolean verify(Signature sig, String hostHeader, String path,
byte[] bytes) throws SignatureException {
synchronized (sig) {
sig.update(hostHeader.getBytes());
sig.update(path.getBytes());
if (bytes != null) {
sig.update(bytes);
}
return sig.verify(bytes);
}
}
}

View file

@ -0,0 +1,160 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.http.auth;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.codec.binary.Base64;
/**
* Base class for signature authentication scheme
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 25, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public abstract class SignatureAuthScheme {
protected static final String RANDOM_ALG = "SHA1PRNG";
protected static final int KEY_SIZE = 256;
protected static final String KEY_ALG = "EC";
protected static final String SIG_ALG = "SHA256WITHECDSA";
public static final String HTTP_AUTH_HEADER = "Authorization";
public static final String AUTH_PARAMETER_DELIM = ",";
public static final String CRED_FIELD_NAME = "Credential";
public static final String SIG_FIELD_NAME = "Signature";
/**
* matches '[alorithm-name] [credentials-and-signature]'
*/
private static final Pattern AUTH_HEADER_PATTERN = Pattern
.compile("^(\\S+)\\s+(\\S.+)$");
/**
* matches header parameter key/value pairs '[key1]=[val1],[key2]=[val2]'
*/
private static final Pattern AUTH_PARAMETER_PATTERN = Pattern
.compile("([^,=]+)=([^,=]+)");
/**
* Create an Authorization header in the form
*
* <pre>
* '[algorithm-name] Credential=[userid],Signature=[signature]'
* </pre>
*
* Using the default signature algorithm.
*
* @param userid
* @param signature
* @return
*/
public static String formatAuthHeader(String userid, String signature) {
return formatAuthHeader(new SignedCredential(userid, signature, SIG_ALG));
}
/**
* Create an Authorization header in the form
*
* <pre>
* '[algorithm-name] Credential=[userid],Signature=[signature]'
* </pre>
*
* @param sc
* @return
*/
public static String formatAuthHeader(SignedCredential sc) {
StringBuilder builder = new StringBuilder();
builder.append(sc.getAlgorithm()).append(" ");
builder.append(CRED_FIELD_NAME).append("=");
builder.append(sc.getUserid()).append(AUTH_PARAMETER_DELIM);
builder.append(SIG_FIELD_NAME).append("=");
builder.append(sc.getSignature());
return builder.toString();
}
/**
* Parse an Authorization header in the form
*
* <pre>
* '[algorithm-name] Credential=[userid],Signature=[signature]'
* </pre>
*
* @param authHeader
* @return
*/
public static SignedCredential parseAuthHeader(String authHeader) {
Matcher m = AUTH_HEADER_PATTERN.matcher(authHeader.trim());
if (!m.matches()) {
return null;
}
String algorithm = m.group(1).trim();
String paramStr = m.group(2).trim();
Map<String, String> parameters = new HashMap<String, String>(2);
m = AUTH_PARAMETER_PATTERN.matcher(paramStr);
while (m.find()) {
parameters.put(m.group(1).trim().toLowerCase(), m.group(2).trim());
}
String userid = parameters.get(CRED_FIELD_NAME.toLowerCase());
String signature = parameters.get(SIG_FIELD_NAME.toLowerCase());
return new SignedCredential(userid, signature, algorithm);
}
/**
* Create a non-chuncked (no newlines) base64 string from bytes
*
* @param bytes
* @return
*/
public static final String base64Encode(byte[] bytes) {
bytes = Base64.encodeBase64(bytes, false);
return org.apache.commons.codec.binary.StringUtils.newStringUtf8(bytes);
}
/**
* Decode a base64 encoded string
*
* @param encString
* @return
*/
public static final byte[] base64Decode(String encString) {
return Base64.decodeBase64(encString);
}
}

View file

@ -0,0 +1,78 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.http.auth;
/**
* Credentials used in an authorization header
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 25, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class SignedCredential {
private final String userid;
private final String signature;
private final String algorithm;
/**
* @param userid
* @param signature
* @param algorithm
*/
public SignedCredential(String userid, String signature, String algorithm) {
this.userid = userid;
this.signature = signature;
this.algorithm = algorithm;
}
/**
* @return the userid
*/
public String getUserid() {
return userid;
}
/**
* @return the signature
*/
public String getSignature() {
return signature;
}
/**
* @return the algorithm
*/
public String getAlgorithm() {
return algorithm;
}
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.raytheon.uf.common.xmpp</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,7 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6

View file

@ -0,0 +1,12 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Common Xmpp
Bundle-SymbolicName: com.raytheon.uf.common.xmpp
Bundle-Version: 1.14
Bundle-Vendor: RAYTHEON
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.jivesoftware.smack,
org.apache.commons.lang
Export-Package: com.raytheon.uf.common.xmpp,
com.raytheon.uf.common.xmpp.ext,
com.raytheon.uf.common.xmpp.iq

View file

@ -0,0 +1,4 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.

View file

@ -0,0 +1,167 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.xmpp;
import java.io.IOException;
import java.util.Iterator;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.jivesoftware.smackx.packet.DiscoverInfo.Feature;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
/**
* Base class for XMPP IQ and extension providers which are used to parse XMPP
* packets.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 24, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public abstract class BaseProvider<T> {
protected final String tagName;
/**
* @param tagName
* packet tag name, used to determine when provider is done
* parsing
*/
public BaseProvider(String tagName) {
this.tagName = tagName;
}
/**
* Parse contents of packet from XMPP stream.
*
* @param parser
* @return
* @throws XmlPullParserException
* @throws IOException
* when errors occurs with XMPP stream
*/
abstract protected T parseInternal(XmlPullParser parser)
throws XmlPullParserException, IOException;
/**
* Parse contents of packet from XMPP stream. Ensures that parser is left in
* a good state so the stream isn't corrupted.
*
* @param parser
* @return
* @throws XmlPullParserException
* @throws IOException
*/
protected T parse(XmlPullParser parser) throws XmlPullParserException,
IOException {
try {
return parseInternal(parser);
} finally {
// ensure that we are at the end of the packet so we don't corrupt
// stream
while (!atEndOfPacket(parser)) {
parser.next();
}
}
}
/**
* @param parser
* @return true if parser is at the end tag of the packet
* @throws XmlPullParserException
*/
protected boolean atEndOfPacket(XmlPullParser parser)
throws XmlPullParserException {
return atEndOfTag(parser, tagName);
}
/**
* @param parser
* @param tag
* @return true if parser is at the end of the specified tag
* @throws XmlPullParserException
*/
protected boolean atEndOfTag(XmlPullParser parser, String tag)
throws XmlPullParserException {
return parser.getEventType() == XmlPullParser.END_TAG
&& parser.getName().equals(tag);
}
/**
* Get any text elements under current tag
*
* @param parser
* @return
* @throws XmlPullParserException
* @throws IOException
*/
protected String getText(XmlPullParser parser)
throws XmlPullParserException, IOException {
if (parser.getEventType() == XmlPullParser.TEXT) {
return parser.getText();
} else if (parser.getEventType() != XmlPullParser.START_TAG) {
return null;
}
String tag = parser.getName();
StringBuilder allText = new StringBuilder();
while (!atEndOfTag(parser, tag)) {
if (parser.getEventType() == XmlPullParser.TEXT) {
allText.append(parser.getText());
}
parser.next();
}
return allText.toString();
}
/**
* @param conn
* @return true if server has feature listed in supported features
* @throws XMPPException
*/
public static boolean serverSupportsFeature(XMPPConnection conn,
String feature) throws XMPPException {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager
.getInstanceFor(conn);
boolean rval = false;
DiscoverInfo discoverInfo = sdm.discoverInfo(null);
Iterator<Feature> iter = discoverInfo.getFeatures();
while (iter.hasNext()) {
String supportedFeature = iter.next().getVar();
if (supportedFeature.equals(feature)) {
rval = true;
break;
}
}
return rval;
}
}

View file

@ -0,0 +1,49 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.xmpp;
/**
* Custom XMPP packet constants
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 24, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class PacketConstants {
public static final String COLLAB_XMLNS = "urn:uf:viz:collaboration";
public static final String XMLNS_ATTRIBUTE = "xmlns";
public static final String QUERY_ELEMENT_NAME = "query";
private PacketConstants() {
}
}

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider;
package com.raytheon.uf.common.xmpp;
import java.io.IOException;
import java.util.HashSet;
@ -43,6 +43,7 @@ import org.xmlpull.v1.XmlPullParserException;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Dec 17, 2013 2562 bclement Initial creation
* Feb 27, 2013 2756 bclement moved to common.xmpp from collaboration
*
* </pre>
*

View file

@ -0,0 +1,187 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.xmpp;
import java.util.Collections;
import java.util.List;
/**
* Simple XML string builder utility
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 26, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class XmlBuilder {
private final StringBuilder builder = new StringBuilder();
/**
* Key value pair object
*/
public static class Pair {
public final String name;
public final String value;
public Pair(String name, String value) {
this.name = name;
this.value = value;
}
}
/**
* Append open tag to XML
*
* @param name
* @return
*/
public XmlBuilder startTag(String name){
return startTag(name, Collections.<Pair> emptyList());
}
/**
* Append open tag to XML
*
* @param name
* @param namespace
* xmlns attribute to be included in tag
* @return
*/
public XmlBuilder startTag(String name, String namespace) {
return startTag(name, namespace, Collections.<Pair> emptyList());
}
/**
* Append open tag to XML
*
* @param name
* @param attributes
* @return
*/
public XmlBuilder startTag(String name, List<Pair> attributes) {
return startTag(name, null, attributes);
}
/**
* Append open tag to XML
*
* @param name
* @param namespace
* xmlns attribute to be included in tag
* @param attributes
* @return
*/
public XmlBuilder startTag(String name, String namespace,
List<Pair> attributes) {
return appendTag(name, namespace, attributes, false);
}
/**
* Append self closing tag to XML
*
* @param name
* @param attributes
* @return
*/
public XmlBuilder selfClosingTag(String name, List<Pair> attributes) {
return appendTag(name, null, attributes, true);
}
/**
* Append tag to XML
*
* @param name
* @param namespace
* xmlns attribute to be included in tag
* @param attributes
* @param selfClose
* if true, tag will self close
* @return
*/
public XmlBuilder appendTag(String name, String namespace,
List<Pair> attributes, boolean selfClose) {
builder.append("<").append(name);
if (namespace != null) {
builder.append(" ").append(PacketConstants.XMLNS_ATTRIBUTE)
.append("=\"");
builder.append(namespace).append("\"");
}
for (Pair attrib : attributes) {
builder.append(" ").append(attrib.name).append("=\"");
builder.append(attrib.value).append("\"");
}
if (selfClose) {
builder.append("/>");
} else {
builder.append(">");
}
return this;
}
/**
* Append closing tag to XML
*
* @param name
* @return
*/
public XmlBuilder endTag(String name) {
builder.append("</").append(name).append(">");
return this;
}
/**
* Append text to XML
*
* @param text
* @return
*/
public XmlBuilder appendText(String text) {
builder.append(text);
return this;
}
/**
* @return a string containing the XML added to builder
*/
public String toXml() {
return builder.toString();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return toXml();
}
}

View file

@ -0,0 +1,71 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.xmpp.ext;
import org.jivesoftware.smack.packet.PacketExtension;
/**
* Base packet extension class. Used for custom XMPP packet payloads.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 24, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public abstract class BaseExtension implements PacketExtension {
protected final String elementName;
protected final String namespace;
/**
* @param elementName
* @param namespace
*/
public BaseExtension(String elementName, String namespace) {
this.elementName = elementName;
this.namespace = namespace;
}
/* (non-Javadoc)
* @see org.jivesoftware.smack.packet.PacketExtension#getElementName()
*/
@Override
public String getElementName() {
return elementName;
}
/* (non-Javadoc)
* @see org.jivesoftware.smack.packet.PacketExtension#getNamespace()
*/
@Override
public String getNamespace() {
return namespace;
}
}

View file

@ -17,13 +17,18 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.viz.collaboration.comm.provider.session;
package com.raytheon.uf.common.xmpp.ext;
import java.util.Arrays;
import org.jivesoftware.smackx.pubsub.Affiliation;
import org.jivesoftware.smackx.pubsub.Node;
import org.jivesoftware.smackx.pubsub.NodeExtension;
import org.jivesoftware.smackx.pubsub.PubSubElementType;
import com.raytheon.uf.common.xmpp.XmlBuilder;
import com.raytheon.uf.common.xmpp.XmlBuilder.Pair;
/**
* Packet extension for changing a user's affiliation with a pubsub topic.
* Follows specification at
@ -36,6 +41,7 @@ import org.jivesoftware.smackx.pubsub.PubSubElementType;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 18, 2014 2751 bclement Initial creation
* Feb 27, 2013 2756 bclement moved to common.xmpp from collaboration
*
* </pre>
*
@ -74,19 +80,14 @@ public class ChangeAffiliationExtension extends NodeExtension {
*/
@Override
public String toXML() {
StringBuilder builder = new StringBuilder("<");
builder.append(getElementName());
builder.append(" node='");
builder.append(getNode());
builder.append("'><").append(affiliationName).append(" ");
builder.append(jidAttribute).append("='");
builder.append(this.id);
builder.append("' ").append(affiliationName).append("='");
builder.append(this.type.toString());
builder.append("'/></");
builder.append(getElementName());
builder.append(">");
return builder.toString();
XmlBuilder builder = new XmlBuilder();
builder.startTag(getElementName(),
Arrays.asList(new Pair("node", getNode())));
builder.selfClosingTag(affiliationName, Arrays.asList(new Pair(
jidAttribute, this.id),
new Pair(affiliationName, this.type.toString())));
builder.endTag(getElementName());
return builder.toXml();
}
}

View file

@ -0,0 +1,225 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.xmpp.iq;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.jivesoftware.smack.packet.IQ;
import com.raytheon.uf.common.xmpp.PacketConstants;
import com.raytheon.uf.common.xmpp.XmlBuilder;
import com.raytheon.uf.common.xmpp.XmlBuilder.Pair;
/**
* Custom IQ packet for public key authentication
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 26, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class AuthInfo extends IQ {
public static final String AUTH_QUERY_XMLNS = "urn:uf:viz:collaboration:iq:auth";
public static final String INFO_ELEMENT_NAME = "authinfo";
public static final String PUBKEY_ELEMENT_NAME = "publickey";
public static final String ALG_ATTRIBUTE = "algorithm";
public static final String ID_ATTRIBUTE = "jid";
public static final String SESSION_ATTRIBUTE = "sessionid";
private String encodedKey;
private String algorithm;
private String userid;
private String sessionid;
/**
*
*/
public AuthInfo() {
}
/**
* @param iq
*/
public AuthInfo(IQ iq) {
super(iq);
}
/**
* @param encodedKey
* @param algorithm
* @param userid
* @param sessionid
*/
public AuthInfo(String encodedKey, String algorithm, String userid,
String sessionid) {
this.encodedKey = encodedKey;
this.algorithm = algorithm;
this.userid = userid;
this.sessionid = sessionid;
}
/**
* Construct a setter packet used to store a new public key on server
*
* @param encodedKey
* @param algorithm
* @return
*/
public static AuthInfo createSetPacket(String encodedKey, String algorithm) {
AuthInfo rval = new AuthInfo();
rval.setEncodedKey(encodedKey);
rval.setAlgorithm(algorithm);
rval.setType(Type.SET);
return rval;
}
/**
* Create a getter packet used to query the server for the current public
* key
*
* @param userid
* @return
*/
public static AuthInfo createGetPacket(String userid) {
return createGetPacket(userid, null);
}
/**
* Create a getter packet used to query the server for the current public
* key and check authorization for session ownership.
*
* @param userid
* @param sessionid
* @return
*/
public static AuthInfo createGetPacket(String userid, String sessionid) {
AuthInfo rval = new AuthInfo();
rval.setUserid(userid);
rval.setSessionid(sessionid);
rval.setType(Type.GET);
return rval;
}
/* (non-Javadoc)
* @see org.jivesoftware.smack.packet.IQ#getChildElementXML()
*/
@Override
public String getChildElementXML() {
XmlBuilder builder = new XmlBuilder();
List<Pair> queryAttributes = new ArrayList<Pair>(2);
if (userid != null) {
queryAttributes.add(new Pair(ID_ATTRIBUTE, userid));
}
if (sessionid != null) {
queryAttributes.add(new Pair(SESSION_ATTRIBUTE, sessionid));
}
builder.startTag(PacketConstants.QUERY_ELEMENT_NAME, AUTH_QUERY_XMLNS,
queryAttributes);
builder.startTag(INFO_ELEMENT_NAME, PacketConstants.COLLAB_XMLNS);
builder.startTag(PUBKEY_ELEMENT_NAME,
Arrays.asList(new Pair(ALG_ATTRIBUTE, algorithm)));
builder.appendText(encodedKey);
builder.endTag(PUBKEY_ELEMENT_NAME);
builder.endTag(INFO_ELEMENT_NAME);
builder.endTag(PacketConstants.QUERY_ELEMENT_NAME);
return builder.toXml();
}
/**
* @return the encodedKey
*/
public String getEncodedKey() {
return encodedKey;
}
/**
* @return the algorithm
*/
public String getAlgorithm() {
return algorithm;
}
/**
* @return the userid
*/
public String getUserid() {
return userid;
}
/**
* @return the sessionid
*/
public String getSessionid() {
return sessionid;
}
/**
* @param encodedKey
* the encodedKey to set
*/
public void setEncodedKey(String encodedKey) {
this.encodedKey = encodedKey;
}
/**
* @param algorithm
* the algorithm to set
*/
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
/**
* @param userid
* the userid to set
*/
public void setUserid(String userid) {
this.userid = userid;
}
/**
* @param sessionid
* the sessionid to set
*/
public void setSessionid(String sessionid) {
this.sessionid = sessionid;
}
}

View file

@ -0,0 +1,105 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.xmpp.iq;
import java.io.IOException;
import org.jivesoftware.smack.provider.IQProvider;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import com.raytheon.uf.common.xmpp.BaseProvider;
import com.raytheon.uf.common.xmpp.PacketConstants;
/**
* Custom XMPP IQ packet parsing for public key authentication
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 26, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class AuthInfoProvider extends BaseProvider<AuthInfo> implements
IQProvider {
/**
* @param extensionTagName
*/
public AuthInfoProvider() {
super(PacketConstants.QUERY_ELEMENT_NAME);
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.smack.provider.IQProvider#parseIQ(org.xmlpull.v1.
* XmlPullParser)
*/
@Override
public AuthInfo parseIQ(XmlPullParser parser) throws Exception {
return parse(parser);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.common.xmpp.BaseProvider#parseInternal(org.xmlpull.v1
* .XmlPullParser)
*/
@Override
protected AuthInfo parseInternal(XmlPullParser parser)
throws XmlPullParserException, IOException {
String encodedKey = null;
String algorithm = null;
String userid = null;
String sessionid = null;
do {
String tagName = parser.getName();
switch (parser.getEventType()) {
case XmlPullParser.START_TAG:
if (PacketConstants.QUERY_ELEMENT_NAME.equals(tagName)) {
sessionid = parser.getAttributeValue(null,
AuthInfo.SESSION_ATTRIBUTE);
userid = parser.getAttributeValue(null,
AuthInfo.ID_ATTRIBUTE);
} else if (AuthInfo.PUBKEY_ELEMENT_NAME.equals(tagName)) {
algorithm = parser.getAttributeValue(null,
AuthInfo.ALG_ATTRIBUTE);
encodedKey = getText(parser);
}
break;
}
parser.next();
} while (!atEndOfPacket(parser));
return new AuthInfo(encodedKey, algorithm, userid, sessionid);
}
}

View file

@ -0,0 +1,101 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.xmpp.iq;
import org.jivesoftware.smack.packet.IQ;
import com.raytheon.uf.common.xmpp.PacketConstants;
import com.raytheon.uf.common.xmpp.XmlBuilder;
/**
* Custom XMPP IQ packet for HTTP server configuration
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 26, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class HttpInfo extends IQ {
public static final String INFO_ELEMENT = "httpinfo";
public static final String URL_ELEMENT = "url";
public static final String QUERY_XMLNS = "urn:uf:viz:collaboration:iq:http";
private String url;
/**
*
*/
public HttpInfo() {
}
/**
* @param iq
*/
public HttpInfo(IQ iq) {
super(iq);
}
/**
* @param url
* bare HTTP url of data server
*/
public HttpInfo(String url) {
this.url = url;
}
@Override
public String getChildElementXML() {
XmlBuilder builder = new XmlBuilder();
builder.startTag(PacketConstants.QUERY_ELEMENT_NAME, QUERY_XMLNS);
builder.startTag(INFO_ELEMENT, PacketConstants.COLLAB_XMLNS);
builder.startTag(URL_ELEMENT).appendText(url);
builder.endTag(URL_ELEMENT);
builder.endTag(INFO_ELEMENT);
builder.endTag(PacketConstants.QUERY_ELEMENT_NAME);
return null;
}
/**
* @return the url
*/
public String getUrl() {
return url;
}
/**
* @param url
* the url to set
*/
public void setUrl(String url) {
this.url = url;
}
}

View file

@ -0,0 +1,91 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.xmpp.iq;
import java.io.IOException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import com.raytheon.uf.common.xmpp.BaseProvider;
/**
* Custom XMPP IQ packet parser for HTTP configuration
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 26, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class HttpInfoProvider extends BaseProvider<HttpInfo> implements
IQProvider {
/**
* @param extensionTagName
*/
public HttpInfoProvider() {
super(HttpInfo.QUERY_XMLNS);
}
/* (non-Javadoc)
* @see org.jivesoftware.smack.provider.IQProvider#parseIQ(org.xmlpull.v1.XmlPullParser)
*/
@Override
public IQ parseIQ(XmlPullParser parser) throws Exception {
return parse(parser);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.common.xmpp.BaseProvider#parseInternal(org.xmlpull.v1
* .XmlPullParser)
*/
@Override
protected HttpInfo parseInternal(XmlPullParser parser)
throws XmlPullParserException, IOException {
String url = null;
do {
String tagName = parser.getName();
switch (parser.getEventType()) {
case XmlPullParser.START_TAG:
if (HttpInfo.URL_ELEMENT.equals(tagName)) {
url = getText(parser);
}
break;
}
parser.next();
} while (!atEndOfPacket(parser));
return new HttpInfo(url);
}
}

View file

@ -7,4 +7,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.eclipse.jetty,
com.raytheon.uf.common.util,
org.jivesoftware.smack,
com.raytheon.uf.common.http
com.raytheon.uf.common.http,
com.raytheon.uf.common.xmpp,
org.apache.http,
org.apache.commons.collections

View file

@ -34,7 +34,8 @@ import java.util.Properties;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 5, 2014 2756 bclement Initial creation
* Feb 5, 2014 2756 bclement Initial creation
* Feb 28, 2014 2756 bclement added auth cache size
*
* </pre>
*
@ -77,6 +78,10 @@ public class Config{
public static final String XMPP_SERVER_DEFAULT = "localhost";
public static final String AUTH_CACHE_SIZE_KEY = "auth.key.cache.size";
public static final int AUTH_CACHE_SIZE_DEFAULT = 64;
public static final String config = System.getProperty(
"collaboration.dataserver.config", "config/settings.properties");

View file

@ -31,6 +31,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import com.raytheon.collaboration.dataserver.storage.FileManager;
import com.raytheon.uf.common.http.AcceptHeaderParser;
import com.raytheon.uf.common.http.AcceptHeaderValue;
@ -162,7 +163,6 @@ public class DataService extends HttpServlet {
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO auth
try {
File file = getFile(req);
manager.writeFile(req.getInputStream(), file);
@ -196,7 +196,6 @@ public class DataService extends HttpServlet {
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO auth
try {
File file = getFile(req);
if (!file.exists()) {

View file

@ -26,6 +26,8 @@ import java.util.TimeZone;
import org.eclipse.jetty.util.RolloverFileOutputStream;
import com.raytheon.collaboration.dataserver.auth.ServerAuthManager;
/**
* Entry class for dataserver
*
@ -35,7 +37,8 @@ import org.eclipse.jetty.util.RolloverFileOutputStream;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 5, 2014 2756 bclement Initial creation
* Feb 5, 2014 2756 bclement Initial creation
* Feb 28, 2014 2756 bclement added authManager
*
* </pre>
*
@ -62,15 +65,17 @@ public class DataserverMain {
.println("Continuing using standard out and standard error");
}
final XmppServerConnection xmppConnection;
final ServerAuthManager authManager;
try {
xmppConnection = new XmppServerConnection();
authManager = new ServerAuthManager(xmppConnection);
} catch (Exception e) {
System.err
.println("Unable to connect to XMPP server, shutting down");
e.printStackTrace();
return;
}
final WebServerRunner webServer = new WebServerRunner();
final WebServerRunner webServer = new WebServerRunner(authManager);
new Thread(webServer).start();
wait(CONNECTION_DELAY);
new Thread(xmppConnection).start();

View file

@ -20,11 +20,22 @@
package com.raytheon.collaboration.dataserver;
import java.io.File;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import org.eclipse.jetty.server.DispatcherType;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import com.raytheon.collaboration.dataserver.auth.AuthFilter;
import com.raytheon.collaboration.dataserver.auth.DeleteAuthHandler;
import com.raytheon.collaboration.dataserver.auth.MethodAuthHandler;
import com.raytheon.collaboration.dataserver.auth.PutAuthHandler;
import com.raytheon.collaboration.dataserver.auth.ServerAuthManager;
/**
* Start and run jetty webserver
*
@ -35,6 +46,7 @@ import org.eclipse.jetty.servlet.ServletHolder;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 14, 2014 2756 bclement Initial creation
* Feb 28, 2014 2756 bclement added authManager
*
* </pre>
*
@ -45,6 +57,12 @@ public class WebServerRunner implements Runnable {
private Server server;
private final ServerAuthManager authManager;
public WebServerRunner(ServerAuthManager authManager) {
this.authManager = authManager;
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@ -66,8 +84,14 @@ public class WebServerRunner implements Runnable {
String datapath = Config.getPath(Config.DATAPATH_KEY,
Config.DATAPATH_DEFAULT);
context.addServlet(new ServletHolder(new DataService(base)), datapath
+ "*");
String pathspec = datapath
+ "*";
context.addServlet(new ServletHolder(new DataService(base)), pathspec);
List<MethodAuthHandler> methods = Arrays.asList(new PutAuthHandler(
authManager), new DeleteAuthHandler(authManager));
context.addFilter(new FilterHolder(new AuthFilter(methods)), pathspec,
EnumSet.allOf(DispatcherType.class));
try {
server.start();
System.out.println("Server started");

View file

@ -23,15 +23,18 @@ import java.net.UnknownHostException;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.util.SyncPacketSend;
import com.raytheon.uf.common.xmpp.PacketConstants;
import com.raytheon.uf.common.xmpp.iq.AuthInfo;
import com.raytheon.uf.common.xmpp.iq.AuthInfoProvider;
import com.raytheon.uf.common.xmpp.iq.HttpInfo;
/**
* Starts and runs XMPP client thread for communication with XMPP server
*
@ -42,6 +45,7 @@ import org.jivesoftware.smack.util.SyncPacketSend;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 14, 2014 2756 bclement Initial creation
* Feb 28, 2014 2756 bclement added custom IQ packet support
*
* </pre>
*
@ -50,6 +54,12 @@ import org.jivesoftware.smack.util.SyncPacketSend;
*/
public class XmppServerConnection implements Runnable {
static {
ProviderManager pm = ProviderManager.getInstance();
pm.addIQProvider(PacketConstants.QUERY_ELEMENT_NAME,
AuthInfo.AUTH_QUERY_XMLNS, new AuthInfoProvider());
}
private static final int PACKET_SEND_TIMEOUT = 5000; // 5 seconds
private final XMPPConnection conn;
@ -87,25 +97,7 @@ public class XmppServerConnection implements Runnable {
*/
@Override
public void run() {
conn.addPacketListener(new PacketListener() {
@Override
public void processPacket(Packet packet) {
log.debug(packet.toXML());
}
}, new PacketFilter() {
@Override
public boolean accept(Packet packet) {
return true;
}
});
IQ packet = new IQ() {
@Override
public String getChildElementXML() {
return "<query xmlns=\"urn:uf:viz:collaboration:iq:http\">"
+ "<httpinfo xmlns=\"urn:uf:viz:collaboration\">"
+ "<url>" + dataServerUrl + "</url></httpinfo></query>";
}
};
HttpInfo packet = new HttpInfo(dataServerUrl);
packet.setType(Type.SET);
try {
Packet reply = SyncPacketSend.getReply(conn, packet,
@ -132,4 +124,11 @@ public class XmppServerConnection implements Runnable {
conn.disconnect();
}
/**
* @return the conn
*/
public XMPPConnection getConnection() {
return conn;
}
}

View file

@ -0,0 +1,144 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.collaboration.dataserver.auth;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.raytheon.collaboration.dataserver.RestException;
import com.raytheon.uf.common.http.auth.SignatureAuthScheme;
import com.raytheon.uf.common.http.auth.SignedCredential;
/**
* Servlet filter for authentication and authorization of requests
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 26, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class AuthFilter implements Filter {
private final Map<String, MethodAuthHandler> handlerMap;
/**
* If a method handler isn't provided for a method, method requests will be
* forwarded on to the servlet
*
* @param methodHandlers
*/
public AuthFilter(List<MethodAuthHandler> methodHandlers) {
Map<String, MethodAuthHandler> map = new HashMap<String, MethodAuthHandler>(
methodHandlers.size());
for (MethodAuthHandler handler : methodHandlers) {
map.put(handler.getMethod(), handler);
}
this.handlerMap = Collections.unmodifiableMap(map);
}
/* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
@Override
public void destroy() {
// do nothing
}
/* (non-Javadoc)
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpReq = (HttpServletRequest) req;
MethodAuthHandler handler = handlerMap.get(httpReq.getMethod()
.toLowerCase());
if (handler == null || !handler.getAuthManager().isEnabled()) {
chain.doFilter(req, resp);
return;
}
try {
SignedCredential credential = parseCredentials(httpReq);
ParsedUrl urlparts = ParsedUrl.parse(httpReq);
HttpServletResponse httpResp = (HttpServletResponse) resp;
handler.authorize(httpReq, httpResp, chain, credential, urlparts);
}catch(RestException e){
HttpServletResponse httpResp = (HttpServletResponse) resp;
httpResp.sendError(e.getCode(), e.getLocalizedMessage());
}
}
/**
* Parse Authorization header
*
* @param httpReq
* @return
* @throws RestException
* if header does not exist or is malformed
*/
private SignedCredential parseCredentials(HttpServletRequest httpReq)
throws RestException {
String header = httpReq.getHeader(SignatureAuthScheme.HTTP_AUTH_HEADER);
if (header == null || header.trim().isEmpty()) {
throw new RestException(HttpServletResponse.SC_UNAUTHORIZED,
"Missing header: " + SignatureAuthScheme.HTTP_AUTH_HEADER);
}
SignedCredential credential = SignatureAuthScheme
.parseAuthHeader(header);
if (credential == null || credential.getAlgorithm() == null
|| credential.getSignature() == null
|| credential.getUserid() == null) {
throw new RestException(HttpServletResponse.SC_BAD_REQUEST,
"Malformed header: " + SignatureAuthScheme.HTTP_AUTH_HEADER);
}
return credential;
}
/* (non-Javadoc)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig arg0) throws ServletException {
// do nothing
}
}

View file

@ -0,0 +1,127 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.collaboration.dataserver.auth;
import java.io.IOException;
import java.security.Signature;
import java.security.SignatureException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import com.raytheon.collaboration.dataserver.RestException;
import com.raytheon.uf.common.http.auth.SignatureAuthScheme;
import com.raytheon.uf.common.http.auth.SignedCredential;
import com.raytheon.uf.common.util.StringUtil;
/**
* Auth handler for HTTP DELETE requests
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 27, 2014 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class DeleteAuthHandler extends MethodAuthHandler {
private final Logger log = Log.getLogger(this.getClass());
/**
* @param authManager
*/
public DeleteAuthHandler(ServerAuthManager authManager) {
super(authManager, "delete");
}
/* (non-Javadoc)
* @see com.raytheon.collaboration.dataserver.auth.MethodAuthHandler#authorize(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain, com.raytheon.uf.common.http.auth.SignedCredential, com.raytheon.collaboration.dataserver.auth.ParsedUrl)
*/
@Override
public void authorize(HttpServletRequest httpReq,
HttpServletResponse httpResp, FilterChain chain,
SignedCredential credential, ParsedUrl urlParts)
throws RestException, ServletException, IOException {
String userid = urlParts.getUserid();
Signature sig;
if (StringUtil.isEmptyString(userid)) {
// deleting entire session, verify that user is owner
sig = authManager.getAuthorizedSignatureDirect(credential,
urlParts.getSessionid());
} else {
// verify that user owns resource to delete
if (!userid.equals(credential.getUserid())) {
throw new RestException(HttpServletResponse.SC_FORBIDDEN,
"Credential does not own resource");
}
sig = authManager.getAuthorizedSignature(credential);
}
try {
if (verify(sig, credential, urlParts)) {
chain.doFilter(httpReq, httpResp);
} else {
// possible that we have an outdated public key cached
sig = authManager.getAuthorizedSignatureDirect(credential);
if (verify(sig, credential, urlParts)) {
chain.doFilter(httpReq, httpResp);
} else {
throw new RestException(HttpServletResponse.SC_FORBIDDEN,
"Credentials not authenticated");
}
}
} catch (SignatureException e) {
log.warn("Problem using signature object", e);
throw new RestException(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Error using authentication server");
}
}
/**
* @param sig
* @param credential
* @param urlParts
* @return true if signature matches credentials
* @throws SignatureException
*/
private boolean verify(Signature sig, SignedCredential credential,
ParsedUrl urlParts) throws SignatureException {
synchronized (sig) {
sig.update(urlParts.getHostString().getBytes());
sig.update(urlParts.getPathString().getBytes());
byte[] sigBytes = SignatureAuthScheme.base64Decode(credential
.getSignature());
return sig.verify(sigBytes);
}
}
}

View file

@ -0,0 +1,97 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.collaboration.dataserver.auth;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.raytheon.collaboration.dataserver.RestException;
import com.raytheon.uf.common.http.auth.SignedCredential;
/**
* Base auth handler for HTTP methods
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 27, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public abstract class MethodAuthHandler {
protected final String method;
protected final ServerAuthManager authManager;
/**
* @param authManager
* @param method
*/
public MethodAuthHandler(ServerAuthManager authManager, String method) {
this.authManager = authManager;
this.method = method;
}
/**
* Authorize request using provided credentials. Sends the request down the
* FilterChain if authorized.
*
* @param httpReq
* @param httpResp
* @param chain
* @param credential
* @param urlParts
* @throws RestException
* if request is not authorized or invalid
* @throws ServletException
* @throws IOException
*/
abstract public void authorize(HttpServletRequest httpReq,
HttpServletResponse httpResp, FilterChain chain,
SignedCredential credential, ParsedUrl urlParts)
throws RestException, ServletException, IOException;
/**
* @return the method
*/
public String getMethod() {
return method;
}
/**
* @return the authManager
*/
public ServerAuthManager getAuthManager() {
return authManager;
}
}

View file

@ -0,0 +1,168 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.collaboration.dataserver.auth;
import java.net.URI;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.utils.URIUtils;
import com.raytheon.collaboration.dataserver.RestException;
import com.raytheon.uf.common.util.StringUtil;
/**
* Parsed HTTP request url
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 27, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class ParsedUrl {
/**
* <pre>
* /session_data/[sessionid]/[userid]
* </pre>
*/
private static final Pattern PATH_PATTERN = Pattern
.compile("^/?([^/]+)/([^/]+)(/([^/]+))?.*$");
/**
* parent directory reference (..) anywhere in path
*/
private static final Pattern REL_PATH_PATTERN = Pattern
.compile("^\\.\\./|/\\.\\./|/\\.\\.$|^\\.\\.$");
private final String hostString;
private final String pathString;
private final String sessionid;
private final String userid;
/**
* @param hostString
* @param pathString
* @param sessionid
* @param userid
*/
private ParsedUrl(String hostString, String pathString, String sessionid,
String userid) {
this.hostString = hostString;
this.pathString = pathString;
this.sessionid = sessionid;
this.userid = userid;
}
/**
* Parse URL of request
*
* @param httpReq
* @return
* @throws RestException
*/
public static ParsedUrl parse(HttpServletRequest httpReq)
throws RestException {
URI uri = URI.create(httpReq.getRequestURL().toString());
String hostHeader = URIUtils.extractHost(uri).toHostString();
if (StringUtil.isEmptyString(hostHeader)) {
throw new RestException(HttpServletResponse.SC_BAD_REQUEST,
"Unable to determine host string");
}
String path = uri.getPath();
Matcher m = REL_PATH_PATTERN.matcher(path);
if (m.find()) {
throw new RestException(HttpServletResponse.SC_BAD_REQUEST,
"Relative path inderection is not allowed");
}
m = PATH_PATTERN.matcher(path);
if (!m.matches()) {
throw new RestException(HttpServletResponse.SC_BAD_REQUEST,
"Malformed session data path");
}
/*
* first part of url will always be the path to the servlet
* (session_data). The next is enforced as the sessionid and the data
* provider's userid after that. The userid is optional because topic
* owners can delete the entire session tree
*/
String sessionid = getSafeGroup(m, 2);
String userid = getSafeGroup(m, 4);
return new ParsedUrl(hostHeader, path, sessionid, userid);
}
/**
* Get trimmed matcher group
*
* @param m
* @param group
* @return null if group was empty
*/
public static String getSafeGroup(Matcher m, int group) {
String rval = m.group(group);
if (rval != null) {
rval = rval.trim();
}
return rval;
}
/**
* @return the hostString
*/
public String getHostString() {
return hostString;
}
/**
* @return the pathString
*/
public String getPathString() {
return pathString;
}
/**
* @return the sessionid
*/
public String getSessionid() {
return sessionid;
}
/**
* @return the userid
*/
public String getUserid() {
return userid;
}
}

View file

@ -0,0 +1,133 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.collaboration.dataserver.auth;
import java.io.IOException;
import java.security.Signature;
import java.security.SignatureException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import com.raytheon.collaboration.dataserver.RestException;
import com.raytheon.uf.common.http.auth.SignatureAuthScheme;
import com.raytheon.uf.common.http.auth.SignedCredential;
/**
* Auth handler for HTTP PUT requests
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 27, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class PutAuthHandler extends MethodAuthHandler {
private final Logger log = Log.getLogger(this.getClass());
/**
* @param method
*/
public PutAuthHandler(ServerAuthManager authManager) {
super(authManager, "put");
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.collaboration.dataserver.auth.MethodAuthHandler#authorize
* (javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain,
* com.raytheon.uf.common.http.auth.SignedCredential,
* com.raytheon.collaboration.dataserver.auth.ParsedUrl)
*/
@Override
public void authorize(HttpServletRequest httpReq,
HttpServletResponse httpResp, FilterChain chain,
SignedCredential credential, ParsedUrl urlParts)
throws RestException, ServletException {
if (!urlParts.getUserid().equals(credential.getUserid())) {
throw new RestException(HttpServletResponse.SC_FORBIDDEN,
"Credential does not own resource");
}
Signature sig = authManager.getAuthorizedSignature(credential);
try {
VerifyingRequest wrapper = new VerifyingRequest(httpReq);
if (verify(sig, wrapper, credential, urlParts)) {
chain.doFilter(wrapper, httpResp);
} else {
// possible that we have an outdated public key cached
sig = authManager.getAuthorizedSignatureDirect(credential);
if (verify(sig, wrapper, credential, urlParts)) {
chain.doFilter(wrapper, httpResp);
} else {
throw new RestException(HttpServletResponse.SC_FORBIDDEN,
"Credentials not authenticated");
}
}
} catch (SignatureException e) {
log.warn("Problem using signature object", e);
throw new RestException(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Error using authentication server");
} catch (IOException e) {
log.warn("Problem transferring stream", e);
throw new RestException(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Problem reading from stream");
}
}
/**
* @param sig
* @param wrapper
* @param credential
* @param urlParts
* @return true if signature matches the credentials
* @throws SignatureException
* @throws IOException
*/
private boolean verify(Signature sig, VerifyingRequest wrapper,
SignedCredential credential, ParsedUrl urlParts)
throws SignatureException, IOException {
synchronized (sig) {
sig.update(urlParts.getHostString().getBytes());
sig.update(urlParts.getPathString().getBytes());
byte[] sigBytes = SignatureAuthScheme.base64Decode(credential
.getSignature());
return wrapper.verify(sig, sigBytes);
}
}
}

View file

@ -0,0 +1,230 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.collaboration.dataserver.auth;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.security.Signature;
import java.util.Collections;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.collections.map.LRUMap;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.packet.XMPPError.Condition;
import org.jivesoftware.smack.util.SyncPacketSend;
import com.raytheon.collaboration.dataserver.Config;
import com.raytheon.collaboration.dataserver.RestException;
import com.raytheon.collaboration.dataserver.XmppServerConnection;
import com.raytheon.uf.common.http.auth.ServerSignatureAuth;
import com.raytheon.uf.common.http.auth.SignedCredential;
import com.raytheon.uf.common.xmpp.BaseProvider;
import com.raytheon.uf.common.xmpp.iq.AuthInfo;
/**
* Manages authentication credentials for HTTP data server which are stored on
* the XMPP server
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 25, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class ServerAuthManager {
private final Logger log = Log.getLogger(this.getClass());
private final XmppServerConnection xmppServer;
private final ServerSignatureAuth sigAuth = new ServerSignatureAuth();
private final boolean isEnabled;
private final Map<String, Signature> sigCache;
/**
* @param xmppServer
* @throws XMPPException
*/
@SuppressWarnings("unchecked")
public ServerAuthManager(XmppServerConnection xmppServer)
throws XMPPException {
isEnabled = BaseProvider.serverSupportsFeature(
xmppServer.getConnection(), AuthInfo.AUTH_QUERY_XMLNS);
this.xmppServer = xmppServer;
int cacheSize = Config.getInt(Config.AUTH_CACHE_SIZE_KEY,
Config.AUTH_CACHE_SIZE_DEFAULT);
this.sigCache = Collections.synchronizedMap(new LRUMap(cacheSize));
}
/**
* Returns cached signature verification for credential.
*
* @param credential
* @return
* @throws RestException
* if there was an internal error or credentials are not
* authorized for request
*/
public Signature getAuthorizedSignature(SignedCredential credential)
throws RestException {
Signature rval;
rval = sigCache.get(credential.getUserid());
if (rval == null) {
rval = getAuthorizedSignatureDirect(credential);
}
return rval;
}
/**
* Returns signature verification for credential from server. Caches result.
*
* @param credential
* @return
* @throws RestException
* if there was an internal error or credentials are not
* authorized for request
*/
public Signature getAuthorizedSignatureDirect(SignedCredential credential)
throws RestException {
return getAuthorizedSignatureDirect(credential, null);
}
/**
* Returns signature verification for credential from server. Caches result.
*
* @param credential
* @param sessionid
* @return
* @throws RestException
* if there was an internal error or credentials are not
* authorized for request
*/
public Signature getAuthorizedSignatureDirect(SignedCredential credential,
String sessionid) throws RestException {
AuthInfo query;
if (sessionid == null) {
query = AuthInfo.createGetPacket(credential.getUserid());
} else {
query = AuthInfo.createGetPacket(credential.getUserid(),
sessionid);
}
AuthInfo info = queryServerForAuth(query);
Signature rval = getSignature(credential, info);
sigCache.put(credential.getUserid(), rval);
return rval;
}
/**
* Query XMPP server for auth information
*
* @param query
* @return
* @throws RestException
* if there was an internal error or credentials are not
* authorized for request
*/
private AuthInfo queryServerForAuth(AuthInfo query) throws RestException {
AuthInfo rval;
try {
XMPPConnection conn = xmppServer.getConnection();
Packet response = SyncPacketSend.getReply(conn, query);
if (response instanceof AuthInfo) {
rval = (AuthInfo) response;
} else {
log.warn("Unexpected return type from XMPP server: "
+ response.toXML());
throw new RestException(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Problem communicating with authentication server");
}
} catch (XMPPException e) {
XMPPError xmppError = e.getXMPPError();
if ( xmppError != null &&xmppError.getCondition().equals(Condition.not_allowed)){
log.debug("Credential not authorized for sessionid: "
+ xmppError.getMessage());
throw new RestException(HttpServletResponse.SC_FORBIDDEN,
"Credential not authorized for session");
} else {
log.warn("Problem getting signature from server", e);
throw new RestException(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Problem communicating with authentication server");
}
}
return rval;
}
/**
* Construct signature validation object using credentials and private key
* from XMPP server.
*
* @param credential
* @param info
* @return
* @throws RestException
* if XMPP server contains malformed auth info
*/
private Signature getSignature(SignedCredential credential, AuthInfo info)
throws RestException {
if (info.getAlgorithm() == null || info.getEncodedKey() == null) {
log.warn("Missing elements from auth info packet: " + info.toXML());
throw new RestException(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Authentication server contains malformed authorization information");
}
Signature rval;
try {
PublicKey key = sigAuth.decodePublicKey(info.getEncodedKey(),
info.getAlgorithm());
rval = Signature.getInstance(credential.getAlgorithm());
rval.initVerify(key);
} catch (GeneralSecurityException e) {
log.warn("Unable to create signature verification", e);
throw new RestException(
HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Authentication server contains malformed authorization information");
}
return rval;
}
/**
* @return true if XMPP server supports public key auth scheme
*/
public boolean isEnabled() {
return isEnabled;
}
}

View file

@ -0,0 +1,153 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.collaboration.dataserver.auth;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.Signature;
import java.security.SignatureException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import com.raytheon.collaboration.dataserver.storage.FileManager;
/**
* HTTP Servlet Request Wrapper for public key signature verification. Allows
* body of request to be read multiple times.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 26, 2014 2756 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public class VerifyingRequest extends HttpServletRequestWrapper {
private final Logger log = Log.getLogger(this.getClass());
private byte[] body = null;
/**
* @param request
*/
public VerifyingRequest(HttpServletRequest request) throws IOException {
super(request);
}
/*
* (non-Javadoc)
*
* @see javax.servlet.ServletRequestWrapper#getInputStream()
*/
@Override
public ServletInputStream getInputStream() throws IOException {
if (body == null) {
ByteArrayOutputStream out = new ByteArrayOutputStream(
FileManager.BUFFER_SIZE);
FileManager.copy(super.getInputStream(), out);
body = out.toByteArray();
}
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
};
}
/**
* @param verification
* @param signature
* @return true if signature matches request
* @throws IOException
*/
private boolean verifyInternal(final Signature verification,
byte[] signature) throws IOException {
final boolean[] errorFlag = { false };
ServletInputStream in = super.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream(
FileManager.BUFFER_SIZE) {
@Override
public synchronized void write(byte[] b, int off, int len) {
super.write(b, off, len);
try {
verification.update(b, off, len);
} catch (SignatureException e) {
log.warn("Problem verifying request", e);
errorFlag[0] = true;
}
}
@Override
public synchronized void write(int b) {
super.write(b);
try {
verification.update((byte) b);
} catch (SignatureException e) {
log.warn("Problem verifying request", e);
errorFlag[0] = true;
}
}
};
FileManager.copy(in, out);
this.body = out.toByteArray();
boolean rval = false;
try {
rval = errorFlag[0] ? false : verification.verify(signature);
} catch (SignatureException e) {
log.warn("Problem verifying request", e);
rval = false;
}
return rval;
}
/**
* @param verification
* @param signature
* @return true if signature matches request
* @throws IOException
* @throws SignatureException
*/
public boolean verify(Signature verification, byte[] signature)
throws IOException, SignatureException {
if (this.body == null) {
return verifyInternal(verification, signature);
} else {
verification.update(body);
return verification.verify(signature);
}
}
}

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.collaboration.dataserver;
package com.raytheon.collaboration.dataserver.storage;
import java.io.File;
import java.io.FileInputStream;
@ -33,6 +33,7 @@ import java.util.ListIterator;
import javax.servlet.http.HttpServletResponse;
import com.raytheon.collaboration.dataserver.RestException;
import com.raytheon.uf.common.util.concurrent.KeyLock;
import com.raytheon.uf.common.util.concurrent.KeyLocker;
@ -47,7 +48,8 @@ import com.raytheon.uf.common.util.concurrent.KeyLocker;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 6, 2014 2756 bclement Initial creation
* Feb 6, 2014 2756 bclement Initial creation
* Feb 28, 2014 2756 bclement moved to storage package, made buffer size public
*
* </pre>
*
@ -56,7 +58,7 @@ import com.raytheon.uf.common.util.concurrent.KeyLocker;
*/
public class FileManager {
private static final int BUFFER_SIZE = 1024 * 256; // 256K
public static final int BUFFER_SIZE = 1024 * 256; // 256K
private static final ThreadLocal<byte[]> localBuffer = new ThreadLocal<byte[]>() {

View file

@ -51,6 +51,7 @@ import org.xmpp.packet.PacketError.Condition;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 12, 2014 2756 bclement Initial creation
* Feb 28, 2014 2756 bclement reordered retrieve method operations for clarity
*
* </pre>
*
@ -264,12 +265,15 @@ public abstract class AbstractConfigHandler extends IQHandler implements
*/
protected IQ retrieve(IQ requestPacket, String id, Element key) {
Element queryElem = requestPacket.getChildElement();
Element respElem = storage.get(id, key);
IQ rval = IQ.createResultIQ(requestPacket);
queryElem.setParent(null);
Element respElem = storage.get(id, key);
respElem.setParent(null);
removeChildren(queryElem);
queryElem.add(respElem);
queryElem.setParent(null);
rval.setChildElement(queryElem);
queryElem.add(respElem);
log.info(rval.toXML());
return rval;
}

View file

@ -46,6 +46,7 @@ import org.xmpp.packet.PacketError.Condition;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 10, 2014 2756 bclement Initial creation
* Feb 28, 2014 2756 bclement if sessionid is not provided, skip authorization step
*
* </pre>
*
@ -105,25 +106,25 @@ public class DataAuthHandler extends AbstractConfigHandler {
}
JID target = new JID(jid);
String sessionId = queryElem.attributeValue(SESSIONID_ATTRIBUTE);
if (StringUtils.isBlank(sessionId)) {
String msg = "Missing attribute: " + SESSIONID_ATTRIBUTE;
log.debug(msg);
return createError(packet, new PacketError(Condition.bad_request,
PacketError.Type.modify, msg));
}
Node node = pubsub.getNode(sessionId);
if (node == null) {
String msg = "No topic found for session: " + sessionId;
log.debug(msg);
return createError(packet, new PacketError(Condition.not_allowed,
PacketError.Type.cancel, msg));
}
if (!isOwner(jid, node)){
String msg = "User '" + jid + "' is not an owner of session '"
+ sessionId + "'";
log.debug(msg);
return createError(packet, new PacketError(Condition.not_allowed,
PacketError.Type.cancel, msg));
if (!StringUtils.isBlank(sessionId)) {
/*
* only check authorization if session id is specified, otherwise we
* are just doing authentication
*/
Node node = pubsub.getNode(sessionId);
if (node == null) {
String msg = "No topic found for session: " + sessionId;
log.debug(msg);
return createError(packet, new PacketError(
Condition.not_allowed, PacketError.Type.cancel, msg));
}
if (!isOwner(jid, node)) {
String msg = "User '" + jid + "' is not an owner of session '"
+ sessionId + "'";
log.debug(msg);
return createError(packet, new PacketError(
Condition.not_allowed, PacketError.Type.cancel, msg));
}
}
return retrieve(packet, target.getNode(),
createElement(INFO_ELEMENT_NAME, COLLAB_XMLNS));