Реализация Tomcat Realm с аутентификацией LDAP и авторизацией JDBC - PullRequest
9 голосов
/ 16 июля 2009

Я работаю в устаревшей среде, где сервер LDAP используется только для аутентификации и не содержит ролей, а авторизация выполняется для базы данных, которая содержит сопоставление ролей пользователей, но без паролей.

Мой план состоит в том, чтобы внедрить новую область Tomcat, расширив JNDIRealm и переопределив методы роли для вызова инкапсулированного JDBCRealm.

Моя область объявлена ​​в server.xml:

<Realm className="com.example.LdapJdbcRealm"
   connectionURL="ldap://ldaphost:389"
   resourceName="LDAP Auth"
   userPattern="uid={0}, ou=Portal, dc=example, dc=com"
   dbConnectionURL="jdbc:oracle:thin:@oracledb:1521:dbname"
   userTable="db_user" userNameCol="user_id"
   userRoleTable="db_user_role_xref" roleNameCol="role_id" />

Это комбинация стандартных имен свойств для JNDIRealm и JDBCRealm, с небольшим изменением, так как они оба используют connectionURL.

package com.example;

import org.apache.catalina.Realm;
import org.apache.catalina.Context;
import org.apache.catalina.deploy.SecurityConstraint;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.realm.JNDIRealm;
import org.apache.catalina.realm.JDBCRealm;

import java.security.Principal;
import java.io.IOException;

public class LdapJdbcRealm extends JNDIRealm implements Realm
{
    private JDBCRealm jdbcRealm = new JDBCRealm();

    protected static final String info = "com.example.LdapJdbcRealm/1.0";
    protected static final String name = "LdapJdbcRealm";

    public String getDbConnectionURL() {
        return jdbcRealm.getConnectionURL();
    }

    public void setDbConnectionURL(String dbConnectionURL) {
        jdbcRealm.setConnectionURL(dbConnectionURL);
    }

    public String getUserTable() {
        return jdbcRealm.getUserTable();
    }

    public void setUserTable(String userTable) {
        jdbcRealm.setUserTable(userTable);
    }

    public String getUserNameCol() {
        return jdbcRealm.getUserNameCol();
    }

    public void setUserNameCol(String userNameCol) {
        jdbcRealm.setUserNameCol(userNameCol);
    }

    public String getUserRoleTable() {
        return jdbcRealm.getUserRoleTable();
    }

    public void setUserRoleTable(String userRoleTable) {
        jdbcRealm.setUserRoleTable(userRoleTable);
    }

    public String getRoleNameCol() {
        return jdbcRealm.getRoleNameCol();
    }

    public void setRoleNameCol(String roleNameCol) {
        jdbcRealm.setRoleNameCol(roleNameCol);
    }

    public boolean hasResourcePermission(Request request,
                                         Response response,
                                         SecurityConstraint[]constraints,
                                         Context context) throws IOException
    {
        return jdbcRealm.hasResourcePermission(request, response, constraints, context);
    }

    public boolean hasRole(Principal principal, String role) {
        return jdbcRealm.hasRole(principal, role);
    }
}

В основном это работает, авторизация возвращает принципала из LDAP, который не имеет должных ролей. Тот же Принципал входит в hasResourcePermission() и терпит неудачу, потому что у него нет требуемых ролей в нем. Очевидно, я упускаю какой-то важный код.

Я ищу решения. Я мог бы попытаться расширить JDBCRealm и добавить аутентификацию LDAP, но это похоже на дополнительную работу.

Я также считаю, что эта аутентификация LDAP / авторизация БД не является необычной схемой. Есть ли альтернативное решение уже доступно?

В мои полномочия входит , а не - добавлять роли в LDAP или пароли в БД, поэтому для меня это не решение.

Ответы [ 2 ]

13 голосов
/ 23 февраля 2010

Я по-прежнему получаю электронные письма по этому вопросу с регулярной периодичностью, поэтому вот конечный продукт для всех.


