org.graylog2.security.OrderedAuthenticatingRealms Maven / Gradle / Ivy
/**
* This file is part of Graylog.
*
* Graylog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Graylog is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Graylog. If not, see .
*/
package org.graylog2.security;
import com.google.common.collect.ImmutableList;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.Realm;
import org.graylog2.cluster.ClusterConfigChangedEvent;
import org.graylog2.plugin.cluster.ClusterConfigService;
import org.graylog2.utilities.LenientExplicitOrdering;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.util.AbstractCollection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* Runtime (re-)orderable collection of Shiro AuthenticatingRealms.
*
* The generic type is Realm, even though it really only contains AuthenticatingRealms. This is simply to avoid having to
* cast the generic collection when passing it to the SecurityManager.
*/
public class OrderedAuthenticatingRealms extends AbstractCollection {
private final Map availableRealms;
private final ClusterConfigService clusterConfigService;
private final AtomicReference> orderedRealms = new AtomicReference<>();
@Inject
public OrderedAuthenticatingRealms(Map realms,
ClusterConfigService clusterConfigService,
EventBus eventBus) {
this.availableRealms = realms;
this.clusterConfigService = clusterConfigService;
eventBus.register(this);
sortRealms();
// sortRealms should have produced a reasonable default
Objects.requireNonNull(orderedRealms.get());
}
@Subscribe
public void handleOrderingUpdate(ClusterConfigChangedEvent event) {
if (!AuthenticationConfig.class.getCanonicalName().equals(event.type())) {
return;
}
sortRealms();
}
private void sortRealms() {
final AuthenticationConfig config = clusterConfigService.getOrDefault(AuthenticationConfig.class,
AuthenticationConfig.defaultInstance());
final LenientExplicitOrdering ordering = new LenientExplicitOrdering<>(config.realmOrder());
final ImmutableList newRealmOrder = ordering.immutableSortedCopy(availableRealms.keySet());
orderedRealms.set(newRealmOrder.stream()
.filter(name -> !config.disabledRealms().contains(name))
.map(availableRealms::get)
.collect(Collectors.toList()));
}
@Nonnull
@Override
public Iterator iterator() {
return orderedRealms.get().iterator();
}
@Override
public int size() {
return orderedRealms.get().size();
}
}