2009-07-16 5 views
9

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

Мой план состоит в том, чтобы реализовать новое царство 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 или пароли к БД, поэтому для меня это не решения.

+0

Да, я работаю с Tomcat 6.0.18 –

ответ

5

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

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

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

+0

Я переопределены findSecurityConstraints() & hasUserDataPermission() вызвать хотя JDBCRealm. Однако функция getRoles() JDBCRealm защищена. Как вы предлагаете я это называю? –

+1

У вас есть 3 варианта: использовать отражение ('Method.setAccessible()' поможет с 'protected'), переместить реализацию вашего царства в пакет' org.apache.catalina.realm' или полностью отказаться от JDBCRealm и написать свой собственный код для извлекать роли из базы данных). – ChssPly76

+0

Переезд в пакет org.apache.catalina.realm работал очень хорошо. Я также забыл указать драйвер, поэтому я добавил для него геттеры и сеттеры, а также пользователя и пароль БД. Все хорошо работает сейчас, спасибо. –

13

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


LdapJdbcRealm.java

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; 
* </pre> 
* 
* @author Greg Chabala 
* 
* Created by IntelliJ IDEA. 
* User: gchabala 
* Date: Jul 14, 2009 
* Time: 4:56:37 PM 
*/ 
public class LdapJdbcRealm extends JNDIRealm implements Realm 
{ 
    /** 
    * Encapsulated <b>JDBCRealm</b> to do role lookups 
    */ 
    private JDBCRealm jdbcRealm = new JDBCRealm(); 

    /** 
    * Descriptive information about this <b>Realm</b> implementation. 
    */ 
    protected static final String info = "org.apache.catalina.realm.LdapJdbcRealm/1.0"; 

    /** 
    * Descriptive information about this <b>Realm</b> implementation. 
    */ 
    protected static final String name = "LdapJdbcRealm"; 

    /** 
    * Set the all roles mode. 
    * 
    * @param allRolesMode authentication mode 
    */ 
    public void setAllRolesMode(String allRolesMode) { 
     super.setAllRolesMode(allRolesMode); 
     jdbcRealm.setAllRolesMode(allRolesMode); 
    } 

    /** 
    * Return the username to use to connect to the database. 
    * 
    * @return username 
    * @see JDBCRealm#getConnectionName() 
    */ 
    public String getDbConnectionName() { 
     return jdbcRealm.getConnectionName(); 
    } 

    /** 
    * Set the username to use to connect to the database. 
    * 
    * @param dbConnectionName username 
    * @see JDBCRealm#setConnectionName(String) 
    */ 
    public void setDbConnectionName(String dbConnectionName) { 
     jdbcRealm.setConnectionName(dbConnectionName); 
    } 

    /** 
    * Return the password to use to connect to the database. 
    * 
    * @return password 
    * @see JDBCRealm#getConnectionPassword() 
    */ 
    public String getDbConnectionPassword() { 
     return jdbcRealm.getConnectionPassword(); 
    } 

    /** 
    * Set the password to use to connect to the database. 
    * 
    * @param dbConnectionPassword password 
    * @see JDBCRealm#setConnectionPassword(String) 
    */ 
    public void setDbConnectionPassword(String dbConnectionPassword) { 
     jdbcRealm.setConnectionPassword(dbConnectionPassword); 
    } 

    /** 
    * Return the URL to use to connect to the database. 
    * 
    * @return database connection URL 
    * @see JDBCRealm#getConnectionURL() 
    */ 
    public String getDbConnectionURL() { 
     return jdbcRealm.getConnectionURL(); 
    } 

    /** 
    * Set the URL to use to connect to the database. 
    * 
    * @param dbConnectionURL The new connection URL 
    * @see JDBCRealm#setConnectionURL(String) 
    */ 
    public void setDbConnectionURL(String dbConnectionURL) { 
     jdbcRealm.setConnectionURL(dbConnectionURL); 
    } 

    /** 
    * Return the JDBC driver that will be used. 
    * 
    * @return driver classname 
    * @see JDBCRealm#getDriverName() 
    */ 
    public String getDriverName() { 
     return jdbcRealm.getDriverName(); 
    } 

    /** 
    * Set the JDBC driver that will be used. 
    * 
    * @param driverName The driver name 
    * @see JDBCRealm#setDriverName(String) 
    */ 
    public void setDriverName(String driverName) { 
     jdbcRealm.setDriverName(driverName); 
    } 

    /** 
    * Return the table that holds user data.. 
    * 
    * @return table name 
    * @see JDBCRealm#getUserTable() 
    */ 
    public String getUserTable() { 
     return jdbcRealm.getUserTable(); 
    } 

    /** 
    * Set the table that holds user data. 
    * 
    * @param userTable The table name 
    * @see JDBCRealm#setUserTable(String) 
    */ 
    public void setUserTable(String userTable) { 
     jdbcRealm.setUserTable(userTable); 
    } 

    /** 
    * Return the column in the user table that holds the user's name. 
    * 
    * @return username database column name 
    * @see JDBCRealm#getUserNameCol() 
    */ 
    public String getUserNameCol() { 
     return jdbcRealm.getUserNameCol(); 
    } 

    /** 
    * Set the column in the user table that holds the user's name. 
    * 
    * @param userNameCol The column name 
    * @see JDBCRealm#setUserNameCol(String) 
    */ 
    public void setUserNameCol(String userNameCol) { 
     jdbcRealm.setUserNameCol(userNameCol); 
    } 

    /** 
    * Return the table that holds the relation between user's and roles. 
    * 
    * @return user role database table name 
    * @see JDBCRealm#getUserRoleTable() 
    */ 
    public String getUserRoleTable() { 
     return jdbcRealm.getUserRoleTable(); 
    } 

    /** 
    * Set the table that holds the relation between user's and roles. 
    * 
    * @param userRoleTable The table name 
    * @see JDBCRealm#setUserRoleTable(String) 
    */ 
    public void setUserRoleTable(String userRoleTable) { 
     jdbcRealm.setUserRoleTable(userRoleTable); 
    } 

    /** 
    * Return the column in the user role table that names a role. 
    * 
    * @return role column name 
    * @see JDBCRealm#getRoleNameCol() 
    */ 
    public String getRoleNameCol() { 
     return jdbcRealm.getRoleNameCol(); 
    } 

    /** 
    * Set the column in the user role table that names a role. 
    * 
    * @param roleNameCol The column name 
    * @see JDBCRealm#setRoleNameCol(String) 
    */ 
    public void setRoleNameCol(String roleNameCol) { 
     jdbcRealm.setRoleNameCol(roleNameCol); 
    } 

    @Override 
    public SecurityConstraint[] findSecurityConstraints(Request request, Context context) 
    { 
     return jdbcRealm.findSecurityConstraints(request, context); 
    } 

    @Override 
    public boolean hasUserDataPermission(Request request, Response response, 
             SecurityConstraint []constraints) throws IOException 
    { 
     return jdbcRealm.hasUserDataPermission(request, response, constraints); 
    } 

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

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

    /** 
    * Return a List of roles associated with the given User. If no roles 
    * are associated with this user, a zero-length List is returned. 
    * 
    * @param context unused. JDBC does not need this field. 
    * @param user The User to be checked 
    * @return list of role names 
    * 
    * @see JNDIRealm#getRoles(DirContext, User) 
    * @see JDBCRealm#getRoles(String) 
    */ 
    @Override 
    protected List<String> getRoles(DirContext context, User user) 
    { 
     return jdbcRealm.getRoles(user.username); 
    } 
} 
+0

Привет, я положил это на github: https://github.com/rasenderhase/nest-tomcat-realms/ Я рад за запросы на получение. – andy

Смежные вопросы