aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2020-01-15 20:50:44 -0800
committerGitHub <noreply@github.com>2020-01-15 20:50:44 -0800
commit729021a19086d982c1b4ec5661d9140c42f030f8 (patch)
treea31c0870cc6e62b1f002d62f8c602ef124f173ab
parent50d8c39d41113a73fdae7a30971b4b39c35c5566 (diff)
parentb62d3ba2a545a2f6b2963a2aa2c36b53abdfd6bc (diff)
downloadtrackermap-server-729021a19086d982c1b4ec5661d9140c42f030f8.tar.gz
trackermap-server-729021a19086d982c1b4ec5661d9140c42f030f8.tar.bz2
trackermap-server-729021a19086d982c1b4ec5661d9140c42f030f8.zip
Merge pull request #4460 from DeveloperKurt/failedLoginLogsIp-developerKurt
Failed Login Attempts logs IP Addresses
-rw-r--r--src/main/java/org/traccar/api/resource/SessionResource.java2
-rw-r--r--src/main/java/org/traccar/helper/LogAction.java16
-rw-r--r--src/main/java/org/traccar/helper/ServletHelper.java28
-rw-r--r--src/test/java/org/traccar/helper/ServletHelperTest.java407
4 files changed, 452 insertions, 1 deletions
diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java
index fd331c766..e3c5d457f 100644
--- a/src/main/java/org/traccar/api/resource/SessionResource.java
+++ b/src/main/java/org/traccar/api/resource/SessionResource.java
@@ -18,6 +18,7 @@ package org.traccar.api.resource;
import org.traccar.Context;
import org.traccar.api.BaseResource;
import org.traccar.helper.DataConverter;
+import org.traccar.helper.ServletHelper;
import org.traccar.helper.LogAction;
import org.traccar.model.User;
@@ -106,6 +107,7 @@ public class SessionResource extends BaseResource {
LogAction.login(user.getId());
return user;
} else {
+ LogAction.failedLogin(ServletHelper.retrieveRemoteAddress(request));
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build());
}
}
diff --git a/src/main/java/org/traccar/helper/LogAction.java b/src/main/java/org/traccar/helper/LogAction.java
index db13337b8..21fe4c3fa 100644
--- a/src/main/java/org/traccar/helper/LogAction.java
+++ b/src/main/java/org/traccar/helper/LogAction.java
@@ -38,12 +38,14 @@ public final class LogAction {
private static final String ACTION_LOGIN = "login";
private static final String ACTION_LOGOUT = "logout";
+ private static final String ACTION_FAILED_LOGIN_NO_IP = "Failed Login Attempt. IP address: failed to retrieve";
private static final String ACTION_DEVICE_ACCUMULATORS = "resetDeviceAccumulators";
private static final String PATTERN_OBJECT = "user: %d, action: %s, object: %s, id: %d";
private static final String PATTERN_LINK = "user: %d, action: %s, owner: %s, id: %d, property: %s, id: %d";
private static final String PATTERN_LOGIN = "user: %d, action: %s";
+ private static final String PATTERN_FAILED_LOGIN = "Failed Login Attempt. IP address: %s";
private static final String PATTERN_DEVICE_ACCUMULATORS = "user: %d, action: %s, deviceId: %d";
public static void create(long userId, BaseModel object) {
@@ -74,6 +76,18 @@ public final class LogAction {
logLoginAction(ACTION_LOGOUT, userId);
}
+ public static void failedLogin(String ipAddress) {
+
+ if (ipAddress == null || ipAddress.isEmpty()) {
+ LOGGER.info(ACTION_FAILED_LOGIN_NO_IP);
+ } else {
+ LOGGER.info(String.format(
+ PATTERN_FAILED_LOGIN, ipAddress));
+ }
+
+ }
+
+
public static void resetDeviceAccumulators(long userId, long deviceId) {
LOGGER.info(String.format(
PATTERN_DEVICE_ACCUMULATORS, userId, ACTION_DEVICE_ACCUMULATORS, deviceId));
@@ -85,7 +99,7 @@ public final class LogAction {
}
private static void logLinkAction(String action, long userId,
- Class<?> owner, long ownerId, Class<?> property, long propertyId) {
+ Class<?> owner, long ownerId, Class<?> property, long propertyId) {
LOGGER.info(String.format(
PATTERN_LINK, userId, action,
Introspector.decapitalize(owner.getSimpleName()), ownerId,
diff --git a/src/main/java/org/traccar/helper/ServletHelper.java b/src/main/java/org/traccar/helper/ServletHelper.java
new file mode 100644
index 000000000..f951d17c0
--- /dev/null
+++ b/src/main/java/org/traccar/helper/ServletHelper.java
@@ -0,0 +1,28 @@
+package org.traccar.helper;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+public final class ServletHelper {
+
+
+ private ServletHelper() {
+ }
+
+ public static String retrieveRemoteAddress(HttpServletRequest request) {
+
+ if (request != null) {
+ String ipAddress = request.getHeader("X-FORWARDED-FOR");
+
+ if (ipAddress != null && !ipAddress.isEmpty()) {
+ return ipAddress.substring(0, ipAddress.indexOf(",")); //Removes the additional data
+ } else {
+ ipAddress = request.getRemoteAddr();
+ return ipAddress;
+ }
+
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/src/test/java/org/traccar/helper/ServletHelperTest.java b/src/test/java/org/traccar/helper/ServletHelperTest.java
new file mode 100644
index 000000000..963be998c
--- /dev/null
+++ b/src/test/java/org/traccar/helper/ServletHelperTest.java
@@ -0,0 +1,407 @@
+package org.traccar.helper;
+
+
+import org.junit.Before;
+import org.junit.Test;
+
+
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.*;
+
+import static org.junit.Assert.assertEquals;
+
+public class ServletHelperTest {
+
+
+ private MockHttpServletRequestForRemoteAddr mockHttpServletRequest;
+
+
+ @Before
+ public void init() {
+ mockHttpServletRequest = new MockHttpServletRequestForRemoteAddr();
+ }
+
+ @Test
+ public void testIpBehindReverseProxy() {
+ mockHttpServletRequest.setRemoteAddr("147.120.1.5");
+ mockHttpServletRequest.addHeader("X-FORWARDED-FOR", "231.23.45.65, 10.20.10.33, 10.20.20.34");
+
+ assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(mockHttpServletRequest));
+ }
+
+ @Test
+ public void testNormalIp() {
+ mockHttpServletRequest.setRemoteAddr("231.23.45.65");
+ assertEquals("231.23.45.65", ServletHelper.retrieveRemoteAddress(mockHttpServletRequest));
+
+ }
+
+ /**
+ * This mock implementation only supports IP address-related operations.
+ */
+ private final class MockHttpServletRequestForRemoteAddr implements HttpServletRequest {
+
+ private String remoteAddr;
+ private Map<String, String> headers = new HashMap<>();
+
+ public void setRemoteAddr(String remoteAddr) {
+ this.remoteAddr = remoteAddr;
+ }
+
+ public void addHeader(String name, String value) {
+ headers.put(name, value);
+ }
+
+ @Override
+ public String getHeader(String name) {
+ return headers.get(name);
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return remoteAddr;
+ }
+
+ @Override
+ public String getAuthType() {
+ return null;
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ return new Cookie[0];
+ }
+
+ @Override
+ public long getDateHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public Enumeration<String> getHeaders(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getHeaderNames() {
+ return null;
+ }
+
+ @Override
+ public int getIntHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public String getMethod() {
+ return null;
+ }
+
+ @Override
+ public String getPathInfo() {
+ return null;
+ }
+
+ @Override
+ public String getPathTranslated() {
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ return null;
+ }
+
+ @Override
+ public String getQueryString() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return null;
+ }
+
+ @Override
+ public boolean isUserInRole(String role) {
+ return false;
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return null;
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ return null;
+ }
+
+ @Override
+ public String getRequestURI() {
+ return null;
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return null;
+ }
+
+ @Override
+ public String getServletPath() {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession(boolean create) {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return null;
+ }
+
+ @Override
+ public String changeSessionId() {
+ return null;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromUrl() {
+ return false;
+ }
+
+ @Override
+ public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
+ return false;
+ }
+
+ @Override
+ public void login(String username, String password) throws ServletException {
+
+ }
+
+ @Override
+ public void logout() throws ServletException {
+
+ }
+
+ @Override
+ public Collection<Part> getParts() throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public Part getPart(String name) throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
+
+ }
+
+ @Override
+ public int getContentLength() {
+ return 0;
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getParameter(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getParameterNames() {
+ return null;
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ return new String[0];
+ }
+
+ @Override
+ public Map<String, String[]> getParameterMap() {
+ return null;
+ }
+
+ @Override
+ public String getProtocol() {
+ return null;
+ }
+
+ @Override
+ public String getScheme() {
+ return null;
+ }
+
+ @Override
+ public String getServerName() {
+ return null;
+ }
+
+ @Override
+ public int getServerPort() {
+ return 0;
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return null;
+ }
+
+ @Override
+ public void setAttribute(String name, Object o) {
+
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+
+ }
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public Enumeration<Locale> getLocales() {
+ return null;
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ return null;
+ }
+
+ @Override
+ public int getRemotePort() {
+ return 0;
+ }
+
+ @Override
+ public String getLocalName() {
+ return null;
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return null;
+ }
+
+ @Override
+ public int getLocalPort() {
+ return 0;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public boolean isAsyncStarted() {
+ return false;
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ return false;
+ }
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ return null;
+ }
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ return null;
+ }
+ }
+
+}