Shiro LDAP授权配置

时间:2014-06-05 14:06:17

标签: java authentication ldap vaadin shiro

请你帮我解决以下情况?

背景资料:

  

[主要]

contextFactory = org.apache.shiro.realm.ldap.JndiLdapContextFactory 
contextFactory.url = ldaps://<SERVER>:636 
contextFactory.systemUsername = <USERNAME>@<COMPANY>
contextFactory.systemPassword = <PASSWORD>
contextFactory.environment[java.naming.security.protocol] = ssl 

realm = org.apache.shiro.realm.activedirectory.ActiveDirectoryRealm 
realm.ldapContextFactory = $contextFactory 
realm.searchBase = "OU=<APPDIR>,DC=<COMPANY>,DC=lcl" 
realm.groupRolesMap = "CN=<ROLE>,OU=<APPDIR>,DC=<COMPANY>,DC=lcl":"Admin"
  

[角色]

 # 'Admin' role has permissions * 
 Admin = * 

目标

  • 基于currentUser的memberOf字段的授权映射。

问题

  • currentUser.hasRole(“Admin”)始终返回false。

问题

  • 上面的shiro.ini是否正确?
  • 如何解决问题?

1 个答案:

答案 0 :(得分:1)

我使用Shiro 1.2.4遇到了类似的问题。您的Shiro配置可能没问题,问题在于ActiveDirectory配置。

在我的设置中,某些用户设置了 userPrincipalName 属性,而其他用户则没有。例如,您可以使用Sysinternals Active Directory Explorer检查您的AD服务器 此属性是Shiro用于搜索特定用户的属性,然后查找 memberOf 属性中定义的组。
查看ActiveDirectoryRealm.java源代码,方法Set<String> getRoleNamesForUser(String username, LdapContext ldapContext)使用的确切查询是
String searchFilter = "(&(objectClass=*)(userPrincipalName={0}))";

所以你有两个解决方案:

  • 在每个用户
  • 上设置 userPrincipalName 属性
  • 更改Shiro搜索用户的方式

我去了第二个解决方案。更改搜索查询比应该更难:您必须自定义queryForAuthorizationInfogetRoleNamesForUserActiveDirectoryRealm的{​​{1}}方法。我就这样做了:

public class CustomActiveDirectoryRealm extends ActiveDirectoryRealm {

    @Override
    protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals, LdapContextFactory ldapContextFactory) throws NamingException {
        String username = (String) getAvailablePrincipal(principals);

        // Perform context search
        LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();

        Set<String> roleNames = null;

        try {
            roleNames = getRoleNamesForUser(username, ldapContext);

        } finally {
            LdapUtils.closeContext(ldapContext);
        }

        return buildAuthorizationInfo(roleNames);
    }

    // Customize your search query here
    private static final String USER_SEARCH_FILTER = "(&(objectClass=*)(sn={0}))";
    private Set<String> getRoleNamesForUser(String username, LdapContext ldapContext) throws NamingException {
        Set<String> roleNames;
        roleNames = new LinkedHashSet<String>();

        SearchControls searchCtls = new SearchControls();
        searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        String userPrincipalName = username.replace("acegas\\", "");
        if (principalSuffix != null) {
            userPrincipalName += principalSuffix;
        }

        Object[] searchArguments = new Object[]{userPrincipalName};

        NamingEnumeration answer = ldapContext.search(searchBase, USER_SEARCH_FILTER, searchArguments, searchCtls);

        while (answer.hasMoreElements()) {
            SearchResult sr = (SearchResult) answer.next();

            Attributes attrs = sr.getAttributes();

            if (attrs != null) {
                NamingEnumeration ae = attrs.getAll();
                while (ae.hasMore()) {
                    Attribute attr = (Attribute) ae.next();

                    if (attr.getID().equals("memberOf")) {

                        Collection<String> groupNames = LdapUtils.getAllAttributeValues(attr);

                        Collection<String> rolesForGroups = getRoleNamesForGroups(groupNames);
                        roleNames.addAll(rolesForGroups);
                    }
                }
            }
        }
        return roleNames;
    }
}

然后当然在shiro.ini中将此类用作Realm

[main]
realm = your.package.CustomActiveDirectoryRealm
realm.ldapContextFactory = $contextFactory 
realm.searchBase = "OU=<APPDIR>,DC=<COMPANY>,DC=lcl" 
realm.groupRolesMap = "CN=<ROLE>,OU=<APPDIR>,DC=<COMPANY>,DC=lcl":"Admin"