Package examples.security.rdbmsrealm

Source Code of examples.security.rdbmsrealm.RDBMSDelegate$Finished

package examples.security.rdbmsrealm;


import examples.security.util.RealmProperties;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.security.Principal;
import java.security.acl.Acl;
import java.security.acl.Group;
import java.security.acl.NotOwnerException;
import java.security.acl.Permission;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import weblogic.security.acl.AclEntryImpl;
import weblogic.security.acl.AclImpl;
import weblogic.security.acl.PermissionImpl;
import weblogic.security.acl.User;
import weblogic.security.acl.UserInfo;
import weblogic.utils.reuse.Factory;


/**
* The RDBMS delegate class.  An instance of this class communicates
* with a single database connection.  A pool of instacnes is then
* maintained by RDBMSRealm to provide high performance.
*
* @author Copyright (c) 1998-2000 by BEA Systems, Inc. All Rights Reserved.
*/
public class RDBMSDelegate
{
  // The following are some names that we look for in the property file.

  static final String DRIVER            = "driver";
  static final String DB_URL            = "dbURL";
  static final String DB_USER           = "dbUser";
  static final String DB_PASSWORD       = "dbPassword";

  /**
   * The realm with which this delegate is associated.
   */
  protected RDBMSRealm realm;
 
  /**
   * The main connection to the database.
   */
  protected Connection conn;

  // We use multiple connections for JDBC drivers that can't handle
  // multiple open result sets on a single connection.

  protected Connection conn2;
  protected Connection conn3;
  protected Connection conn4;

  private RealmProperties properties;
 
  // We maintain a number of prepared SQL statements for performing
  // database lookups.
 
  private PreparedStatement getUserStmt;
  private PreparedStatement getGroupMembersStmt;
  private PreparedStatement getPermissionStmt;
  private PreparedStatement getAclEntriesStmt;
  private PreparedStatement getUsersStmt;
  private PreparedStatement getGroupsStmt;
  private PreparedStatement getAclsStmt;
  private PreparedStatement getPermissionsStmt;

  private PreparedStatement newUserStmt;
  private PreparedStatement addGroupMemberStmt;

  private PreparedStatement removeGroupMemberStmt;
 
  private PreparedStatement deleteUserStmt1;
  private PreparedStatement deleteUserStmt2;
  private PreparedStatement deleteUserStmt3;

  private PreparedStatement deleteGroupStmt1;
  private PreparedStatement deleteGroupStmt2;

  /**
   * Determine whether or not we need to create a new SQL statement
   * for recursive calls to getGroup.  Some servers need this, and
   * some don't.
   */
  private boolean getGroupNewStatement;
 
  /**
   * This is the bogus owner associated with all ACLs found in the
   * database.
   */
  protected Principal aclOwner = new User("unperson");


  /**
   * A shorthand convenience function for preparing an SQL statement.
   *
   * @param name the name of the statement to prepare
   */
  protected PreparedStatement prepare(String propKey)
    throws SQLException, RDBMSException
  {
    String sqlStr = properties.get(propKey);
    if (sqlStr == null)
    {
      throw new RDBMSException("realm initialization failed, could not find property '" +
                               propKey + "' in properties file " +
             RDBMSRealm.RDBMS_PROPS);
    }
    return conn.prepareStatement(sqlStr);
  }


