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 */ 017package org.apache.activemq.security; 018 019import java.security.Principal; 020import java.security.cert.X509Certificate; 021import java.util.Set; 022 023import javax.security.auth.Subject; 024import javax.security.auth.login.LoginContext; 025 026import org.apache.activemq.broker.Broker; 027import org.apache.activemq.broker.ConnectionContext; 028import org.apache.activemq.command.ConnectionInfo; 029import org.apache.activemq.jaas.JassCredentialCallbackHandler; 030 031/** 032 * Logs a user in using JAAS. 033 * 034 * 035 */ 036public class JaasAuthenticationBroker extends AbstractAuthenticationBroker { 037 038 private final String jassConfiguration; 039 040 public JaasAuthenticationBroker(Broker next, String jassConfiguration) { 041 super(next); 042 this.jassConfiguration = jassConfiguration; 043 } 044 045 static class JaasSecurityContext extends SecurityContext { 046 047 private final Subject subject; 048 049 public JaasSecurityContext(String userName, Subject subject) { 050 super(userName); 051 this.subject = subject; 052 } 053 054 @Override 055 public Set<Principal> getPrincipals() { 056 return subject.getPrincipals(); 057 } 058 } 059 060 @Override 061 public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { 062 if (context.getSecurityContext() == null) { 063 // Set the TCCL since it seems JAAS needs it to find the login module classes. 064 ClassLoader original = Thread.currentThread().getContextClassLoader(); 065 Thread.currentThread().setContextClassLoader(JaasAuthenticationBroker.class.getClassLoader()); 066 SecurityContext securityContext = null; 067 try { 068 securityContext = authenticate(info.getUserName(), info.getPassword(), null); 069 context.setSecurityContext(securityContext); 070 securityContexts.add(securityContext); 071 super.addConnection(context, info); 072 } catch (Exception error) { 073 if (securityContext != null) { 074 securityContexts.remove(securityContext); 075 } 076 context.setSecurityContext(null); 077 throw error; 078 } finally { 079 Thread.currentThread().setContextClassLoader(original); 080 } 081 } else { 082 super.addConnection(context, info); 083 } 084 } 085 086 @Override 087 public SecurityContext authenticate(String username, String password, X509Certificate[] certificates) throws SecurityException { 088 SecurityContext result = null; 089 JassCredentialCallbackHandler callback = new JassCredentialCallbackHandler(username, password); 090 try { 091 LoginContext lc = new LoginContext(jassConfiguration, callback); 092 lc.login(); 093 Subject subject = lc.getSubject(); 094 095 result = new JaasSecurityContext(username, subject); 096 } catch (Exception ex) { 097 throw new SecurityException("User name [" + username + "] or password is invalid.", ex); 098 } 099 100 return result; 101 } 102}