opends/resource/config/config.ldif
@@ -498,6 +498,7 @@ ds-cfg-ssl-client-auth-policy: optional ds-cfg-ssl-cert-nickname: server-cert ds-cfg-config-file: config/http-config.json ds-cfg-authentication-required: true dn: cn=LDIF Connection Handler,cn=Connection Handlers,cn=config objectClass: top opends/resource/schema/02-config.ldif
@@ -3671,6 +3671,12 @@ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.119 NAME 'ds-cfg-authentication-required' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'OpenDJ Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.1 NAME 'ds-cfg-access-control-handler' SUP top @@ -3848,7 +3854,8 @@ ds-cfg-ssl-cipher-suite $ ds-cfg-max-blocked-write-time-limit $ ds-cfg-buffer-size $ ds-cfg-config-file ) ds-cfg-config-file $ ds-cfg-authentication-required ) X-ORIGIN 'OpenDJ Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.14 NAME 'ds-cfg-entry-cache' opends/src/admin/defn/org/opends/server/admin/std/HTTPConnectionHandlerConfiguration.xml
@@ -217,7 +217,7 @@ <adm:property name="max-request-size" advanced="true"> <adm:synopsis> Specifies the size in bytes of the largest HTTP request message that will be allowed by this HTTP Connection handler. be allowed by the <adm:user-friendly-name />. </adm:synopsis> <adm:description> This can help prevent denial-of-service attacks by clients that indicate @@ -429,7 +429,7 @@ </adm:property> <adm:property name="config-file" mandatory="true"> <adm:synopsis> Specifies the name of the configuration file for the HTTP Connection Handler. Specifies the name of the configuration file for the <adm:user-friendly-name />. </adm:synopsis> <adm:default-behavior> <adm:defined> @@ -453,4 +453,32 @@ </ldap:attribute> </adm:profile> </adm:property> <adm:property name="authentication-required" mandatory="true"> <adm:synopsis> Specifies whether only authenticated requests can be processed by the <adm:user-friendly-name />. </adm:synopsis> <adm:description> If true, only authenticated requests will be processed by the <adm:user-friendly-name />. If false, both authenticated requests and unauthenticated requests will be processed. All requests are subject to ACI limitations and unauthenticated requests are subject to server limits like maximum number of entries returned. Note that setting ds-cfg-reject-unauthenticated-requests to true will override the current setting. </adm:description> <adm:default-behavior> <adm:defined> <adm:value>true</adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:boolean /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:name>ds-cfg-authentication-required</ldap:name> </ldap:attribute> </adm:profile> </adm:property> </adm:managed-object> opends/src/admin/messages/HTTPConnectionHandlerCfgDefn.properties
@@ -12,6 +12,8 @@ property.allowed-client.requires-admin-action.synopsis=Changes to this property take effect immediately and do not interfere with connections that may have already been established. property.allow-tcp-reuse-address.synopsis=Indicates whether the HTTP Connection Handler should reuse socket descriptors. property.allow-tcp-reuse-address.description=If enabled, the SO_REUSEADDR socket option is used on the server listen socket to potentially allow the reuse of socket descriptors for clients in a TIME_WAIT state. This may help the server avoid temporarily running out of socket descriptors in cases in which a very large number of short-lived connections have been established from the same client system. property.authentication-required.synopsis=Specifies whether only authenticated requests can be processed by the HTTP Connection Handler. property.authentication-required.description=If true, only authenticated requests will be processed by the HTTP Connection Handler. If false, both authenticated requests and unauthenticated requests will be processed. All requests are subject to ACI limitations and unauthenticated requests are subject to server limits like maximum number of entries returned. Note that setting ds-cfg-reject-unauthenticated-requests to true will override the current setting. property.buffer-size.synopsis=Specifies the size in bytes of the HTTP response message write buffer. property.buffer-size.description=This property specifies write buffer size allocated by the server for each client connection and used to buffer HTTP response messages data when writing. property.config-file.synopsis=Specifies the name of the configuration file for the HTTP Connection Handler. @@ -31,7 +33,7 @@ property.listen-port.description=Only a single port number may be provided. property.max-blocked-write-time-limit.synopsis=Specifies the maximum length of time that attempts to write data to HTTP clients should be allowed to block. property.max-blocked-write-time-limit.description=If an attempt to write data to a client takes longer than this length of time, then the client connection is terminated. property.max-request-size.synopsis=Specifies the size in bytes of the largest HTTP request message that will be allowed by this HTTP Connection handler. property.max-request-size.synopsis=Specifies the size in bytes of the largest HTTP request message that will be allowed by the HTTP Connection Handler. property.max-request-size.description=This can help prevent denial-of-service attacks by clients that indicate they send extremely large requests to the server causing it to attempt to allocate large amounts of memory. property.ssl-cert-nickname.synopsis=Specifies the nickname (also called the alias) of the certificate that the HTTP Connection Handler should use when performing SSL communication. property.ssl-cert-nickname.description=This is only applicable when the HTTP Connection Handler is configured to use SSL. opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
@@ -134,29 +134,24 @@ Connection connection = new SdkConnectionAdapter(clientConnection); String[] userPassword = extractUsernamePassword(request); if (userPassword != null && userPassword.length == 2) AuthenticationInfo authInfo = getAuthenticationInfo(request, connection); if (authInfo != null) { AuthenticationInfo authInfo = authenticate(userPassword[0], userPassword[1], connection); if (authInfo != null) { clientConnection.setAuthenticationInfo(authInfo); clientConnection.setAuthenticationInfo(authInfo); /* * WARNING: This action triggers 3-4 others: Set the connection for * use with this request on the HttpServletRequest. It will make * Rest2LDAPContextFactory create an AuthenticatedConnectionContext * which will in turn ensure Rest2LDAP uses the supplied Connection * object */ request.setAttribute( Rest2LDAPContextFactory.ATTRIBUTE_AUTHN_CONNECTION, connection); /* * WARNING: This action triggers 3-4 others: Set the connection for use * with this request on the HttpServletRequest. It will make * Rest2LDAPContextFactory create an AuthenticatedConnectionContext * which will in turn ensure Rest2LDAP uses the supplied Connection * object. */ request.setAttribute( Rest2LDAPContextFactory.ATTRIBUTE_AUTHN_CONNECTION, connection); // send the request further down the filter chain or pass to servlet chain.doFilter(request, response); return; } // send the request further down the filter chain or pass to servlet chain.doFilter(request, response); return; } // The user could not be authenticated. Send an HTTP Basic authentication @@ -227,6 +222,37 @@ } /** * Returns an {@link AuthenticationInfo} object if the request is accepted. An * {@link AuthenticationInfo} object will be returned if authentication * credentials were valid or if unauthenticated requests are allowed on this * server. * * @param request * the request used to extract the {@link AuthenticationInfo} * @param connection * the connection used to retrieve the {@link AuthenticationInfo} * @return an {@link AuthenticationInfo} if the request is accepted, null if * the request was rejected * @throws Exception * if any problem occur */ AuthenticationInfo getAuthenticationInfo(ServletRequest request, Connection connection) throws Exception { String[] userPassword = extractUsernamePassword(request); if (userPassword != null && userPassword.length == 2) { return authenticate(userPassword[0], userPassword[1], connection); } else if (this.connectionHandler.acceptUnauthenticatedRequests()) { // return unauthenticated return new AuthenticationInfo(); } return null; } /** * Extracts the username and password from the request using one of the * enabled authentication mechanism: HTTP Basic authentication or HTTP Custom * headers. If no username and password can be obtained, then send back an opends/src/server/org/opends/server/protocols/http/HTTPConnectionHandler.java
@@ -186,6 +186,20 @@ super(DEFAULT_FRIENDLY_NAME); } /** * Returns whether unauthenticated HTTP requests are allowed. The server * checks whether unauthenticated requests are allowed server-wide first then * for the HTTP Connection Handler second. * * @return true if unauthenticated requests are allowed, false otherwise. */ public boolean acceptUnauthenticatedRequests() { // the global setting overrides the more specific setting here. return !DirectoryServer.rejectUnauthenticatedRequests() && !this.currentConfig.isAuthenticationRequired(); } /** {@inheritDoc} */ @Override public ConfigChangeResult applyConfigurationChange( opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java
@@ -28,6 +28,7 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import static org.opends.server.protocols.http.CollectClientConnectionsFilter.*; import java.io.IOException; @@ -36,15 +37,15 @@ import javax.servlet.http.HttpServletResponse; import org.opends.server.DirectoryServerTestCase; import org.opends.server.types.AuthenticationInfo; import org.opends.server.util.Base64; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @SuppressWarnings("javadoc") public class CollectClientConnectionsFilterTest extends DirectoryServerTestCase { private static final String AUTHORIZATION = CollectClientConnectionsFilter.HTTP_BASIC_AUTH_HEADER; private static final String USERNAME = "Aladdin"; private static final String PASSWORD = "open sesame"; private static final String BASE64_USERPASS = Base64 @@ -131,7 +132,7 @@ authConfig.setBasicAuthenticationSupported(true); HttpServletRequest request = mock(HttpServletRequest.class); when(request.getHeader(AUTHORIZATION)).thenReturn( when(request.getHeader(HTTP_BASIC_AUTH_HEADER)).thenReturn( "Basic " + BASE64_USERPASS); assertThat(filter.extractUsernamePassword(request)).containsExactly( @@ -156,4 +157,23 @@ USERNAME, PASSWORD); } /** * Tests that getAuthenticationInfo() without basic auth header or custom * headers returns an unauthenticated info when the server accepts * unauthenticated requests. */ @Test public void getAuthenticationInfoReturnsUnauthenticatedInfo() throws Exception { HttpServletRequest request = mock(HttpServletRequest.class); HTTPConnectionHandler cfg = mock(HTTPConnectionHandler.class); when(cfg.acceptUnauthenticatedRequests()).thenReturn(true); filter = new CollectClientConnectionsFilter(cfg, authConfig); AuthenticationInfo authInfo = filter.getAuthenticationInfo(request, null); assertThat(authInfo).isNotNull(); assertThat(authInfo.isAuthenticated()).isFalse(); } }