  /**
   * Create a new delegate, associated with the given realm.
   *
   * @exception RDBMSException an error occurred in fetching
   * properties or communicating with the database
   */
  protected RDBMSDelegate(RDBMSRealm realm)
  {
    this.realm = realm;

    if (realm.log != null)
      realm.log.debug("loading realm properties: " + RDBMSRealm.RDBMS_PROPS);

    try
    {
      properties = new RealmProperties(RDBMSRealm.class, RDBMSRealm.RDBMS_PROPS);
    }
    catch (IOException e)
    {
      throw new RDBMSException("could not find properties", e);
    }

    getGroupNewStatement = properties.getBoolean("getGroupNewStatement", true);

    String action = "properties.get";    // used to help diagnose an exception

    try
    {
      String driver = properties.get(DRIVER);
     
      if (realm.log != null)
  realm.log.debug("driver is " + driver);

      action = "driver.newInstance()";
      Class.forName(driver).newInstance();

      action = "properties.get";
      String url = properties.get(DB_URL);
      String user = properties.get(DB_USER);
      String passwd = properties.get(DB_PASSWORD);
     
      if (realm.log != null)
  realm.log.debug("connecting to " + url);

      action = "DriverManager.getConnection";
      conn = DriverManager.getConnection(url, user, passwd);
    }
    catch (Exception e)
    {
      throw new RDBMSException("realm initialization failed, action '" +
             action + "', ", e);
    }

    // pkey is only used to help diagnose an SQLException; prepare()
    // generates an RDBMSException if the property key is not found.

    String pkey = null;

    try
    {
      if (realm.log != null)
  realm.log.debug("preparing statements from " + RDBMSRealm.RDBMS_PROPS);

      getUserStmt = prepare(pkey = "getUser");
      getAclEntriesStmt = prepare(pkey = "getAclEntries");
      getUsersStmt = prepare(pkey = "getUsers");
      getGroupsStmt = prepare(pkey = "getGroups");
      getAclsStmt = prepare(pkey = "getAcls");
      getPermissionStmt = prepare(pkey = "getPermission");
      getPermissionsStmt = prepare(pkey = "getPermissions");

      if (getGroupNewStatement == false)
      {
  getGroupMembersStmt = prepare(pkey = "getGroupMembers");
      }

      newUserStmt = prepare(pkey = "newUser");
      addGroupMemberStmt = prepare(pkey = "addGroupMember");

      removeGroupMemberStmt = prepare(pkey = "removeGroupMember");
      deleteUserStmt1 = prepare(pkey = "deleteUser1");
      deleteUserStmt2 = prepare(pkey = "deleteUser2");
      deleteUserStmt3 = prepare(pkey = "deleteUser3");

      deleteGroupStmt1 = prepare(pkey = "deleteGroup1");
      deleteGroupStmt2 = prepare(pkey = "deleteGroup2");
    }
    catch (SQLException se)
    {
      String sqlStr = properties.get(pkey)// this call will succeed, it has already worked in prepare()
      throw new RDBMSException("realm initialization failed, Connection.prepareStatement() failed on statement \"" +
                               sqlStr + "\", ", se);
    }
  }


  /**
   * We use this class to indicate to a caller that a method has
   * reached the end of a ResultSet.  This is <i>not</i> an indication
   * of error; it's just a slightly uncommon (in Java, anyway) way of
   * returning more than one value.
   */
  protected static class Finished
    extends Throwable
  {
    /**
     * The value associated with this object.
     */
    private Object value;


    /**
     * Create a new object, with given value.
     */
    Finished(Object value)
    {
      this.value = value;
    }


    /**
     * Return the value associated with this object.
     */
    Object getValue()
    {
      return value;
    }
  }

 
  /**
   * Get a user from the database, or null if the user doesn't exist.
   */
  public User getUser(String name)
    throws SQLException
  {
    if (realm.log != null)
      realm.log.debug("getUser(\"" + name + "\")");
   
    getUserStmt.setString(1, name);

    ResultSet rs = getUserStmt.executeQuery();

    try
    {
      // If the ResultSet is empty, the user doesn't exist in the
      // database.
     
      return rs.next()
  ? realm.createUser(rs.getString(1), rs.getString(2)) : null;
    }
    finally
    {
      // Politely clean up after ourselves.
     
      rs.close();
    }
  }


