001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.servicemix.cxfbc.interceptors;
018    
019    import java.security.GeneralSecurityException;
020    import java.security.cert.X509Certificate;
021    import java.util.Iterator;
022    import java.util.List;
023    import java.util.Vector;
024    
025    import javax.security.auth.Subject;
026    
027    import org.apache.cxf.binding.soap.SoapMessage;
028    import org.apache.cxf.interceptor.Fault;
029    import org.apache.cxf.phase.Phase;
030    import org.apache.cxf.ws.security.wss4j.AbstractWSS4JInterceptor;
031    import org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JInInterceptor;
032    import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
033    import org.apache.servicemix.common.security.AuthenticationService;
034    import org.apache.ws.security.WSSecurityEngineResult;
035    import org.apache.ws.security.WSUsernameTokenPrincipal;
036    import org.apache.ws.security.handler.WSHandlerConstants;
037    import org.apache.ws.security.handler.WSHandlerResult;
038    
039    
040    public class JbiJAASInterceptor extends AbstractWSS4JInterceptor {
041    
042        private String domain = "servicemix-domain";
043        private AuthenticationService authenticationService;
044        private ThreadLocal<Subject> currentSubject = new ThreadLocal<Subject>();
045        private boolean x509;
046        private boolean delegateToJaas;
047        
048        
049        public JbiJAASInterceptor(AuthenticationService authenticationService, boolean x509, boolean delegateToJaas) {
050            super();
051            setPhase(Phase.PRE_PROTOCOL);
052            getAfter().add(WSS4JInInterceptor.class.getName());
053            getAfter().add(PolicyBasedWSS4JInInterceptor.class.getName());
054            this.authenticationService = authenticationService;
055            this.x509 = x509;
056            this.delegateToJaas = delegateToJaas;
057        }
058        
059        
060        public void handleMessage(SoapMessage message) throws Fault {
061         
062            try {
063                if (!delegateToJaas) {
064                    return;
065                }
066                Subject subject = (Subject) currentSubject.get();
067                
068                if (subject == null) {
069                    subject = new Subject();
070                    currentSubject.set(subject);
071                }
072                List<Object> results = (Vector<Object>)message.get(WSHandlerConstants.RECV_RESULTS);
073                if (results == null) {
074                    return;
075                }
076                for (Iterator iter = results.iterator(); iter.hasNext();) {
077                    WSHandlerResult hr = (WSHandlerResult) iter.next();
078                    if (hr == null || hr.getResults() == null) {
079                        return;
080                    }
081                    boolean authenticated = false;
082                    
083                    //favor WSSE UsernameToken based authentication over X.509 certificate
084                    //based authentication. For that purpose we iterate twice over the 
085                    //WSHandler result list
086                    for (Iterator it = hr.getResults().iterator(); it.hasNext();) {
087                        WSSecurityEngineResult er = (WSSecurityEngineResult) it.next();
088                            
089                        if (er != null && er.getPrincipal() instanceof WSUsernameTokenPrincipal) {
090                            WSUsernameTokenPrincipal p = (WSUsernameTokenPrincipal)er.getPrincipal();
091                            subject.getPrincipals().add(p);
092                            this.authenticationService.authenticate(subject, domain, p.getName(), p.getPassword());
093                            authenticated = true;
094                        }
095                    }
096                    
097                    //Second iteration checking for X.509 certificate to run authentication on
098                    //but only if not already authenticated on WSSE UsernameToken
099                    if (!authenticated && x509) {
100                            for (Iterator it = hr.getResults().iterator(); it.hasNext();) {
101                              WSSecurityEngineResult er = (WSSecurityEngineResult) it.next();
102            
103                                if (er != null && er.getCertificate() instanceof X509Certificate) {
104                                  X509Certificate cert = er.getCertificate();
105                                  this.authenticationService.authenticate(subject, domain, cert.getIssuerX500Principal().getName(), cert);
106                              }
107                            }
108                    }
109                }
110                
111                message.put(Subject.class, subject);
112            } catch (GeneralSecurityException e) {
113                throw new Fault(e);
114            } catch (java.lang.reflect.UndeclaredThrowableException e) {
115                java.lang.Throwable undeclared = e.getUndeclaredThrowable();
116                if (undeclared != null
117                        && undeclared instanceof java.lang.reflect.InvocationTargetException) {
118                    throw new Fault(
119                            ((java.lang.reflect.InvocationTargetException) undeclared)
120                                    .getTargetException());
121                }
122    
123            } finally {
124                currentSubject.set(null);
125            }
126        }
127    
128    }