如何配置嵌入式Jetty以使用LdapLoginModule?

问题描述 投票:3回答:2

我的Jetty Servlet有以下初始化。 HashLoginService工作但是LdapLoginModule没有连接到JAASLoginService,“ldaploginmodule”指的是我想要跳过的默认ldap-loginModule.conf并传递选项Map中的所有参数(或以某种方式指定为文件位置)。

Server jettyServer = new Server(8080);

ServletContextHandler context = new ServletContextHandler(jettyServer, "/", ServletContextHandler.SESSIONS | ServletContextHandler.SECURITY);

context.addServlet(new ServletHolder(new DefaultServlet() {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getSession().invalidate();  // do logout
        response.getWriter().append("<html><form method='POST' action='/j_security_check'>"
            + "<input type='text' name='j_username'/>"
            + "<input type='password' name='j_password'/>"
            + "<input type='submit' value='Login'/></form></html>");
         }
     }), "/login");

context.addServlet(new ServletHolder(new MyServlet()),"/*");

Constraint constraint = new Constraint();
constraint.setName(Constraint.__FORM_AUTH);
constraint.setRoles(new String[]{"user"});
constraint.setAuthenticate(true);

ConstraintMapping constraintMapping = new ConstraintMapping();
constraintMapping.setConstraint(constraint);
constraintMapping.setPathSpec("/*");

ConstraintSecurityHandler securityHandler;

if (ldapEnabled) { // *** something is missing ****
    LdapLoginModule lm = new LdapLoginModule();
    Map options = new HashMap<>();
    options.put( "hostname", "127.0.0.1" );
    options.put( "port", "389" );
    options.put( "contextFactory", "com.sun.jndi.ldap.LdapCtxFactory" );
    options.put( "bindDn", "CN=admin,OU=example,OU=com" );
    options.put( "bindPassword", "password" );
    options.put( "userBaseDn", "dc=example,dc=com" );
    lm.initialize(null,null,null,options);

    securityHandler = new ConstraintSecurityHandler ();
    securityHandler.addConstraintMapping(constraintMapping);
    JAASLoginService loginService = new JAASLoginService("ldaploginmodule");
    loginService.setIdentityService(new DefaultIdentityService());
    securityHandler.setLoginService(loginService);
} else {  // This works
    securityHandler = new ConstraintSecurityHandler();
    securityHandler.addConstraintMapping(constraintMapping);
    HashLoginService loginService = new HashLoginService();
    loginService.putUser("username", new Password("password"), new String[]{"user"});
    securityHandler.setLoginService(loginService);
}

当用户尝试以ldapEnabled模式登录时

HTTP错误:500

访问/ j_security_check时出现问题。原因:

java.io.IOException: ldap-loginModule.conf (No such file or directory)

如何在不使用配置文件的情况下实现此功能(jetty服务器作为动态加载的jar嵌入到另一个应用程序中)

ldap jetty embedded-jetty jetty-9
2个回答
1
投票

