Author: anil.saldhana(a)jboss.com
Date: 2011-04-06 12:14:24 -0400 (Wed, 06 Apr 2011)
New Revision: 864
Added:
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/handler/BinaryTokenHandler.java
Modified:
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/Constants.java
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/handler/SecurityActions.java
Log:
PLFED-162: a binary token handler to pick from http header or http cookie
Modified: trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/Constants.java
===================================================================
---
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/Constants.java 2011-04-05
17:22:13 UTC (rev 863)
+++
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/Constants.java 2011-04-06
16:14:24 UTC (rev 864)
@@ -27,14 +27,23 @@
/**
* @author Jason T. Greene
+ * @author Anil Saldhana
*/
public class Constants
{
public static final String WSS_SOAP_NS =
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0";
+
+ public static final String WSSE_LOCAL = "Security";
public static final String WSSE_PREFIX = "wsse";
public static final String WSSE_NS =
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
+
+ public static final String WSSE_BINARY_SECURITY_TOKEN =
"BinarySecurityToken";
+
+ public static final String WSSE_ENCODING_TYPE = "EncodingType";
+
+ public static final String WSSE_VALUE_TYPE = "ValueType";
public static final String WSU_PREFIX = "wsu";
Added:
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/handler/BinaryTokenHandler.java
===================================================================
---
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/handler/BinaryTokenHandler.java
(rev 0)
+++
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/handler/BinaryTokenHandler.java 2011-04-06
16:14:24 UTC (rev 864)
@@ -0,0 +1,377 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.picketlink.trust.jbossws.handler;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPElement;
+import javax.xml.soap.SOAPEnvelope;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPFactory;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.ws.handler.MessageContext;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+
+import org.apache.log4j.Logger;
+import org.jboss.wsf.common.handler.GenericSOAPHandler;
+import org.picketlink.trust.jbossws.Constants;
+import org.picketlink.trust.jbossws.Util;
+
+/**
+ * <p>
+ * Handler that looks for a binary data that exists
+ * in the HTTP payload either as a header or a cookie
+ * based on configuration.
+ * </p>
+ * <p>
+ * <b>Configuration:</b>
+ * <p>
+ * <i>System Properties:</i>
+ * <ul>
+ * <li>binary.http.header: http header name</li>
+ * <li>binary.http.cookie: http cookie name</li>
+ * <li>binary.http.encodingType: attribute value of the EncodingType
attribute</li>
+ * <li>binary.http.valueType: attribute value of the ValueType
attribute</li>
+ * <li>binary.http.valueType.namespace: namespace for the ValueType
attribute</li>
+ * <li>binary.http.valueType.prefix: namespace for the ValueType
attribute</li>
+ * <li>binary.http.cleanToken: true or false dependending on whether the binary
token has to be cleaned</li>
+ * </ul>
+ * <i>Setters:</i>
+ * <p> Please see the see also section. </p>
+ *
+ * @see #setHttpHeaderName(String)
+ * @see #setHttpCookieName(String)
+ * @see #setEncodingType(String)
+ * @see #setValueType(String)
+ * @see #setValueTypeNamespace(String)
+ * @see #setValueTypePrefix(String)
+ * @see #setCleanToken(boolean)
+ * </p>
+ * </p>
+ * @author Anil.Saldhana(a)redhat.com
+ * @since Apr 5, 2011
+ */
+@SuppressWarnings("rawtypes")
+public class BinaryTokenHandler extends GenericSOAPHandler
+{
+ protected static Logger log = Logger.getLogger(BinaryTokenHandler.class);
+ protected boolean trace = log.isTraceEnabled();
+
+ private static Set<QName> headers;
+
+ /**
+ * The HTTP header name that this token looks for. Either this or the httpCookieName
should be set.
+ */
+ private String httpHeaderName =
SecurityActions.getSystemProperty("binary.http.header", null);
+
+ /**
+ * The HTTP cookie name that this token looks for. Either this or the httpHeaderName
should be set.
+ */
+ private String httpCookieName =
SecurityActions.getSystemProperty("binary.http.cookie", null);
+
+ /**
+ * Attribute value for the EncodingType attribute
+ */
+ private String encodingType =
SecurityActions.getSystemProperty("binary.http.encodingType",
+ "http://docs.oasis-open.org/wss/2004/01/
oasis-200401-wss-soap-message-security-1.0#Base64Binary");
+
+ /**
+ * Attribute value for the ValueType attribute
+ */
+ private String valueType =
SecurityActions.getSystemProperty("binary.http.valueType", null);
+
+ /**
+ * Namespace for the ValueType. Can be null. If null, then a separate namespace is not
added.
+ */
+ private String valueTypeNamespace =
SecurityActions.getSystemProperty("binary.http.valueType.namespace", null);
+
+ /**
+ * Prefix for the ValueType. Can be null.
+ */
+ private String valueTypePrefix =
SecurityActions.getSystemProperty("binary.http.valueType.prefix", null);
+
+ /**
+ * Some binary tokens need to be cleaned. This handler just cleans upto the first
blank space and discards before that.
+ */
+ private boolean cleanToken =
Boolean.parseBoolean(SecurityActions.getSystemProperty("binary.http.cleanToken",
"false"));
+
+ private SOAPFactory factory = null;
+
+ static
+ {
+ HashSet<QName> set = new HashSet<QName>();
+ set.add(Constants.WSSE_HEADER_QNAME);
+ headers = Collections.unmodifiableSet(set);
+ }
+
+ /**
+ * <p> Set the EncodingType value.</p>
+ * <p> Alternatively, set the system property
"binary.http.encodingType"</p>
+ *
+ * @param binaryEncodingType
+ */
+ public void setEncodingType(String binaryEncodingType)
+ {
+ this.encodingType = binaryEncodingType;
+ }
+
+ /**
+ * <p> Set the Value type</p>
+ * <p> Alternatively, set the system property
"binary.http.valueType"</p>
+ *
+ * @param binaryValueType
+ */
+ public void setValueType(String binaryValueType)
+ {
+ this.valueType = binaryValueType;
+ }
+
+ /**
+ * <p> Set the ValueType Namespace </p>
+ * <p> Alternatively, set the system property
"binary.http.valueType.namespace"</p>
+ *
+ * @param binaryValueNamespace
+ */
+ public void setValueTypeNamespace(String binaryValueNamespace)
+ {
+ this.valueTypeNamespace = binaryValueNamespace;
+ }
+
+ /**
+ * <p> Set the Value Type Prefix </p>
+ * <p> Alternatively, set the system property
"binary.http.valueType.prefix" </p>
+ *
+ * @param binaryValuePrefix
+ */
+ public void setValueTypePrefix(String binaryValuePrefix)
+ {
+ this.valueTypePrefix = binaryValuePrefix;
+ }
+
+ public Set<QName> getHeaders()
+ {
+ //return a collection with just the wsse:Security header to pass the MustUnderstand
check on it
+ return headers;
+ }
+
+ /**
+ * <p>
+ * Set the Http Header Name
+ * </p>
+ * <p>
+ * Alternatively, set the system property: "binary.http.header"
+ * </p>
+ *
+ * @param http
+ */
+ public void setHttpHeaderName(String http)
+ {
+ httpHeaderName = http;
+ }
+
+ /**
+ * <p>
+ * Set the Http Cookie Name
+ * </p>
+ * <p>
+ * Alternatively, set the system property: ""binary.http.cookie"
+ * </p>
+ *
+ * @param http
+ */
+ public void setHttpCookieName(String http)
+ {
+ httpCookieName = http;
+ }
+
+ /**
+ * <p>
+ * Should we not clean the extracted binary token.
+ * </p>
+ * <p>
+ * Alternatively, set the system property: "binary.http.cleanToken"
+ * </p>
+ *
+ * @param clean
+ */
+ public void setCleanToken( boolean clean)
+ {
+ this.cleanToken = clean;
+ }
+
+ @Override
+ protected boolean handleOutbound(MessageContext msgContext)
+ {
+ if( httpHeaderName == null && httpCookieName == null )
+ throw new RuntimeException("Either httpHeaderName or httpCookieName should
be set" );
+
+ HttpServletRequest servletRequest = getHttpRequest(msgContext);
+ if( servletRequest == null )
+ throw new IllegalStateException("Unable to proceed as Http request is
null");
+
+ String token = getTokenValue(servletRequest);
+ if(token==null)
+ throw new IllegalStateException("Null Token");
+ SOAPElement security = null;
+ try
+ {
+ security = create(token);
+ }
+ catch (SOAPException e)
+ {
+ log.error("Unable to create binary token", e);
+ }
+ if( security == null)
+ {
+ log.warn("Was not able to create security token. Just sending message
without binary token");
+ return true;
+ }
+ SOAPMessage sm = ((SOAPMessageContext)msgContext).getMessage();
+ SOAPEnvelope envelope;
+ try
+ {
+ envelope = sm.getSOAPPart().getEnvelope();
+ SOAPHeader header = (SOAPHeader)Util.
+ findElement(envelope, new QName(envelope.getNamespaceURI(),
"Header"));
+ if (header == null)
+ {
+ header = (SOAPHeader)envelope.getOwnerDocument().createElementNS(
+ envelope.getNamespaceURI(), envelope.getPrefix() +
":Header");
+ envelope.insertBefore(header, envelope.getFirstChild());
+ }
+ header.addChildElement(security);
+ }
+ catch (SOAPException e)
+ {
+ log.error("Unable to create WSSE Binary Header::",e);
+ }
+ return true;
+ }
+
+ /**
+ * Get the {@link HttpServletRequest} from the {@link MessageContext}
+ * @param msgContext
+ * @return
+ */
+ private HttpServletRequest getHttpRequest(MessageContext msgContext)
+ {
+ return (HttpServletRequest) msgContext.get(MessageContext.SERVLET_REQUEST);
+ }
+
+ /**
+ * Given the {@link HttpServletRequest}, look for the http header or
+ * the cookie depending on the configuration
+ * @param http
+ * @return
+ */
+ private String getTokenValue(HttpServletRequest http)
+ {
+ if( httpHeaderName!= null && !httpHeaderName.isEmpty())
+ {
+ String header = http.getHeader(httpHeaderName);
+ if( header != null)
+ return clean(header);
+ }
+ if( httpCookieName != null && !httpCookieName.isEmpty())
+ {
+ Cookie[] cookies = http.getCookies();
+ if( cookies != null )
+ {
+ for(Cookie cookie: cookies)
+ {
+ if(cookie.getName().equals(httpCookieName))
+ {
+ return clean(cookie.getValue());
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Given a binary token, create a {@link SOAPElement}
+ * @param token
+ * @return
+ * @throws SOAPException
+ */
+ private SOAPElement create(String token) throws SOAPException
+ {
+ if(factory == null)
+ factory = SOAPFactory.newInstance();
+ SOAPElement security = factory.createElement(Constants.WSSE_LOCAL,
Constants.WSSE_PREFIX, Constants.WSSE_NS);
+
+ if (valueTypeNamespace != null)
+ {
+ security.addNamespaceDeclaration(valueTypePrefix, valueTypeNamespace);
+ }
+
+ SOAPElement binarySecurityToken = factory.
+ createElement(Constants.WSSE_BINARY_SECURITY_TOKEN, Constants.WSSE_PREFIX,
Constants.WSSE_NS);
+ binarySecurityToken.addTextNode(token);
+ if( valueType != null && !valueType.isEmpty())
+ {
+ binarySecurityToken.setAttribute(Constants.WSSE_VALUE_TYPE, valueType);
+ }
+ if (encodingType != null)
+ {
+ binarySecurityToken.setAttribute(Constants.WSSE_ENCODING_TYPE, encodingType);
+ }
+
+ security.addChildElement(binarySecurityToken);
+ return security;
+ }
+
+ /**
+ * Some 3rd party systems send in the binary token in the format
Discardable<space>ValidToken
+ * @param value
+ * @return
+ */
+ private String clean(String value)
+ {
+ if( trace)
+ {
+ log.trace("Cleaning:"+value);
+ }
+ int i= -1;
+
+ if( cleanToken)
+ {
+ value = value.trim();
+ while((i = value.indexOf(' ')) != -1)
+ {
+ value = value.substring(i + 1);
+ }
+ }
+ if(trace)
+ {
+ log.trace("Cleaned:"+value);
+ }
+ return value;
+ }
+}
\ No newline at end of file
Modified:
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/handler/SecurityActions.java
===================================================================
---
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/handler/SecurityActions.java 2011-04-05
17:22:13 UTC (rev 863)
+++
trust/trunk/jbossws/src/main/java/org/picketlink/trust/jbossws/handler/SecurityActions.java 2011-04-06
16:14:24 UTC (rev 864)
@@ -88,4 +88,21 @@
}
});
}
+
+ /**
+ * Get a system property
+ * @param key the property name
+ * @param defaultValue default value in absence of property
+ * @return
+ */
+ static String getSystemProperty( final String key, final String defaultValue)
+ {
+ return AccessController.doPrivileged(new PrivilegedAction<String>()
+ {
+ public String run()
+ {
+ return System.getProperty(key, defaultValue);
+ }
+ });
+ }
}
\ No newline at end of file