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 }