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.shiro.subject; 018 019import org.apache.activemq.broker.ConnectionContext; 020import org.apache.activemq.command.ConnectionInfo; 021import org.apache.activemq.security.SecurityContext; 022import org.apache.activemq.shiro.ConnectionReference; 023import org.apache.activemq.shiro.DefaultSecurityContextFactory; 024import org.apache.activemq.shiro.SecurityContextFactory; 025import org.apache.activemq.shiro.env.EnvironmentFilter; 026import org.apache.shiro.subject.Subject; 027 028/** 029 * The {@code SubjectFilter} ensures a Shiro {@link Subject} representing the client's identity is associated with 030 * every connection to the ActiveMQ Broker. The {@code Subject} is made available to downstream broker filters so 031 * they may perform security checks as necessary. 032 * <p/> 033 * This implementation does not perform any security checks/assertions itself. It is expected that other broker filters 034 * will be configured after this one and those will perform any security behavior or checks as necessary. 035 * 036 * @since 5.10.0 037 */ 038public class SubjectFilter extends EnvironmentFilter { 039 040 private ConnectionSubjectFactory connectionSubjectFactory; 041 private SecurityContextFactory securityContextFactory; 042 043 public SubjectFilter() { 044 this.connectionSubjectFactory = new DefaultConnectionSubjectFactory(); 045 this.securityContextFactory = new DefaultSecurityContextFactory(); 046 } 047 048 public ConnectionSubjectFactory getConnectionSubjectFactory() { 049 return connectionSubjectFactory; 050 } 051 052 public void setConnectionSubjectFactory(ConnectionSubjectFactory connectionSubjectFactory) { 053 if (connectionSubjectFactory == null) { 054 throw new IllegalArgumentException("ConnectionSubjectFactory argument cannot be null."); 055 } 056 this.connectionSubjectFactory = connectionSubjectFactory; 057 } 058 059 public SecurityContextFactory getSecurityContextFactory() { 060 return this.securityContextFactory; 061 } 062 063 public void setSecurityContextFactory(SecurityContextFactory securityContextFactory) { 064 if (securityContextFactory == null) { 065 throw new IllegalArgumentException("SecurityContextFactory argument cannot be null."); 066 } 067 this.securityContextFactory = securityContextFactory; 068 } 069 070 protected Subject createSubject(ConnectionReference conn) { 071 return this.connectionSubjectFactory.createSubject(conn); 072 } 073 074 protected SecurityContext createSecurityContext(SubjectConnectionReference conn) { 075 return this.securityContextFactory.createSecurityContext(conn); 076 } 077 078 /** 079 * Creates a {@link Subject} instance reflecting the specified Connection. The {@code Subject} is then stored in 080 * a {@link SecurityContext} instance which is set as the Connection's 081 * {@link ConnectionContext#setSecurityContext(org.apache.activemq.security.SecurityContext) securityContext}. 082 * 083 * @param context state associated with the client's connection 084 * @param info info about the client's connection 085 * @throws Exception if there is a problem creating a Subject or {@code SecurityContext} instance. 086 */ 087 @Override 088 public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { 089 090 if (isEnabled()) { 091 092 SecurityContext secCtx = context.getSecurityContext(); 093 094 if (secCtx == null) { 095 ConnectionReference conn = new ConnectionReference(context, info, getEnvironment()); 096 Subject subject = createSubject(conn); 097 SubjectConnectionReference subjectConn = new SubjectConnectionReference(context, info, getEnvironment(), subject); 098 secCtx = createSecurityContext(subjectConn); 099 context.setSecurityContext(secCtx); 100 } 101 } 102 103 try { 104 super.addConnection(context, info); 105 } catch (Exception e) { 106 context.setSecurityContext(null); 107 throw e; 108 } 109 } 110 111 @Override 112 public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception { 113 try { 114 super.removeConnection(context, info, error); 115 } finally { 116 context.setSecurityContext(null); 117 } 118 } 119}