Tomcatで使用する認証レルムを作成します。
今回は、簡単なJDBCレルムに相当するJAVAクラスを作成して試してみます。
①開発環境(Eclipse)において、以下のJARファイルをビルドパスに通します。
・catalina.jar(C:\Program Files\Apache Software Foundation\Tomcat 6.0\lib配下)
・tomcat-juli.jar(C:\Program Files\Apache Software Foundation\Tomcat 6.0\bin配下)
②以下のようなJDBCレルムもどきのクラスを作成します。本来ならば、ユーザが入力したパスワードとMySQLのパスワードの比較処理において、ダイジェスト値を考慮したものにしないといけませんが、まずは平文パスワードの比較を試してみます。ポイントは以下です。
◎org.apache.catalina.realm.RealmBase抽象クラスを継承します。
◎server.xmlの<Realm>要素の属性として指定したものが、setXXXメソッドに渡ってきます。
(たとえば、connectionName属性の値は、setConnectionNameの引数に渡ってきます)
◎authenticateメソッドが認証処理を行うメインメソッドとなります。
◎getPassword、getPrincipal、getNameメソッドは必ず実装する必要があります。
--------------------------------------------------------------------------
package com.yosiyosi.realm;
import java.security.Principal;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.catalina.realm.RealmBase;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class CustomJDBCRealm extends RealmBase {
 private static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
   .getLog(CustomJDBCRealm.class);
 private Connection dbConnection = null;
 private PreparedStatement preparedAuthenticate = null;
 private PreparedStatement preparedRoles = null;
 protected String connectionURL = null;
 protected String connectionName = null;
 protected String connectionPassword = null;
 protected String userTable = null;
 protected String userNameCol = null;
 protected String userCredCol = null;
 protected String userRoleTable = null;
 protected String roleNameCol = null;
 protected String driverName = null;
 /**
  * JDBCドライバをセット
  * 
  * @param driverName
  */
 public void setDriverName(String driverName) {
  this.driverName = driverName;
 }
 /**
  * 接続先URLのセット
  * 
  * @param connectionURL
  */
 public void setConnectionURL(String connectionURL) {
  this.connectionURL = connectionURL;
 }
 /**
  * 接続用ユーザ名のセット
  * 
  * @param connectionName
  */
 public void setConnectionName(String connectionName) {
  this.connectionName = connectionName;
 }
 /**
  * 接続用パスワードのセット
  * 
  * @param connectionPassword
  */
 public void setConnectionPassword(String connectionPassword) {
  this.connectionPassword = connectionPassword;
 }
 /**
  * ユーザテーブル名のセット
  * 
  * @param userTable
  */
 public void setUserTable(String userTable) {
  this.userTable = userTable;
 }
 /**
  * ユーザテーブルのユーザカラム名のセット
  * 
  * @param userNameCol
  */
 public void setUserNameCol(String userNameCol) {
  this.userNameCol = userNameCol;
 }
 /**
  * ユーザテーブルのパスワードカラム名のセット
  * 
  * @param userCredCol
  */
 public void setUserCredCol(String userCredCol) {
  this.userCredCol = userCredCol;
 }
 /**
  * ロールテーブル名のセット
  * 
  * @param userRoleTable
  */
 public void setUserRoleTable(String userRoleTable) {
  this.userRoleTable = userRoleTable;
 }
 /**
  * ロールテーブルのロールカラム名のセット
  * 
  * @param roleNameCol
  */
 public void setRoleNameCol(String roleNameCol) {
  this.roleNameCol = roleNameCol;
 }
 /**
  * 認証に成功したら、Principalをかえす。 失敗したら、nullを返す
  */
 @Override
 public Principal authenticate(String user, String password) {
  // DBのパスワードを取得
  String dbPass = getPassword(user);
  // DBのロールリストを取得
  List<String> dbRole = getUserRoles(user);
  log.info("username=" + user + " password=" + password);
  log.info("DB password:" + dbPass);
  // 平文パスワードの比較
  if (dbPass != null && dbPass.equals(password)) {
   return new GenericPrincipal(this, user, dbPass, dbRole);
  }
  return null;
 }
 /**
  * 認証するユーザのパスワードをDB検索する。
  * 
  * @param username
  * @return パスワード
  */
 public synchronized String getPassword(String username) {
  try {
   // DBコネクションが確立されているかをチェック
   if (!checkConnection()) {
    return null;
   }
   if (preparedAuthenticate == null) {
    preparedAuthenticate = getPreparedPasswd(dbConnection);
   }
   // ユーザの検索
   preparedAuthenticate.setString(1, username);
   ResultSet rs1 = preparedAuthenticate.executeQuery();
   if (rs1.next()) {
    return rs1.getString(1).trim();
   }
   rs1.close();
   return null;
  } catch (SQLException ex) {
   ex.printStackTrace();
   close();
   return null;
  }
 }
 /**
  * 認証するユーザのロールをDB検索する。
  * 
  * @param username
  * @return ロールのリスト
  */
 public synchronized List<String> getUserRoles(String username) {
  try {
   // DBコネクションが確立されているかをチェック
   if (!checkConnection())
    return null;
   if (preparedRoles == null) {
    preparedRoles = getPreparedRoles(dbConnection);
   }
   // ロール検索
   preparedRoles.clearParameters();
   preparedRoles.setString(1, username);
   ResultSet rs = preparedRoles.executeQuery();
   List<String> vrol = new ArrayList<String>();
   while (rs.next()) {
    vrol.add(rs.getString(1).trim());
   }
   return vrol;
  } catch (SQLException ex) {
   ex.printStackTrace();
   close();
  }
  return null;
 }
 /**
  * パスワード検索用のSQL文の作成
  * 
  * @param conn
  * @return SQL文
  * @throws SQLException
  */
 protected PreparedStatement getPreparedPasswd(Connection conn)
   throws SQLException {
  String sql = "SELECT " + userCredCol + " FROM " + userTable + " WHERE "
    + userNameCol + " = ?";
  return conn.prepareStatement(sql);
 }
 /**
  * ロール検索用のSQL文の作成
  * 
  * @param conn
  * @return SQL文
  * @throws SQLException
  */
 protected PreparedStatement getPreparedRoles(Connection conn)
   throws SQLException {
  String sql = "SELECT " + roleNameCol + " FROM " + userRoleTable
    + " WHERE " + userNameCol + " = ?";
  return conn.prepareStatement(sql);
 }
 /**
  * DBへのコネクションが確立しているかをチェック
  * 
  * @return コネクションが確立されていたらtrue
  */
 private boolean checkConnection() {
  try {
   if ((dbConnection == null) || dbConnection.isClosed()) {
    Class.forName(driverName);
    dbConnection = DriverManager.getConnection(connectionURL,
      connectionName, connectionPassword);
    if (dbConnection == null || dbConnection.isClosed()) {
     return false;
    }
   }
   return true;
  } catch (SQLException ex) {
   ex.printStackTrace();
   close();
   return false;
  } catch (ClassNotFoundException ex) {
   throw new RuntimeException("CustomJDBCRealm.checkConnection: " + ex);
  }
 }
 /**
  * DB切断
  */
 private void close() {
  if (preparedRoles != null) {
   try {
    preparedRoles.close();
   } catch (Throwable t) {
    ;
   }
   preparedRoles = null;
  }
  if (preparedAuthenticate != null) {
   try {
    preparedAuthenticate.close();
   } catch (Throwable t) {
    ;
   }
   preparedAuthenticate = null;
  }
  if (dbConnection != null) {
   try {
    dbConnection.close();
   } catch (Throwable t) {
    ;
   }
   dbConnection = null;
  }
 }
 /**
  * 主体者情報を取得
  */
 protected Principal getPrincipal(String username) {
  return (new GenericPrincipal(this, username, getPassword(username),
    getUserRoles(username)));
 }
 @Override
 protected String getName() {
  // TODO Auto-generated method stub
  return null;
 }
}
----------------------------------------------------------------------------
③JAVAクラスを作成したら、JARファイルを作成します。作成したJARをC:\Program Files\Apache Software Foundation\Tomcat 6.0\libに格納します。
④server.xml(C:\Program Files\Apache Software Foundation\Tomcat 6.0\conf配下)を編集します。<Realm>要素のclassName属性をカスタマイズしたクラス名に修正します。
      <Realm className="com.yosiyosi.realm.CustomJDBCRealm"
             driverName="org.gjt.mm.mysql.Driver"
             connectionURL="jdbc:mysql://localhost:3306/bushido"
             userTable="auth_users" userNameCol="user_name" userCredCol="user_password"
             userRoleTable="auth_roles" roleNameCol="role_name"
             connectionName="root" connectionPassword="password"/>
⑤Tomcatを再起動します。
「http://127.0.0.1:8080/sampleapp/sample.html」にアクセスし、FORM認証が成功することを確認します。また、Tomcatのサーバログに、以下のログメッセージが表示されていることを確認し、カスタマイズしたJAVAクラスが使用されていることを確認します。
------------------------------------------------------------------
2011/11/12 23:05:44 com.yosiyosi.realm.CustomJDBCRealm authenticate
情報: username=hanako password=pass
2011/11/12 23:05:44 com.yosiyosi.realm.CustomJDBCRealm authenticate
情報: DB password:pass
------------------------------------------------------------------
 
0 件のコメント:
コメントを投稿