LdapJdbcRealm.java

<code>package org.apache.catalina.realm;

import org.apache.catalina.Realm;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.deploy.SecurityConstraint;

import javax.naming.directory.DirContext;
import java.io.IOException;
import java.security.Principal;
import java.util.List;

/**
 * LdapJdbcRealm is a minimal implementation of a <b>Realm</b> to connect to LDAP
 * for authentication and a database for authorization.<br>
 * <br>
 * Example server.xml configuration fragment:<br>
 * <pre>
   &lt;Realm className="org.apache.catalina.realm.LdapJdbcRealm"
      connectionURL="ldap://ldaphost:389"
      resourceName="LDAP Auth" driverName="oracle.jdbc.driver.OracleDriver"
      userPattern="uid={0}, ou=Portal, dc=example, dc=com"
      dbConnectionName="dbuser" dbConnectionPassword="dbpassword"
      dbConnectionURL="jdbc:oracle:thin:@oracledb:1521:dbname"
      userTable="users" userNameCol="user_id"
      userRoleTable="user_role_xref" roleNameCol="role_id" /&gt;
 * 
* * @author Грег Чабала * * Создано IntelliJ IDEA. * Пользователь: gchabala * Дата: 14 июля 2009 г. * Время: 16:56:37 * / открытый класс LdapJdbcRealm расширяет JNDIRealm реализует Realm { / ** * Encapsulated JDBCRealm для поиска ролей * / приватный JDBCRealm jdbcRealm = new JDBCRealm (); / ** * Описательная информация об этой Realm реализации. * / защищенная статическая конечная строка String info = "org.apache.catalina.realm.LdapJdbcRealm / 1.0"; / ** * Описательная информация об этой Realm реализации. * / защищенная статическая конечная строка имя = "LdapJdbcRealm"; / ** * Установите режим всех ролей. * * @param allRolesMode режим аутентификации * / public void setAllRolesMode (String allRolesMode) { super.setAllRolesMode (allRolesMode); jdbcRealm.setAllRolesMode (allRolesMode); } / ** * Вернуть имя пользователя, чтобы использовать для подключения к базе данных. * * @return имя пользователя * @see JDBCRealm # getConnectionName () * / public String getDbConnectionName () { return jdbcRealm.getConnectionName (); } / ** * Установите имя пользователя для подключения к базе данных. * * @param dbConnectionName имя пользователя * @see JDBCRealm # setConnectionName (String) * / public void setDbConnectionName (String dbConnectionName) { jdbcRealm.setConnectionName (dbConnectionName); } / ** * Верните пароль, чтобы использовать для подключения к базе данных. * * @ вернуть пароль * @see JDBCRealm # getConnectionPassword () * / public String getDbConnectionPassword () { return jdbcRealm.getConnectionPassword (); } / ** * Установите пароль, чтобы использовать для подключения к базе данных. * * @param dbConnectionPassword пароль * @see JDBCRealm # setConnectionPassword (String) * / public void setDbConnectionPassword (String dbConnectionPassword) { jdbcRealm.setConnectionPassword (dbConnectionPassword); } / ** * Вернуть URL-адрес, чтобы использовать для подключения к базе данных. * * URL возврата базы данных * @see JDBCRealm # getConnectionURL () * / public String getDbConnectionURL () { return jdbcRealm.getConnectionURL (); } / ** * Установите URL-адрес для подключения к базе данных. * * @param dbConnectionURL URL нового соединения * @see JDBCRealm # setConnectionURL (String) * / public void setDbConnectionURL (String dbConnectionURL) { jdbcRealm.setConnectionURL (dbConnectionURL); } / ** * Верните драйвер JDBC, который будет использоваться. * * @return имя класса водителя * @see JDBCRealm # getDriverName () * / public String getDriverName () { return jdbcRealm.getDriverName (); } / ** * Установите драйвер JDBC, который будет использоваться. * * @param driverName Имя драйвера * @see JDBCRealm # setDriverName (String) * / public void setDriverName (String driverName) { jdbcRealm.setDriverName (DriverName); } / ** * Вернуть таблицу, которая содержит данные пользователя. * * @ возвращаем имя таблицы * @see JDBCRealm # getUserTable () * / public String getUserTable () { return jdbcRealm.getUserTable (); } / ** * Установите таблицу, которая содержит пользовательские данные. * * @param userTable Имя таблицы * @see JDBCRealm # setUserTable (String) * / public void setUserTable (String userTable) { jdbcRealm.setUserTable (userTable); } / ** * Вернуть столбец в пользовательской таблице, который содержит имя пользователя. * * @return username имя столбца базы данных * @see JDBCRealm # getUserNameCol () * / public String getUserNameCol () { return jdbcRealm.getUserNameCol (); } / *** Установите столбец в пользовательской таблице, который содержит имя пользователя. * * @param userNameCol Имя столбца * @see JDBCRealm # setUserNameCol (String) * / public void setUserNameCol (String userNameCol) { jdbcRealm.setUserNameCol (userNameCol); } / ** * Вернуть таблицу, которая содержит отношения между пользователем и ролями. * * @return имя таблицы базы данных ролей пользователей * @see JDBCRealm # getUserRoleTable () * / public String getUserRoleTable () { return jdbcRealm.getUserRoleTable (); } / ** * Установите таблицу, которая содержит отношения между пользователем и ролями. * * @param userRoleTable Имя таблицы * @see JDBCRealm # setUserRoleTable (String) * / public void setUserRoleTable (String userRoleTable) { jdbcRealm.setUserRoleTable (userRoleTable); } / ** * Вернуть столбец в таблице ролей пользователей, в которой указаны роли. * * @ возвращение имени столбца роли * @see JDBCRealm # getRoleNameCol () * / public String getRoleNameCol () { return jdbcRealm.getRoleNameCol (); } / ** * Установите столбец в таблице ролей пользователей, который называет роль. * * @param roleNameCol Имя столбца * @see JDBCRealm # setRoleNameCol (String) * / public void setRoleNameCol (String roleNameCol) { jdbcRealm.setRoleNameCol (roleNameCol); } @Override public SecurityConstraint [] findSecurityConstraints (запрос запроса, контекстный контекст) { return jdbcRealm.findSecurityConstraints (запрос, контекст); } @Override public boolean hasUserDataPermission (Запрос запроса, Ответный ответ, SecurityConstraint [] ограничения) выдает IOException { return jdbcRealm.hasUserDataPermission (запрос, ответ, ограничения); } @Override public boolean hasResourcePermission (Запрос запроса, Ответный ответ, SecurityConstraint [] ограничение, Контекстный контекст) выдает IOException { return jdbcRealm.hasResourcePermission (запрос, ответ, ограничения, контекст); } @Override public boolean hasRole (Принципал, Строковая роль) { return jdbcRealm.hasRole (принципал, роль); } / ** * Вернуть список ролей, связанных с данным пользователем. Если нет ролей * связаны с этим пользователем, возвращается список нулевой длины. * * @param context не используется. JDBC не нуждается в этом поле. * @param user Пользователь, который будет проверен * @ вернуть список ролей * * @see JNDIRealm # getRoles (DirContext, Пользователь) * @see JDBCRealm # getRoles (String) * / @Override Защищенный список getRoles (контекст DirContext, пользователь пользователя) { return jdbcRealm.getRoles (user.username); } }
5 голосов
/ 16 июля 2009

Вы не указали версию Tomcat, которую вы используете, поэтому я собираюсь использовать 6.x здесь.

Похоже, что вы делегируете hasResourcePermission в JDBC, а findSecurityConstraints и hasUserDataPermission остаются в руках JNDI. Вы должны делегировать их всех или ни одного из них.

Обновление : JNDIRealm вызывает protected getRoles(DirContext, User) как часть его authenticate() метода. Вам необходимо переопределить это и переслать его в JDBCRealm getRoles().

...