Do not echo back username on auth failure (#10097)

* Do not echo back username on auth failure

* use bad username

* Remove username from exception messages

* fix tests

* fix the tests

* hopefully this time

* this time the tests work

* fixed this time

* fix

* upgrade to Jetty 9.4.30

* Unknown users echo back Unauthorized

* fix
This commit is contained in:
Suneet Saldanha 2020-07-10 12:19:10 -07:00 committed by GitHub
parent b7f4ce70cc
commit 58f2e51161
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 16 deletions

View File

@ -48,7 +48,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Locale;
import java.util.Map; import java.util.Map;
@JsonTypeName("basic") @JsonTypeName("basic")
@ -218,9 +217,7 @@ public class BasicHTTPAuthenticator implements Authenticator
} }
catch (BasicSecurityAuthenticationException ex) { catch (BasicSecurityAuthenticationException ex) {
LOG.info("Exception authenticating user %s - %s", user, ex.getMessage()); LOG.info("Exception authenticating user %s - %s", user, ex.getMessage());
httpResp.sendError(HttpServletResponse.SC_UNAUTHORIZED, httpResp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "User authentication failed.");
String.format(Locale.getDefault(),
"User authentication failed username[%s].", user));
} }
} }

View File

@ -165,7 +165,7 @@ public class LDAPCredentialsValidator implements CredentialsValidator
if (!validatePassword(this.ldapConfig, userDn, password)) { if (!validatePassword(this.ldapConfig, userDn, password)) {
LOG.debug("Password incorrect for LDAP user %s", username); LOG.debug("Password incorrect for LDAP user %s", username);
throw new BasicSecurityAuthenticationException("User LDAP authentication failed username[%s].", userDn.toString()); throw new BasicSecurityAuthenticationException("User LDAP authentication failed.");
} }
byte[] salt = BasicAuthUtils.generateSalt(); byte[] salt = BasicAuthUtils.generateSalt();

View File

@ -83,7 +83,7 @@ public class MetadataStoreCredentialsValidator implements CredentialsValidator
return new AuthenticationResult(username, authorizerName, authenticatorName, null); return new AuthenticationResult(username, authorizerName, authenticatorName, null);
} else { } else {
LOG.debug("Password incorrect for metadata store user %s", username); LOG.debug("Password incorrect for metadata store user %s", username);
throw new BasicSecurityAuthenticationException("User metadata store authentication failed username[%s].", username); throw new BasicSecurityAuthenticationException("User metadata store authentication failed.");
} }
} }
} }

View File

@ -174,7 +174,7 @@ public class BasicHTTPAuthenticatorTest
EasyMock.replay(req); EasyMock.replay(req);
HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class); HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "User authentication failed username[userA]."); resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "User authentication failed.");
EasyMock.expectLastCall().times(1); EasyMock.expectLastCall().times(1);
EasyMock.replay(resp); EasyMock.replay(resp);
@ -210,7 +210,7 @@ public class BasicHTTPAuthenticatorTest
validator.validateCredentials(EasyMock.eq("basic"), EasyMock.eq("basic"), EasyMock.eq("userA"), EasyMock.aryEq("badpassword".toCharArray())) validator.validateCredentials(EasyMock.eq("basic"), EasyMock.eq("basic"), EasyMock.eq("userA"), EasyMock.aryEq("badpassword".toCharArray()))
) )
.andThrow( .andThrow(
new BasicSecurityAuthenticationException("User authentication failed username[%s].", "userA") new BasicSecurityAuthenticationException("User authentication failed.")
) )
.times(1); .times(1);
EasyMock.replay(validator); EasyMock.replay(validator);
@ -220,7 +220,7 @@ public class BasicHTTPAuthenticatorTest
EasyMock.replay(req); EasyMock.replay(req);
HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class); HttpServletResponse resp = EasyMock.createMock(HttpServletResponse.class);
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "User authentication failed username[userA]."); resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "User authentication failed.");
EasyMock.expectLastCall().times(1); EasyMock.expectLastCall().times(1);
EasyMock.replay(resp); EasyMock.replay(resp);

View File

@ -143,7 +143,7 @@ public class DBCredentialsValidatorTest
String password = "badpassword"; String password = "badpassword";
expectedException.expect(BasicSecurityAuthenticationException.class); expectedException.expect(BasicSecurityAuthenticationException.class);
expectedException.expectMessage("User metadata store authentication failed username[userA]."); expectedException.expectMessage("User metadata store authentication failed.");
validator.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray()); validator.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray());
} }
} }

View File

@ -317,7 +317,8 @@ public class ITBasicAuthConfigurationTest
datasourceWithStateUserClient, datasourceWithStateUserClient,
SYS_SCHEMA_SERVER_SEGMENTS_QUERY, SYS_SCHEMA_SERVER_SEGMENTS_QUERY,
adminServerSegments.stream() adminServerSegments.stream()
.filter((serverSegmentEntry) -> ((String) serverSegmentEntry.get("segment_id")).contains("auth_test")) .filter((serverSegmentEntry) -> ((String) serverSegmentEntry.get("segment_id")).contains(
"auth_test"))
.collect(Collectors.toList()) .collect(Collectors.toList())
); );
@ -471,6 +472,26 @@ public class ITBasicAuthConfigurationTest
testOptionsRequests(adminClient); testOptionsRequests(adminClient);
} }
@Test
public void testMaliciousUser()
{
String maliciousUsername = "<script>alert('hello')</script>";
HttpClient maliciousClient = new CredentialedHttpClient(
new BasicCredentials(maliciousUsername, "noPass"),
httpClient
);
StatusResponseHolder responseHolder = HttpUtil.makeRequestWithExpectedStatus(
maliciousClient,
HttpMethod.GET,
config.getBrokerUrl() + "/status",
null,
HttpResponseStatus.UNAUTHORIZED
);
String responseContent = responseHolder.getContent();
Assert.assertTrue(responseContent.contains("<tr><th>MESSAGE:</th><td>Unauthorized</td></tr>"));
Assert.assertFalse(responseContent.contains(maliciousUsername));
}
private void testOptionsRequests(HttpClient httpClient) private void testOptionsRequests(HttpClient httpClient)
{ {
HttpUtil.makeRequest(httpClient, HttpMethod.OPTIONS, config.getCoordinatorUrl() + "/status", null); HttpUtil.makeRequest(httpClient, HttpMethod.OPTIONS, config.getCoordinatorUrl() + "/status", null);
@ -522,7 +543,7 @@ public class ITBasicAuthConfigurationTest
catch (AvaticaSqlException ase) { catch (AvaticaSqlException ase) {
Assert.assertEquals( Assert.assertEquals(
ase.getErrorMessage(), ase.getErrorMessage(),
"Error while executing SQL \"SELECT * FROM INFORMATION_SCHEMA.COLUMNS\": Remote driver error: BasicSecurityAuthenticationException: User metadata store authentication failed username[admin]." "Error while executing SQL \"SELECT * FROM INFORMATION_SCHEMA.COLUMNS\": Remote driver error: BasicSecurityAuthenticationException: User metadata store authentication failed."
); );
return; return;
} }