  /**
   * Get all users from the database.
   */
  public Enumeration getUsers()
    throws SQLException
  {
    if (realm.log != null)
      realm.log.debug("getUsers()");

    ResultSet rs = getUsersStmt.executeQuery();
    Vector users = new Vector(1);

    try
    {
      while (rs.next())
      {
  users.addElement(realm.createUser(rs.getString(1), rs.getString(2)));

      }

      return users.elements();
    }
    finally
    {
      rs.close();
    }
  }

 
  /**
   * Get the named group from the database, or null if it doesn't
   * exist.
   */
  public Group getGroup(String name)
    throws SQLException
  {
    if (realm.log != null)
      realm.log.debug("getGroup(\"" + name + "\")");

    // If getGroupNewStatement is enabled, this may incur more
    // overhead than it needs to, because it creates a new
    // PreparedStatement that is only used once.
   
    PreparedStatement stmt = getGroupNewStatement
      ? prepare("getGroupMembers")
      : getGroupMembersStmt;

    stmt.setString(1, name);

    ResultSet rs = stmt.executeQuery();

    try
    {
      return rs.next() ? getGroupInternal(name, rs) : null;
     
    }
    catch (Finished f)
    {
      // If getGroupInternal threw us a Finished object, we just
      // return the value inside it.

      return (RDBMSGroup) f.getValue();
    }
    finally
    {
      rs.close();

      if (getGroupNewStatement)
      {
  stmt.close();
      }
    }
  }


  /**
   * Get all groups from the database.  Note that in this realm, empty
   * groups cannot currently exist.
   */
  public Enumeration getGroups()
    throws SQLException
  {
    if (realm.log != null)
      realm.log.debug("getGroups()");

    ResultSet rs = getGroupsStmt.executeQuery();
    Vector groups = new Vector(1);

    try
    {
      // We loop forever until getGroupInternal throws a Finished
      // object to let us know that we've reached the end of the
      // ResultSet.

      if (rs.next())
      {
  while (true)
  {
    groups.addElement(getGroupInternal(null, rs));
  }
      }
    }
    catch (Finished f)
    {
      // Add the last element to the set of groups.
     
      groups.addElement(f.getValue());
    }
    finally
    {
      rs.close();
    }

    return groups.elements();
  }

 
  public User newUser(String name, String passwd)
    throws SQLException, SecurityException
  {
    if (realm.log != null)
      realm.log.debug("newUser(\"" + name + "\", \"" + passwd + "\")");

    if (getUser(name) != null)
    {
      throw new SecurityException("user \"" + name + "\" already exists");
    }
   
    newUserStmt.setString(1, name);
    newUserStmt.setString(2, passwd);

    int rows = newUserStmt.executeUpdate();

    if (rows != 1)
    {
      throw new RDBMSException("insert updated " + rows + " rows (should be 1)");
    }
   
    return realm.createUser(name, passwd);
  }


  public void deleteUser(User user)
    throws SQLException
  {
    String name = user.getName();

    deleteUserStmt1.setString(1, name);
    deleteUserStmt2.setString(1, name);
    deleteUserStmt3.setString(1, name);

    deleteUserStmt1.executeUpdate();
    deleteUserStmt2.executeUpdate();
    deleteUserStmt3.executeUpdate();
  }
 

  public void deleteGroup(Group group)
    throws SQLException
  {
    String name = group.getName();

    deleteGroupStmt1.setString(1, name);
    deleteGroupStmt2.setString(1, name);

    deleteGroupStmt1.executeUpdate();
    deleteGroupStmt2.executeUpdate();
  }
 

