From fcad646a7c912463c53de946b2586e4a49a6e1ff Mon Sep 17 00:00:00 2001 From: developerKurt Date: Wed, 1 Jan 2020 13:42:05 +0300 Subject: As requested in issue #4393, added logging IP address functionality when login attempts fail. --- build.gradle | 1 + pom.xml | 8 ++++ .../org/traccar/api/resource/SessionResource.java | 2 + src/main/java/org/traccar/helper/IpRetriever.java | 48 ++++++++++++++++++++++ src/main/java/org/traccar/helper/LogAction.java | 16 ++++++++ .../java/org/traccar/helper/IpRetrieverTest.java | 38 +++++++++++++++++ 6 files changed, 113 insertions(+) create mode 100644 src/main/java/org/traccar/helper/IpRetriever.java create mode 100644 src/test/java/org/traccar/helper/IpRetrieverTest.java diff --git a/build.gradle b/build.gradle index 8e65bfdd1..3622bdbd4 100644 --- a/build.gradle +++ b/build.gradle @@ -75,6 +75,7 @@ dependencies { implementation "com.sun.xml.bind:jaxb-impl:2.3.2" implementation "javax.activation:activation:1.1.1" testImplementation "junit:junit:4.12" + testImplementation group: 'org.springframework', name: 'spring-test', version: '5.2.2.RELEASE' } task copyDependencies(type: Copy) { diff --git a/pom.xml b/pom.xml index 050321d7b..1de77eb66 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,14 @@ + + + org.springframework + spring-test + 5.2.2.RELEASE + test + + junit junit diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index fd331c766..65e05a4a2 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.IpRetriever; 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(IpRetriever.retrieveIP(request)); throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); } } diff --git a/src/main/java/org/traccar/helper/IpRetriever.java b/src/main/java/org/traccar/helper/IpRetriever.java new file mode 100644 index 000000000..37a1e8662 --- /dev/null +++ b/src/main/java/org/traccar/helper/IpRetriever.java @@ -0,0 +1,48 @@ +package org.traccar.helper; + +import javax.servlet.http.HttpServletRequest; + +/** + * Gets the client's IP address regardless of whether the server is behind a proxy server or a load balancer. + * + */ +public final class IpRetriever + { + + + /** + * Retrieves the client's IP address. + * Handles the cases like whether the server is behind a proxy server or a load balancer + * also if the request is being made by using a reverse proxy. + * + * @param request {@link HttpServletRequest} instance + * @return client's IP address + */ + public static String retrieveIP(HttpServletRequest request) { + + if(request != null){ + String ipAddress = request.getHeader("X-FORWARDED-FOR"); + + if (ipAddress != null && !ipAddress.isEmpty()) { + return removeUnwantedData(ipAddress); + } + else{ + ipAddress = request.getRemoteAddr(); + return ipAddress; + } + + } else return null; + + } + + /** + * If the request uses a reverse proxy, the header value will also contain load balancer and reverse proxy server IPs + * This method gets rid of them. + * + * @param ipAddress IP address value from the header + * @return IP address of the client + */ + private static String removeUnwantedData(String ipAddress){ + return ipAddress.contains(",") ? ipAddress.split(",")[0] : ipAddress; + } +} diff --git a/src/main/java/org/traccar/helper/LogAction.java b/src/main/java/org/traccar/helper/LogAction.java index db13337b8..1fbd78c4d 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,20 @@ 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)); diff --git a/src/test/java/org/traccar/helper/IpRetrieverTest.java b/src/test/java/org/traccar/helper/IpRetrieverTest.java new file mode 100644 index 000000000..628b5dd63 --- /dev/null +++ b/src/test/java/org/traccar/helper/IpRetrieverTest.java @@ -0,0 +1,38 @@ +package org.traccar.helper; + + +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; + +import static org.junit.Assert.assertEquals; + +public class IpRetrieverTest { + + private static final String NORMAL_IP_ADDRESS = "231.23.45.65"; + private static final String GATEWAY_IP_ADDRESS = "147.120.1.5"; + private static final String IP_ADDRESS_BEHIND_REVERSE_PROXY = "231.23.45.65, 10.20.10.33, 10.20.20.34"; + + private MockHttpServletRequest mockHttpServletRequest; + + @Before + public void init(){ + mockHttpServletRequest = new MockHttpServletRequest(); + } + + @Test + public void testIpBehindReverseProxy(){ + mockHttpServletRequest.setRemoteAddr(GATEWAY_IP_ADDRESS); + mockHttpServletRequest.addHeader("X-FORWARDED-FOR",IP_ADDRESS_BEHIND_REVERSE_PROXY); + + assertEquals(NORMAL_IP_ADDRESS, IpRetriever.retrieveIP(mockHttpServletRequest)); + } + + @Test + public void testNormalIp(){ + mockHttpServletRequest.setRemoteAddr(NORMAL_IP_ADDRESS); + assertEquals(NORMAL_IP_ADDRESS, IpRetriever.retrieveIP(mockHttpServletRequest)); + + } + +} -- cgit v1.2.3