我已经设法为嵌入式Jetty编写了一个LoginService,似乎没有讨厌“你必须使用的jvm patameters,因为它是一个jvm要求”(或者当他们在这里关闭问题时他们的意思是https://github.com/eclipse/jetty.project/issues/1349

请注意,由于缺乏“命名”经验并且主要是LDAP,我并不总是理解我在做什么,因此请随意改进此代码。

这是一个匿名类,我在将其放入ConstraintSecurityHandler之前正在内联创建。组被视为角色。

    LoginService loginService = new AbstractLoginService() {

        private final InitialLdapContext _ldap = _getLdap(
                "cn=" + CONFIG.getString("ldap.manager") + "," + CONFIG.getString("ldap.baseDn"), 
                CONFIG.getString("ldap.managerPassword"));

        @Override
        protected void finalize() throws Throwable {
            _ldap.close();
        }

        private InitialLdapContext _getLdap(String userDn, String password) {
            Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            env.put(Context.SECURITY_AUTHENTICATION, "simple");
            env.put(Context.PROVIDER_URL, CONFIG.getString("ldap.server"));
            env.put(Context.SECURITY_PRINCIPAL, userDn);
            env.put(Context.SECURITY_CREDENTIALS, password);//dn user password
            try {
                InitialLdapContext ldap = new InitialLdapContext(env, null);
                return ldap;
            } catch (AuthenticationException e) {
                return null;
            } catch (NamingException e) {
                return null;
            }
        }

        // Based on https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java
        private String _escapeLDAPSearchFilter(String filter) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < filter.length(); i++) {
                char curChar = filter.charAt(i);
                switch (curChar) {
                    case '\\':
                        sb.append("\\5c");
                        break;
                    case '*':
                        sb.append("\\2a");
                        break;
                    case '(':
                        sb.append("\\28");
                        break;
                    case ')':
                        sb.append("\\29");
                        break;
                    case '\u0000':
                        sb.append("\\00");
                        break;
                    default:
                        sb.append(curChar);
                }
            }
            return sb.toString();
        }

        @Override
        protected String[] loadRoleInfo(AbstractLoginService.UserPrincipal user) {
            String groupBaseDn = CONFIG.getString("ldap.groupBaseDn") + "," + CONFIG.getString("ldap.baseDn");

            String search = CONFIG.getString("ldap.groupFilter");

            String userDn;
            if (CONFIG.getBoolean("ldap.usePosixGroups", true)) {
                userDn = user.getName();
            } else {
                userDn = "uid=" + user.getName() + "," + CONFIG.getString("ldap.userBaseDn") + "," + CONFIG.getString("ldap.baseDn"); // TODO: not sure in this, never tested
            }
            search = search + "(" + CONFIG.getString("ldap.groupMemberAttribute") + "=" + _escapeLDAPSearchFilter(userDn) + ")";

            search = "(&" + search + ")";

            SearchControls searchControls = new SearchControls();
            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
            searchControls.setTimeLimit(30000);

            NamingEnumeration<SearchResult> enumeration = null;

            ArrayList<String> roles = new ArrayList<>();
            try {
                enumeration = _ldap.search(groupBaseDn, search, searchControls);
                while(enumeration.hasMore()){
                    SearchResult result = enumeration.nextElement();
                    final Attributes attributes = result.getAttributes();
                    Attribute attribute = attributes.get(CONFIG.getString("ldap.groupIdAttribute"));
                    if (attribute != null) {
                        roles.add((String) attribute.get());
                    }
                }
            } catch (NamingException e) {

            } finally {
                if (enumeration != null) {
                    try {
                        enumeration.close();
                    } catch (NamingException ee) {

                    }
                }
            }

            String[] ret = new String[roles.size()];
            return roles.toArray(ret);

        }

        @Override
        protected AbstractLoginService.UserPrincipal loadUserInfo(String username) {

            final Credential credential = new Credential() {
                @Override
                public boolean check(Object credentials) {
                    InitialLdapContext myLdap = _getLdap(
                            "uid=" + username + "," + CONFIG.getString("ldap.userBaseDn") + "," + CONFIG.getString("ldap.baseDn"), 
                            (String) credentials);
                    if (myLdap == null) {
                        return false;
                    } else {
                        try {
                            myLdap.close();
                        } catch (NamingException e) {
                            //okay...
                        }
                        return true;
                    }
                }
            };

            final AbstractLoginService.UserPrincipal webUser = new UserPrincipal(username, credential);

            return webUser;

        }
    };

CONFIG是我的配置文件,如下所示:

ldap.server=ldap://192.168.100.200
ldap.manager=admin
ldap.managerPassword=ldapadmin
ldap.baseDn=dc=example,dc=com
ldap.userBaseDn=ou=People
ldap.groupBaseDn=ou=Groups
ldap.groupMemberAttribute=memberUid
ldap.usePosixGroups=true
ldap.userFilter=(objectClass=inetOrgPerson)
ldap.groupFilter=(objectClass=posixGroup)
ldap.groupIdAttribute=cn

Ldap在ldap://192.168.100.200上配置了以下设置(我想,很久以前)

dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
ou: People

dn: ou=Groups,dc=example,dc=com
objectClass: organizationalUnit
ou: Groups

dn: uid=testuser01,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: testuser01
sn: User01
givenName: Test01
cn: testuser01
displayName: Test User 01
uidNumber: 10001
gidNumber: 10001
userPassword: 12345qw
homeDirectory: /home/testuser01

dn: uid=testuser02,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: testuser02
sn: User02
givenName: Test02
cn: testuser02
displayName: Test User 02
uidNumber: 10002
gidNumber: 10002
userPassword: 12345qw
homeDirectory: /home/testuser02

dn: uid=testuser03,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: testuser03
sn: User03
givenName: Test03
cn: testuser03
displayName: Test User 03
uidNumber: 10003
gidNumber: 10003
userPassword: 12345qw
homeDirectory: /home/testuser03

dn: cn=admins,ou=Groups,dc=example,dc=com
objectClass: posixGroup
cn: admins
gidNumber: 5000
memberUid: testuser01

dn: cn=staff,ou=Groups,dc=example,dc=com
objectClass: posixGroup
cn: staff
gidNumber: 5001
memberUid: testuser01
memberUid: testuser02
memberUid: testuser03

dn: cn=management,ou=Groups,dc=example,dc=com
objectClass: posixGroup
cn: management
gidNumber: 5003
memberUid: testuser02

如果在任何地方都有一个两个三个方法的包装器,它会做同样但在不同的环境中测试会很好,所以我不必写这个。


0
投票

听起来我们错过了一个api供你这样做,打开一个增强请求:

https://github.com/eclipse/jetty.project/issues

欢迎提出拉动请求。 :)

© www.soinside.com 2019 - 2024. All rights reserved.