/*
 * Copyright 2008-2011 Red Hat, Inc, and individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.torquebox.base.deployers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.jboss.beans.metadata.plugins.builder.BeanMetaDataBuilderFactory;
import org.jboss.beans.metadata.spi.BeanMetaData;
import org.jboss.beans.metadata.spi.builder.BeanMetaDataBuilder;
import org.jboss.deployers.spi.DeploymentException;
import org.jboss.deployers.spi.deployer.DeploymentStages;
import org.jboss.deployers.spi.deployer.helpers.AbstractDeployer;
import org.jboss.deployers.structure.spi.DeploymentUnit;
import org.jboss.kernel.Kernel;
import org.jboss.security.microcontainer.beans.metadata.ApplicationPolicyMetaDataFactory;
import org.jboss.security.microcontainer.beans.metadata.AuthenticationMetaData;
import org.jboss.security.microcontainer.beans.metadata.BaseModuleMetaData;
import org.jboss.security.microcontainer.beans.metadata.FlaggedModuleMetaData;
import org.torquebox.auth.UsersRolesAuthenticator;
import org.torquebox.base.metadata.AuthMetaData;
import org.torquebox.base.metadata.AuthMetaData.Config;
import org.torquebox.base.metadata.RubyApplicationMetaData;
import org.torquebox.mc.AttachmentUtils;

public class AuthenticatorDeployer extends AbstractDeployer {
    private Kernel kernel;
    private String applicationName;

    public AuthenticatorDeployer() {
        setStage(DeploymentStages.REAL);
        setInput(RubyApplicationMetaData.class);
        addOutput(AuthenticationMetaData.class);
        addInput(AuthMetaData.class);
        addOutput(BeanMetaData.class);
    }

    public void setKernel(Kernel kernel) {
        this.kernel = kernel;
    }

    public Kernel getKernel() {
        return kernel;
    }

    public void setApplicationName(String applicationName) {
        this.applicationName = applicationName;
    }

    public String getApplicationName() {
        return this.applicationName;
    }

    @Override
    public void deploy(DeploymentUnit unit) throws DeploymentException {
        if (this.getKernel() == null) {
            log.error("Unable to configure authentication. No KernelController available");
        } else {
            RubyApplicationMetaData appMetaData = unit.getAttachment(RubyApplicationMetaData.class);
            String applicationName = appMetaData.getApplicationName();
            this.setApplicationName(applicationName);

            AuthMetaData authMetaData = unit.getAttachment(AuthMetaData.class);
            if (authMetaData != null) {
                Collection<Config> authConfigs = authMetaData.getConfigurations();
                for (Config config : authConfigs) {
                    installAuthenticator(unit, config.getName(), config.getStrategy(), config.getDomain());
                }
            }
        }
    }

    private void installAuthenticator(DeploymentUnit unit, String name, String strategy, String domain) {

        String strategyClass = classFor(strategy);
        if (name != null && domain != null && strategyClass != null) {

            AuthenticationMetaData jaasMetaData = new AuthenticationMetaData();
            unit.addAttachment(AuthenticationMetaData.class, jaasMetaData);

            ApplicationPolicyMetaDataFactory factory = new ApplicationPolicyMetaDataFactory();
            factory.setPolicyName(domain);

            // Create some metadata for the authentication bits
            FlaggedModuleMetaData metaData = new FlaggedModuleMetaData();
            metaData.setCode(strategyClass);

            ArrayList<BaseModuleMetaData> authModules = new ArrayList<BaseModuleMetaData>();
            authModules.add(metaData);
            jaasMetaData.setModules(authModules);
            factory.setAuthentication(jaasMetaData);

            // Get our bean metadata and attach it to the DeploymentUnit
            List<BeanMetaData> authBeanMetaData = factory.getBeans();
            for (BeanMetaData bmd : authBeanMetaData) {
                log.info("Attaching JAAS BeanMetaData: " + bmd.getName() + " - " + bmd.getBean());
                AttachmentUtils.attach(unit, bmd);
            }

            // Set up our authenticator
            String authenticatorBeanName = this.getApplicationName() + "-authentication-" + name;
            BeanMetaDataBuilder authenticatorBuilder = BeanMetaDataBuilderFactory.createBuilder(authenticatorBeanName, UsersRolesAuthenticator.class.getName());
            authenticatorBuilder.addPropertyMetaData("authDomain", domain);
            BeanMetaData bmd = authenticatorBuilder.getBeanMetaData();
            log.info("Attaching TorqueBox BeanMetaData: " + bmd.getName() + " - " + bmd.getBean());
            AttachmentUtils.attach(unit, bmd);
        }
    }

    private String classFor(String strategy) {
        String result = null;
        if (strategy == null) {
            log.warn("No authentication strategy supplied.");
        } else if (strategy.equals("file")) {
            result = "org.jboss.security.auth.spi.UsersRolesLoginModule.class";
        } else {
            log.warn("Sorry - I don't know how to authenticate with the " + strategy + " strategy yet.");
        }
        return result;
    }
}

@@ -1736,32 +1736,110 @@
 ModuleMetaData;%0A
+import org.jboss.security.microcontainer.beans.metadata.ModuleOptionMetaData;%0A
 import org.torqu
@@ -3584,60 +3584,8 @@
 nfig
-.getName(), config.getStrategy(), config.getDomain()
 );%0A 
@@ -3695,55 +3695,172 @@
 it, 
-String name, String strategy, String domain) %7B%0A
+Config config) %7B%0A%0A        String name     = config.getName();%0A        String strategy = config.getStrategy();%0A        String domain   = config.getDomain();%0A        
 %0A   
@@ -4429,37 +4429,470 @@
     
-metaData.setCode(strategyClas
+%0A            // Set the strategy class%0A            metaData.setCode(strategyClass);%0A%0A            // Tell it where to find users/passwords%0A            List%3CModuleOptionMetaData%3E moduleOptions = new ArrayList%3CModuleOptionMetaData%3E();%0A            moduleOptions.add(createModuleOption(%22usersProperties%22, %22users.properties%22));%0A            moduleOptions.add(createModuleOption(%22rolesProperties%22, %22roles.properties%22));%0A            metaData.setModuleOptions(moduleOption
 s);%0A
@@ -6094,32 +6094,271 @@
        %7D%0A    %7D%0A%0A
+    private ModuleOptionMetaData createModuleOption(String name, String value) %7B%0A        ModuleOptionMetaData option = new ModuleOptionMetaData();%0A        option.setName(name);%0A        option.setValue(value);%0A        return option;%0A    %7D%0A%0A
     private Stri

Add default file locations for users and roles properties