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.callback.acegi;
018:
019: import java.io.IOException;
020: import java.security.cert.X509Certificate;
021:
022: import javax.security.auth.callback.Callback;
023: import javax.security.auth.callback.UnsupportedCallbackException;
024:
025: import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
026: import org.acegisecurity.Authentication;
027: import org.acegisecurity.AuthenticationException;
028: import org.acegisecurity.AuthenticationManager;
029: import org.acegisecurity.context.SecurityContextHolder;
030: import org.acegisecurity.providers.x509.X509AuthenticationToken;
031:
032: import org.springframework.util.Assert;
033: import org.springframework.ws.soap.security.xwss.callback.AbstractCallbackHandler;
034:
035: /**
036: * Callback handler that validates a certificate using an Acegi <code>AuthenticationManager</code>. Logic based on
037: * Acegi's <code>X509ProcessingFilter</code>.
038: * <p/>
039: * An Acegi <code>X509AuthenticationToken</code> is created with the certificate as the credentials.
040: * <p/>
041: * The configured authentication manager is expected to supply a provider which can handle this token (usually an
042: * instance of <code>X509AuthenticationProvider</code>).</p>
043: * <p/>
044: * This class only handles <code>CertificateValidationCallback</code>s, and throws an
045: * <code>UnsupportedCallbackException</code> for others.
046: *
047: * @author Arjen Poutsma
048: * @see X509AuthenticationToken
049: * @see org.acegisecurity.providers.x509.X509AuthenticationProvider
050: * @see org.acegisecurity.ui.x509.X509ProcessingFilter
051: * @see CertificateValidationCallback
052: */
053: public class AcegiCertificateValidationCallbackHandler extends
054: AbstractCallbackHandler {
055:
056: private AuthenticationManager authenticationManager;
057:
058: private boolean ignoreFailure = false;
059:
060: /**
061: * Sets the Acegi authentication manager. Required.
062: */
063: public void setAuthenticationManager(
064: AuthenticationManager authenticationManager) {
065: this .authenticationManager = authenticationManager;
066: }
067:
068: public void setIgnoreFailure(boolean ignoreFailure) {
069: this .ignoreFailure = ignoreFailure;
070: }
071:
072: public void afterPropertiesSet() throws Exception {
073: Assert.notNull(authenticationManager,
074: "authenticationManager is required");
075: }
076:
077: /**
078: * Handles <code>CertificateValidationCallback</code>s, and throws an <code>UnsupportedCallbackException</code> for
079: * others
080: *
081: * @throws UnsupportedCallbackException when the callback is not supported
082: */
083: protected void handleInternal(Callback callback)
084: throws IOException, UnsupportedCallbackException {
085: if (callback instanceof CertificateValidationCallback) {
086: ((CertificateValidationCallback) callback)
087: .setValidator(new AcegiCertificateValidator());
088: } else {
089: throw new UnsupportedCallbackException(callback);
090: }
091: }
092:
093: private class AcegiCertificateValidator implements
094: CertificateValidationCallback.CertificateValidator {
095:
096: public boolean validate(X509Certificate certificate)
097: throws CertificateValidationCallback.CertificateValidationException {
098: boolean result;
099: try {
100: Authentication authResult = authenticationManager
101: .authenticate(new X509AuthenticationToken(
102: certificate));
103: if (logger.isDebugEnabled()) {
104: logger
105: .debug("Authentication request for certificate with DN ["
106: + certificate
107: .getSubjectX500Principal()
108: .getName() + "] successful");
109: }
110: SecurityContextHolder.getContext().setAuthentication(
111: authResult);
112: return true;
113: } catch (AuthenticationException failed) {
114: if (logger.isDebugEnabled()) {
115: logger
116: .debug("Authentication request for certificate with DN ["
117: + certificate
118: .getSubjectX500Principal()
119: .getName()
120: + "] failed: "
121: + failed.toString());
122: }
123: SecurityContextHolder.getContext().setAuthentication(
124: null);
125: result = ignoreFailure;
126: }
127: return result;
128: }
129: }
130: }
|