diff --git a/.mvn/maven-build-cache-config.xml b/.mvn/maven-build-cache-config.xml
index 34c6f62ed85..4dc674a369b 100644
--- a/.mvn/maven-build-cache-config.xml
+++ b/.mvn/maven-build-cache-config.xml
@@ -90,6 +90,7 @@
+
diff --git a/build/build-resources/pom.xml b/build/build-resources/pom.xml
index 54c23f18a3b..9ec89c5a64b 100644
--- a/build/build-resources/pom.xml
+++ b/build/build-resources/pom.xml
@@ -13,11 +13,11 @@
Build :: Resources
- true
- true
+ 3.1.1
+ 3.4.0
3.1.0
- 3.1.2
+ 3.2.1
UTF-8
true
diff --git a/documentation/jetty-documentation/src/main/asciidoc/old_docs/security/jaas-support.adoc b/documentation/jetty-documentation/src/main/asciidoc/old_docs/security/jaas-support.adoc
index 145f64bb439..bb3ada5eb0d 100644
--- a/documentation/jetty-documentation/src/main/asciidoc/old_docs/security/jaas-support.adoc
+++ b/documentation/jetty-documentation/src/main/asciidoc/old_docs/security/jaas-support.adoc
@@ -175,7 +175,7 @@ To allow the greatest degree of flexibility in using JAAS with web applications,
Note that you don't ordinarily need to set these explicitly, as Jetty has defaults which will work in 99% of cases.
However, should you need to, you can configure:
-* a CallbackHandler (Default: `org.eclipse.jetty.jaas.callback.DefaultCallbackHandler`)
+* a CallbackHandler (Default: `org.eclipse.jetty.security.jaas.callback.DefaultCallbackHandler`)
* a list of classnames for the Principal implementation that equate to a user role (Default: `org.eclipse.jetty.jaas.JAASRole`)
Here's an example of setting each of these (to their default values):
@@ -186,7 +186,7 @@ Here's an example of setting each of these (to their default values):
Test JAAS Realm
xyz
- org.eclipse.jetty.jaas.callback.DefaultCallbackHandler
+ org.eclipse.jetty.security.jaas.callback.DefaultCallbackHandler
diff --git a/jetty-core/jetty-security/pom.xml b/jetty-core/jetty-security/pom.xml
index e0edf2c5166..f2508cc029e 100644
--- a/jetty-core/jetty-security/pom.xml
+++ b/jetty-core/jetty-security/pom.xml
@@ -12,11 +12,28 @@
The common Jetty security implementation
+ 2.1.5
+ 2.0.0.AM27
${project.groupId}.security
org.eclipse.jetty.security.*
+
+ org.apache.directory.api
+ api-asn1-api
+ ${apache.directory.api.version}
+
+
+ org.apache.directory.api
+ api-ldap-model
+ ${apache.directory.api.version}
+
+
+ org.apache.directory.api
+ api-util
+ ${apache.directory.api.version}
+
org.eclipse.jetty
jetty-server
@@ -25,6 +42,70 @@
org.slf4j
slf4j-api
+
+ org.apache.directory.api
+ api-ldap-schema-data
+ ${apache.directory.api.version}
+ test
+
+
+ org.apache.directory.server
+ apacheds-core-integ
+ ${apacheds.version}
+ test
+
+
+ org.apache.directory.api
+ api-ldap-schema-data
+
+
+
+ org.apache.directory.shared
+ shared-ldap-schema
+
+
+
+
+ org.apache.directory.server
+ apacheds-server-integ
+ ${apacheds.version}
+ test
+
+
+ org.apache.directory.api
+ api-ldap-schema-data
+
+
+
+ org.apache.directory.shared
+ shared-ldap-schema
+
+
+
+
+ org.apache.directory.server
+ apacheds-test-framework
+ ${apacheds.version}
+ test
+
+
+ junit
+ junit
+
+
+ org.apache.directory.api
+ api-ldap-schema-data
+
+
+
+ org.apache.directory.shared
+ shared-ldap-schema
+
+
+
org.eclipse.jetty
jetty-http-tools
@@ -55,7 +136,8 @@
@{argLine}
${jetty.surefire.argLine}
- --add-reads org.eclipse.jetty.security=org.eclipse.jetty.logging
+ --add-reads org.eclipse.jetty.security=org.eclipse.jetty.logging
+ --add-exports org.eclipse.jetty.security/org.eclipse.jetty.security.jaas.spi=java.base
diff --git a/jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/JAASLdapLoginServiceTest.java b/jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/JAASLdapLoginServiceTest.java
deleted file mode 100644
index 35d8ae1110c..00000000000
--- a/jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/JAASLdapLoginServiceTest.java
+++ /dev/null
@@ -1,319 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
-//
-// This program and the accompanying materials are made available under the
-// terms of the Eclipse Public License v. 2.0 which is available at
-// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
-// which is available at https://www.apache.org/licenses/LICENSE-2.0.
-//
-// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
-// ========================================================================
-//
-
-package org.eclipse.jetty.security.jaas;
-
-/* TODO
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Base64;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.security.auth.login.AppConfigurationEntry;
-import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
-import javax.security.auth.login.Configuration;
-
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServlet;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.apache.directory.server.annotations.CreateLdapServer;
-import org.apache.directory.server.annotations.CreateTransport;
-import org.apache.directory.server.core.annotations.ApplyLdifs;
-import org.apache.directory.server.core.annotations.CreateDS;
-import org.apache.directory.server.core.annotations.CreatePartition;
-import org.apache.directory.server.core.integ.FrameworkRunner;
-import org.apache.directory.server.ldap.LdapServer;
-import org.eclipse.jetty.ee10.jaas.spi.LdapLoginModule;
-import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
-import org.eclipse.jetty.ee10.servlet.ServletHandler;
-import org.eclipse.jetty.ee10.servlet.ServletHolder;
-import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
-import org.eclipse.jetty.ee10.servlet.security.DefaultIdentityService;
-import org.eclipse.jetty.ee10.servlet.security.authentication.BasicAuthenticator;
-import org.eclipse.jetty.server.LocalConnector;
-import org.eclipse.jetty.server.Server;
-import org.junit.Test;
-import org.junit.jupiter.api.condition.EnabledForJreRange;
-import org.junit.jupiter.api.condition.JRE;
-import org.junit.runner.RunWith;
-
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.startsWith;
-
-@EnabledForJreRange(max = JRE.JAVA_17, disabledReason = "sun.security.x509.X509CertInfo.set not present in Java 21, needs a Java 21 compatible version of Apache Directory Server")
-@RunWith(FrameworkRunner.class)
-@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP")})
-@CreateDS(allowAnonAccess = false, partitions = {
- @CreatePartition(name = "Users Partition", suffix = "ou=people,dc=jetty,dc=org"),
- @CreatePartition(name = "Groups Partition", suffix = "ou=groups,dc=jetty,dc=org")
-})
-@ApplyLdifs({
- // Entry 1
- "dn: ou=people,dc=jetty,dc=org",
- "objectClass: organizationalunit",
- "objectClass: top",
- "ou: people",
- // Entry # 2
- "dn:uid=someone,ou=people,dc=jetty,dc=org",
- "objectClass: inetOrgPerson",
- "cn: someone",
- "sn: sn test",
- "userPassword: complicatedpassword",
- // Entry # 3
- "dn:uid=someoneelse,ou=people,dc=jetty,dc=org",
- "objectClass: inetOrgPerson",
- "cn: someoneelse",
- "sn: sn test",
- "userPassword: verycomplicatedpassword",
- // Entry 4
- "dn: ou=groups,dc=jetty,dc=org",
- "objectClass: organizationalunit",
- "objectClass: top",
- "ou: groups",
- // Entry 5
- "dn: ou=subdir,ou=people,dc=jetty,dc=org",
- "objectClass: organizationalunit",
- "objectClass: top",
- "ou: subdir",
- // Entry # 6
- "dn:uid=uniqueuser,ou=subdir,ou=people,dc=jetty,dc=org",
- "objectClass: inetOrgPerson",
- "cn: uniqueuser",
- "sn: unique user",
- "userPassword: hello123",
- // Entry # 7
- "dn:uid=ambiguousone,ou=people,dc=jetty,dc=org",
- "objectClass: inetOrgPerson",
- "cn: ambiguous1",
- "sn: ambiguous user",
- "userPassword: foobar",
- // Entry # 8
- "dn:uid=ambiguousone,ou=subdir,ou=people,dc=jetty,dc=org",
- "objectClass: inetOrgPerson",
- "cn: ambiguous2",
- "sn: ambiguous subdir user",
- "userPassword: barfoo",
- // Entry 9
- "dn: cn=developers,ou=groups,dc=jetty,dc=org",
- "objectClass: groupOfUniqueNames",
- "objectClass: top",
- "ou: groups",
- "description: People who try to build good software",
- "uniquemember: uid=someone,ou=people,dc=jetty,dc=org",
- "uniquemember: uid=uniqueuser,ou=subdir,ou=people,dc=jetty,dc=org",
- "cn: developers",
- // Entry 10
- "dn: cn=admin,ou=groups,dc=jetty,dc=org",
- "objectClass: groupOfUniqueNames",
- "objectClass: top",
- "ou: groups",
- "description: People who try to run software build by developers",
- "uniquemember: uid=someone,ou=people,dc=jetty,dc=org",
- "uniquemember: uid=someoneelse,ou=people,dc=jetty,dc=org",
- "uniquemember: uid=uniqueuser,ou=subdir,ou=people,dc=jetty,dc=org",
- "cn: admin"
-})
-*/
-
-public class JAASLdapLoginServiceTest
-{
- /* TODO restore this test
- public static class TestConfiguration extends Configuration
- {
- private boolean forceBindingLogin;
-
- public TestConfiguration(boolean forceBindingLogin)
- {
- this.forceBindingLogin = forceBindingLogin;
- }
-
- @Override
- public AppConfigurationEntry[] getAppConfigurationEntry(String name)
- {
- Map options = new HashMap<>();
- options.put("hostname", "localhost");
- options.put("port", Integer.toString(_ldapServer.getTransports()[0].getPort()));
- options.put("contextFactory", "com.sun.jndi.ldap.LdapCtxFactory");
- options.put("bindDn", "uid=admin,ou=system");
- options.put("bindPassword", "secret");
- options.put("userBaseDn", "ou=people,dc=jetty,dc=org");
- options.put("roleBaseDn", "ou=groups,dc=jetty,dc=org");
- options.put("roleNameAttribute", "cn");
- options.put("forceBindingLogin", Boolean.toString(forceBindingLogin));
- AppConfigurationEntry entry = new AppConfigurationEntry(LdapLoginModule.class.getCanonicalName(), LoginModuleControlFlag.REQUIRED, options);
-
- return new AppConfigurationEntry[]{entry};
- }
- }
-
- public static LdapServer getLdapServer()
- {
- return _ldapServer;
- }
-
- public static void setLdapServer(LdapServer ldapServer)
- {
- _ldapServer = ldapServer;
- }
-
- private static LdapServer _ldapServer;
- private Server _server;
- private LocalConnector _connector;
- private ServletContextHandler _context;
-
- public void setUp() throws Exception
- {
- _server = new Server();
- _connector = new LocalConnector(_server);
- _server.addConnector(_connector);
-
- _context = new ServletContextHandler();
- _context.setContextPath("/ctx");
- _server.setHandler(_context);
- ConstraintSecurityHandler security = new ConstraintSecurityHandler();
- security.setAuthenticator(new BasicAuthenticator());
- _context.setSecurityHandler(security);
- }
-
- private JAASLoginService jaasLoginService(String name)
- {
- JAASLoginService ls = new JAASLoginService("foo");
- ls.setCallbackHandlerClass("org.eclipse.jetty.ee10.jaas.callback.DefaultCallbackHandler");
- ls.setIdentityService(new DefaultIdentityService());
- ls.setConfiguration(new TestConfiguration(true));
- return ls;
- }
-
- private String doLogin(String username, String password, List hasRoles, List hasntRoles) throws Exception
- {
- JAASLoginService ls = jaasLoginService("foo");
- _server.addBean(ls, true);
-
- _context.setServletHandler(new ServletHandler());
- ServletHolder holder = new ServletHolder();
- holder.setServlet(new TestServlet(hasRoles, hasntRoles));
- _context.getServletHandler().addServletWithMapping(holder, "/");
-
- _server.start();
-
- return _connector.getResponse("GET /ctx/test HTTP/1.0\n" + "Authorization: Basic " +
- Base64.getEncoder().encodeToString((username + ":" + password).getBytes(ISO_8859_1)) + "\n\n");
- }
-
- @Test
- public void testLdapUserIdentity() throws Exception
- {
- setUp();
- _context.setServletHandler(new ServletHandler());
- ServletHolder holder = new ServletHolder();
- holder.setServlet(new TestServlet(Arrays.asList("developers", "admin"), Arrays.asList("blabla")));
- _context.getServletHandler().addServletWithMapping(holder, "/");
-
- JAASLoginService ls = new JAASLoginService("foo");
- ls.setCallbackHandlerClass("org.eclipse.jetty.ee10.jaas.callback.DefaultCallbackHandler");
- ls.setIdentityService(new DefaultIdentityService());
- ls.setConfiguration(new TestConfiguration(false));
-
- _server.addBean(ls, true);
- _server.start();
-
- String response = _connector.getResponse("GET /ctx/test HTTP/1.0\n" + "Authorization: Basic " +
- Base64.getEncoder().encodeToString("someone:complicatedpassword".getBytes(ISO_8859_1)) + "\n\n");
- assertThat(response, startsWith("HTTP/1.1 200 OK"));
-
- _server.stop();
-
- _context.setServletHandler(new ServletHandler());
- holder = new ServletHolder();
- holder.setServlet(new TestServlet(Arrays.asList("admin"), Arrays.asList("developers, blabla")));
- _context.getServletHandler().addServletWithMapping(holder, "/");
-
- _server.start();
-
- response = _connector.getResponse("GET /ctx/test HTTP/1.0\n" + "Authorization: Basic " +
- Base64.getEncoder().encodeToString("someoneelse:verycomplicatedpassword".getBytes(ISO_8859_1)) + "\n\n");
- assertThat(response, startsWith("HTTP/1.1 200 OK"));
- }
-
- @Test
- public void testLdapUserIdentityBindingLogin() throws Exception
- {
- setUp();
- _context.setServletHandler(new ServletHandler());
- ServletHolder holder = new ServletHolder();
- holder.setServlet(new TestServlet(Arrays.asList("developers", "admin"), Arrays.asList("blabla")));
- _context.getServletHandler().addServletWithMapping(holder, "/");
- JAASLoginService ls = new JAASLoginService("foo");
- ls.setCallbackHandlerClass("org.eclipse.jetty.ee10.jaas.callback.DefaultCallbackHandler");
- ls.setIdentityService(new DefaultIdentityService());
- ls.setConfiguration(new TestConfiguration(true));
- _server.addBean(ls, true);
- _server.start();
-
-
- String response = _connector.getResponse("GET /ctx/test HTTP/1.0\n" + "Authorization: Basic " +
- Base64.getEncoder().encodeToString("someone:complicatedpassword".getBytes(ISO_8859_1)) + "\n\n");
- assertThat(response, startsWith("HTTP/1.1 200 OK"));
-
- _server.stop();
- _context.setServletHandler(new ServletHandler());
- _context.addServlet(new HttpServlet()
- {
- @Override
- protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- {
- //check authentication status
- if (req.getUserPrincipal() == null)
- req.authenticate(resp);
- }
-
- }, "/");
- _server.start();
-
- //TODO this test shows response already committed!
- response = _connector.getResponse("GET /ctx/test HTTP/1.0\n" + "Authorization: Basic " +
- Base64.getEncoder().encodeToString("someone:wrongpassword".getBytes(ISO_8859_1)) + "\n\n");
- System.err.println(response);
- assertThat(response, startsWith("HTTP/1.1 " + HttpServletResponse.SC_UNAUTHORIZED));
- }
-
- @Test
- public void testLdapBindingSubdirUniqueUserName() throws Exception
- {
- setUp();
- String response = doLogin("uniqueuser", "hello123", Arrays.asList("developers", "admin"), Arrays.asList("blabla"));
- assertThat(response, startsWith("HTTP/1.1 200 OK"));
- }
-
- //TODO test is failing, needs more work
- @Test
- public void testLdapBindingAmbiguousUserName() throws Exception
- {
- setUp();
- String response = doLogin("ambiguousone", "foobar", null, null);
- assertThat(response, startsWith("HTTP/1.1 " + HttpServletResponse.SC_UNAUTHORIZED));
- }
-
- //TODO test is failing, needs more work
- @Test
- public void testLdapBindingSubdirAmbiguousUserName() throws Exception
- {
- setUp();
- String response = doLogin("ambiguousone", "barfoo", null, null);
- assertThat(response, startsWith("HTTP/1.1 " + HttpServletResponse.SC_UNAUTHORIZED));
- }
- */
-}
diff --git a/jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/JAASLdapLoginServiceTest.java b/jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/JAASLdapLoginServiceTest.java
new file mode 100644
index 00000000000..e2692df08b5
--- /dev/null
+++ b/jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/JAASLdapLoginServiceTest.java
@@ -0,0 +1,400 @@
+//
+// ========================================================================
+// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License v. 2.0 which is available at
+// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+// ========================================================================
+//
+
+package org.eclipse.jetty.security.jaas;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
+import javax.security.auth.login.Configuration;
+
+import org.apache.directory.server.annotations.CreateLdapServer;
+import org.apache.directory.server.annotations.CreateTransport;
+import org.apache.directory.server.core.annotations.ApplyLdifs;
+import org.apache.directory.server.core.annotations.CreateDS;
+import org.apache.directory.server.core.annotations.CreatePartition;
+import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
+import org.apache.directory.server.core.integ.ApacheDSTestExtension;
+import org.eclipse.jetty.http.HttpCookie;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.io.Content;
+import org.eclipse.jetty.security.DefaultIdentityService;
+import org.eclipse.jetty.security.UserIdentity;
+import org.eclipse.jetty.security.jaas.spi.LdapLoginModule;
+import org.eclipse.jetty.server.Components;
+import org.eclipse.jetty.server.ConnectionMetaData;
+import org.eclipse.jetty.server.Context;
+import org.eclipse.jetty.server.HttpStream;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Session;
+import org.eclipse.jetty.server.TunnelSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * JAASLdapLoginServiceTest
+ */
+@ExtendWith(ApacheDSTestExtension.class)
+@CreateLdapServer(transports = {@CreateTransport(protocol = "LDAP")})
+@CreateDS(name = "JAASLdapLoginServiceTest-class", partitions = {
+ @CreatePartition(name = "Users Partition", suffix = "ou=people,dc=jetty,dc=org"),
+ @CreatePartition(name = "Groups Partition", suffix = "ou=groups,dc=jetty,dc=org")
+})
+@ApplyLdifs({
+ // Entry 1
+ "dn: ou=people,dc=jetty,dc=org",
+ "objectClass: organizationalunit",
+ "objectClass: top",
+ "ou: people",
+ // Entry # 2
+ "dn:uid=someone,ou=people,dc=jetty,dc=org",
+ "objectClass: inetOrgPerson",
+ "cn: someone",
+ "sn: sn test",
+ "userPassword: complicatedpassword",
+ // Entry # 3
+ "dn:uid=someoneelse,ou=people,dc=jetty,dc=org",
+ "objectClass: inetOrgPerson",
+ "cn: someoneelse",
+ "sn: sn test",
+ "userPassword: verycomplicatedpassword",
+ // Entry 4
+ "dn: ou=groups,dc=jetty,dc=org",
+ "objectClass: organizationalunit",
+ "objectClass: top",
+ "ou: groups",
+ // Entry 5
+ "dn: ou=subdir,ou=people,dc=jetty,dc=org",
+ "objectClass: organizationalunit",
+ "objectClass: top",
+ "ou: subdir",
+ // Entry # 6
+ "dn:uid=uniqueuser,ou=subdir,ou=people,dc=jetty,dc=org",
+ "objectClass: inetOrgPerson",
+ "cn: uniqueuser",
+ "sn: unique user",
+ "userPassword: hello123",
+ // Entry # 7
+ "dn:uid=ambiguousone,ou=people,dc=jetty,dc=org",
+ "objectClass: inetOrgPerson",
+ "cn: ambiguous1",
+ "sn: ambiguous user",
+ "userPassword: foobar",
+ // Entry # 8
+ "dn:uid=ambiguousone,ou=subdir,ou=people,dc=jetty,dc=org",
+ "objectClass: inetOrgPerson",
+ "cn: ambiguous2",
+ "sn: ambiguous subdir user",
+ "userPassword: barfoo",
+ // Entry 9
+ "dn: cn=developers,ou=groups,dc=jetty,dc=org",
+ "objectClass: groupOfUniqueNames",
+ "objectClass: top",
+ "ou: groups",
+ "description: People who try to build good software",
+ "uniquemember: uid=someone,ou=people,dc=jetty,dc=org",
+ "uniquemember: uid=uniqueuser,ou=subdir,ou=people,dc=jetty,dc=org",
+ "cn: developers",
+ // Entry 10
+ "dn: cn=admin,ou=groups,dc=jetty,dc=org",
+ "objectClass: groupOfUniqueNames",
+ "objectClass: top",
+ "ou: groups",
+ "description: People who try to run software build by developers",
+ "uniquemember: uid=someone,ou=people,dc=jetty,dc=org",
+ "uniquemember: uid=someoneelse,ou=people,dc=jetty,dc=org",
+ "uniquemember: uid=uniqueuser,ou=subdir,ou=people,dc=jetty,dc=org",
+ "cn: admin"
+})
+public class JAASLdapLoginServiceTest extends AbstractLdapTestUnit
+{
+ private JAASLoginService jaasLoginService(String name)
+ {
+ JAASLoginService ls = new JAASLoginService("foo");
+ ls.setCallbackHandlerClass("org.eclipse.jetty.security.jaas.callback.DefaultCallbackHandler");
+ ls.setIdentityService(new DefaultIdentityService());
+ ls.setConfiguration(new TestConfiguration(true));
+ return ls;
+ }
+
+ private UserIdentity doLogin(String username, String password) throws Exception
+ {
+ JAASLoginService ls = jaasLoginService("foo");
+ Request request = new MockCoreRequest();
+ return ls.login(username, password, request, null);
+ }
+
+ public static class TestConfiguration extends Configuration
+ {
+ private boolean forceBindingLogin;
+
+ public TestConfiguration(boolean forceBindingLogin)
+ {
+ this.forceBindingLogin = forceBindingLogin;
+ }
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name)
+ {
+ Map options = new HashMap<>();
+ options.put("hostname", "localhost");
+ options.put("port", Integer.toString(ldapServer.getTransports()[0].getPort()));
+ options.put("contextFactory", "com.sun.jndi.ldap.LdapCtxFactory");
+ options.put("bindDn", "uid=admin,ou=system");
+ options.put("bindPassword", "secret");
+ options.put("userBaseDn", "ou=people,dc=jetty,dc=org");
+ options.put("roleBaseDn", "ou=groups,dc=jetty,dc=org");
+ options.put("roleNameAttribute", "cn");
+ options.put("forceBindingLogin", Boolean.toString(forceBindingLogin));
+ AppConfigurationEntry entry = new AppConfigurationEntry(LdapLoginModule.class.getCanonicalName(), LoginModuleControlFlag.REQUIRED, options);
+
+ return new AppConfigurationEntry[]{entry};
+ }
+ }
+
+ @Test
+ public void testLdapUserIdentity() throws Exception
+ {
+ JAASLoginService ls = new JAASLoginService("foo");
+ ls.setCallbackHandlerClass("org.eclipse.jetty.security.jaas.callback.DefaultCallbackHandler");
+ ls.setIdentityService(new DefaultIdentityService());
+ ls.setConfiguration(new TestConfiguration(false));
+ Request request = new MockCoreRequest();
+ UserIdentity userIdentity = ls.login("someone", "complicatedpassword", request, null);
+ assertNotNull(userIdentity);
+ assertTrue(userIdentity.isUserInRole("developers"));
+ assertTrue(userIdentity.isUserInRole("admin"));
+ assertFalse(userIdentity.isUserInRole("blabla"));
+
+ userIdentity = ls.login("someoneelse", "verycomplicatedpassword", request, null);
+ assertNotNull(userIdentity);
+ assertFalse(userIdentity.isUserInRole("developers"));
+ assertTrue(userIdentity.isUserInRole("admin"));
+ assertFalse(userIdentity.isUserInRole("blabla"));
+ }
+
+ @Test
+ public void testLdapUserIdentityBindingLogin() throws Exception
+ {
+ JAASLoginService ls = new JAASLoginService("foo");
+ ls.setCallbackHandlerClass("org.eclipse.jetty.security.jaas.callback.DefaultCallbackHandler");
+ ls.setIdentityService(new DefaultIdentityService());
+ ls.setConfiguration(new TestConfiguration(true));
+ Request request = new MockCoreRequest();
+ UserIdentity userIdentity = ls.login("someone", "complicatedpassword", request, null);
+ assertNotNull(userIdentity);
+ assertTrue(userIdentity.isUserInRole("developers"));
+ assertTrue(userIdentity.isUserInRole("admin"));
+ assertFalse(userIdentity.isUserInRole("blabla"));
+
+ userIdentity = ls.login("someone", "wrongpassword", request, null);
+ assertNull(userIdentity);
+ }
+
+ @Test
+ public void testLdapBindingSubdirUniqueUserName() throws Exception
+ {
+ UserIdentity userIdentity = doLogin("uniqueuser", "hello123");
+ assertNotNull(userIdentity);
+ assertTrue(userIdentity.isUserInRole("developers"));
+ assertTrue(userIdentity.isUserInRole("admin"));
+ assertFalse(userIdentity.isUserInRole("blabla"));
+ }
+
+ @Test
+ public void testLdapBindingAmbiguousUserName() throws Exception
+ {
+ UserIdentity userIdentity = doLogin("ambiguousone", "foobar");
+ assertNull(userIdentity);
+ }
+
+ @Test
+ public void testLdapBindingSubdirAmbiguousUserName() throws Exception
+ {
+ UserIdentity userIdentity = doLogin("ambiguousone", "barfoo");
+ assertNull(userIdentity);
+ }
+
+ private static class MockCoreRequest implements Request
+ {
+
+ @Override
+ public Object removeAttribute(String name)
+ {
+ return null;
+ }
+
+ @Override
+ public Object setAttribute(String name, Object attribute)
+ {
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String name)
+ {
+ return null;
+ }
+
+ @Override
+ public Set getAttributeNameSet()
+ {
+ return null;
+ }
+
+ @Override
+ public void clearAttributes()
+ {
+ }
+
+ @Override
+ public String getId()
+ {
+ return null;
+ }
+
+ @Override
+ public Components getComponents()
+ {
+ return null;
+ }
+
+ @Override
+ public ConnectionMetaData getConnectionMetaData()
+ {
+ return null;
+ }
+
+ @Override
+ public String getMethod()
+ {
+ return null;
+ }
+
+ @Override
+ public HttpURI getHttpURI()
+ {
+ return null;
+ }
+
+ @Override
+ public Context getContext()
+ {
+ return null;
+ }
+
+ @Override
+ public HttpFields getHeaders()
+ {
+ return null;
+ }
+
+ @Override
+ public HttpFields getTrailers()
+ {
+ return null;
+ }
+
+ public List getCookies()
+ {
+ return null;
+ }
+
+ @Override
+ public long getBeginNanoTime()
+ {
+ return 0;
+ }
+
+ @Override
+ public long getHeadersNanoTime()
+ {
+ return 0;
+ }
+
+ @Override
+ public boolean isSecure()
+ {
+ return false;
+ }
+
+ @Override
+ public long getLength()
+ {
+ return 0;
+ }
+
+ @Override
+ public Content.Chunk read()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean consumeAvailable()
+ {
+ return false;
+ }
+
+ @Override
+ public void demand(Runnable demandCallback)
+ {
+ }
+
+ @Override
+ public void fail(Throwable failure)
+ {
+ }
+
+ @Override
+ public void addIdleTimeoutListener(Predicate onIdleTimeout)
+ {
+ }
+
+ @Override
+ public void addFailureListener(Consumer onFailure)
+ {
+ }
+
+ @Override
+ public TunnelSupport getTunnelSupport()
+ {
+ return null;
+ }
+
+ @Override
+ public void addHttpStreamWrapper(Function wrapper)
+ {
+ }
+
+ @Override
+ public Session getSession(boolean create)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/JAASLoginServiceTest.java b/jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/JAASLoginServiceTest.java
similarity index 100%
rename from jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/JAASLoginServiceTest.java
rename to jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/JAASLoginServiceTest.java
diff --git a/jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/TestHandler.java b/jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/TestHandler.java
similarity index 100%
rename from jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/TestHandler.java
rename to jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/TestHandler.java
diff --git a/jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/TestLoginModule.java b/jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/TestLoginModule.java
similarity index 100%
rename from jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/TestLoginModule.java
rename to jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/TestLoginModule.java
diff --git a/jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/spi/PropertyFileLoginModuleTest.java b/jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/spi/PropertyFileLoginModuleTest.java
similarity index 100%
rename from jetty-core/jetty-security/src/test/java/org.eclipse.jetty.security.jaas/spi/PropertyFileLoginModuleTest.java
rename to jetty-core/jetty-security/src/test/java/org/eclipse/jetty/security/jaas/spi/PropertyFileLoginModuleTest.java