Skip to content
This repository was archived by the owner on Aug 30, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions sentry-core/src/main/java/io/sentry/core/SentryOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ public class SentryOptions {
/** SdkVersion object that contains the Sentry Client Name and its version */
private @Nullable SdkVersion sdkVersion;

/** whether to send personal identifiable information along with events */
private boolean sendDefaultPii = false;

/**
* Adds an event processor
*
Expand Down Expand Up @@ -996,6 +999,14 @@ public void setSdkVersion(final @Nullable SdkVersion sdkVersion) {
this.sdkVersion = sdkVersion;
}

public boolean isSendDefaultPii() {
return sendDefaultPii;
}

public void setSendDefaultPii(boolean sendDefaultPii) {
this.sendDefaultPii = sendDefaultPii;
}

/** The BeforeSend callback */
public interface BeforeSendCallback {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.sentry.samples.spring;

import io.sentry.core.IHub;
import io.sentry.core.SentryOptions;
import io.sentry.spring.boot.SentrySecurityFilter;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Bean;
Expand All @@ -19,15 +20,19 @@
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

private final @NotNull IHub hub;
private final @NotNull SentryOptions options;

public SecurityConfiguration(final @NotNull IHub hub) {
public SecurityConfiguration(final @NotNull IHub hub, final @NotNull SentryOptions options) {
this.hub = hub;
this.options = options;
}

// this API is meant to be consumed by non-browser clients thus the CSRF protection is not needed.
@Override
@SuppressWarnings("lgtm[java/spring-disabled-csrf-protection]")
protected void configure(final @NotNull HttpSecurity http) throws Exception {
// register SentrySecurityFilter to attach user information to SentryEvents
http.addFilterAfter(new SentrySecurityFilter(hub), AnonymousAuthenticationFilter.class)
http.addFilterAfter(new SentrySecurityFilter(hub, options), AnonymousAuthenticationFilter.class)
.csrf()
.disable()
.authorizeRequests()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry project/dashboard
sentry.dsn=https://[email protected]/1808954
sentry.send-default-pii=true
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ static class SentryWebMvcConfiguration {

@Bean
public @NotNull FilterRegistrationBean<SentryRequestFilter> sentryRequestFilter(
final @NotNull IHub sentryHub) {
final @NotNull IHub sentryHub, final @NotNull SentryOptions sentryOptions) {
FilterRegistrationBean<SentryRequestFilter> filterRegistrationBean =
new FilterRegistrationBean<>(new SentryRequestFilter(sentryHub));
new FilterRegistrationBean<>(new SentryRequestFilter(sentryHub, sentryOptions));
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.jakewharton.nopen.annotation.Open;
import io.sentry.core.IHub;
import io.sentry.core.SentryOptions;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
Expand All @@ -14,9 +15,11 @@
@Open
public class SentryRequestFilter extends OncePerRequestFilter {
private final @NotNull IHub hub;
private final @NotNull SentryOptions options;

public SentryRequestFilter(final @NotNull IHub hub) {
public SentryRequestFilter(final @NotNull IHub hub, final @NotNull SentryOptions options) {
this.hub = hub;
this.options = options;
}

@Override
Expand All @@ -29,7 +32,7 @@ protected void doFilterInternal(

hub.configureScope(
scope -> {
scope.addEventProcessor(new SentryRequestHttpServletRequestProcessor(request));
scope.addEventProcessor(new SentryRequestHttpServletRequestProcessor(request, options));
});
filterChain.doFilter(request, response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import com.jakewharton.nopen.annotation.Open;
import io.sentry.core.EventProcessor;
import io.sentry.core.SentryEvent;
import io.sentry.core.SentryOptions;
import io.sentry.core.protocol.Request;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.jetbrains.annotations.NotNull;
Expand All @@ -15,10 +18,16 @@
/** Attaches information about HTTP request to {@link SentryEvent}. */
@Open
public class SentryRequestHttpServletRequestProcessor implements EventProcessor {
private static final List<String> SENSITIVE_HEADERS =
Arrays.asList("X-FORWARDED-FOR", "AUTHORIZATION", "COOKIES");

private final @NotNull HttpServletRequest request;
private final @NotNull SentryOptions options;

public SentryRequestHttpServletRequestProcessor(final @NotNull HttpServletRequest request) {
public SentryRequestHttpServletRequestProcessor(
final @NotNull HttpServletRequest request, final @NotNull SentryOptions options) {
this.request = request;
this.options = options;
}

@Override
Expand All @@ -30,22 +39,27 @@ public SentryRequestHttpServletRequestProcessor(final @NotNull HttpServletReques

// httpRequest.getRequestURL() returns StringBuffer which is considered an obsolete class.
@SuppressWarnings("JdkObsolete")
private static @NotNull Request resolveSentryRequest(
final @NotNull HttpServletRequest httpRequest) {
private @NotNull Request resolveSentryRequest(final @NotNull HttpServletRequest httpRequest) {
final Request sentryRequest = new Request();
sentryRequest.setMethod(httpRequest.getMethod());
sentryRequest.setQueryString(httpRequest.getQueryString());
sentryRequest.setUrl(httpRequest.getRequestURL().toString());
sentryRequest.setHeaders(resolveHeadersMap(httpRequest));
sentryRequest.setCookies(toString(httpRequest.getHeaders("Cookie")));

if (options.isSendDefaultPii()) {
sentryRequest.setCookies(toString(httpRequest.getHeaders("Cookie")));
}
return sentryRequest;
}

private static @NotNull Map<String, String> resolveHeadersMap(
private @NotNull Map<String, String> resolveHeadersMap(
final @NotNull HttpServletRequest request) {
final Map<String, String> headersMap = new HashMap<>();
for (String headerName : Collections.list(request.getHeaderNames())) {
headersMap.put(headerName, toString(request.getHeaders(headerName)));
// do not copy personal information identifiable headers
if (options.isSendDefaultPii() || !SENSITIVE_HEADERS.contains(headerName.toUpperCase())) {
headersMap.put(headerName, toString(request.getHeaders(headerName)));
}
}
return headersMap;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.jakewharton.nopen.annotation.Open;
import io.sentry.core.IHub;
import io.sentry.core.SentryOptions;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
Expand All @@ -17,9 +18,11 @@
@Open
public class SentrySecurityFilter extends OncePerRequestFilter {
private final @NotNull IHub hub;
private final @NotNull SentryOptions options;

public SentrySecurityFilter(final @NotNull IHub hub) {
public SentrySecurityFilter(final @NotNull IHub hub, final @NotNull SentryOptions options) {
this.hub = hub;
this.options = options;
}

@Override
Expand All @@ -32,7 +35,7 @@ protected void doFilterInternal(
scope ->
scope.addEventProcessor(
new SentryUserHttpServletRequestProcessor(
request.getUserPrincipal(), toIpAddress(request))));
request.getUserPrincipal(), toIpAddress(request), options)));
filterChain.doFilter(request, response);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.jakewharton.nopen.annotation.Open;
import io.sentry.core.EventProcessor;
import io.sentry.core.SentryEvent;
import io.sentry.core.SentryOptions;
import io.sentry.core.protocol.User;
import java.security.Principal;
import java.util.Optional;
Expand All @@ -14,25 +15,31 @@
public class SentryUserHttpServletRequestProcessor implements EventProcessor {
private final @Nullable Principal principal;
private final @Nullable String ipAddress;
private final @NotNull SentryOptions options;

public SentryUserHttpServletRequestProcessor(
final @Nullable Principal principal, final @Nullable String ipAddress) {
final @Nullable Principal principal,
final @Nullable String ipAddress,
final @NotNull SentryOptions options) {
this.principal = principal;
this.ipAddress = ipAddress;
this.options = options;
}

@Override
public SentryEvent process(final @NotNull SentryEvent event, final @Nullable Object hint) {
final User user = Optional.ofNullable(event.getUser()).orElseGet(User::new);
if (options.isSendDefaultPii()) {
final User user = Optional.ofNullable(event.getUser()).orElseGet(User::new);

if (ipAddress != null) {
user.setIpAddress(ipAddress);
}
if (principal != null) {
user.setUsername(principal.getName());
}
if (ipAddress != null) {
user.setIpAddress(ipAddress);
}
if (principal != null) {
user.setUsername(principal.getName());
}

event.setUser(user);
event.setUser(user);
}
return event;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package io.sentry.spring.boot

import io.sentry.core.SentryEvent
import io.sentry.core.SentryOptions
import java.net.URI
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertTrue
import org.springframework.http.MediaType
import org.springframework.mock.web.MockServletContext
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
Expand All @@ -17,7 +21,7 @@ class SentryRequestHttpServletRequestProcessorTest {
.header("some-header", "some-header value")
.accept(MediaType.APPLICATION_JSON)
.buildRequest(MockServletContext())
val eventProcessor = SentryRequestHttpServletRequestProcessor(request)
val eventProcessor = SentryRequestHttpServletRequestProcessor(request, SentryOptions())
val event = SentryEvent()

eventProcessor.process(event, null)
Expand All @@ -38,7 +42,7 @@ class SentryRequestHttpServletRequestProcessorTest {
.header("another-header", "another value")
.header("another-header", "another value2")
.buildRequest(MockServletContext())
val eventProcessor = SentryRequestHttpServletRequestProcessor(request)
val eventProcessor = SentryRequestHttpServletRequestProcessor(request, SentryOptions())
val event = SentryEvent()

eventProcessor.process(event, null)
Expand All @@ -49,17 +53,59 @@ class SentryRequestHttpServletRequestProcessorTest {
}

@Test
fun `attaches cookies information`() {
fun `when sendDefaultPii is set to true, attaches cookies information`() {
val request = MockMvcRequestBuilders
.get(URI.create("http://example.com?param1=xyz"))
.header("Cookie", "name=value")
.header("Cookie", "name2=value2")
.buildRequest(MockServletContext())
val eventProcessor = SentryRequestHttpServletRequestProcessor(request)
val sentryOptions = SentryOptions()
sentryOptions.isSendDefaultPii = true
val eventProcessor = SentryRequestHttpServletRequestProcessor(request, sentryOptions)
val event = SentryEvent()

eventProcessor.process(event, null)

assertEquals("name=value,name2=value2", event.request.cookies)
}

@Test
fun `when sendDefaultPii is set to false, does not attach cookies`() {
val request = MockMvcRequestBuilders
.get(URI.create("http://example.com?param1=xyz"))
.header("Cookie", "name=value")
.buildRequest(MockServletContext())
val sentryOptions = SentryOptions()
sentryOptions.isSendDefaultPii = false
val eventProcessor = SentryRequestHttpServletRequestProcessor(request, sentryOptions)
val event = SentryEvent()

eventProcessor.process(event, null)

assertNull(event.request.cookies)
}

@Test
fun `when sendDefaultPii is set to false, does not attach sensitive headers`() {
val request = MockMvcRequestBuilders
.get(URI.create("http://example.com?param1=xyz"))
.header("some-header", "some-header value")
.header("X-FORWARDED-FOR", "192.168.0.1")
.header("authorization", "Token")
.header("Authorization", "Token")
.header("Cookies", "some cookies")
.buildRequest(MockServletContext())
val sentryOptions = SentryOptions()
sentryOptions.isSendDefaultPii = false
val eventProcessor = SentryRequestHttpServletRequestProcessor(request, sentryOptions)
val event = SentryEvent()

eventProcessor.process(event, null)

assertFalse(event.request.headers.containsKey("X-FORWARDED-FOR"))
assertFalse(event.request.headers.containsKey("Authorization"))
assertFalse(event.request.headers.containsKey("authorization"))
assertFalse(event.request.headers.containsKey("Cookies"))
assertTrue(event.request.headers.containsKey("some-header"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.nhaarman.mockitokotlin2.verify
import io.sentry.core.IHub
import io.sentry.core.Sentry
import io.sentry.core.SentryEvent
import io.sentry.core.SentryOptions
import io.sentry.core.transport.ITransport
import org.assertj.core.api.Assertions.assertThat
import org.awaitility.kotlin.await
Expand Down Expand Up @@ -37,7 +38,7 @@ import org.springframework.web.bind.annotation.RestController
@SpringBootTest(
classes = [App::class],
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
properties = ["sentry.dsn=http://key@localhost/proj"]
properties = ["sentry.dsn=http://key@localhost/proj", "sentry.send-default-pii=true"]
)
class SentrySpringIntegrationTest {

Expand Down Expand Up @@ -97,11 +98,14 @@ class HelloController {
}

@Configuration
open class SecurityConfiguration(private val hub: IHub) : WebSecurityConfigurerAdapter() {
open class SecurityConfiguration(
private val hub: IHub,
private val options: SentryOptions
) : WebSecurityConfigurerAdapter() {

override fun configure(http: HttpSecurity) {
http
.addFilterAfter(SentrySecurityFilter(hub), AnonymousAuthenticationFilter::class.java)
.addFilterAfter(SentrySecurityFilter(hub, options), AnonymousAuthenticationFilter::class.java)
.csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and()
Expand Down
Loading