aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.gradle1
-rw-r--r--pom.xml8
-rw-r--r--src/main/java/org/traccar/api/resource/SessionResource.java2
-rw-r--r--src/main/java/org/traccar/helper/IpRetriever.java48
-rw-r--r--src/main/java/org/traccar/helper/LogAction.java16
-rw-r--r--src/test/java/org/traccar/helper/IpRetrieverTest.java38
6 files changed, 113 insertions, 0 deletions
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 @@
</properties>
<dependencies>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-test</artifactId>
+ <version>5.2.2.RELEASE</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
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));
+
+ }
+
+}