  /**
   * This method is called both by getGroup and getGroups.  It looks
   * through the given ResultSet and gathers group members until it
   * either hits a differently-named group or the end of the
   * ResultSet.
   */
  protected Group getGroupInternal(String name, ResultSet rs)
    throws Finished, SQLException
  {
    // All of the other methods in this class with similar names are
    // patterned after this one.

    // We expect the ResultSet that we are reading to cluster all the
    // members of a given group together in contiguous rows.  If this
    // is not the case, this code will fail miserably.

    Hashtable members = new Hashtable();
    boolean more = true;

    // We expect our ResultSet to already point at the first member of
    // a group, hence this being a "do ... while" loop.
    do
    {
      String groupName = rs.getString(1);
      String memberName = rs.getString(2);
   
      if (name == null)
      {
  name = groupName;
      }
      else if (groupName.equals(name) == false)
      {
  // We've encountered a group with a different name than the
  // one we were interested in, so we're done for the current
  // invocation.

  break;
      }

      Principal p = getPrincipal(memberName);

      if (p == null)
      {
  throw new RDBMSException("group \"" + name + "\" contains nonexistent " +
         "principal \"" + memberName + "\"");
      }
     
      members.put(memberName, p);
    } while (more = rs.next());

    RDBMSGroup result = realm.createGroup(name, members);
   
    // Sanity-check the new group to ensure that it doesn't contain
    // any groups that contain it.  You can turn this off if your
    // database can't get corrupted in this way.
   
    if (true)
    {
      Enumeration enum = members.elements();
   
      while (enum.hasMoreElements())
      {
  Object obj = enum.nextElement();

  if (obj instanceof Group)
  {
    Group g = (Group) obj;

    if (g.isMember(result))
    {
      throw new RDBMSException("group membership circularity between \"" +
             g.getName() + "\" and \"" + name + "\"");
    }
  }
      }
    }

    if (more == false)
    {
      // We've hit the end of the ResultSet, so let our caller know.
     
      throw new Finished(result);
    }
   
    // We have not hit the end of the ResultSet, so just return
    // normally.
   
    return result;
  }

 
  public boolean addGroupMember(RDBMSGroup group, Principal member)
    throws SQLException
  {
    addGroupMemberStmt.setString(1, group.getName());
    addGroupMemberStmt.setString(2, member.getName());

    int rows = addGroupMemberStmt.executeUpdate();

    if (rows != 1)
    {
      throw new RDBMSException("insert updated " + rows + " rows (should be 1)");
    }

    return true;
  }

 
  public boolean removeGroupMember(RDBMSGroup group, Principal member)
    throws SQLException
  {
    removeGroupMemberStmt.setString(1, group.getName());
    removeGroupMemberStmt.setString(2, member.getName());

    int rows = removeGroupMemberStmt.executeUpdate();

    if (rows != 1)
    {
      throw new RDBMSException("delete updated " + rows + " rows (should be 1)");
    }

    return true;
  }
 

  /**
   * Get an ACL from the database, or null if the ACL doesn't exist.
   */
  public Acl getAcl(String name)
    throws SQLException
  {
    if (realm.log != null)
      realm.log.debug("getAcl(\"" + name + "\")");

    getAclEntriesStmt.setString(1, name);

    ResultSet rs = getAclEntriesStmt.executeQuery();

    try
    {
      return rs.next() ? getAclInternal(name, rs) : null;
    }
    catch (Finished f)
    {
      return (Acl) f.getValue();
    }
    finally
    {
      rs.close();
    }
  }


  /**
   * Get all ACLs from the database.
   */
  public Enumeration getAcls()
    throws SQLException
  {
    if (realm.log != null)
      realm.log.debug("getAcls()");

    ResultSet rs = getAclsStmt.executeQuery();
    Vector acls = new Vector(1);
   
    try
    {
      if (rs.next())
      {
  while (true)
  {
    acls.addElement(getAclInternal(null, rs));
  }
      }
    }
    catch (Finished f)
    {
      acls.addElement(f.getValue());
    }
    finally
    {
      rs.close();
    }

    return acls.elements();
  }

 
  /**
   * Called by both getAcl and getAcls.
   */
  protected Acl getAclInternal(String name, ResultSet rs)
    throws Finished, SQLException
  {
    // This method follows a similar pattern to getGroupInternal, but
    // has the added twist that it expects rows for a given ACL to be
    // grouped together by principal.

    boolean more = true;
   
    AclImpl result = new AclImpl(aclOwner, null);
    AclEntryImpl entry = null;
    String currentPrincipal = null;

    try
    {
      do
      {
  String aclName = rs.getString(1);
  String principal = rs.getString(2);
  String permission = rs.getString(3);

  if (name == null)
  {
    name = aclName;
  }
  else if (aclName.equals(name) == false)
  {
    break;
  }
     
  if (currentPrincipal == null || currentPrincipal.equals(principal) == false)
  {
    // We're dealing with a new principal, so create a new AclEntry.
   
    currentPrincipal = principal;

    // There's an ordering constraint imposed here by the
    // AclImpl implementation: we must add all the Permissions
    // we will need to an AclEntry before adding the AclEntry to
    // the Acl.

    if (entry != null)
    {
      result.addEntry(aclOwner, entry);
    }

    Principal p = getPrincipal(principal);
   
    if (p == null)
    {
      throw new RDBMSException("acl \"" + name + "\" contains nonexistent " +
             "principal \"" + principal + "\"");
    }
   
    entry = new AclEntryImpl(p);
  }

  entry.addPermission(new PermissionImpl(permission));
      } while (more = rs.next());

      if (entry != null)
      {
  result.addEntry(aclOwner, entry);
      }
     
      result.setName(aclOwner, name);
    }
    catch (NotOwnerException e)
    {
      throw new RDBMSException("caught unexpected exception", e);
    }

    if (more == false)
    {
      throw new Finished(result);
    }

    return result;
  }


