package com.bansheeproject.features; import java.io.IOException; import java.security.SecureRandom; import java.util.Date; import java.util.Iterator; import javax.xml.namespace.QName; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPMessage; import org.apache.commons.codec.binary.Base64; import org.w3c.dom.Node; import com.bansheeproject.SOAPInvocationData; import com.bansheeproject.WebServicesInvocationData; import com.bansheeproject.engine.InvocationContext; import com.bansheeproject.engine.soap.SOAPUtils; import com.bansheeproject.engine.soap.SOAPVersion; import com.bansheeproject.exceptions.InstallFeatureException; import com.bansheeproject.utils.DateTimeUtils; /** * Implements WS-Security username and password for WSDL-based services. * @author Alexandre Saudate * @since 1.0 */ public class WSSecurityUsernamePassword implements WSSecurityFeature{ private String userName; private String password; private PasswordType passwordType; private boolean mustUnderstand; private String elementId; private SOAPVersion version; public WSSecurityUsernamePassword(String userName, String password, SOAPVersion version) { this(userName, password, PasswordType.TEXT, version); } public WSSecurityUsernamePassword(String userName, String password, PasswordType passwordType, SOAPVersion version) { this (userName, password, passwordType, false, version); } public WSSecurityUsernamePassword(String userName, String password, PasswordType passwordType, boolean mustUnderstand, SOAPVersion version) { this(userName, password, passwordType, mustUnderstand, "UsernameToken-1", version); } public WSSecurityUsernamePassword(String userName, String password, PasswordType passwordType, boolean mustUnderstand, String elementId, SOAPVersion version) { this.userName = userName; this.password = password; this.passwordType = passwordType; this.mustUnderstand = mustUnderstand; this.elementId = elementId; this.version = version; } public void install(InvocationContext context) throws InstallFeatureException { try { WebServicesInvocationData webServicesInvocationData = context.getInvocationData(); if (!(webServicesInvocationData instanceof SOAPInvocationData)) { throw new InstallFeatureException("This feature can only be added to a SOAP environment."); } SOAPInvocationData soapInvocationData = (SOAPInvocationData)webServicesInvocationData; String stringMessage = context.getRequestData(); SOAPMessage message = SOAPUtils.buildMessage(stringMessage, version); SOAPElement securityElement = null; Iterator it = message.getSOAPHeader().getChildElements(WS_SECURITY_ELEMENT); if (it.hasNext()) { securityElement = (SOAPElement)it.next(); } else { securityElement = message.getSOAPHeader().addChildElement(WS_SECURITY_ELEMENT); } if (mustUnderstand) securityElement.addAttribute(new QName(soapInvocationData.getVersion().getNamespace(), "mustUnderstand"), soapInvocationData.getVersion().getMustUnderstandAttribute()); else securityElement.addAttribute(new QName(soapInvocationData.getVersion().getNamespace(), "mustUnderstand"), soapInvocationData.getVersion().getDoNotNeedToUnderstandAttribute()); if (securityElement.getChildElements(WS_USERNAME_TOKEN_ELEMENT).hasNext()) { Node child = (Node)securityElement.getChildElements(WS_USERNAME_TOKEN_ELEMENT).next(); securityElement.removeChild(child); } SOAPElement tokenElement = securityElement.addChildElement(WS_USERNAME_TOKEN_ELEMENT); tokenElement.addAttribute(new QName(WS_SECURITY_UTILITY_NAMESPACE, "Id"), elementId); SOAPElement userElement = tokenElement.addChildElement(new QName(WS_SECURITY_NAMESPACE, "Username", "wsse")); userElement.setTextContent(userName); SOAPElement passwordElement = tokenElement.addChildElement(new QName(WS_SECURITY_NAMESPACE, "Password", "wsse")); passwordElement.addAttribute(new QName("Type"), passwordType.getNamespace()); String nonce = getNonce(); String created = DateTimeUtils.getXMLTimestamp(new Date()); passwordElement.setValue(passwordType.encode(password, nonce, created)); SOAPElement nonceElement = tokenElement.addChildElement(new QName(WS_SECURITY_NAMESPACE, "Nonce", "wsse")); nonceElement.addAttribute(new QName("EncodingType"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"); nonceElement.setValue(new String(new Base64().encode(nonce.getBytes()))); SOAPElement createdElement = tokenElement.addChildElement(new QName(WS_SECURITY_UTILITY_NAMESPACE, "Created", "wsu")); createdElement.setValue(created); } catch (SOAPException ex) { throw new InstallFeatureException(ex); } catch (IOException e) { throw new InstallFeatureException(e); } } private String getNonce() { SecureRandom secureRandom = new SecureRandom(); byte[] seed = new byte[16]; secureRandom.nextBytes(seed); //Base64 base64 = new Base64(); //seed = base64.encode(seed); return new String(seed); } @Override public String toString() { return "WS-Security Username and Password Feature"; } }