org.picketlink.trust.jbossws.handler.BinaryTokenHandler Maven / Gradle / Ivy
/*
* 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 org.picketlink.common.util.StringUtil;
import org.picketlink.identity.federation.core.util.SOAPUtil;
import org.picketlink.trust.jbossws.Constants;
import org.picketlink.trust.jbossws.Util;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
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 java.util.ArrayList;
import java.util.List;
/**
* Handler that looks for a binary data that exists in the HTTP payload either as a header or a cookie based on configuration.
*
Configuration:
System Properties:
- binary.http.header: http header name. Can be a comma
* separated set of names
- binary.http.cookie: http cookie name
- binary.http.encodingType: attribute value of the
* EncodingType attribute
- binary.http.valueType: attribute value of the ValueType attribute
* - binary.http.valueType.namespace: namespace for the ValueType attribute
- binary.http.valueType.prefix: namespace for
* the ValueType attribute
- binary.http.cleanToken: true or false dependending on whether the binary token has to be
* cleaned
Setters: Please see the see also section.
*
* @author [email protected]
* @see #setHttpHeaderName(String)
* @see #setHttpCookieName(String)
* @see #setEncodingType(String)
* @see #setValueType(String)
* @see #setValueTypeNamespace(String)
* @see #setValueTypePrefix(String)
* @see #setCleanToken(boolean)
* @since Apr 5, 2011
*/
public class BinaryTokenHandler extends AbstractPicketLinkTrustHandler {
/**
* 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;
/**
* Set the EncodingType value.
Alternatively, set the system property "binary.http.encodingType"
*
* @param binaryEncodingType
*/
public void setEncodingType(String binaryEncodingType) {
this.encodingType = binaryEncodingType;
}
/**
* Set the Value type
Alternatively, set the system property "binary.http.valueType"
*
* @param binaryValueType
*/
public void setValueType(String binaryValueType) {
this.valueType = binaryValueType;
}
/**
* Set the ValueType Namespace
Alternatively, set the system property "binary.http.valueType.namespace"
*
* @param binaryValueNamespace
*/
public void setValueTypeNamespace(String binaryValueNamespace) {
this.valueTypeNamespace = binaryValueNamespace;
}
/**
* Set the Value Type Prefix
Alternatively, set the system property "binary.http.valueType.prefix"
*
* @param binaryValuePrefix
*/
public void setValueTypePrefix(String binaryValuePrefix) {
this.valueTypePrefix = binaryValuePrefix;
}
/**
* Set the Http Header Name
Alternatively, set the system property: "binary.http.header"
*
* @param http
*/
public void setHttpHeaderName(String http) {
httpHeaderName = http;
}
/**
* Set the Http Cookie Name
Alternatively, set the system property: ""binary.http.cookie"
*
* @param http
*/
public void setHttpCookieName(String http) {
httpCookieName = http;
}
/**
* Should we not clean the extracted binary token.
Alternatively, set the system property: "binary.http.cleanToken"
*
*
* @param clean
*/
public void setCleanToken(boolean clean) {
this.cleanToken = clean;
}
@Override
protected boolean handleOutbound(MessageContext msgContext) {
logger.trace("Handling Outbound Message");
if (httpHeaderName == null && httpCookieName == null) {
throw logger.injectedValueMissing("Either httpHeaderName or httpCookieName should be set");
}
HttpServletRequest servletRequest = getHttpRequest(msgContext);
if (servletRequest == null) {
throw logger.nullValueError("Http request");
}
String token = getTokenValue(servletRequest);
if (token == null) {
throw logger.nullValueError("Null Token");
}
SOAPElement security = null;
try {
security = create(token);
} catch (SOAPException e) {
logger.jbossWSUnableToCreateBinaryToken(e);
}
if (security == null) {
logger.jbossWSUnableToCreateSecurityToken();
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) {
logger.jbossWSUnableToCreateBinaryToken(e);
}
if (logger.isTraceEnabled()) {
logger.trace("SOAP Message=" + SOAPUtil.soapMessageAsString(sm));
}
return true;
}
/**
* Get the {@link HttpServletRequest} from the {@link MessageContext}
*
* @param msgContext
*
* @return
*/
private HttpServletRequest getHttpRequest(MessageContext msgContext) {
HttpServletRequest request = (HttpServletRequest) msgContext.get(MessageContext.SERVLET_REQUEST);
if (request == null) {
try {
request = (HttpServletRequest) PolicyContext.getContext("javax.servlet.http.HttpServletRequest");
} catch (PolicyContextException e) {
throw new RuntimeException(e);
}
}
return 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()) {
// Sometime the http header name can be a comma separated list of names
if (httpHeaderName.contains(",")) {
List headers = getHeaderNames(httpHeaderName);
StringBuilder builder = new StringBuilder();
for (String header : headers) {
String value = getTokenValue(http, header);
if (value != null) {
builder.append(value);
}
}
String headerValue = builder.toString();
logger.trace("Header value has been identified " + headerValue);
return clean(headerValue);
} else {
String header = http.getHeader(httpHeaderName);
if (header != null) {
logger.trace("Header value has been identified " + header);
return clean(header);
}
}
}
if (httpCookieName != null && !httpCookieName.isEmpty()) {
Cookie[] cookies = http.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(httpCookieName)) {
logger.trace("Cookie value has been identified " + cookie.getValue());
return clean(cookie.getValue());
}
}
}
}
return null;
}
private String getTokenValue(HttpServletRequest http, String header) {
String headerValue = http.getHeader(header);
if (headerValue != null && !headerValue.isEmpty()) {
return clean(headerValue);
}
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 DiscardableValidToken
*
* @param value
*
* @return
*/
private String clean(String value) {
int i = -1;
if (cleanToken) {
value = value.trim();
while ((i = value.indexOf(' ')) != -1) {
value = value.substring(i + 1);
}
}
return value;
}
private List getHeaderNames(String str) {
List list = new ArrayList();
if (StringUtil.isNotNull(str)) {
list.addAll(StringUtil.tokenize(str));
}
return list;
}
}