/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.activemq.shiro; import org.apache.activemq.ConfigurationException; import org.apache.activemq.broker.Broker; import org.apache.activemq.broker.BrokerPluginSupport; import org.apache.activemq.shiro.authc.AuthenticationFilter; import org.apache.activemq.shiro.authc.AuthenticationPolicy; import org.apache.activemq.shiro.authc.DefaultAuthenticationPolicy; import org.apache.activemq.shiro.authz.AuthorizationFilter; import org.apache.activemq.shiro.env.IniEnvironment; import org.apache.activemq.shiro.subject.ConnectionSubjectFactory; import org.apache.activemq.shiro.subject.DefaultConnectionSubjectFactory; import org.apache.activemq.shiro.subject.SubjectFilter; import org.apache.shiro.config.Ini; import org.apache.shiro.env.Environment; import org.apache.shiro.mgt.SecurityManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @since 5.10.0 */ public class ShiroPlugin extends BrokerPluginSupport { private static final Logger LOG = LoggerFactory.getLogger(ShiroPlugin.class); private volatile boolean enabled = true; private Broker broker; //the downstream broker after any/all Shiro-specific broker filters private SecurityManager securityManager; private Environment environment; private IniEnvironment iniEnvironment; //only used if the above environment instance is not explicitly configured private SubjectFilter subjectFilter; private AuthenticationFilter authenticationFilter; private AuthorizationFilter authorizationFilter; public ShiroPlugin() { //Default if this.environment is not configured. See the ensureEnvironment() method below. iniEnvironment = new IniEnvironment(); authorizationFilter = new AuthorizationFilter(); // we want to share one AuthenticationPolicy instance across both the AuthenticationFilter and the // ConnectionSubjectFactory: AuthenticationPolicy authcPolicy = new DefaultAuthenticationPolicy(); authenticationFilter = new AuthenticationFilter(); authenticationFilter.setAuthenticationPolicy(authcPolicy); authenticationFilter.setNext(authorizationFilter); subjectFilter = new SubjectFilter(); DefaultConnectionSubjectFactory subjectFactory = new DefaultConnectionSubjectFactory(); subjectFactory.setAuthenticationPolicy(authcPolicy); subjectFilter.setConnectionSubjectFactory(subjectFactory); subjectFilter.setNext(authenticationFilter); } public SubjectFilter getSubjectFilter() { return subjectFilter; } public void setSubjectFilter(SubjectFilter subjectFilter) { this.subjectFilter = subjectFilter; this.subjectFilter.setNext(this.authenticationFilter); } public AuthenticationFilter getAuthenticationFilter() { return authenticationFilter; } public void setAuthenticationFilter(AuthenticationFilter authenticationFilter) { this.authenticationFilter = authenticationFilter; this.authenticationFilter.setNext(this.authorizationFilter); this.subjectFilter.setNext(authenticationFilter); } public AuthorizationFilter getAuthorizationFilter() { return authorizationFilter; } public void setAuthorizationFilter(AuthorizationFilter authorizationFilter) { this.authorizationFilter = authorizationFilter; this.authorizationFilter.setNext(this.broker); this.authenticationFilter.setNext(authorizationFilter); } public void setEnabled(boolean enabled) { this.enabled = enabled; if (isInstalled()) { //we're running, so apply the changes now: applyEnabled(enabled); } } public boolean isEnabled() { if (isInstalled()) { return getNext() == this.subjectFilter; } return enabled; } private void applyEnabled(boolean enabled) { if (enabled) { //ensure the SubjectFilter and downstream filters are used: super.setNext(this.subjectFilter); } else { //Shiro is not enabled, restore the original downstream broker: super.setNext(this.broker); } } public Environment getEnvironment() { return environment; } public void setEnvironment(Environment environment) { this.environment = environment; } public SecurityManager getSecurityManager() { return securityManager; } public void setSecurityManager(SecurityManager securityManager) { this.securityManager = securityManager; } public void setIni(Ini ini) { this.iniEnvironment.setIni(ini); } public void setIniConfig(String iniConfig) { this.iniEnvironment.setIniConfig(iniConfig); } public void setIniResourcePath(String resourcePath) { this.iniEnvironment.setIniResourcePath(resourcePath); } // =============================================================== // Authentication Configuration // =============================================================== public void setAuthenticationEnabled(boolean authenticationEnabled) { this.authenticationFilter.setEnabled(authenticationEnabled); } public boolean isAuthenticationEnabled() { return this.authenticationFilter.isEnabled(); } public AuthenticationPolicy getAuthenticationPolicy() { return authenticationFilter.getAuthenticationPolicy(); } public void setAuthenticationPolicy(AuthenticationPolicy authenticationPolicy) { authenticationFilter.setAuthenticationPolicy(authenticationPolicy); //also set it on the ConnectionSubjectFactory: ConnectionSubjectFactory factory = subjectFilter.getConnectionSubjectFactory(); if (factory instanceof DefaultConnectionSubjectFactory) { ((DefaultConnectionSubjectFactory) factory).setAuthenticationPolicy(authenticationPolicy); } } // =============================================================== // Authorization Configuration // =============================================================== public void setAuthorizationEnabled(boolean authorizationEnabled) { this.authorizationFilter.setEnabled(authorizationEnabled); } public boolean isAuthorizationEnabled() { return this.authorizationFilter.isEnabled(); } private Environment ensureEnvironment() throws ConfigurationException { if (this.environment != null) { return this.environment; } //this.environment is null - set it: if (this.securityManager != null) { this.environment = new Environment() { @Override public SecurityManager getSecurityManager() { return ShiroPlugin.this.securityManager; } }; return this.environment; } this.iniEnvironment.init(); //will automatically catch any config errors and throw. this.environment = iniEnvironment; return this.iniEnvironment; } @Override public Broker installPlugin(Broker broker) throws Exception { Environment environment = ensureEnvironment(); this.authorizationFilter.setEnvironment(environment); this.authenticationFilter.setEnvironment(environment); this.subjectFilter.setEnvironment(environment); this.broker = broker; this.authorizationFilter.setNext(broker); this.authenticationFilter.setNext(this.authorizationFilter); this.subjectFilter.setNext(this.authenticationFilter); Broker next = this.subjectFilter; if (!this.enabled) { //not enabled at startup - default to the original broker: next = broker; } setNext(next); return this; } private boolean isInstalled() { return getNext() != null; } }