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;
018:
019: import java.util.Locale;
020: import javax.xml.namespace.QName;
021:
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024: import org.springframework.util.Assert;
025: import org.springframework.ws.context.MessageContext;
026: import org.springframework.ws.soap.SoapBody;
027: import org.springframework.ws.soap.SoapHeaderElement;
028: import org.springframework.ws.soap.SoapMessage;
029: import org.springframework.ws.soap.server.SoapEndpointInterceptor;
030:
031: /**
032: * Interceptor base class for interceptors that handle WS-Security.
033: * <p/>
034: * Subclasses of this base class can be configured to validate incoming and secure outgoing messages. By default, both
035: * are on.
036: *
037: * @author Arjen Poutsma
038: */
039: public abstract class AbstractWsSecurityInterceptor implements
040: SoapEndpointInterceptor {
041:
042: private static final QName WS_SECURITY_NAME = new QName(
043: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
044: "Security");
045:
046: /** Logger available to subclasses. */
047: protected final Log logger = LogFactory.getLog(getClass());
048:
049: private boolean secureResponse = true;
050:
051: private boolean validateRequest = true;
052:
053: /** Indicates whether outgoing responsed are to be secured. Defaults to <code>true</code>. */
054: public void setSecureResponse(boolean secureResponse) {
055: this .secureResponse = secureResponse;
056: }
057:
058: /** Indicates whether incoming request are to be validated. Defaults to <code>true</code>. */
059: public void setValidateRequest(boolean validateRequest) {
060: this .validateRequest = validateRequest;
061: }
062:
063: public final boolean handleRequest(MessageContext messageContext,
064: Object endpoint) throws Exception {
065: if (validateRequest) {
066: Assert
067: .isTrue(
068: messageContext.getRequest() instanceof SoapMessage,
069: "WsSecurityInterceptor requires a SoapMessage request");
070: try {
071: validateMessage((SoapMessage) messageContext
072: .getRequest());
073: return true;
074: } catch (WsSecurityValidationException ex) {
075: return handleValidationException(ex, messageContext);
076: }
077: } else {
078: return true;
079: }
080: }
081:
082: public final boolean handleResponse(MessageContext messageContext,
083: Object endpoint) throws Exception {
084: if (secureResponse) {
085: Assert
086: .isTrue(
087: messageContext.getResponse() instanceof SoapMessage,
088: "WsSecurityInterceptor requires a SoapMessage response");
089: try {
090: secureMessage((SoapMessage) messageContext
091: .getResponse());
092: return true;
093: } catch (WsSecuritySecurementException ex) {
094: return handleSecurementException(ex, messageContext);
095: }
096: } else {
097: return true;
098: }
099: }
100:
101: /** Returns <code>true</code>, i.e. faults are not secured. */
102: public boolean handleFault(MessageContext messageContext,
103: Object endpoint) throws Exception {
104: return true;
105: }
106:
107: public boolean understands(SoapHeaderElement headerElement) {
108: return WS_SECURITY_NAME.equals(headerElement.getName());
109: }
110:
111: /**
112: * Handles an securement exception. Default implementation logs the given exception, and returns
113: * <code>false</code>.
114: *
115: * @param ex the validation exception
116: * @param messageContext the message context
117: * @return <code>true</code> to continue processing the message, <code>false</code> (the default) otherwise
118: */
119: protected boolean handleSecurementException(
120: WsSecuritySecurementException ex,
121: MessageContext messageContext) {
122: if (logger.isErrorEnabled()) {
123: logger.error("Could not secure response: "
124: + ex.getMessage(), ex);
125: }
126: return false;
127: }
128:
129: /**
130: * Handles an invalid SOAP message. Default implementation logs the given exception, and creates a SOAP 1.1 Client
131: * or SOAP 1.2 Sender Fault with the exception message as fault string, and returns <code>false</code>.
132: *
133: * @param ex the validation exception
134: * @param messageContext the message context
135: * @return <code>true</code> to continue processing the message, <code>false</code> (the default) otherwise
136: */
137: protected boolean handleValidationException(
138: WsSecurityValidationException ex,
139: MessageContext messageContext) {
140: if (logger.isWarnEnabled()) {
141: logger.warn("Could not validate request: "
142: + ex.getMessage());
143: }
144: SoapBody response = ((SoapMessage) messageContext.getResponse())
145: .getSoapBody();
146: response
147: .addClientOrSenderFault(ex.getMessage(), Locale.ENGLISH);
148: return false;
149: }
150:
151: /**
152: * Abstract template method. Subclasses are required to validate the request contained in the given {@link
153: * SoapMessage}, and replace the original request with the validated version.
154: *
155: * @param soapMessage the soap message to validate
156: * @throws WsSecurityValidationException in case of validation errors
157: */
158: protected abstract void validateMessage(SoapMessage soapMessage)
159: throws WsSecurityValidationException;
160:
161: /**
162: * Abstract template method. Subclasses are required to secure the response contained in the given {@link
163: * SoapMessage}, and replace the original response with the secured version.
164: *
165: * @param soapMessage the soap message to secure
166: * @throws WsSecuritySecurementException in case of securement errors
167: */
168: protected abstract void secureMessage(SoapMessage soapMessage)
169: throws WsSecuritySecurementException;
170: }
|