Package org.apache.geronimo.security.realm.providers

Source Code of org.apache.geronimo.security.realm.providers.SQLLoginModule

/**
*
* Copyright 2003-2004 The Apache Software Foundation
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/

package org.apache.geronimo.security.realm.providers;

import java.io.IOException;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import javax.sql.DataSource;

import org.apache.geronimo.gbean.AbstractName;
import org.apache.geronimo.gbean.AbstractNameQuery;
import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
import org.apache.geronimo.kernel.GBeanNotFoundException;
import org.apache.geronimo.kernel.Kernel;
import org.apache.geronimo.kernel.KernelRegistry;
import org.apache.geronimo.management.geronimo.JCAManagedConnectionFactory;
import org.apache.geronimo.security.jaas.JaasLoginModuleUse;


/**
* A login module that loads security information from a SQL database.  Expects
* to be run by a GenericSecurityRealm (doesn't work on its own).
* <p>
* This requires database connectivity information (either 1: a dataSourceName and
* optional dataSourceApplication or 2: a JDBC driver, URL, username, and password)
* and 2 SQL queries.
* <p>
* The userSelect query should return 2 values, the username and the password in
* that order.  It should include one PreparedStatement parameter (a ?) which
* will be filled in with the username.  In other words, the query should look
* like: <tt>SELECT user, password FROM users WHERE username=?</tt>
* <p>
* The groupSelect query should return 2 values, the username and the group name in
* that order (but it may return multiple rows, one per group).  It should include
* one PreparedStatement parameter (a ?) which will be filled in with the username.
* In other words, the query should look like:
* <tt>SELECT user, role FROM user_roles WHERE username=?</tt>
*
* @version $Rev: 407961 $ $Date: 2006-05-20 09:26:08 +0200 (Sat, 20 May 2006) $
*/
public class SQLLoginModule implements LoginModule {
    public final static String USER_SELECT = "userSelect";
    public final static String GROUP_SELECT = "groupSelect";
    public final static String CONNECTION_URL = "jdbcURL";
    public final static String USER = "jdbcUser";
    public final static String PASSWORD = "jdbcPassword";
    public final static String DRIVER = "jdbcDriver";
    public final static String DATABASE_POOL_NAME = "dataSourceName";
    public final static String DATABASE_POOL_APP_NAME = "dataSourceApplication";
    private String connectionURL;
    private Properties properties;
    private Driver driver;
    private JCAManagedConnectionFactory factory;
    private String userSelect;
    private String groupSelect;

    private Subject subject;
    private CallbackHandler handler;
    private String cbUsername;
    private String cbPassword;
    private final Set groups = new HashSet();

    public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
        this.subject = subject;
        this.handler = callbackHandler;
        userSelect = (String) options.get(USER_SELECT);
        groupSelect = (String) options.get(GROUP_SELECT);

        String dataSourceName = (String) options.get(DATABASE_POOL_NAME);
        if(dataSourceName != null) {
            dataSourceName = dataSourceName.trim();
            String dataSourceAppName = (String) options.get(DATABASE_POOL_APP_NAME);
            if(dataSourceAppName == null || dataSourceAppName.trim().equals("")) {
                dataSourceAppName = "null";
            } else {
                dataSourceAppName = dataSourceAppName.trim();
            }
            String kernelName = (String) options.get(JaasLoginModuleUse.KERNEL_NAME_LM_OPTION);
            Kernel kernel = KernelRegistry.getKernel(kernelName);
            Set set = kernel.listGBeans(new AbstractNameQuery(JCAManagedConnectionFactory.class.getName()));
            JCAManagedConnectionFactory factory;
            for (Iterator it = set.iterator(); it.hasNext();) {
                AbstractName name = (AbstractName) it.next();
                if(name.getName().get(NameFactory.J2EE_APPLICATION).equals(dataSourceAppName) &&
                    name.getName().get(NameFactory.J2EE_NAME).equals(dataSourceName)) {
                    try {
                        factory = (JCAManagedConnectionFactory) kernel.getGBean(name);
                        String type = factory.getConnectionFactoryInterface();
                        if(type.equals(DataSource.class.getName())) {
                            this.factory = factory;
                            break;
                        }
                    } catch (GBeanNotFoundException e) {
                        // ignore... GBean was unregistered
                    }
                }
            }
        } else {
            connectionURL = (String) options.get(CONNECTION_URL);
            properties = new Properties();
            if(options.get(USER) != null) {
                properties.put("user", options.get(USER));
            }
            if(options.get(PASSWORD) != null) {
                properties.put("password", options.get(PASSWORD));
            }
            ClassLoader cl = (ClassLoader) options.get(JaasLoginModuleUse.CLASSLOADER_LM_OPTION);
            try {
                driver = (Driver) cl.loadClass((String) options.get(DRIVER)).newInstance();
            } catch (ClassNotFoundException e) {
                throw new IllegalArgumentException("Driver class " + options.get(DRIVER) + " is not available.  Perhaps you need to add it as a dependency in your deployment plan?");
            } catch (Exception e) {
                throw new IllegalArgumentException("Unable to load, instantiate, register driver " + options.get(DRIVER) + ": " + e.getMessage());
            }
        }
    }

    public boolean login() throws LoginException {
        Callback[] callbacks = new Callback[2];

        callbacks[0] = new NameCallback("User name");
        callbacks[1] = new PasswordCallback("Password", false);
        try {
            handler.handle(callbacks);
        } catch (IOException ioe) {
            throw (LoginException) new LoginException().initCause(ioe);
        } catch (UnsupportedCallbackException uce) {
            throw (LoginException) new LoginException().initCause(uce);
        }
        assert callbacks.length == 2;
        cbUsername = ((NameCallback) callbacks[0]).getName();
        if (cbUsername == null || cbUsername.equals("")) {
            return false;
        }
        char[] provided = ((PasswordCallback) callbacks[1]).getPassword();
        cbPassword = provided == null ? null : new String(provided);

        boolean found = false;
        try {
            Connection conn;
            if(factory != null) {
                DataSource ds = (DataSource) factory.getConnectionFactory();
                conn = ds.getConnection();
            } else {
                conn = driver.connect(connectionURL, properties);
            }

            try {
                PreparedStatement statement = conn.prepareStatement(userSelect);
                try {
                    int count = countParameters(userSelect);
                    for(int i=0; i<count; i++) {
                        statement.setObject(i+1, cbUsername);
                    }
                    ResultSet result = statement.executeQuery();

                    try {
                        while (result.next()) {
                            String userName = result.getString(1);
                            String userPassword = result.getString(2);

                            if (cbUsername.equals(userName)) {
                                found = (cbPassword == null && userPassword == null) ||
                                        (cbPassword != null && userPassword != null && cbPassword.equals(userPassword));
                                break;
                            }
                        }
                    } finally {
                        result.close();
                    }
                } finally {
                    statement.close();
                }

                if (!found) {
                    throw new FailedLoginException();
                }

                statement = conn.prepareStatement(groupSelect);
                try {
                    int count = countParameters(groupSelect);
                    for(int i=0; i<count; i++) {
                        statement.setObject(i+1, cbUsername);
                    }
                    ResultSet result = statement.executeQuery();

                    try {
                        while (result.next()) {
                            String userName = result.getString(1);
                            String groupName = result.getString(2);

                            if (cbUsername.equals(userName)) {
                                groups.add(new GeronimoGroupPrincipal(groupName));
                            }
                        }
                    } finally {
                        result.close();
                    }
                } finally {
                    statement.close();
                }
            } finally {
                conn.close();
            }
        } catch (SQLException sqle) {
            throw (LoginException) new LoginException("SQL error").initCause(sqle);
        }

        return true;
    }

    public boolean commit() throws LoginException {
        Set principals = subject.getPrincipals();
        principals.add(new GeronimoUserPrincipal(cbUsername));
        Iterator iter = groups.iterator();
        while (iter.hasNext()) {
            principals.add(iter.next());
        }

        return true;
    }

    public boolean abort() throws LoginException {
        cbUsername = null;
        cbPassword = null;

        return true;
    }

    public boolean logout() throws LoginException {
        cbUsername = null;
        cbPassword = null;
        //todo: should remove principals put in by commit
        return true;
    }

    private static int countParameters(String sql) {
        int count = 0;
        int pos = -1;
        while((pos = sql.indexOf('?', pos+1)) != -1) {
            ++count;
        }
        return count;
    }
}
TOP

Related Classes of org.apache.geronimo.security.realm.providers.SQLLoginModule

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.