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; 018 019import org.apache.activemq.ConfigurationException; 020import org.apache.activemq.broker.Broker; 021import org.apache.activemq.broker.BrokerPluginSupport; 022import org.apache.activemq.shiro.authc.AuthenticationFilter; 023import org.apache.activemq.shiro.authc.AuthenticationPolicy; 024import org.apache.activemq.shiro.authc.DefaultAuthenticationPolicy; 025import org.apache.activemq.shiro.authz.AuthorizationFilter; 026import org.apache.activemq.shiro.env.IniEnvironment; 027import org.apache.activemq.shiro.subject.ConnectionSubjectFactory; 028import org.apache.activemq.shiro.subject.DefaultConnectionSubjectFactory; 029import org.apache.activemq.shiro.subject.SubjectFilter; 030import org.apache.shiro.config.Ini; 031import org.apache.shiro.env.Environment; 032import org.apache.shiro.mgt.SecurityManager; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036/** 037 * @since 5.10.0 038 */ 039public class ShiroPlugin extends BrokerPluginSupport { 040 041 private static final Logger LOG = LoggerFactory.getLogger(ShiroPlugin.class); 042 043 private volatile boolean enabled = true; 044 045 private Broker broker; //the downstream broker after any/all Shiro-specific broker filters 046 047 private SecurityManager securityManager; 048 private Environment environment; 049 private IniEnvironment iniEnvironment; //only used if the above environment instance is not explicitly configured 050 051 private SubjectFilter subjectFilter; 052 053 private AuthenticationFilter authenticationFilter; 054 055 private AuthorizationFilter authorizationFilter; 056 057 public ShiroPlugin() { 058 059 //Default if this.environment is not configured. See the ensureEnvironment() method below. 060 iniEnvironment = new IniEnvironment(); 061 062 authorizationFilter = new AuthorizationFilter(); 063 064 // we want to share one AuthenticationPolicy instance across both the AuthenticationFilter and the 065 // ConnectionSubjectFactory: 066 AuthenticationPolicy authcPolicy = new DefaultAuthenticationPolicy(); 067 068 authenticationFilter = new AuthenticationFilter(); 069 authenticationFilter.setAuthenticationPolicy(authcPolicy); 070 authenticationFilter.setNext(authorizationFilter); 071 072 subjectFilter = new SubjectFilter(); 073 DefaultConnectionSubjectFactory subjectFactory = new DefaultConnectionSubjectFactory(); 074 subjectFactory.setAuthenticationPolicy(authcPolicy); 075 subjectFilter.setConnectionSubjectFactory(subjectFactory); 076 subjectFilter.setNext(authenticationFilter); 077 } 078 079 public SubjectFilter getSubjectFilter() { 080 return subjectFilter; 081 } 082 083 public void setSubjectFilter(SubjectFilter subjectFilter) { 084 this.subjectFilter = subjectFilter; 085 this.subjectFilter.setNext(this.authenticationFilter); 086 } 087 088 public AuthenticationFilter getAuthenticationFilter() { 089 return authenticationFilter; 090 } 091 092 public void setAuthenticationFilter(AuthenticationFilter authenticationFilter) { 093 this.authenticationFilter = authenticationFilter; 094 this.authenticationFilter.setNext(this.authorizationFilter); 095 this.subjectFilter.setNext(authenticationFilter); 096 } 097 098 public AuthorizationFilter getAuthorizationFilter() { 099 return authorizationFilter; 100 } 101 102 public void setAuthorizationFilter(AuthorizationFilter authorizationFilter) { 103 this.authorizationFilter = authorizationFilter; 104 this.authorizationFilter.setNext(this.broker); 105 this.authenticationFilter.setNext(authorizationFilter); 106 } 107 108 public void setEnabled(boolean enabled) { 109 this.enabled = enabled; 110 if (isInstalled()) { 111 //we're running, so apply the changes now: 112 applyEnabled(enabled); 113 } 114 } 115 116 public boolean isEnabled() { 117 if (isInstalled()) { 118 return getNext() == this.subjectFilter; 119 } 120 return enabled; 121 } 122 123 private void applyEnabled(boolean enabled) { 124 if (enabled) { 125 //ensure the SubjectFilter and downstream filters are used: 126 super.setNext(this.subjectFilter); 127 } else { 128 //Shiro is not enabled, restore the original downstream broker: 129 super.setNext(this.broker); 130 } 131 } 132 133 public Environment getEnvironment() { 134 return environment; 135 } 136 137 public void setEnvironment(Environment environment) { 138 this.environment = environment; 139 } 140 141 public SecurityManager getSecurityManager() { 142 return securityManager; 143 } 144 145 public void setSecurityManager(SecurityManager securityManager) { 146 this.securityManager = securityManager; 147 } 148 149 public void setIni(Ini ini) { 150 this.iniEnvironment.setIni(ini); 151 } 152 153 public void setIniConfig(String iniConfig) { 154 this.iniEnvironment.setIniConfig(iniConfig); 155 } 156 157 public void setIniResourcePath(String resourcePath) { 158 this.iniEnvironment.setIniResourcePath(resourcePath); 159 } 160 161 // =============================================================== 162 // Authentication Configuration 163 // =============================================================== 164 public void setAuthenticationEnabled(boolean authenticationEnabled) { 165 this.authenticationFilter.setEnabled(authenticationEnabled); 166 } 167 168 public boolean isAuthenticationEnabled() { 169 return this.authenticationFilter.isEnabled(); 170 } 171 172 public AuthenticationPolicy getAuthenticationPolicy() { 173 return authenticationFilter.getAuthenticationPolicy(); 174 } 175 176 public void setAuthenticationPolicy(AuthenticationPolicy authenticationPolicy) { 177 authenticationFilter.setAuthenticationPolicy(authenticationPolicy); 178 //also set it on the ConnectionSubjectFactory: 179 ConnectionSubjectFactory factory = subjectFilter.getConnectionSubjectFactory(); 180 if (factory instanceof DefaultConnectionSubjectFactory) { 181 ((DefaultConnectionSubjectFactory) factory).setAuthenticationPolicy(authenticationPolicy); 182 } 183 } 184 185 // =============================================================== 186 // Authorization Configuration 187 // =============================================================== 188 public void setAuthorizationEnabled(boolean authorizationEnabled) { 189 this.authorizationFilter.setEnabled(authorizationEnabled); 190 } 191 192 public boolean isAuthorizationEnabled() { 193 return this.authorizationFilter.isEnabled(); 194 } 195 196 private Environment ensureEnvironment() throws ConfigurationException { 197 if (this.environment != null) { 198 return this.environment; 199 } 200 201 //this.environment is null - set it: 202 if (this.securityManager != null) { 203 this.environment = new Environment() { 204 @Override 205 public SecurityManager getSecurityManager() { 206 return ShiroPlugin.this.securityManager; 207 } 208 }; 209 return this.environment; 210 } 211 212 this.iniEnvironment.init(); //will automatically catch any config errors and throw. 213 214 this.environment = iniEnvironment; 215 216 return this.iniEnvironment; 217 } 218 219 @Override 220 public Broker installPlugin(Broker broker) throws Exception { 221 222 Environment environment = ensureEnvironment(); 223 224 this.authorizationFilter.setEnvironment(environment); 225 this.authenticationFilter.setEnvironment(environment); 226 this.subjectFilter.setEnvironment(environment); 227 228 this.broker = broker; 229 this.authorizationFilter.setNext(broker); 230 this.authenticationFilter.setNext(this.authorizationFilter); 231 this.subjectFilter.setNext(this.authenticationFilter); 232 233 Broker next = this.subjectFilter; 234 if (!this.enabled) { 235 //not enabled at startup - default to the original broker: 236 next = broker; 237 } 238 239 setNext(next); 240 return this; 241 } 242 243 private boolean isInstalled() { 244 return getNext() != null; 245 } 246}