mirror of https://github.com/apache/druid.git
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:
parent
b7f4ce70cc
commit
58f2e51161
|
@ -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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,8 +291,8 @@ public class ITBasicAuthConfigurationTest
|
||||||
datasourceOnlyUserClient,
|
datasourceOnlyUserClient,
|
||||||
SYS_SCHEMA_TASKS_QUERY,
|
SYS_SCHEMA_TASKS_QUERY,
|
||||||
adminTasks.stream()
|
adminTasks.stream()
|
||||||
.filter((taskEntry) -> "auth_test".equals(taskEntry.get("datasource")))
|
.filter((taskEntry) -> "auth_test".equals(taskEntry.get("datasource")))
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
|
|
||||||
// as user that can read auth_test and STATE
|
// as user that can read auth_test and STATE
|
||||||
|
@ -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())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -326,8 +327,8 @@ public class ITBasicAuthConfigurationTest
|
||||||
datasourceWithStateUserClient,
|
datasourceWithStateUserClient,
|
||||||
SYS_SCHEMA_TASKS_QUERY,
|
SYS_SCHEMA_TASKS_QUERY,
|
||||||
adminTasks.stream()
|
adminTasks.stream()
|
||||||
.filter((taskEntry) -> "auth_test".equals(taskEntry.get("datasource")))
|
.filter((taskEntry) -> "auth_test".equals(taskEntry.get("datasource")))
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
|
|
||||||
// as user that can only read STATE
|
// as user that can only read STATE
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue