2009-07-16 87 views
9

我正在使用LDAP服务器仅用于身份验证并且不包含任何角色的遗留环境,并且针对包含用户角色映射的数据库执行授权,但没有密码。使用LDAP身份验证和JDBC授权实现Tomcat领域

我的计划是通过扩展JNDIRealm并重写角色方法来调用封装的JDBCRealm来实现新的Tomcat领域。

我的境界是在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认证/ DB授权并不罕见。是否有可用的替代解决方案?

这是而不是在我的控制范围内添加角色到数据库的LDAP或密码,所以这些都不是我的解决方案。

+0

是的,我在Tomcat 6.0.18 – 2009-07-16 16:18:20

回答

5

你还没有指定你正在使用的Tomcat版本,所以我在这里使用6.x。

它看起来像你正在委托hasResourcePermission JDBC,同时把findSecurityConstraintshasUserDataPermission留在JNDI的手中。您应该委派他们全部或全部都没有。

更新JNDIRealm调用protected getRoles(DirContext, User)authenticate()方法的一部分。你需要覆盖它并将其转发给JDBCRealm的getRoles()

+0

我已经覆盖findSecurityConstraints()hasUserDataPermission()工作虽然JDBCRealm打电话。但是,JDBCRealm的getRoles()受到保护。你如何建议我打电话? – 2009-07-16 18:47:21

+1

你有3个选择:使用反射('Method.setAccessible()'将有助于'protected'),将你的领域实现移动到'org.apache.catalina.realm'包中,或者完全放弃JDBCRealm并将你自己的代码写入从数据库中检索角色)。 – ChssPly76 2009-07-16 19:13:49

+0

转到包org.apache.catalina.realm工作得很好。我也忽略了指定驱动程序,所以我添加了getter和setter以及DB用户和密码。现在一切正常,谢谢。 – 2009-07-17 14:42:55

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 2017-06-14 10:55:34