public class AuthenticationEventImpl implements AuthenticationEvent {
private static final Logger LOGGER = Loggers.get("auth.event");
+ private static final int FLOOD_THRESHOLD = 128;
@Override
public void login(HttpServletRequest request, @Nullable String login, Source source) {
LOGGER.info("login success [method|{}][provider|{}|{}][IP|{}|{}][login|{}]",
source.getMethod(), source.getProvider(), source.getProviderName(),
request.getRemoteAddr(), getAllIps(request),
- emptyIfNull(login));
+ preventLogFlood(emptyIfNull(login)));
}
private static String getAllIps(HttpServletRequest request) {
emptyIfNull(e.getMessage()),
source.getMethod(), source.getProvider(), source.getProviderName(),
request.getRemoteAddr(), getAllIps(request),
- emptyIfNull(e.getLogin()));
+ preventLogFlood(emptyIfNull(e.getLogin())));
}
private static String emptyIfNull(@Nullable String login) {
return login == null ? "" : login;
}
+ private static String preventLogFlood(String str) {
+ if (str.length() > FLOOD_THRESHOLD) {
+ return str.substring(0, FLOOD_THRESHOLD) + "...(" + str.length() + ")";
+ }
+ return str;
+ }
+
}
import static org.sonar.server.authentication.event.AuthenticationException.newBuilder;
public class AuthenticationEventImplTest {
+ private static final String LOGIN_129_CHARS = "012345678901234567890123456789012345678901234567890123456789" +
+ "012345678901234567890123456789012345678901234567890123456789012345678";
+
@Rule
public LogTester logTester = new LogTester();
@Rule
verifyLog("login success [method|BASIC][provider|REALM|some provider name][IP||][login|foo]");
}
+ @Test
+ public void login_prevents_log_flooding_on_login_starting_from_128_chars() {
+ underTest.login(mockRequest(), LOGIN_129_CHARS, Source.realm(Method.BASIC, "some provider name"));
+
+ verifyLog("login success [method|BASIC][provider|REALM|some provider name][IP||][login|012345678901234567890123456789012345678901234567890123456789" +
+ "01234567890123456789012345678901234567890123456789012345678901234567...(129)]");
+ }
+
@Test
public void login_logs_remote_ip_from_request() {
underTest.login(mockRequest("1.2.3.4"), "foo", Source.realm(Method.EXTERNAL, "bar"));
@Test
public void failure_creates_INFO_log_with_method_provider_and_login() {
AuthenticationException exception = newBuilder()
- .setSource(Source.realm(Method.BASIC, "some provider name"))
- .setMessage("something got terribly wrong")
- .setLogin("BaR")
- .build();
+ .setSource(Source.realm(Method.BASIC, "some provider name"))
+ .setMessage("something got terribly wrong")
+ .setLogin("BaR")
+ .build();
underTest.failure(mockRequest(), exception);
verifyLog("login failure [cause|something got terribly wrong][method|BASIC][provider|REALM|some provider name][IP||][login|BaR]");
}
+ @Test
+ public void failure_prevents_log_flooding_on_login_starting_from_128_chars() {
+ AuthenticationException exception = newBuilder()
+ .setSource(Source.realm(Method.BASIC, "some provider name"))
+ .setMessage("pop")
+ .setLogin(LOGIN_129_CHARS)
+ .build();
+ underTest.failure(mockRequest(), exception);
+
+ verifyLog("login failure [cause|pop][method|BASIC][provider|REALM|some provider name][IP||][login|012345678901234567890123456789012345678901234567890123456789" +
+ "01234567890123456789012345678901234567890123456789012345678901234567...(129)]");
+ }
+
@Test
public void failure_logs_remote_ip_from_request() {
AuthenticationException exception = newBuilder()
- .setSource(Source.realm(Method.EXTERNAL, "bar"))
- .setMessage("Damn it!")
- .setLogin("Baaad")
- .build();
+ .setSource(Source.realm(Method.EXTERNAL, "bar"))
+ .setMessage("Damn it!")
+ .setLogin("Baaad")
+ .build();
underTest.failure(mockRequest("1.2.3.4"), exception);
verifyLog("login failure [cause|Damn it!][method|EXTERNAL][provider|REALM|bar][IP|1.2.3.4|][login|Baaad]");
@Test
public void failure_logs_X_Forwarded_For_header_from_request() {
AuthenticationException exception = newBuilder()
- .setSource(Source.realm(Method.EXTERNAL, "bar"))
- .setMessage("Hop la!")
- .setLogin("foo")
- .build();
+ .setSource(Source.realm(Method.EXTERNAL, "bar"))
+ .setMessage("Hop la!")
+ .setLogin("foo")
+ .build();
HttpServletRequest request = mockRequest("1.2.3.4", asList("2.3.4.5"));
underTest.failure(request, exception);
@Test
public void failure_logs_X_Forwarded_For_header_from_request_and_supports_multiple_headers() {
AuthenticationException exception = newBuilder()
- .setSource(Source.realm(Method.EXTERNAL, "bar"))
- .setMessage("Boom!")
- .setLogin("foo")
- .build();
+ .setSource(Source.realm(Method.EXTERNAL, "bar"))
+ .setMessage("Boom!")
+ .setLogin("foo")
+ .build();
HttpServletRequest request = mockRequest("1.2.3.4", asList("2.3.4.5", "6.5.4.3"), asList("9.5.6.7"), asList("6.3.2.4"));
underTest.failure(request, exception);