package org.dcache.xrootd.spring;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Required;
import java.util.List;
import java.util.ServiceLoader;
import org.dcache.auth.LoginStrategy;
import org.dcache.xrootd.door.LoginAuthenticationHandlerFactory;
import org.dcache.xrootd.plugins.AuthenticationFactory;
import org.dcache.xrootd.plugins.AuthenticationProvider;
import org.dcache.xrootd.plugins.ChannelHandlerFactory;
import org.dcache.xrootd.plugins.authn.none.NoAuthenticationFactory;
import static com.google.common.base.Predicates.containsPattern;
import static com.google.common.collect.Iterables.*;
/**
* A Spring FactoryBean that creates ChannelHandlerFactory instances.
*
* A ChannelHandlerFactory is created by an ChannelHandlerProvider.
* The FactoryBean uses the Java 6 ServiceLoader system to obtain
* ChannelHandlerProvider instances.
*/
public class GplazmaAwareChannelHandlerFactoryFactoryBean
extends ChannelHandlerFactoryFactoryBean
{
private static final ServiceLoader<AuthenticationProvider> _authenticationProviders =
ServiceLoader.load(AuthenticationProvider.class);
private static final String GPLAZMA_PREFIX = "gplazma:";
private LoginStrategy _loginStrategy;
private LoginStrategy _anonymousLoginStrategy;
@Required
public void setPlugins(String plugins)
{
super.setPlugins(plugins);
if (any(_plugins, containsPattern("^authn:"))) {
throw new IllegalArgumentException("The authn: prefix is not allowed in the xrootd door");
}
if (size(filter(_plugins, containsPattern("^gplazma:"))) != 1) {
throw new IllegalArgumentException("Exactly one authentication plugin is required");
}
int authn = indexOf(_plugins, containsPattern("^gplazma:"));
int authz = indexOf(_plugins, containsPattern("^authz:"));
if (authz > -1 && authz < authn) {
throw new IllegalArgumentException("Authorization plugins must be placed after authentication plugins");
}
}
@Required
public void setLoginStrategy(LoginStrategy loginStrategy)
{
_loginStrategy = loginStrategy;
}
@Required
public void setAnonymousLoginStrategy(
LoginStrategy anonymousLoginStrategy)
{
_anonymousLoginStrategy = anonymousLoginStrategy;
}
@Override
public List<ChannelHandlerFactory> getObject()
throws Exception
{
List<ChannelHandlerFactory> factories = Lists.newArrayList();
for (String plugin: _plugins) {
/* We need special logic for the authentication handler as we
* cannot use a generic provider: The provider would not have
* access to the login strategies. REVISIT: Is there some way
* we could get Spring to inject them anyway?
*/
if (plugin.startsWith(GPLAZMA_PREFIX)) {
String name = plugin.substring(GPLAZMA_PREFIX.length());
factories.add(createAuthenticationHandlerFactory(name));
} else {
factories.add(createChannelHandlerFactory(plugin));
}
}
return factories;
}
private ChannelHandlerFactory createAuthenticationHandlerFactory(
String name) throws Exception
{
if (name.equals("none")) {
return new LoginAuthenticationHandlerFactory(
GPLAZMA_PREFIX + "none", new NoAuthenticationFactory(), _anonymousLoginStrategy);
}
for (AuthenticationProvider provider: _authenticationProviders) {
AuthenticationFactory factory = provider.createFactory(name, _properties);
if (factory != null) {
return new LoginAuthenticationHandlerFactory(
GPLAZMA_PREFIX + name, factory, _loginStrategy);
}
}
throw new IllegalArgumentException("Authentication plugin not found: " + name);
}
}