*/
package org.opendaylight.aaa.shiro.filters;
+import static java.util.Objects.requireNonNull;
+
import javax.servlet.Filter;
-import org.apache.shiro.web.servlet.ShiroFilter;
+import org.apache.shiro.web.env.WebEnvironment;
+import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * The default AAA JAX-RS 1.X Web Filter. Unlike AAAFilter, which is aimed towards
- * supporting RESTCONF and its existing API mechanisms, AAAShiroFilter is a generic
- * <code>ShiroFilter</code> for use with any other ODL Servlets. The main difference
- * is that <code>AAAFilter</code> was designed to support the existing noauth
- * mechanism, while this filter cannot be disabled.
- *
- * <p>
- * This class is also responsible for delivering debug information; to enable these
- * debug statements, please issue the following in the karaf shell:
- *
- * <code>log:set DEBUG AAAShiroFilter</code>
- *
- * @see Filter
- * @see ShiroFilter
+ * The default AAA JAX-RS Web {@link Filter} based on {@link AbstractShiroFilter}. It gets a constant reference
+ * to a Shiro {@link WebEnvironment} at instantiation time and it during {@link #init()}.
*/
-public final class AAAShiroFilter extends ShiroFilter {
+public final class AAAShiroFilter extends AbstractShiroFilter {
private static final Logger LOG = LoggerFactory.getLogger(AAAShiroFilter.class);
- public AAAShiroFilter() {
- LOG.debug("Creating the AAAShiroFilter");
+ private final WebEnvironment env;
+
+ public AAAShiroFilter(final WebEnvironment env) {
+ this.env = requireNonNull(env);
+ LOG.debug("Instantiated AAAShiroFilter for {}", env);
}
@Override
- public void init() throws Exception {
- super.init();
- LOG.debug("Initializing the AAAShiroFilter");
+ public void init() {
+ LOG.debug("Initializing AAAShiroFilter");
+ setSecurityManager(env.getWebSecurityManager());
+
+ final var resolver = env.getFilterChainResolver();
+ if (resolver != null) {
+ setFilterChainResolver(resolver);
+ }
+ LOG.debug("AAAShiroFilter initialized");
}
}
+++ /dev/null
-/*
- * Copyright (c) 2018 Inocybe Technologies and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.aaa.shiro.web.env;
-
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.config.Ini;
-import org.apache.shiro.config.IniSecurityManagerFactory;
-import org.apache.shiro.mgt.SecurityManager;
-import org.apache.shiro.util.Factory;
-import org.apache.shiro.web.env.IniWebEnvironment;
-import org.opendaylight.aaa.api.AuthenticationService;
-import org.opendaylight.aaa.api.TokenStore;
-import org.opendaylight.aaa.api.password.service.PasswordHashService;
-import org.opendaylight.aaa.cert.api.ICertificateManager;
-import org.opendaylight.aaa.shiro.realm.KeystoneAuthRealm;
-import org.opendaylight.aaa.shiro.realm.MDSALDynamicAuthorizationFilter;
-import org.opendaylight.aaa.shiro.realm.MdsalRealm;
-import org.opendaylight.aaa.shiro.realm.MoonRealm;
-import org.opendaylight.aaa.shiro.realm.TokenAuthRealm;
-import org.opendaylight.aaa.tokenauthrealm.auth.TokenAuthenticators;
-import org.opendaylight.aaa.web.servlet.ServletSupport;
-import org.opendaylight.mdsal.binding.api.DataBroker;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.shiro.configuration.Main;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.shiro.configuration.Urls;
-import org.opendaylight.yangtools.util.ClassLoaderUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Extends <code>IniWebEnvironment</code> to provide the Ini configuration via a clustered app config,
- * and sets the TCCL (x2) so that loading of classes by name (from aaa-app-config.xml) works even with
- * ShiroWebContextSecurer.
- *
- * @author Ryan Goulding
- * @author Thomas Pantelis
- * @author Michael Vorburger - use of TCCL for ShiroWebContextSecurer
- */
-class AAAIniWebEnvironment extends IniWebEnvironment {
- private static final Logger LOG = LoggerFactory.getLogger(AAAIniWebEnvironment.class);
-
- private static final String MAIN_SECTION_HEADER = "main";
- private static final String URLS_SECTION_HEADER = "urls";
-
- private final ShiroConfiguration shiroConfiguration;
- private final DataBroker dataBroker;
- private final ICertificateManager certificateManager;
- private final AuthenticationService authenticationService;
- private final TokenAuthenticators tokenAuthenticators;
- private final TokenStore tokenStore;
- private final PasswordHashService passwordHashService;
- private final ServletSupport servletSupport;
-
- AAAIniWebEnvironment(final ShiroConfiguration shiroConfiguration, final DataBroker dataBroker,
- final ICertificateManager certificateManager,
- final AuthenticationService authenticationService,
- final TokenAuthenticators tokenAuthenticators, final TokenStore tokenStore,
- final PasswordHashService passwordHashService, final ServletSupport servletSupport) {
- this.shiroConfiguration = shiroConfiguration;
- this.dataBroker = dataBroker;
- this.certificateManager = certificateManager;
- this.authenticationService = authenticationService;
- this.tokenAuthenticators = tokenAuthenticators;
- this.tokenStore = tokenStore;
- this.passwordHashService = passwordHashService;
- this.servletSupport = servletSupport;
- LOG.debug("AAAIniWebEnvironment created");
- }
-
- static Ini createIniFromClusteredAppConfig(final ShiroConfiguration shiroConfiguration) {
- final Ini ini = new Ini();
-
- final Ini.Section mainSection = ini.addSection(MAIN_SECTION_HEADER);
- for (final Main main : shiroConfiguration.nonnullMain()) {
- mainSection.put(main.getPairKey(), main.getPairValue());
- }
-
- final Ini.Section urlsSection = ini.addSection(URLS_SECTION_HEADER);
- for (final Urls url : shiroConfiguration.nonnullUrls()) {
- urlsSection.put(url.getPairKey(), url.getPairValue());
- }
-
- final Factory<SecurityManager> factory = new IniSecurityManagerFactory(ini);
- final SecurityManager securityManager = ClassLoaderUtils.getWithClassLoader(
- AAAIniWebEnvironment.class.getClassLoader(), factory::getInstance);
- SecurityUtils.setSecurityManager(securityManager);
-
- return ini;
- }
-
- @Override
- public void init() {
- try (
- var filterLoad = MDSALDynamicAuthorizationFilter.prepareForLoad(dataBroker);
- var keyStoneLoad = KeystoneAuthRealm.prepareForLoad(certificateManager, servletSupport);
- var mdsalLoad = MdsalRealm.prepareForLoad(passwordHashService, dataBroker);
- var moonLoad = MoonRealm.prepareForLoad(servletSupport);
- var tokenAuthLoad = TokenAuthRealm.prepareForLoad(authenticationService, tokenAuthenticators, tokenStore)) {
- // Initialize the Shiro environment from clustered-app-config
- final Ini ini = createIniFromClusteredAppConfig(shiroConfiguration);
- setIni(ini);
- ClassLoaderUtils.runWithClassLoader(AAAIniWebEnvironment.class.getClassLoader(), super::init);
- }
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2018 Inocybe Technologies and others. All rights reserved.
+ * Copyright (c) 2022 PANTHEON.tech, s.r.o.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.shiro.web.env;
+
+import org.apache.shiro.config.Ini;
+import org.apache.shiro.web.env.IniWebEnvironment;
+import org.opendaylight.aaa.api.AuthenticationService;
+import org.opendaylight.aaa.api.TokenStore;
+import org.opendaylight.aaa.api.password.service.PasswordHashService;
+import org.opendaylight.aaa.cert.api.ICertificateManager;
+import org.opendaylight.aaa.shiro.realm.KeystoneAuthRealm;
+import org.opendaylight.aaa.shiro.realm.MDSALDynamicAuthorizationFilter;
+import org.opendaylight.aaa.shiro.realm.MdsalRealm;
+import org.opendaylight.aaa.shiro.realm.MoonRealm;
+import org.opendaylight.aaa.shiro.realm.TokenAuthRealm;
+import org.opendaylight.aaa.tokenauthrealm.auth.TokenAuthenticators;
+import org.opendaylight.aaa.web.servlet.ServletSupport;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Extends {@code BasicInitEnvironment} to provide the {@link Ini} configuration via a clustered app config,
+ * Initialization happens in the context of this class's ClassLoader, with dependencies being injected into their
+ * thread-local variables.
+ */
+public final class AAAWebEnvironment extends IniWebEnvironment {
+ private static final Logger LOG = LoggerFactory.getLogger(AAAWebEnvironment.class);
+
+ private AAAWebEnvironment(final Ini ini) {
+ setIni(ini);
+ }
+
+ public static AAAWebEnvironment create(final ShiroConfiguration shiroConfiguration, final DataBroker dataBroker,
+ final ICertificateManager certificateManager, final AuthenticationService authenticationService,
+ final TokenAuthenticators tokenAuthenticators, final TokenStore tokenStore,
+ final PasswordHashService passwordHashService, final ServletSupport servletSupport) {
+ // Turn ShiroConfiguration into an Ini
+ final var ini = new Ini();
+
+ final var mainSection = ini.addSection("main");
+ for (var main : shiroConfiguration.nonnullMain()) {
+ mainSection.put(main.getPairKey(), main.getPairValue());
+ }
+
+ final var urlsSection = ini.addSection("urls");
+ for (var url : shiroConfiguration.nonnullUrls()) {
+ urlsSection.put(url.getPairKey(), url.getPairValue());
+ }
+
+ // Create an instance
+ final var ret = new AAAWebEnvironment(ini);
+
+ // Configure the instance with all known custom components prepared for loading via their thread locals and
+ // clean up afterwards. This needs to happen on our class loader so Shiro's ReflectionBuilder use of
+ // Class.forName() is happy.
+ ClassLoaderUtils.runWithClassLoader(AAAWebEnvironment.class.getClassLoader(), () -> {
+ try (var filterLoad = MDSALDynamicAuthorizationFilter.prepareForLoad(dataBroker);
+ var keyStoneLoad = KeystoneAuthRealm.prepareForLoad(certificateManager, servletSupport);
+ var mdsalLoad = MdsalRealm.prepareForLoad(passwordHashService, dataBroker);
+ var moonLoad = MoonRealm.prepareForLoad(servletSupport);
+ var tokenAuthLoad = TokenAuthRealm.prepareForLoad(authenticationService, tokenAuthenticators,
+ tokenStore)) {
+ ret.configure();
+ }
+ });
+
+ LOG.debug("AAAWebEnvironment created");
+ return ret;
+ }
+}
import static java.util.Objects.requireNonNull;
-import org.apache.shiro.web.env.EnvironmentLoaderListener;
+import org.apache.shiro.web.env.WebEnvironment;
import org.opendaylight.aaa.shiro.filters.AAAShiroFilter;
import org.opendaylight.aaa.web.FilterDetails;
import org.opendaylight.aaa.web.WebContext;
* @author Michael Vorburger.ch
*/
public class ShiroWebContextSecurer implements WebContextSecurer {
- private final EnvironmentLoaderListener environmentLoaderListener;
+ private final WebEnvironment webEnvironment;
- public ShiroWebContextSecurer(final EnvironmentLoaderListener environmentLoaderListener) {
- this.environmentLoaderListener = requireNonNull(environmentLoaderListener);
+ public ShiroWebContextSecurer(final WebEnvironment webEnvironment) {
+ this.webEnvironment = requireNonNull(webEnvironment);
}
@Override
public void requireAuthentication(final WebContextBuilder webContextBuilder, final boolean asyncSupported,
final String... urlPatterns) {
webContextBuilder
- .addListener(environmentLoaderListener)
// AAA filter in front of these REST web services as well as for moon endpoints
.addFilter(FilterDetails.builder()
- .filter(new AAAShiroFilter())
+ .filter(new AAAShiroFilter(webEnvironment))
.addUrlPatterns(urlPatterns)
.asyncSupported(asyncSupported)
.build());
+++ /dev/null
-/*
- * Copyright (c) 2018 Inocybe Technologies and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.aaa.shiro.web.env;
-
-import javax.servlet.ServletContext;
-import org.apache.shiro.web.env.EnvironmentLoaderListener;
-import org.apache.shiro.web.env.WebEnvironment;
-import org.opendaylight.aaa.api.AuthenticationService;
-import org.opendaylight.aaa.api.TokenStore;
-import org.opendaylight.aaa.api.password.service.PasswordHashService;
-import org.opendaylight.aaa.cert.api.ICertificateManager;
-import org.opendaylight.aaa.tokenauthrealm.auth.TokenAuthenticators;
-import org.opendaylight.aaa.web.servlet.ServletSupport;
-import org.opendaylight.mdsal.binding.api.DataBroker;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Initializes shiro components for a web environment.
- *
- * @author Thomas Pantelis
- */
-public class ShiroWebEnvironmentLoaderListener extends EnvironmentLoaderListener {
- private static final Logger LOG = LoggerFactory.getLogger(ShiroWebEnvironmentLoaderListener.class);
-
- private final ShiroConfiguration shiroConfiguration;
- private final DataBroker dataBroker;
- private final ICertificateManager certificateManager;
- private final AuthenticationService authenticationService;
- private final TokenAuthenticators tokenAuthenticators;
- private final TokenStore tokenStore;
- private final PasswordHashService passwordHashService;
- private final ServletSupport servletSupport;
-
- public ShiroWebEnvironmentLoaderListener(final ShiroConfiguration shiroConfiguration, final DataBroker dataBroker,
- final ICertificateManager certificateManager, final AuthenticationService authenticationService,
- final TokenAuthenticators tokenAuthenticators, final TokenStore tokenStore,
- final PasswordHashService passwordHashService, final ServletSupport servletSupport) {
- this.shiroConfiguration = shiroConfiguration;
- this.dataBroker = dataBroker;
- this.certificateManager = certificateManager;
- this.authenticationService = authenticationService;
- this.tokenAuthenticators = tokenAuthenticators;
- this.tokenStore = tokenStore;
- this.passwordHashService = passwordHashService;
- this.servletSupport = servletSupport;
- LOG.debug("ShiroWebEnvironmentLoaderListenerImpl created");
- }
-
- @Override
- protected WebEnvironment determineWebEnvironment(final ServletContext servletContext) {
- return new AAAIniWebEnvironment(shiroConfiguration, dataBroker, certificateManager, authenticationService,
- tokenAuthenticators, tokenStore, passwordHashService, servletSupport);
- }
-}
<reference id="servletSupport" interface="org.opendaylight.aaa.web.servlet.ServletSupport"/>
- <bean id="shiroWebEnvLoader" class="org.opendaylight.aaa.shiro.web.env.ShiroWebEnvironmentLoaderListener">
+ <bean id="webEnvironment" class="org.opendaylight.aaa.shiro.web.env.AAAWebEnvironment" factory-method="create">
<argument ref="shiroConfiguration"/>
<argument ref="dataBroker"/>
<argument ref="certManager"/>
<argument ref="servletSupport"/>
</bean>
- <reference id="customFilterAdapterConfig"
- interface="org.opendaylight.aaa.filterchain.configuration.CustomFilterAdapterConfiguration"/>
-
<bean id="webContextSecurer" class="org.opendaylight.aaa.shiro.web.env.ShiroWebContextSecurer">
- <argument ref="shiroWebEnvLoader"/>
+ <argument ref="webEnvironment"/>
</bean>
<service ref="webContextSecurer" interface="org.opendaylight.aaa.web.WebContextSecurer" />
+ <reference id="customFilterAdapterConfig"
+ interface="org.opendaylight.aaa.filterchain.configuration.CustomFilterAdapterConfiguration"/>
<reference id="webServer" interface="org.opendaylight.aaa.web.WebServer" />
<bean id="webInitializer" class="org.opendaylight.aaa.shiro.web.env.WebInitializer" destroy-method="close">