/*
* JBoss, Home of Professional Open Source Copyright 2008, Red Hat Middleware
* LLC, and individual contributors by the @authors tag. See the copyright.txt
* 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.jboss.soa.esb.services.security.auth.ws;
import static org.jboss.soa.esb.services.security.auth.ws.SoapExtractionUtil.isEndOfHeader;
import static org.jboss.soa.esb.services.security.auth.ws.SoapExtractionUtil.isStartOfBody;
import static org.jboss.soa.esb.services.security.auth.ws.SoapExtractionUtil.isStartOfHeader;
import java.io.StringReader;
import java.util.HashSet;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.apache.log4j.Logger;
import org.jboss.internal.soa.esb.assertion.AssertArgument;
import org.jboss.soa.esb.services.security.auth.AuthenticationRequest;
import org.jboss.soa.esb.services.security.auth.AuthenticationRequestImpl;
import org.jboss.soa.esb.services.security.auth.ExtractionException;
import org.jboss.soa.esb.services.security.auth.SecurityInfoExtractor;
/**
* This SecurityInfoExtractor implementation will extract data from a
* BinarySecurityToken if one exist in the xml String passed to this instances
* extractSecurityInfo method.
*
* @author <a href="mailto:dbevenius@redhat.com">Daniel Bevenius</a>
*/
public class BinarySecurityTokenExtractor implements SecurityInfoExtractor<String>
{
private static final XMLInputFactory XML_INPUT_FACTORY = getXmlInputFactory();
private Logger log = Logger.getLogger(BinarySecurityTokenExtractor.class);
/**
* The QName for the BinarySecurityToken element.
*/
private QName binarySecurityTokenQName;
/**
* The QName for the EncodingType attribute.
*/
private QName encodingTypeQName = new QName("EncodingType");
/**
* The QName for the ValueType attribute.
*/
private QName valueTypeQName = new QName("ValueType");
/**
* Creates a instance and uses the passed-in security namespace (NS) as the
* namesspace for the BinarySecurityToken.
*
* @param securityNS
* The namespace for the BinarySecurityToken element.
*/
public BinarySecurityTokenExtractor(final String securityNS)
{
AssertArgument.isNotNullAndNotEmpty(securityNS, "securityNS");
binarySecurityTokenQName = new QName(securityNS, "BinarySecurityToken");
}
/**
* Will extract the data from a BinarySecurityToken element from the
* passed-in SOAP message String. The extracted BinarySecurityToken keyj will be
* attached to the AuthenticationRequest as a credential.
*
* @param soap
* The String containing the SOAP message xml.
* @return {@link AuthenticationRequest} The ESB AuthenticationRequest with
* a credential of the content of the BinarySecurityToken, or null if the SOAP
* String did not contain a BinarySecurityHeader.
*/
public AuthenticationRequest extractSecurityInfo(final String soap) throws ExtractionException
{
if (soap == null || !soap.startsWith("<"))
return null;
final BinarySecurityToken binarySecurityToken = extractBinarySecurityToken(soap);
if (binarySecurityToken == null)
return null;
final Set<Object> credentials = new HashSet<Object>();
credentials.add(binarySecurityToken.getKey());
return new AuthenticationRequestImpl.Builder(null, credentials).build();
}
private BinarySecurityToken extractBinarySecurityToken(final String soap) throws ExtractionException
{
XMLEventReader xmlReader = null;
try
{
xmlReader = XML_INPUT_FACTORY.createXMLEventReader(new StringReader(soap));
while (xmlReader.hasNext())
{
XMLEvent xmlEvent = xmlReader.nextEvent();
if (isStartOfHeader(xmlEvent))
{
while (xmlReader.hasNext())
{
xmlEvent = xmlReader.nextEvent();
if (isStartOfBinarySecurityToken(xmlEvent))
{
final StartElement bstElement = (StartElement) xmlEvent;
BinarySecurityToken bst = new BinarySecurityToken();
bst.setEncodingType(bstElement.getAttributeByName(encodingTypeQName).getValue());
bst.setValueType(bstElement.getAttributeByName(valueTypeQName).getValue());
final StringBuilder data = new StringBuilder();
while (xmlReader.hasNext())
{
final XMLEvent nextEvent = xmlReader.nextEvent();
if (nextEvent.isCharacters())
{
Characters characters = nextEvent.asCharacters();
data.append(characters.getData());
}
if (isEndOfBinarySecurityToken(nextEvent))
{
bst.setKey(data.toString());
return bst;
}
}
}
if (isEndOfHeader(xmlEvent))
return null;
}
}
if (isStartOfBody(xmlEvent))
return null;
}
}
catch (final XMLStreamException e)
{
throw new ExtractionException(e.getMessage(), e);
}
finally
{
close(xmlReader);
}
return null;
}
private boolean isStartOfBinarySecurityToken(final XMLEvent event)
{
return event.isStartElement() && ((StartElement) event).getName().equals(binarySecurityTokenQName);
}
private boolean isEndOfBinarySecurityToken(final XMLEvent event)
{
return event.isEndElement() && ((EndElement) event).getName().equals(binarySecurityTokenQName);
}
private static XMLInputFactory getXmlInputFactory()
{
final XMLInputFactory factory = XMLInputFactory.newInstance();
// set any properies here if required before returning.
return factory;
}
private void close(final XMLEventReader reader)
{
if (reader != null)
{
try
{
reader.close();
}
catch (final XMLStreamException ignore)
{
log.error("XMLStreamException caught while trying to close the XMLEventReader", ignore);
}
}
}
}