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.WSS4JInInterceptor;
032    import org.apache.servicemix.jbi.security.auth.AuthenticationService;
033    import org.apache.ws.security.WSSecurityEngineResult;
034    import org.apache.ws.security.WSUsernameTokenPrincipal;
035    import org.apache.ws.security.handler.WSHandlerConstants;
036    import org.apache.ws.security.handler.WSHandlerResult;
037    
038    public class JbiJAASInterceptor extends AbstractWSS4JInterceptor {
039    
040        private String domain = "servicemix-domain";
041        private AuthenticationService authenticationService;
042        private ThreadLocal<Subject> currentSubject = new ThreadLocal<Subject>();
043        private boolean x509;
044        
045        
046        public JbiJAASInterceptor(AuthenticationService authenticationService, boolean x509) {
047            super();
048            setPhase(Phase.PRE_PROTOCOL);
049            getAfter().add(WSS4JInInterceptor.class.getName());
050            this.authenticationService = authenticationService;
051            this.x509 = x509;
052        }
053        
054        
055        public void handleMessage(SoapMessage message) throws Fault {
056         
057            try {
058                
059                Subject subject = (Subject) currentSubject.get();
060                
061                if (subject == null) {
062                    subject = new Subject();
063                    currentSubject.set(subject);
064                }
065                List<Object> results = (Vector<Object>)message.get(WSHandlerConstants.RECV_RESULTS);
066                if (results == null) {
067                    return;
068                }
069                
070                for (Iterator iter = results.iterator(); iter.hasNext();) {
071                    WSHandlerResult hr = (WSHandlerResult) iter.next();
072                    if (hr == null || hr.getResults() == null) {
073                        return;
074                    }
075                    boolean authenticated = false;
076                    //favor WSSE UsernameToken based authentication over X.509 certificate
077                    //based authentication. For that purpose we iterate twice over the
078                    //WSHandler result list
079    
080                    for (Iterator it = hr.getResults().iterator(); it.hasNext();) {
081                        WSSecurityEngineResult er = (WSSecurityEngineResult) it.next();
082                            
083                        if (er != null && er.getPrincipal() instanceof WSUsernameTokenPrincipal) {
084                            WSUsernameTokenPrincipal p = (WSUsernameTokenPrincipal)er.getPrincipal();
085                            subject.getPrincipals().add(p);
086                            this.authenticationService.authenticate(subject, domain, p.getName(), p.getPassword());
087                            authenticated = true;
088                        }
089                    }
090                    //Second iteration checking for X.509 certificate to run authentication on
091                    //but only if not already authenticated on WSSE UsernameToken
092                    if (!authenticated && x509) {
093                        for (Iterator it = hr.getResults().iterator(); it.hasNext();) {
094                            WSSecurityEngineResult er = (WSSecurityEngineResult) it.next();
095                            if (er != null && er.getCertificate() instanceof X509Certificate) {
096                                X509Certificate cert = er.getCertificate();
097                                this.authenticationService.authenticate(subject, domain, cert.getIssuerX500Principal().getName(), cert);
098                            }
099                        }
100                    }
101    
102                }
103                
104                message.put(Subject.class, subject);
105            } catch (GeneralSecurityException e) {
106                throw new Fault(e);
107            } finally {
108                currentSubject.set(null);
109            }
110        }
111    
112    }