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 067 try { 068 SecurityContext s = authenticate(info.getUserName(), info.getPassword(), null); 069 context.setSecurityContext(s); 070 securityContexts.add(s); 071 } finally { 072 Thread.currentThread().setContextClassLoader(original); 073 } 074 } 075 super.addConnection(context, info); 076 } 077 078 @Override 079 public SecurityContext authenticate(String username, String password, X509Certificate[] certificates) throws SecurityException { 080 SecurityContext result = null; 081 JassCredentialCallbackHandler callback = new JassCredentialCallbackHandler(username, password); 082 try { 083 LoginContext lc = new LoginContext(jassConfiguration, callback); 084 lc.login(); 085 Subject subject = lc.getSubject(); 086 087 result = new JaasSecurityContext(username, subject); 088 } catch (Exception ex) { 089 throw new SecurityException("User name [" + username + "] or password is invalid.", ex); 090 } 091 092 return result; 093 } 094}