001: /*
002: * Copyright 2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.ws.soap.security.xwss;
018:
019: import java.io.InputStream;
020: import javax.security.auth.callback.CallbackHandler;
021: import javax.xml.soap.SOAPMessage;
022:
023: import com.sun.xml.wss.ProcessingContext;
024: import com.sun.xml.wss.XWSSProcessor;
025: import com.sun.xml.wss.XWSSProcessorFactory;
026: import com.sun.xml.wss.XWSSecurityException;
027: import org.springframework.beans.factory.InitializingBean;
028: import org.springframework.core.io.Resource;
029: import org.springframework.util.Assert;
030: import org.springframework.ws.soap.SoapMessage;
031: import org.springframework.ws.soap.saaj.SaajSoapMessage;
032: import org.springframework.ws.soap.security.AbstractWsSecurityInterceptor;
033: import org.springframework.ws.soap.security.WsSecurityValidationException;
034: import org.springframework.ws.soap.security.xwss.callback.CallbackHandlerChain;
035:
036: /**
037: * WS-Security endpoint interceptor that is based on Sun's XML and Web Services Security package (XWSS). This
038: * WS-Security implementation is part of the Java Web Services Developer Pack (Java WSDP).
039: * <p/>
040: * This interceptor needs a <code>CallbackHandler</code> to operate. This handler is used to retrieve certificates,
041: * private keys, validate user credentials, etc. Refer to the XWSS Javadoc to learn more about the specific
042: * <code>Callback</code>s fired by XWSS. You can also set multiple handlers, each of which will be used in turn.
043: * <p/>
044: * Additionally, you must define a XWSS policy file by setting <code>policyConfiguration</code> property. The format of
045: * the policy file is documented in the <a href="http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp529900">Java
046: * Web Services Tutorial</a>.
047: * <p/>
048: * <b>Note</b> that this interceptor depends on SAAJ, and thus requires <code>SaajSoapMessage</code>s to operate. This
049: * means that you must use a <code>SaajSoapMessageFactory</code> to create the SOAP messages.
050: *
051: * @author Arjen Poutsma
052: * @see #setCallbackHandler(javax.security.auth.callback.CallbackHandler)
053: * @see #setPolicyConfiguration(org.springframework.core.io.Resource)
054: * @see com.sun.xml.wss.impl.callback.XWSSCallback
055: * @see org.springframework.ws.soap.saaj.SaajSoapMessageFactory
056: * @see <a href="https://xwss.dev.java.net/">XWSS</a>
057: */
058: public class XwsSecurityInterceptor extends
059: AbstractWsSecurityInterceptor implements InitializingBean {
060:
061: private XWSSProcessor processor;
062:
063: private CallbackHandler callbackHandler;
064:
065: private Resource policyConfiguration;
066:
067: /**
068: * Sets the handler to resolve XWSS callbacks. Setting either this propery, or <code>callbackHandlers</code>, is
069: * required.
070: *
071: * @see com.sun.xml.wss.impl.callback.XWSSCallback
072: * @see #setCallbackHandlers(javax.security.auth.callback.CallbackHandler[])
073: */
074: public void setCallbackHandler(CallbackHandler callbackHandler) {
075: this .callbackHandler = callbackHandler;
076: }
077:
078: /**
079: * Sets the handlers to resolve XWSS callbacks. Setting either this propery, or <code>callbackHandlers</code>, is
080: * required.
081: *
082: * @see com.sun.xml.wss.impl.callback.XWSSCallback
083: * @see #setCallbackHandler(javax.security.auth.callback.CallbackHandler)
084: */
085: public void setCallbackHandlers(CallbackHandler[] callbackHandler) {
086: this .callbackHandler = new CallbackHandlerChain(callbackHandler);
087: }
088:
089: /**
090: * Sets the policy configuration to use for XWSS. Required.
091: */
092: public void setPolicyConfiguration(Resource policyConfiguration) {
093: this .policyConfiguration = policyConfiguration;
094: }
095:
096: public void afterPropertiesSet() throws Exception {
097: Assert.notNull(policyConfiguration,
098: "policyConfiguration is required");
099: Assert.isTrue(policyConfiguration.exists(),
100: "policyConfiguration [" + policyConfiguration
101: + "] does not exist");
102: Assert.notNull(callbackHandler, "callbackHandler is required");
103: XWSSProcessorFactory processorFactory = XWSSProcessorFactory
104: .newInstance();
105: InputStream is = null;
106: try {
107: if (logger.isInfoEnabled()) {
108: logger.info("Loading policy configuration from from '"
109: + policyConfiguration.getFilename() + "'");
110: }
111: is = policyConfiguration.getInputStream();
112: processor = processorFactory
113: .createProcessorForSecurityConfiguration(is,
114: callbackHandler);
115: } finally {
116: if (is != null) {
117: is.close();
118: }
119: }
120: }
121:
122: /**
123: * Secures the given SoapMessage message in accordance with the defined security policy.
124: *
125: * @param soapMessage the message to be secured
126: * @throws XwsSecuritySecurementException in case of errors
127: * @throws IllegalArgumentException when soapMessage is not a <code>SaajSoapMessage</code>
128: */
129: protected void secureMessage(SoapMessage soapMessage)
130: throws XwsSecuritySecurementException {
131: Assert
132: .isTrue(
133: soapMessage instanceof SaajSoapMessage,
134: "XwsSecurityInterceptor requires a SaajSoapMessage. "
135: + "Use a SaajSoapMessageFactory to create the SOAP messages.");
136: SaajSoapMessage saajSoapMessage = (SaajSoapMessage) soapMessage;
137: try {
138: ProcessingContext context = processor
139: .createProcessingContext(saajSoapMessage
140: .getSaajMessage());
141: SOAPMessage result = processor
142: .secureOutboundMessage(context);
143: saajSoapMessage.setSaajMessage(result);
144: } catch (XWSSecurityException ex) {
145: throw new XwsSecuritySecurementException(ex.getMessage(),
146: ex);
147: }
148: }
149:
150: /**
151: * Validates the given SoapMessage message in accordance with the defined security policy.
152: *
153: * @param soapMessage the message to be validated
154: * @throws XwsSecurityValidationException in case of errors
155: * @throws IllegalArgumentException when soapMessage is not a <code>SaajSoapMessage</code>
156: */
157: protected void validateMessage(SoapMessage soapMessage)
158: throws WsSecurityValidationException {
159: Assert
160: .isTrue(
161: soapMessage instanceof SaajSoapMessage,
162: "XwsSecurityInterceptor requires a SaajSoapMessage. "
163: + "Use a SaajSoapMessageFactory to create the SOAP messages.");
164: SaajSoapMessage saajSoapMessage = (SaajSoapMessage) soapMessage;
165: try {
166: ProcessingContext context = processor
167: .createProcessingContext(saajSoapMessage
168: .getSaajMessage());
169: SOAPMessage result = processor
170: .verifyInboundMessage(context);
171: saajSoapMessage.setSaajMessage(result);
172: } catch (XWSSecurityException ex) {
173: throw new XwsSecurityValidationException(ex.getMessage(),
174: ex);
175: }
176: }
177: }
|