Skip to content
Snippets Groups Projects
Commit 938621cf authored by Tucker Gary Siegel's avatar Tucker Gary Siegel
Browse files

update for userAgent parsing

parent ff1574e6
No related branches found
Tags 0.9.0
No related merge requests found
......@@ -36,6 +36,7 @@ dependencies {
implementation 'org.aspectj:aspectjweaver:1.9.19' // common
implementation 'org.aspectj:aspectjrt:1.9.19' // common
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.0-rc1'
implementation 'nl.basjes.parse.useragent:yauaa:7.17.1'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
......
......@@ -5,6 +5,9 @@ import edu.umd.dawn.common.jwt.JWTUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
/**
......@@ -12,27 +15,30 @@ import org.springframework.web.servlet.HandlerInterceptor;
* @implNote This does NOT throw any error if a jwt is not provided
*/
@Log4j2
@Component
public class JWTInterceptor implements HandlerInterceptor {
@Value("${config.serviceName:dawn-service}")
private String serviceName;
@Value("${config.local:false}")
private boolean local;
@Value("${config.jwt.warn:true}")
private boolean warn;
@Value("${config.accessSecret:empty}")
private String accessSecret;
/**
*
* @param accessSecret JWT Access Secret from configuration
* @param local is the environment a local env or not
* @param warn should a warning be thrown if no jwt is provided
*/
public JWTInterceptor(String accessSecret, boolean local, boolean warn) {
this.local = local;
this.accessSecret = accessSecret;
this.warn = warn;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (accessSecret.equals("empty")) {
log.warn("This service has not been provided the configuration value for `config.accessSecret` in the application.properties configuration. Since it uses the JWTInterceptor, this is a required value for proper functionality.");
}
if (!local) {
String token = request.getHeader("Authorization");
if (token != null && !token.equals("")) {
......
package edu.umd.dawn.common.interceptor;
import edu.umd.dawn.common.logging.RequestLog;
import edu.umd.dawn.common.services.UserAgentService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Enumeration;
......@@ -10,15 +11,24 @@ import java.util.UUID;
import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.Level;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
@Log4j2
@Component
public class RequestInterceptor implements HandlerInterceptor {
private String TRACE_HEADER = "X-Request-Id";
@Value("${config.serviceName:dawn-service}")
private String serviceName;
@Autowired
private UserAgentService userAgentService;
public RequestInterceptor(String serviceName) {
MDC.put("requestId", UUID.randomUUID().toString());
this.serviceName = serviceName;
......@@ -90,13 +100,16 @@ public class RequestInterceptor implements HandlerInterceptor {
String path = fullPath.replace(servletPath, servletPattern);
Map<String, String> headers = getRequestHeaders(request);
RequestLog requestLog = RequestLog.builder()
.path(path)
.method(request.getMethod())
.statusCode(response.getStatus())
.headers(getRequestHeaders(request))
.headers(headers)
.parameters(getParemeters(request))
.duration(executeTime)
.userAgent(userAgentService.parse(headers))
.build();
log.log(Level.forName("REQUEST", 10), requestLog);
......
package edu.umd.dawn.common.logging;
import java.util.List;
import java.util.Map;
import edu.umd.dawn.common.models.UserAgent;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
......@@ -19,10 +22,13 @@ public class RequestLog extends Log {
private int statusCode;
private String method;
private String path;
private List<String> ips;
@ToString.Exclude
private Map<String, String> headers;
@ToString.Exclude
private Map<String, String> parameters;
private UserAgent userAgent;
}
package edu.umd.dawn.common.models;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class UserAgent {
@Builder.Default
private boolean bot = false;
@Builder.Default
private boolean tablet = false;
@Builder.Default
private boolean mobile = false;
@Builder.Default
private boolean desktop = false;
private String device;
private String os;
private String osVersion;
private String name;
private String version;
}
package edu.umd.dawn.common.services;
import org.springframework.stereotype.Service;
import edu.umd.dawn.common.models.UserAgent.UserAgentBuilder;
import nl.basjes.parse.useragent.UserAgent;
import nl.basjes.parse.useragent.UserAgentAnalyzer;
import static nl.basjes.parse.useragent.classify.DeviceClass.TABLET;
import static nl.basjes.parse.useragent.classify.DeviceClass.PHONE;;
@Service
public class UserAgentService {
private UserAgentAnalyzer uaa = UserAgentAnalyzer
.newBuilder()
.hideMatcherLoadStats()
.withCache(10000)
.build();
private UserAgentBuilder setDeviceType(UserAgent ua, UserAgentBuilder builder) {
String deviceType = ua.get(UserAgent.DEVICE_CLASS).getValue().toLowerCase();
if (deviceType.equals(TABLET.getValue().toLowerCase())) {
builder.tablet(true);
} else if (deviceType.equals(PHONE.getValue().toLowerCase())) {
builder.mobile(true);
} else if (deviceType.startsWith("robot")) {
builder.bot(true);
} else {
builder.desktop(true);
}
return builder;
}
public edu.umd.dawn.common.models.UserAgent parse(String userAgenString) {
UserAgent ua = uaa.parse(userAgenString);
UserAgentBuilder builder = edu.umd.dawn.common.models.UserAgent.builder();
builder = setDeviceType(ua, builder);
builder.device(ua.get(UserAgent.DEVICE_NAME).getValue());
return builder.build();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment