Save This Page
Home » JBoss-5.1.0 » org » jboss » security » auth » spi » [javadoc | source]
    1   /*
    2   * JBoss, Home of Professional Open Source
    3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
    4   * by the @authors tag. See the copyright.txt in the distribution for a
    5   * full listing of individual contributors.
    6   *
    7   * This is free software; you can redistribute it and/or modify it
    8   * under the terms of the GNU Lesser General Public License as
    9   * published by the Free Software Foundation; either version 2.1 of
   10   * the License, or (at your option) any later version.
   11   *
   12   * This software is distributed in the hope that it will be useful,
   13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   15   * Lesser General Public License for more details.
   16   *
   17   * You should have received a copy of the GNU Lesser General Public
   18   * License along with this software; if not, write to the Free
   19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   21   */
   22   package org.jboss.security.auth.spi;
   23   
   24   import java.security.acl.Group;
   25   import java.sql.Connection;
   26   import java.sql.PreparedStatement;
   27   import java.sql.ResultSet;
   28   import java.sql.SQLException;
   29   import java.util.Map;
   30   
   31   import javax.naming.InitialContext;
   32   import javax.naming.NamingException;
   33   import javax.security.auth.Subject;
   34   import javax.security.auth.callback.CallbackHandler;
   35   import javax.security.auth.login.FailedLoginException;
   36   import javax.security.auth.login.LoginException;
   37   import javax.sql.DataSource;
   38   import javax.transaction.SystemException;
   39   import javax.transaction.Transaction;
   40   import javax.transaction.TransactionManager;
   41   
   42   import org.jboss.security.plugins.TransactionManagerLocator;
   43   
   44   
   45   /**
   46    * A JDBC based login module that supports authentication and role mapping.
   47    * It is based on two logical tables:
   48    * <ul>
   49    * <li>Principals(PrincipalID text, Password text)
   50    * <li>Roles(PrincipalID text, Role text, RoleGroup text)
   51    * </ul>
   52    * <p>
   53    * LoginModule options:
   54    * <ul>
   55    * <li><em>dsJndiName</em>: The name of the DataSource of the database
   56    * containing the Principals, Roles tables
   57    * <li><em>principalsQuery</em>: The prepared statement query, equivalent to:
   58    * <pre>
   59    *    "select Password from Principals where PrincipalID=?"
   60    * </pre>
   61    * <li><em>rolesQuery</em>: The prepared statement query, equivalent to:
   62    * <pre>
   63    *    "select Role, RoleGroup from Roles where PrincipalID=?"
   64    * </pre>
   65    * </ul>
   66    *
   67    * @author <a href="mailto:on@ibis.odessa.ua">Oleg Nitz</a>
   68    * @author Scott.Stark@jboss.org
   69    * @version $Revision: 86122 $
   70    */
   71   public class DatabaseServerLoginModule extends UsernamePasswordLoginModule
   72   {
   73      /** The JNDI name of the DataSource to use */
   74      protected String dsJndiName;
   75      /** The sql query to obtain the user password */
   76      protected String principalsQuery = "select Password from Principals where PrincipalID=?";
   77      /** The sql query to obtain the user roles */
   78      protected String rolesQuery = "select Role, RoleGroup from Roles where PrincipalID=?";
   79      /** Whether to suspend resume transactions during database operations */
   80      protected boolean suspendResume = true;
   81      
   82      protected String TX_MGR_JNDI_NAME = "java:/TransactionManager";
   83      
   84      protected TransactionManager tm = null;
   85   
   86      /**
   87       * Initialize this LoginModule.
   88       * 
   89       * @param options -
   90       * dsJndiName: The name of the DataSource of the database containing the
   91       *    Principals, Roles tables
   92       * principalsQuery: The prepared statement query, equivalent to:
   93       *    "select Password from Principals where PrincipalID=?"
   94       * rolesQuery: The prepared statement query, equivalent to:
   95       *    "select Role, RoleGroup from Roles where PrincipalID=?"
   96       */
   97      public void initialize(Subject subject, CallbackHandler callbackHandler,
   98         Map<String,?> sharedState, Map<String,?> options)
   99      {
  100         super.initialize(subject, callbackHandler, sharedState, options);
  101         dsJndiName = (String) options.get("dsJndiName");
  102         if( dsJndiName == null )
  103            dsJndiName = "java:/DefaultDS";
  104         Object tmp = options.get("principalsQuery");
  105         if( tmp != null )
  106            principalsQuery = tmp.toString();
  107         tmp = options.get("rolesQuery");
  108         if( tmp != null )
  109            rolesQuery = tmp.toString();
  110         tmp = options.get("suspendResume");
  111         if( tmp != null )
  112            suspendResume = Boolean.valueOf(tmp.toString()).booleanValue();
  113         if (log.isTraceEnabled())
  114         {
  115            log.trace("DatabaseServerLoginModule, dsJndiName="+dsJndiName);
  116            log.trace("principalsQuery="+principalsQuery);
  117            log.trace("rolesQuery="+rolesQuery);
  118            log.trace("suspendResume="+suspendResume);
  119         }
  120         //Get the Transaction Manager JNDI Name
  121         String jname = (String) options.get("transactionManagerJndiName");
  122         if(jname != null)
  123            this.TX_MGR_JNDI_NAME = jname;
  124         
  125         try
  126         {
  127            if(this.suspendResume)
  128               tm = this.getTransactionManager();
  129         }
  130         catch (NamingException e)
  131         {
  132            throw new RuntimeException("Unable to get Transaction Manager", e);
  133         }
  134      }
  135   
  136      /** Get the expected password for the current username available via
  137       * the getUsername() method. This is called from within the login()
  138       * method after the CallbackHandler has returned the username and
  139       * candidate password.
  140       * @return the valid password String
  141       */
  142      protected String getUsersPassword() throws LoginException
  143      {
  144         boolean trace = log.isTraceEnabled();
  145         String username = getUsername();
  146         String password = null;
  147         Connection conn = null;
  148         PreparedStatement ps = null;
  149         ResultSet rs = null;
  150         
  151         Transaction tx = null;
  152         if (suspendResume)
  153         {
  154            //tx = TransactionDemarcationSupport.suspendAnyTransaction();
  155            try
  156            {
  157               if(tm == null)
  158                  throw new IllegalStateException("Transaction Manager is null");
  159               tx = tm.suspend();
  160            }
  161            catch (SystemException e)
  162            {
  163               throw new RuntimeException(e);
  164            }
  165            if (trace)
  166               log.trace("suspendAnyTransaction");
  167         }
  168   
  169         try
  170         {
  171            InitialContext ctx = new InitialContext();
  172            DataSource ds = (DataSource) ctx.lookup(dsJndiName);
  173            conn = ds.getConnection();
  174            // Get the password
  175            if (trace)
  176               log.trace("Excuting query: "+principalsQuery+", with username: "+username);
  177            ps = conn.prepareStatement(principalsQuery);
  178            ps.setString(1, username);
  179            rs = ps.executeQuery();
  180            if( rs.next() == false )
  181            {
  182               if(trace)
  183                  log.trace("Query returned no matches from db");
  184               throw new FailedLoginException("No matching username found in Principals");
  185            }
  186            
  187            password = rs.getString(1);
  188            password = convertRawPassword(password);
  189            if(trace)
  190               log.trace("Obtained user password");
  191         }
  192         catch(NamingException ex)
  193         {
  194            LoginException le = new LoginException("Error looking up DataSource from: "+dsJndiName);
  195            le.initCause(ex);
  196            throw le;
  197         }
  198         catch(SQLException ex)
  199         {
  200            LoginException le = new LoginException("Query failed");
  201            le.initCause(ex);
  202            throw le;
  203         }
  204         finally
  205         {
  206            if (rs != null)
  207            {
  208               try
  209               {
  210                  rs.close();
  211               }
  212               catch(SQLException e)
  213               {}
  214            }
  215            if( ps != null )
  216            {
  217               try
  218               {
  219                  ps.close();
  220               }
  221               catch(SQLException e)
  222               {}
  223            }
  224            if( conn != null )
  225            {
  226               try
  227               {
  228                  conn.close();
  229               }
  230               catch (SQLException ex)
  231               {}
  232            }
  233            if (suspendResume)
  234            {
  235               //TransactionDemarcationSupport.resumeAnyTransaction(tx);
  236               try
  237               {
  238                  tm.resume(tx);
  239               }
  240               catch (Exception e)
  241               {
  242                  throw new RuntimeException(e);
  243               } 
  244               if (log.isTraceEnabled())
  245                  log.trace("resumeAnyTransaction");
  246            }
  247         }
  248         return password;
  249      }
  250   
  251      /** Execute the rolesQuery against the dsJndiName to obtain the roles for
  252       the authenticated user.
  253        
  254       @return Group[] containing the sets of roles
  255       */
  256      protected Group[] getRoleSets() throws LoginException
  257      {
  258         String username = getUsername();
  259         if (log.isTraceEnabled())
  260            log.trace("getRoleSets using rolesQuery: "+rolesQuery+", username: "+username);
  261         Group[] roleSets = Util.getRoleSets(username, dsJndiName, rolesQuery, this,
  262            suspendResume);
  263         return roleSets;
  264      }
  265      
  266      /** A hook to allow subclasses to convert a password from the database
  267       into a plain text string or whatever form is used for matching against
  268       the user input. It is called from within the getUsersPassword() method.
  269       @param rawPassword - the password as obtained from the database
  270       @return the argument rawPassword
  271       */
  272      protected String convertRawPassword(String rawPassword)
  273      {
  274         return rawPassword;
  275      }
  276      
  277      protected TransactionManager getTransactionManager() throws NamingException
  278      {
  279         TransactionManagerLocator tml = new TransactionManagerLocator();
  280         return tml.getTM(this.TX_MGR_JNDI_NAME);
  281      } 
  282   }

Save This Page
Home » JBoss-5.1.0 » org » jboss » security » auth » spi » [javadoc | source]