Apache Shiro LDAP 配置(两步验证)
Apache Shiro LDAP Configuration (2 Step Authentication)
我正在使用以下内容开发网络应用程序:
- Apache Shiro 1.2.4
- Tomcat 8
- Java 8
我正在尝试通过 LDAP 领域对用户进行身份验证。
我使用以下值测试了 JXplorer 的登录:
- BaseND:ou=学生,ou=用户,o=数据
- UserDN/BindDN: cn={我的专名},ou=学生,ou=用户,o=数据
- JXplorer 也有我导入的证书
现在我的问题是:
我必须不是基于 cn
而是基于 uid
来验证用户。
但是,这不会起作用。
我公司的 LDAP-Admin 建议的工作流程:
我有一个系统用户(据我所知)应该连接到 LDAP 服务器,根据给定的 uid
和 returns 搜索用户 cn
对于该用户。
在第二步中,应该可以使用他的 cn
对用户进行身份验证,就像在 JXplorer 中(成功)完成的那样。
我的 shiro.ini 配置看起来像我的测试 LDAP(不是我现在尝试验证的那个)
ldapRealm = org.apache.shiro.realm.ldap.JndiLdapRealm
ldapRealm.userDnTemplate = cn={0},ou=People,dc=maxcrc,dc=com
ldapRealm.contextFactory.url = ldap://localhost:389
我现在面临的问题是我无法找到有关如何配置我的 shiro.ini 文件的信息,以便对上面建议的工作流进行数学计算。
问题 #1
我可以使用标准 org.apache.shiro.realm.ldap.JndiLdapRealm
(我该如何配置)?特别是对于证书的集成我找不到任何合适的东西。
问题 #2
我是否需要为此“两步验证”创建一个自定义的 JndiLdapRealm?这样的 Realm 应该是什么样子?
我找到了一个解决方案,那就是重载 JndiLdapRealm
中的 getUserDN()
方法
现在看起来像这样:
/**
* Addition to standard shiro code
* User logs in with his {@link principal} (username) but login needs to be performed with his cn instead
* The addition is an ldap query to get the users cn from the ldap server and store it (instead of the given principal) in the return String
* @return UserDN with user uid (cn) instead of principal (username)
*/
@Override
protected String getUserDn( final String principal ) throws IllegalArgumentException, IllegalStateException {
if (!StringUtils.hasText(principal)) {
throw new IllegalArgumentException("User principal cannot be null or empty for User DN construction.");
}
String prefix = getUserDnPrefix();
String suffix = getUserDnSuffix();
if (prefix == null && suffix == null) {
log.debug("userDnTemplate property has not been configured, indicating the submitted " +
"AuthenticationToken's principal is the same as the User DN. Returning the method argument " +
"as is.");
return principal;
}
int prefixLength = prefix != null ? prefix.length() : 0;
int suffixLength = suffix != null ? suffix.length() : 0;
StringBuilder sb = new StringBuilder(prefixLength + principal.length() + suffixLength);
if (prefixLength > 0) {
sb.append(prefix);
}
/*############################################################################################
* ADDITION TO STANDARD SHIRO CODE
* User logs in with his {@link principal} (username) but login needs to be performed with his cn instead
* => translate username to cn
*/
AppSettings_Controler settings = Startup.getAppSettingsControler();
LDAP_Manager ldap_manager = new LDAP_Manager();
LdapContext ctx = ldap_manager.getLdapConnection();
String user_uid = "";
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrIDs = {"cn"};
constraints.setReturningAttributes(attrIDs);
NamingEnumeration answer = null;
try{
answer = ctx.search(settings.get_ldap_search_dn_1(), settings.get_ldap_uname_field_name_1() + "=" + principal, constraints);
if (answer.hasMore()) {
Attributes attrs = ((SearchResult) answer.next()).getAttributes();
user_uid = attrs.get("cn").toString().substring(attrIDs[0].length() + 2);
} else {
throw new Exception("Invalid User");
}
} catch (Exception ex) {
// Error Handling & Fallback to my second LDAP-Server
try{
answer = ctx.search(settings.get_ldap_search_dn_2(), settings.get_ldap_uname_field_name_2() + "=" + principal, constraints);
if (answer.hasMore()) {
Attributes attrs = ((SearchResult) answer.next()).getAttributes();
user_uid = attrs.get("cn").toString().substring(attrIDs[0].length() + 2);
} else {
throw new Exception("Invalid User");
}
}catch (Exception exe) {
// Error Handling
}
}
try {
ctx.close();
} catch (NamingException ex) {
JndiLdapRealm_custom_error_logger.error("getUserDn(); Fehler beim schließen: ", ex);
}
//############################################################################################
//############################################################################################
// Shiro Standard Code -> add principal to String
//sb.append(principal);
/*############################################################################################
/*############################################################################################
* ALTERED CODE
* Instead -> Add user's cn to String
*/
sb.append(user_uid);
//############################################################################################
if (suffixLength > 0) {
sb.append(suffix);
}
return sb.toString();
}
此添加执行 LDAP 查询以根据提供的用户名获取用户 uid (cn)。这样,用户只需在我的应用程序中输入他的 LDAP 用户名并遵循上述工作流程即可登录。
如果您有任何建议或意见,请不要犹豫,在这里 post 他们 ;)
我正在使用以下内容开发网络应用程序:
- Apache Shiro 1.2.4
- Tomcat 8
- Java 8
我正在尝试通过 LDAP 领域对用户进行身份验证。
我使用以下值测试了 JXplorer 的登录:
- BaseND:ou=学生,ou=用户,o=数据
- UserDN/BindDN: cn={我的专名},ou=学生,ou=用户,o=数据
- JXplorer 也有我导入的证书
现在我的问题是:
我必须不是基于 cn
而是基于 uid
来验证用户。
但是,这不会起作用。
我公司的 LDAP-Admin 建议的工作流程:
我有一个系统用户(据我所知)应该连接到 LDAP 服务器,根据给定的 uid
和 returns 搜索用户 cn
对于该用户。
在第二步中,应该可以使用他的 cn
对用户进行身份验证,就像在 JXplorer 中(成功)完成的那样。
我的 shiro.ini 配置看起来像我的测试 LDAP(不是我现在尝试验证的那个)
ldapRealm = org.apache.shiro.realm.ldap.JndiLdapRealm
ldapRealm.userDnTemplate = cn={0},ou=People,dc=maxcrc,dc=com
ldapRealm.contextFactory.url = ldap://localhost:389
我现在面临的问题是我无法找到有关如何配置我的 shiro.ini 文件的信息,以便对上面建议的工作流进行数学计算。
问题 #1
我可以使用标准 org.apache.shiro.realm.ldap.JndiLdapRealm
(我该如何配置)?特别是对于证书的集成我找不到任何合适的东西。
问题 #2
我是否需要为此“两步验证”创建一个自定义的 JndiLdapRealm?这样的 Realm 应该是什么样子?
我找到了一个解决方案,那就是重载 JndiLdapRealm
getUserDN()
方法
现在看起来像这样:
/**
* Addition to standard shiro code
* User logs in with his {@link principal} (username) but login needs to be performed with his cn instead
* The addition is an ldap query to get the users cn from the ldap server and store it (instead of the given principal) in the return String
* @return UserDN with user uid (cn) instead of principal (username)
*/
@Override
protected String getUserDn( final String principal ) throws IllegalArgumentException, IllegalStateException {
if (!StringUtils.hasText(principal)) {
throw new IllegalArgumentException("User principal cannot be null or empty for User DN construction.");
}
String prefix = getUserDnPrefix();
String suffix = getUserDnSuffix();
if (prefix == null && suffix == null) {
log.debug("userDnTemplate property has not been configured, indicating the submitted " +
"AuthenticationToken's principal is the same as the User DN. Returning the method argument " +
"as is.");
return principal;
}
int prefixLength = prefix != null ? prefix.length() : 0;
int suffixLength = suffix != null ? suffix.length() : 0;
StringBuilder sb = new StringBuilder(prefixLength + principal.length() + suffixLength);
if (prefixLength > 0) {
sb.append(prefix);
}
/*############################################################################################
* ADDITION TO STANDARD SHIRO CODE
* User logs in with his {@link principal} (username) but login needs to be performed with his cn instead
* => translate username to cn
*/
AppSettings_Controler settings = Startup.getAppSettingsControler();
LDAP_Manager ldap_manager = new LDAP_Manager();
LdapContext ctx = ldap_manager.getLdapConnection();
String user_uid = "";
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrIDs = {"cn"};
constraints.setReturningAttributes(attrIDs);
NamingEnumeration answer = null;
try{
answer = ctx.search(settings.get_ldap_search_dn_1(), settings.get_ldap_uname_field_name_1() + "=" + principal, constraints);
if (answer.hasMore()) {
Attributes attrs = ((SearchResult) answer.next()).getAttributes();
user_uid = attrs.get("cn").toString().substring(attrIDs[0].length() + 2);
} else {
throw new Exception("Invalid User");
}
} catch (Exception ex) {
// Error Handling & Fallback to my second LDAP-Server
try{
answer = ctx.search(settings.get_ldap_search_dn_2(), settings.get_ldap_uname_field_name_2() + "=" + principal, constraints);
if (answer.hasMore()) {
Attributes attrs = ((SearchResult) answer.next()).getAttributes();
user_uid = attrs.get("cn").toString().substring(attrIDs[0].length() + 2);
} else {
throw new Exception("Invalid User");
}
}catch (Exception exe) {
// Error Handling
}
}
try {
ctx.close();
} catch (NamingException ex) {
JndiLdapRealm_custom_error_logger.error("getUserDn(); Fehler beim schließen: ", ex);
}
//############################################################################################
//############################################################################################
// Shiro Standard Code -> add principal to String
//sb.append(principal);
/*############################################################################################
/*############################################################################################
* ALTERED CODE
* Instead -> Add user's cn to String
*/
sb.append(user_uid);
//############################################################################################
if (suffixLength > 0) {
sb.append(suffix);
}
return sb.toString();
}
此添加执行 LDAP 查询以根据提供的用户名获取用户 uid (cn)。这样,用户只需在我的应用程序中输入他的 LDAP 用户名并遵循上述工作流程即可登录。
如果您有任何建议或意见,请不要犹豫,在这里 post 他们 ;)