Author: alessio.soldano(a)jboss.com
Date: 2008-03-05 19:29:13 -0500 (Wed, 05 Mar 2008)
New Revision: 5883
Added:
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/MessageContextConfigSelector.java
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/WSSecurityAPI.java
Modified:
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/WSSecurityDispatcher.java
Log:
[JBWS-2022] Refactoring to provide a WSSecurity API (WIP)
Added:
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/MessageContextConfigSelector.java
===================================================================
---
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/MessageContextConfigSelector.java
(rev 0)
+++
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/MessageContextConfigSelector.java 2008-03-06
00:29:13 UTC (rev 5883)
@@ -0,0 +1,182 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * 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.ws.extensions.security;
+
+//$Id$
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPException;
+import javax.xml.ws.WebServiceException;
+
+import org.jboss.logging.Logger;
+import org.jboss.ws.WSException;
+import org.jboss.ws.core.CommonMessageContext;
+import org.jboss.ws.core.soap.SOAPMessageImpl;
+import org.jboss.ws.metadata.umdm.EndpointMetaData;
+import org.jboss.ws.metadata.umdm.OperationMetaData;
+import org.jboss.ws.metadata.wsse.Config;
+import org.jboss.ws.metadata.wsse.Encrypt;
+import org.jboss.ws.metadata.wsse.Operation;
+import org.jboss.ws.metadata.wsse.Port;
+import org.jboss.ws.metadata.wsse.Requires;
+import org.jboss.ws.metadata.wsse.Sign;
+import org.jboss.ws.metadata.wsse.Timestamp;
+import org.jboss.ws.metadata.wsse.Username;
+import org.jboss.ws.metadata.wsse.WSSecurityConfiguration;
+
+/**
+ * A Config whose attributes are derived from the specified message context.
+ * This is useful to provide the WSSecurityDispatcher with the right config
+ * according to the operation/port the current message is related to.
+ *
+ * @author alessio.soldano(a)jboss.com
+ * @since 06-Mar-2008
+ */
+public class MessageContextConfigSelector extends Config
+{
+ private static Logger log = Logger.getLogger(MessageContextConfigSelector.class);
+ private CommonMessageContext ctx;
+ private WSSecurityConfiguration configuration;
+ private Config config;
+ private QName opName;
+
+ public MessageContextConfigSelector(CommonMessageContext ctx)
+ {
+ this.ctx = ctx;
+ this.configuration =
ctx.getEndpointMetaData().getServiceMetaData().getSecurityConfiguration();
+ if (configuration == null)
+ throw new WSException("Cannot obtain security configuration from message
context");
+ this.config = new Config(); //empty config, no wsse requirements / processing
+ }
+
+ public Encrypt getEncrypt()
+ {
+ readConfig();
+ return config.getEncrypt();
+ }
+
+ public Requires getRequires()
+ {
+ readConfig();
+ return config.getRequires();
+ }
+
+ public Sign getSign()
+ {
+ readConfig();
+ return config.getSign();
+ }
+
+ public Timestamp getTimestamp()
+ {
+ readConfig();
+ return config.getTimestamp();
+ }
+
+ public Username getUsername()
+ {
+ readConfig();
+ return config.getUsername();
+ }
+
+ /**
+ * Gets the operation & port the current message is headed to and
+ * use them to get the right config to use.
+ *
+ */
+ private void readConfig()
+ {
+ //once the operation name is known the specific config
+ //is not going to change
+ if (opName == null)
+ {
+ EndpointMetaData epMetaData = ctx.getEndpointMetaData();
+ QName port = epMetaData.getPortName();
+
+ OperationMetaData opMetaData = ctx.getOperationMetaData();
+ if (opMetaData == null)
+ {
+ // Get the operation meta data from the soap message
+ // for the server side inbound message.
+ SOAPMessageImpl soapMessage = (SOAPMessageImpl)ctx.getSOAPMessage();
+ try
+ {
+ opMetaData = soapMessage.getOperationMetaData(epMetaData);
+ }
+ catch (SOAPException e)
+ {
+ throw new WebServiceException("Error while looking for the operation
meta data: " + e);
+ }
+ }
+ if (opMetaData != null)
+ opName = opMetaData.getQName();
+
+ Config opConfig = getConfig(port, opName);
+ log.debug("WS-Security config: " + opConfig);
+ if (opConfig != null)
+ this.config = opConfig;
+ }
+ }
+
+ private Config getConfig(QName portName, QName opName)
+ {
+ Port port = configuration.getPorts().get(portName != null ? portName.getLocalPart()
: null);
+ if (port == null)
+ return configuration.getDefaultConfig();
+
+ Operation operation = port.getOperations().get(opName != null ? opName.toString() :
null);
+ if (operation == null)
+ {
+ //if the operation name was not available or didn't match any wsse
configured operation,
+ //we fall back to the port wsse config (if available) or the default config.
+ Config portConfig = port.getDefaultConfig();
+ return (portConfig == null) ? configuration.getDefaultConfig() : portConfig;
+
+ }
+ return operation.getConfig();
+ }
+
+ public void setEncrypt(Encrypt encrypt)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSign(Sign sign)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setTimestamp(Timestamp timestamp)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setUsername(Username username)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setRequires(Requires requires)
+ {
+ throw new UnsupportedOperationException();
+ }
+}
Property changes on:
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/MessageContextConfigSelector.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added:
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/WSSecurityAPI.java
===================================================================
--- stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/WSSecurityAPI.java
(rev 0)
+++
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/WSSecurityAPI.java 2008-03-06
00:29:13 UTC (rev 5883)
@@ -0,0 +1,69 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * 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.ws.extensions.security;
+
+//$Id$
+
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPMessage;
+
+import org.jboss.ws.metadata.wsse.Config;
+import org.jboss.ws.metadata.wsse.WSSecurityConfiguration;
+
+public interface WSSecurityAPI
+{
+ /**
+ * Decodes a message using the specified configuration. This includes
+ * unencrypt, signature verification, etc. according to the requirements.
+ *
+ * @param configuration
+ * The WSSecurityConfiguration to use
+ * @param message
+ * The message that needs to be handled
+ * @param operationConfig
+ * The config object defining the operation (requirement checks)
+ * that should be performed on this message; overrides the default
+ * config contained in the provided WSSecurityConfiguration.
+ * @throws SOAPException
+ */
+ public void decodeMessage(WSSecurityConfiguration configuration, SOAPMessage message,
Config operationConfig) throws SOAPException;
+
+ /**
+ * Encodes a message using the specified configuration. This includes
+ * encrypt, signature, username profile, etc. according to the config.
+ *
+ * @param configuration
+ * The WSSecurityConfiguration to use
+ * @param message
+ * The message that needs to be handled
+ * @param operationConfig
+ * The config object defining the operation that should be
+ * performed on this message; overrides the default config
+ * contained in the provided WSSecurityConfiguration.
+ * @param user
+ * The username to use if Username Token is needed.
+ * @param password
+ * The password to use if Username Token is needed.
+ * @throws SOAPException
+ */
+ public void encodeMessage(WSSecurityConfiguration configuration, SOAPMessage message,
Config operationConfig, String user, String password) throws SOAPException;
+}
Property changes on:
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/WSSecurityAPI.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified:
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/WSSecurityDispatcher.java
===================================================================
---
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/WSSecurityDispatcher.java 2008-03-03
17:47:41 UTC (rev 5882)
+++
stack/native/trunk/src/main/java/org/jboss/ws/extensions/security/WSSecurityDispatcher.java 2008-03-06
00:29:13 UTC (rev 5883)
@@ -31,22 +31,18 @@
import javax.xml.rpc.soap.SOAPFaultException;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
+import javax.xml.soap.SOAPMessage;
import javax.xml.ws.BindingProvider;
import org.jboss.logging.Logger;
import org.jboss.ws.WSException;
import org.jboss.ws.core.CommonMessageContext;
import org.jboss.ws.core.CommonSOAPFaultException;
-import org.jboss.ws.core.StubExt;
import org.jboss.ws.core.soap.SOAPMessageImpl;
import org.jboss.ws.extensions.security.exception.InvalidSecurityHeaderException;
import org.jboss.ws.extensions.security.exception.WSSecurityException;
-import org.jboss.ws.metadata.umdm.EndpointMetaData;
-import org.jboss.ws.metadata.umdm.OperationMetaData;
import org.jboss.ws.metadata.wsse.Config;
import org.jboss.ws.metadata.wsse.Encrypt;
-import org.jboss.ws.metadata.wsse.Operation;
-import org.jboss.ws.metadata.wsse.Port;
import org.jboss.ws.metadata.wsse.RequireEncryption;
import org.jboss.ws.metadata.wsse.RequireSignature;
import org.jboss.ws.metadata.wsse.RequireTimestamp;
@@ -57,7 +53,7 @@
import org.jboss.wsf.common.DOMWriter;
import org.w3c.dom.Element;
-public class WSSecurityDispatcher
+public class WSSecurityDispatcher implements WSSecurityAPI
{
// provide logging
private static Logger log = Logger.getLogger(WSSecurityDispatcher.class);
@@ -85,23 +81,6 @@
return newList;
}
- private static Config getConfig(WSSecurityConfiguration config, String portName,
String opName)
- {
- Port port = config.getPorts().get(portName);
- if (port == null)
- return config.getDefaultConfig();
-
- Operation operation = port.getOperations().get(opName);
- if (operation == null)
- {
- Config portConfig = port.getDefaultConfig();
- return (portConfig == null) ? config.getDefaultConfig() : portConfig;
-
- }
-
- return operation.getConfig();
- }
-
private static CommonSOAPFaultException convertToFault(WSSecurityException e)
{
return new CommonSOAPFaultException(e.getFaultCode(), e.getFaultString());
@@ -109,75 +88,10 @@
public static void handleInbound(CommonMessageContext ctx) throws SOAPException,
SOAPFaultException
{
- WSSecurityConfiguration config = getSecurityConfig(ctx);
+ WSSecurityConfiguration configuration = getSecurityConfig(ctx);
SOAPMessageImpl soapMessage = (SOAPMessageImpl)ctx.getSOAPMessage();
-
- SOAPHeader soapHeader = soapMessage.getSOAPHeader();
- QName secQName = new QName(Constants.WSSE_NS, "Security");
- Element secHeaderElement = (soapHeader != null) ? Util.findElement(soapHeader,
secQName) : null;
-
- if (secHeaderElement == null)
- {
- // This is ok, we always allow faults to be received because WS-Security does
not encrypt faults
- if (soapMessage.getSOAPBody().getFault() != null)
- return;
-
- OperationMetaData opMetaData = ctx.getOperationMetaData();
- if (opMetaData == null)
- {
- // Get the operation meta data from the soap message
- // for the server side inbound message.
- EndpointMetaData epMetaData = ctx.getEndpointMetaData();
- opMetaData = soapMessage.getOperationMetaData(epMetaData);
- }
-
- String operation = opMetaData.getQName().toString();
- String port = opMetaData.getEndpointMetaData().getPortName().getLocalPart();
-
- if (hasRequirements(config, operation, port))
- throw convertToFault(new InvalidSecurityHeaderException("This service
requires <wsse:Security>, which is missing."));
-
- return;
- }
-
- try
- {
- SecurityStore securityStore = new SecurityStore(config.getKeyStoreURL(),
config.getKeyStoreType(), config.getKeyStorePassword(), config.getKeyPasswords(),
config.getTrustStoreURL(),
- config.getTrustStoreType(), config.getTrustStorePassword());
- SecurityDecoder decoder = new SecurityDecoder(securityStore);
-
- decoder.decode(soapMessage.getSOAPPart(), secHeaderElement);
-
- if (log.isTraceEnabled())
- log.trace("Decoded Message:\n" +
DOMWriter.printNode(soapMessage.getSOAPPart(), true));
-
- OperationMetaData opMetaData = ctx.getOperationMetaData();
- if (opMetaData == null)
- {
- // Get the operation meta data from the soap message
- // for the server side inbound message.
- EndpointMetaData epMetaData = ctx.getEndpointMetaData();
- opMetaData = soapMessage.getOperationMetaData(epMetaData);
- }
-
- String operation = opMetaData.getQName().toString();
- String port = opMetaData.getEndpointMetaData().getPortName().getLocalPart();
-
- List<OperationDescription<RequireOperation>> operations =
buildRequireOperations(config, operation, port);
-
- decoder.verify(operations);
- if(log.isDebugEnabled()) log.debug("Verification is successful");
-
- decoder.complete();
- }
- catch (WSSecurityException e)
- {
- if (e.isInternalError())
- log.error("Internal error occured handling inbound message:", e);
- else if(log.isDebugEnabled()) log.debug("Returning error to sender: "
+ e.getMessage());
-
- throw convertToFault(e);
- }
+
+ new WSSecurityDispatcher().decodeMessage(configuration, soapMessage, new
MessageContextConfigSelector(ctx)); //TODO!!!
}
private static WSSecurityConfiguration getSecurityConfig(CommonMessageContext ctx)
@@ -189,18 +103,11 @@
return config;
}
- private static boolean hasRequirements(WSSecurityConfiguration config, String
operation, String port)
+ private static List<OperationDescription<RequireOperation>>
buildRequireOperations(Config operationConfig)
{
- Config operationConfig = getConfig(config, port, operation);
- return (operationConfig != null && operationConfig.getRequires() != null);
- }
-
- private static List<OperationDescription<RequireOperation>>
buildRequireOperations(WSSecurityConfiguration config, String operation, String port)
- {
- Config operationConfig = getConfig(config, port, operation);
if (operationConfig == null)
return null;
-
+
Requires requires = operationConfig.getRequires();
if (requires == null)
return null;
@@ -229,50 +136,102 @@
public static void handleOutbound(CommonMessageContext ctx) throws SOAPException,
SOAPFaultException
{
- WSSecurityConfiguration config = getSecurityConfig(ctx);
+ WSSecurityConfiguration configuration = getSecurityConfig(ctx);
SOAPMessageImpl soapMessage = (SOAPMessageImpl)ctx.getSOAPMessage();
+
+ String user = (String)ctx.get(Stub.USERNAME_PROPERTY);
+ String pass = (String)ctx.get(Stub.PASSWORD_PROPERTY);
+
+ if (user == null && pass == null)
+ {
+ user = (String)ctx.get(BindingProvider.USERNAME_PROPERTY);
+ pass = (String)ctx.get(BindingProvider.PASSWORD_PROPERTY);
+ }
- EndpointMetaData epMetaData = ctx.getEndpointMetaData();
- String port = epMetaData.getPortName().getLocalPart();
+ new WSSecurityDispatcher().encodeMessage(configuration, soapMessage, new
MessageContextConfigSelector(ctx), user, pass); //TODO!!
+ }
+
+ private static Config getConfig(WSSecurityConfiguration configuration, Config
operationConfig)
+ {
+ //null operationConfig means default behavior
+ return operationConfig != null ? operationConfig :
configuration.getDefaultConfig();
+ }
+
+ private static boolean hasRequirements(Config config)
+ {
+ return config != null && config.getRequires() != null;
+ }
+
+ public void decodeMessage(WSSecurityConfiguration configuration, SOAPMessage message,
Config operationConfig) throws SOAPException
+ {
+ Config config = getConfig(configuration, operationConfig);
+ SOAPHeader soapHeader = message.getSOAPHeader();
+ QName secQName = new QName(Constants.WSSE_NS, "Security");
+ Element secHeaderElement = (soapHeader != null) ? Util.findElement(soapHeader,
secQName) : null;
+
+ if (secHeaderElement == null)
+ {
+ // This is ok, we always allow faults to be received because WS-Security does
not encrypt faults
+ if (message.getSOAPBody().getFault() != null)
+ return;
+
+ if (hasRequirements(config))
+ throw convertToFault(new InvalidSecurityHeaderException("This service
requires <wsse:Security>, which is missing."));
+
+ return;
+ }
+
+ try
+ {
+ SecurityStore securityStore = new SecurityStore(configuration.getKeyStoreURL(),
configuration.getKeyStoreType(), configuration.getKeyStorePassword(),
+ configuration.getKeyPasswords(), configuration.getTrustStoreURL(),
configuration.getTrustStoreType(), configuration.getTrustStorePassword());
+ SecurityDecoder decoder = new SecurityDecoder(securityStore);
+
+ decoder.decode(message.getSOAPPart(), secHeaderElement);
+
+ if (log.isTraceEnabled())
+ log.trace("Decoded Message:\n" +
DOMWriter.printNode(message.getSOAPPart(), true));
+
+ List<OperationDescription<RequireOperation>> operations =
buildRequireOperations(config);
+
+ decoder.verify(operations);
+ if(log.isDebugEnabled()) log.debug("Verification is successful");
+
+ decoder.complete();
+ }
+ catch (WSSecurityException e)
+ {
+ if (e.isInternalError())
+ log.error("Internal error occured handling inbound message:", e);
+ else if(log.isDebugEnabled()) log.debug("Returning error to sender: "
+ e.getMessage());
+
+ throw convertToFault(e);
+ }
- String opName = null;
- OperationMetaData opMetaData = ctx.getOperationMetaData();
- if (opMetaData != null)
- opName = opMetaData.getQName().toString();
+ }
- Config opConfig = getConfig(config, port, opName);
- log.debug("WS-Security config: " + opConfig);
+ public void encodeMessage(WSSecurityConfiguration configuration, SOAPMessage message,
Config operationConfig, String user, String password) throws SOAPException
+ {
+ Config config = getConfig(configuration, operationConfig);
+ log.debug("WS-Security config: " + config);
// Nothing to process
- if (opConfig == null)
+ if (config == null)
return;
ArrayList<OperationDescription<EncodingOperation>> operations = new
ArrayList<OperationDescription<EncodingOperation>>();
- Timestamp timestamp = opConfig.getTimestamp();
+ Timestamp timestamp = config.getTimestamp();
if (timestamp != null)
{
operations.add(new
OperationDescription<EncodingOperation>(TimestampOperation.class, null, null,
timestamp.getTtl(), null, null, null));
}
- if (opConfig.getUsername() != null)
+ if (config.getUsername() != null && user != null && password !=
null)
{
- Object user = ctx.get(Stub.USERNAME_PROPERTY);
- Object pass = ctx.get(Stub.PASSWORD_PROPERTY);
-
- if (user == null && pass == null)
- {
- user = ctx.get(BindingProvider.USERNAME_PROPERTY);
- pass = ctx.get(BindingProvider.PASSWORD_PROPERTY);
- }
-
- if (user != null && pass != null)
- {
- operations.add(new
OperationDescription<EncodingOperation>(SendUsernameOperation.class, null,
user.toString(), pass.toString(), null, null, null));
- ctx.put(StubExt.PROPERTY_AUTH_TYPE, StubExt.PROPERTY_AUTH_TYPE_WSSE);
- }
+ operations.add(new
OperationDescription<EncodingOperation>(SendUsernameOperation.class, null, user,
password, null, null, null));
}
- Sign sign = opConfig.getSign();
+ Sign sign = config.getSign();
if (sign != null)
{
List<Target> targets = convertTargets(sign.getTargets());
@@ -288,7 +247,7 @@
operations.add(new
OperationDescription<EncodingOperation>(SignatureOperation.class, targets,
sign.getAlias(), null, null, null, sign.getTokenRefType()));
}
- Encrypt encrypt = opConfig.getEncrypt();
+ Encrypt encrypt = config.getEncrypt();
if (encrypt != null)
{
List<Target> targets = convertTargets(encrypt.getTargets());
@@ -298,14 +257,14 @@
if (operations.size() == 0)
return;
- if(log.isDebugEnabled()) log.debug("Encoding Message:\n" +
DOMWriter.printNode(soapMessage.getSOAPPart(), true));
+ if(log.isDebugEnabled()) log.debug("Encoding Message:\n" +
DOMWriter.printNode(message.getSOAPPart(), true));
try
{
- SecurityStore securityStore = new SecurityStore(config.getKeyStoreURL(),
config.getKeyStoreType(), config.getKeyStorePassword(), config.getKeyPasswords() ,
config.getTrustStoreURL(),
- config.getTrustStoreType(), config.getTrustStorePassword());
+ SecurityStore securityStore = new SecurityStore(configuration.getKeyStoreURL(),
configuration.getKeyStoreType(), configuration.getKeyStorePassword(),
+ configuration.getKeyPasswords() , configuration.getTrustStoreURL(),
configuration.getTrustStoreType(), configuration.getTrustStorePassword());
SecurityEncoder encoder = new SecurityEncoder(operations, securityStore);
- encoder.encode(soapMessage.getSOAPPart());
+ encoder.encode(message.getSOAPPart());
}
catch (WSSecurityException e)
{
@@ -316,4 +275,5 @@
throw convertToFault(e);
}
}
+
}