package org.opendaylight.aaa.shiro.realm;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
import com.google.common.collect.Iterables;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
-import org.opendaylight.aaa.shiro.web.env.ThreadLocals;
import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.policies.Policies;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.permission.Permissions;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final DataTreeIdentifier<HttpAuthorization> AUTHZ_CONTAINER = DataTreeIdentifier.create(
LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(HttpAuthorization.class));
+ private static final ThreadLocal<DataBroker> DATABROKER_TL = new ThreadLocal<>();
+
private final DataBroker dataBroker;
private ListenerRegistration<?> reg;
private volatile ListenableFuture<Optional<HttpAuthorization>> authContainer;
public MDSALDynamicAuthorizationFilter() {
- dataBroker = requireNonNull(ThreadLocals.DATABROKER_TL.get());
+ this(verifyNotNull(DATABROKER_TL.get(), "MDSALDynamicAuthorizationFilter loading not prepared"));
+ }
+
+ public MDSALDynamicAuthorizationFilter(final DataBroker dataBroker) {
+ this.dataBroker = requireNonNull(dataBroker);
+ }
+
+ public static Registration prepareForLoad(final DataBroker dataBroker) {
+ DATABROKER_TL.set(requireNonNull(dataBroker));
+ return DATABROKER_TL::remove;
}
@Override
try (ReadTransaction tx = dataBroker.newReadOnlyTransaction()) {
authContainer = tx.read(AUTHZ_CONTAINER.getDatastoreType(), AUTHZ_CONTAINER.getRootIdentifier());
}
- this.reg = dataBroker.registerDataTreeChangeListener(AUTHZ_CONTAINER, this);
+ reg = dataBroker.registerDataTreeChangeListener(AUTHZ_CONTAINER, this);
return super.processPathConfig(path, config);
}
*/
package org.opendaylight.aaa.shiro.realm;
+import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
import com.google.common.collect.Iterables;
import org.opendaylight.aaa.shiro.principal.ODLPrincipalImpl;
import org.opendaylight.aaa.shiro.realm.util.TokenUtils;
import org.opendaylight.aaa.shiro.realm.util.http.header.HeaderUtils;
-import org.opendaylight.aaa.shiro.web.env.ThreadLocals;
import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.authentication.Roles;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.authentication.Users;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final DataTreeIdentifier<Authentication> AUTH_TREE_ID = DataTreeIdentifier.create(
LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Authentication.class));
+ private static final ThreadLocal<PasswordHashService> PASSWORD_HASH_SERVICE_TL = new ThreadLocal<>();
+ private static final ThreadLocal<DataBroker> DATABROKER_TL = new ThreadLocal<>();
+
private final PasswordHashService passwordHashService;
private final ListenerRegistration<?> reg;
private volatile ListenableFuture<Optional<Authentication>> authentication;
public MdsalRealm() {
- this.passwordHashService = requireNonNull(ThreadLocals.PASSWORD_HASH_SERVICE_TL.get());
- final DataBroker dataBroker = requireNonNull(ThreadLocals.DATABROKER_TL.get());
+ this(verifyLoad(PASSWORD_HASH_SERVICE_TL), verifyLoad(DATABROKER_TL));
+ }
+
+ private static <T> T verifyLoad(final ThreadLocal<T> threadLocal) {
+ return verifyNotNull(threadLocal.get(), "MdsalRealm not prepared for loading");
+ }
+
+ public MdsalRealm(final PasswordHashService passwordHashService, final DataBroker dataBroker) {
+ this.passwordHashService = requireNonNull(passwordHashService);
try (ReadTransaction tx = dataBroker.newReadOnlyTransaction()) {
authentication = tx.read(AUTH_TREE_ID.getDatastoreType(), AUTH_TREE_ID.getRootIdentifier());
LOG.info("MdsalRealm created");
}
+ public static Registration prepareForLoad(final PasswordHashService passwordHashService,
+ final DataBroker dataBroker) {
+ PASSWORD_HASH_SERVICE_TL.set(requireNonNull(passwordHashService));
+ DATABROKER_TL.set(requireNonNull(dataBroker));
+ return () -> {
+ PASSWORD_HASH_SERVICE_TL.remove();
+ DATABROKER_TL.remove();
+ };
+ }
+
private void onAuthenticationChanged(final Collection<DataTreeModification<Authentication>> changes) {
final Authentication newVal = Iterables.getLast(changes).getRootNode().getDataAfter();
LOG.debug("Updating authentication information to {}", newVal);
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;
@Override
public void init() {
- ThreadLocals.DATABROKER_TL.set(dataBroker);
- ThreadLocals.PASSWORD_HASH_SERVICE_TL.set(passwordHashService);
try (
+ var filterLoad = MDSALDynamicAuthorizationFilter.prepareForLoad(dataBroker);
var keyStoneLoad = KeystoneAuthRealm.prepareForLoad(certificateManager);
+ 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);
super.init();
return null;
});
- } finally {
- ThreadLocals.DATABROKER_TL.remove();
- ThreadLocals.PASSWORD_HASH_SERVICE_TL.remove();
}
}
}
+++ /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.opendaylight.aaa.api.password.service.PasswordHashService;
-import org.opendaylight.mdsal.binding.api.DataBroker;
-
-/**
- * Holds ThreadLocal variables used to indirectly inject instances into classes that are instantiated by the Shiro
- * lib. Not ideal but a necessary evil to avoid static instances.
- *
- * @author Thomas Pantelis
- */
-public final class ThreadLocals {
- public static final ThreadLocal<DataBroker> DATABROKER_TL = new ThreadLocal<>();
-
- public static final ThreadLocal<PasswordHashService> PASSWORD_HASH_SERVICE_TL = new ThreadLocal<>();
-
- private ThreadLocals() {
- // Hidden on purpose
- }
-}
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.subject.Subject;
-import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.aaa.shiro.web.env.ThreadLocals;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.ReadTransaction;
import org.opendaylight.mdsal.common.api.ReadFailedException;
@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
public class MDSALDynamicAuthorizationFilterTest {
- @Before
- public void setup() {
- }
-
private static DataBroker mockDataBroker(final Object readData) {
final ReadTransaction readOnlyTransaction = mock(ReadTransaction.class);
private static MDSALDynamicAuthorizationFilter newFilter(final Subject subject, final DataBroker dataBroker)
throws ServletException {
- ThreadLocals.DATABROKER_TL.set(dataBroker);
- MDSALDynamicAuthorizationFilter ret;
- try {
- ret = new MDSALDynamicAuthorizationFilter() {
- @Override
- protected Subject getSubject(final ServletRequest request, final ServletResponse servletResponse) {
- return subject;
- }
- };
- } finally {
- ThreadLocals.DATABROKER_TL.remove();
- }
+ final var ret = new MDSALDynamicAuthorizationFilter(dataBroker) {
+ @Override
+ protected Subject getSubject(final ServletRequest request, final ServletResponse servletResponse) {
+ return subject;
+ }
+ };
ret.processPathConfig("test-path","test-config");
return ret;