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.activemq.security; 018 019 import java.security.Principal; 020 import java.util.Iterator; 021 import java.util.Set; 022 import java.util.concurrent.CopyOnWriteArrayList; 023 024 import javax.security.auth.Subject; 025 import javax.security.auth.login.LoginContext; 026 027 import org.apache.activemq.broker.Broker; 028 import org.apache.activemq.broker.BrokerFilter; 029 import org.apache.activemq.broker.ConnectionContext; 030 import org.apache.activemq.command.ConnectionInfo; 031 import org.apache.activemq.jaas.JassCredentialCallbackHandler; 032 033 /** 034 * Logs a user in using JAAS. 035 * 036 * @version $Revision$ 037 */ 038 public class JaasAuthenticationBroker extends BrokerFilter { 039 040 private final String jassConfiguration; 041 private final CopyOnWriteArrayList<SecurityContext> securityContexts = new CopyOnWriteArrayList<SecurityContext>(); 042 043 public JaasAuthenticationBroker(Broker next, String jassConfiguration) { 044 super(next); 045 this.jassConfiguration = jassConfiguration; 046 } 047 048 static class JaasSecurityContext extends SecurityContext { 049 050 private final Subject subject; 051 052 public JaasSecurityContext(String userName, Subject subject) { 053 super(userName); 054 this.subject = subject; 055 } 056 057 public Set<Principal> getPrincipals() { 058 return subject.getPrincipals(); 059 } 060 061 } 062 063 public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { 064 065 if (context.getSecurityContext() == null) { 066 // Set the TCCL since it seems JAAS needs it to find the login 067 // module classes. 068 ClassLoader original = Thread.currentThread().getContextClassLoader(); 069 Thread.currentThread().setContextClassLoader(JaasAuthenticationBroker.class.getClassLoader()); 070 try { 071 // Do the login. 072 try { 073 JassCredentialCallbackHandler callback = new JassCredentialCallbackHandler(info 074 .getUserName(), info.getPassword()); 075 LoginContext lc = new LoginContext(jassConfiguration, callback); 076 lc.login(); 077 Subject subject = lc.getSubject(); 078 079 SecurityContext s = new JaasSecurityContext(info.getUserName(), subject); 080 context.setSecurityContext(s); 081 securityContexts.add(s); 082 } catch (Exception e) { 083 throw (SecurityException)new SecurityException("User name or password is invalid.") 084 .initCause(e); 085 } 086 } finally { 087 Thread.currentThread().setContextClassLoader(original); 088 } 089 } 090 super.addConnection(context, info); 091 } 092 093 public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) 094 throws Exception { 095 super.removeConnection(context, info, error); 096 if (securityContexts.remove(context.getSecurityContext())) { 097 context.setSecurityContext(null); 098 } 099 } 100 101 /** 102 * Previously logged in users may no longer have the same access anymore. 103 * Refresh all the logged into users. 104 */ 105 public void refresh() { 106 for (Iterator<SecurityContext> iter = securityContexts.iterator(); iter.hasNext();) { 107 SecurityContext sc = iter.next(); 108 sc.getAuthorizedReadDests().clear(); 109 sc.getAuthorizedWriteDests().clear(); 110 } 111 } 112 }