  /**
   * Resolve a name to a User or Group.  If the principal in question
   * doesn't exist in the database, we return null.
   */
  public Principal getPrincipal(String name)
    throws SQLException
  {
    Principal result = getUser(name);

    if (result == null)
    {
      result = getGroup(name);
    }

    return result;
  }

 
  /**
   * Obtain the named permission from the database, or null if none.
   */
  public Permission getPermission(String name)
    throws SQLException
  {
    if (realm.log != null)
      realm.log.debug("getPermission(\"" + name + "\")");

    getPermissionStmt.setString(1, name);

    ResultSet rs = getPermissionStmt.executeQuery();

    try
    {
      return rs.next() ? new PermissionImpl(rs.getString(1)) : null;
    }
    finally
    {
      rs.close();
    }
  }

 
  /**
   * Return an Enumeration of the permissions for this realm.
   */
  public Enumeration getPermissions()
    throws SQLException
  {
    if (realm.log != null)
      realm.log.debug("getPermissions()");

    ResultSet rs = getPermissionsStmt.executeQuery();
    Vector permissions = new Vector(1);

    try
    {
      while (rs.next())
      {
  permissions.addElement(new PermissionImpl(rs.getString(1)));
      }

      return permissions.elements();
    }
    finally
    {
      rs.close();
    }
  }


  /**
   * Clean up after ourselves.
   */
  protected void finalize()
  {
    close();
  }

 
  /**
   * Clean up after ourselves.
   */
  public void close()
  {
    try
    {
      try
      {
  if (conn != null)
    conn.close();
      }
      catch (SQLException e)
      {
  // ignore
      }
      try
      {
  if (conn2 != null)
    conn2.close();
      }
      catch (SQLException e)
      {
  // ignore
      }
      try
      {
  if (conn3 != null)
    conn3.close();
      }
      catch (SQLException e)
      {
  // ignore
      }
      try
      {
  if (conn4 != null)
    conn4.close();
      }
      catch (SQLException e)
      {
  // ignore
      }
    }
    finally
    {
      realm = null;
     
      conn = null;
      conn2 = null;
      conn3 = null;
      conn4 = null;

      getUserStmt = null;
      getGroupMembersStmt = null;
      getPermissionStmt = null;
      getAclEntriesStmt = null;
      getUsersStmt = null;
      getGroupsStmt = null;
      getAclsStmt = null;
      getPermissionsStmt = null;
    }
  }

 
  /**
   * This is the factory class that creates instances of the
   * RDBMSDelegate class for pooling.
   */
  static class DFactory implements Factory
  {
    /**
     * The realm that owns all delegates created by this factory.
     */
    private RDBMSRealm owner;

    /**
     * Create an instance of the factory, owned by the given realm.
     */
    DFactory(RDBMSRealm owner)
    {
      this.owner = owner;
    }

    /**
     * Create a new delegate.
     */
    public Object newInstance()
      throws InvocationTargetException
    {
      if (owner.log != null)
  owner.log.debug("new instance");

      return new RDBMSDelegate(owner);
    }

    /**
     * Destroy a delegate.
     */
    public void destroyInstance(Object obj)
    {
      if (owner.log != null)
  owner.log.debug("destroy instance");

      ((RDBMSDelegate) obj).close();
    }
  }
}
TOP

Related Classes of examples.security.rdbmsrealm.RDBMSDelegate$Finished

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.