Skip to content

Commit 2a848ef

Browse files
Update login events public SDK to V2 (#8620)
Update login events public SDK to V2
1 parent 86e5bec commit 2a848ef

File tree

13 files changed

+589
-312
lines changed

13 files changed

+589
-312
lines changed

dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,13 @@ public class GatewayBridge {
6868

6969
/** User tracking tags that will force the collection of request headers */
7070
private static final String[] USER_TRACKING_TAGS = {
71-
"appsec.events.users.login.success.track", "appsec.events.users.login.failure.track"
71+
"appsec.events.users.login.success.track",
72+
"appsec.events.users.login.failure.track",
73+
"appsec.events.users.signup.track"
7274
};
7375

76+
private static final String USER_COLLECTION_MODE_TAG = "_dd.appsec.user.collection_mode";
77+
7478
private static final Map<LoginEvent, Address<?>> EVENT_MAPPINGS = new EnumMap<>(LoginEvent.class);
7579

7680
static {
@@ -708,7 +712,7 @@ private NoopFlow onRequestEnded(RequestContext ctx_, IGSpanInfo spanInfo) {
708712
StackUtils.addStacktraceEventsToMetaStruct(ctx_, METASTRUCT_EXPLOIT, stackTraces);
709713
}
710714

711-
} else if (hasUserTrackingEvent(traceSeg)) {
715+
} else if (hasUserInfo(traceSeg)) {
712716
// Report all collected request headers on user tracking event
713717
writeRequestHeaders(traceSeg, REQUEST_HEADERS_ALLOW_LIST, ctx.getRequestHeaders());
714718
} else {
@@ -803,6 +807,10 @@ public void stop() {
803807
subscriptionService.reset();
804808
}
805809

810+
private static boolean hasUserInfo(final TraceSegment traceSegment) {
811+
return hasUserTrackingEvent(traceSegment) || hasUserCollectionEvent(traceSegment);
812+
}
813+
806814
private static boolean hasUserTrackingEvent(final TraceSegment traceSeg) {
807815
for (String tagName : USER_TRACKING_TAGS) {
808816
final Object value = traceSeg.getTagTop(tagName);
@@ -813,6 +821,10 @@ private static boolean hasUserTrackingEvent(final TraceSegment traceSeg) {
813821
return false;
814822
}
815823

824+
private static boolean hasUserCollectionEvent(final TraceSegment traceSeg) {
825+
return traceSeg.getTagTop(USER_COLLECTION_MODE_TAG) != null;
826+
}
827+
816828
private static void writeRequestHeaders(
817829
final TraceSegment traceSeg,
818830
final Set<String> allowed,

dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/user/AppSecEventTrackerSpecification.groovy

Lines changed: 151 additions & 92 deletions
Large diffs are not rendered by default.

dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/user/EventTrackerAppSecDisabledForkedTest.groovy

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.datadog.appsec.user
22

3+
import datadog.appsec.api.login.EventTrackerV2
34
import datadog.appsec.api.user.User
45
import datadog.trace.api.GlobalTracer
56
import datadog.trace.api.UserIdCollectionMode
@@ -26,6 +27,7 @@ class EventTrackerAppSecDisabledForkedTest extends DDSpecification {
2627
void setup() {
2728
tracker = new AppSecEventTracker()
2829
GlobalTracer.setEventTracker(tracker)
30+
EventTrackerV2.setEventTrackerService(tracker)
2931
User.setUserService(tracker)
3032
traceSegment = Mock(TraceSegment)
3133
final tracer = Stub(AgentTracer.TracerAPI) {
@@ -40,15 +42,15 @@ class EventTrackerAppSecDisabledForkedTest extends DDSpecification {
4042
GlobalTracer.getEventTracker().trackLoginSuccessEvent('user', ['key1': 'value1', 'key2': 'value2'])
4143
4244
then:
43-
1 * traceSegment.setTagTop('_dd.appsec.events.users.login.success.sdk', true)
45+
1 * traceSegment.setTagTop('_dd.appsec.events.users.login.success.sdk', true, true)
4446
}
4547
4648
void 'test track login failure event (SDK)'() {
4749
when:
4850
GlobalTracer.getEventTracker().trackLoginFailureEvent('user', true, ['key1': 'value1', 'key2': 'value2'])
4951
5052
then:
51-
1 * traceSegment.setTagTop('_dd.appsec.events.users.login.failure.sdk', true)
53+
1 * traceSegment.setTagTop('_dd.appsec.events.users.login.failure.sdk', true, true)
5254
}
5355
5456
void 'test track custom event (SDK)'() {
@@ -59,6 +61,30 @@ class EventTrackerAppSecDisabledForkedTest extends DDSpecification {
5961
1 * traceSegment.setTagTop('_dd.appsec.events.myevent.sdk', true, true)
6062
}
6163
64+
void 'test track login success event V2 (SDK)'() {
65+
when:
66+
EventTrackerV2.trackUserLoginSuccess('user', 'id', ['key1': 'value1', 'key2': 'value2'])
67+
68+
then:
69+
1 * traceSegment.setTagTop('_dd.appsec.events.users.login.success.sdk', true, true)
70+
}
71+
72+
void 'test track login failure event V2 (SDK)'() {
73+
when:
74+
EventTrackerV2.trackUserLoginFailure('user', true, ['key1': 'value1', 'key2': 'value2'])
75+
76+
then:
77+
1 * traceSegment.setTagTop('_dd.appsec.events.users.login.failure.sdk', true, true)
78+
}
79+
80+
void 'test track custom event V2 (SDK)'() {
81+
when:
82+
EventTrackerV2.trackCustomEvent('myevent', ['key1': 'value1', 'key2': 'value2'])
83+
84+
then:
85+
1 * traceSegment.setTagTop('_dd.appsec.events.myevent.sdk', true, true)
86+
}
87+
6288
void 'test onSignup'() {
6389
when:
6490
tracker.onSignupEvent(IDENTIFICATION, 'user', ['key1': 'value1', 'key2': 'value2'])

dd-trace-api/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ excludedClassesCoverage += [
3838
'datadog.trace.api.experimental.DataStreamsContextCarrier.NoOp',
3939
'datadog.appsec.api.blocking.*',
4040
'datadog.appsec.api.user.*',
41+
'datadog.appsec.api.login.*',
4142
// Default fallback methods to not break legacy API
4243
'datadog.trace.context.TraceScope',
4344
'datadog.trace.context.NoopTraceScope.NoopContinuation',
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package datadog.appsec.api.login;
2+
3+
import java.util.Map;
4+
5+
public interface EventTrackerService {
6+
7+
EventTrackerService NO_OP =
8+
new EventTrackerService() {
9+
@Override
10+
public void trackUserLoginSuccess(
11+
final String login, final String userId, final Map<String, String> metadata) {}
12+
13+
@Override
14+
public void trackUserLoginFailure(
15+
final String login, final boolean exists, final Map<String, String> metadata) {}
16+
17+
@Override
18+
public void trackCustomEvent(final String eventName, final Map<String, String> metadata) {}
19+
};
20+
21+
void trackUserLoginSuccess(String login, String userId, Map<String, String> metadata);
22+
23+
void trackUserLoginFailure(String login, boolean exists, Map<String, String> metadata);
24+
25+
void trackCustomEvent(String eventName, Map<String, String> metadata);
26+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package datadog.appsec.api.login;
2+
3+
import java.util.Map;
4+
5+
public class EventTrackerV2 {
6+
7+
private static volatile EventTrackerService SERVICE = EventTrackerService.NO_OP;
8+
9+
/**
10+
* Controls the implementation for service. The AppSec subsystem calls this method on startup.
11+
* This can be called explicitly for e.g. testing purposes.
12+
*
13+
* @param service the implementation for the user service.
14+
*/
15+
public static void setEventTrackerService(final EventTrackerService service) {
16+
SERVICE = service;
17+
}
18+
19+
/**
20+
* Tracks a successful user login event.
21+
*
22+
* @param login the non-null login data (e.g., username or email) used for authentication.
23+
* @param userId an optional user ID string; can be null.
24+
* @param metadata optional metadata for the login event; can be null.
25+
*/
26+
public static void trackUserLoginSuccess(
27+
final String login, final String userId, Map<String, String> metadata) {
28+
SERVICE.trackUserLoginSuccess(login, userId, metadata);
29+
}
30+
31+
/**
32+
* Tracks a failed user login event.
33+
*
34+
* @param login the non-null login data (e.g., username or email) used for authentication.
35+
* @param exists indicates whether the provided login identifier corresponds to an existing user.
36+
* @param metadata optional metadata for the login event; can be null.
37+
*/
38+
public static void trackUserLoginFailure(
39+
String login, boolean exists, Map<String, String> metadata) {
40+
SERVICE.trackUserLoginFailure(login, exists, metadata);
41+
}
42+
43+
/**
44+
* Method for tracking custom events.
45+
*
46+
* @param eventName name of the custom event
47+
* @param metadata custom metadata data represented as key/value map
48+
*/
49+
public static void trackCustomEvent(String eventName, Map<String, String> metadata) {
50+
SERVICE.trackCustomEvent(eventName, metadata);
51+
}
52+
}

dd-trace-api/src/main/java/datadog/trace/api/EventTracker.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package datadog.trace.api;
22

3+
import datadog.appsec.api.login.EventTrackerV2;
34
import java.util.Map;
45

6+
/** This class has been deprecated in favor of {@link EventTrackerV2} */
7+
@Deprecated
58
public class EventTracker {
69

710
public static final EventTracker NO_EVENT_TRACKER = new EventTracker();
@@ -12,7 +15,9 @@ public class EventTracker {
1215
*
1316
* @param userId user id used for login
1417
* @param metadata custom metadata data represented as key/value map
18+
* @deprecated use {@link EventTrackerV2#trackUserLoginSuccess(String, String, Map)}
1519
*/
20+
@Deprecated
1621
public void trackLoginSuccessEvent(String userId, Map<String, String> metadata) {}
1722

1823
/**
@@ -22,6 +27,7 @@ public void trackLoginSuccessEvent(String userId, Map<String, String> metadata)
2227
* @param userId user id used for login
2328
* @param exists flag indicates if provided userId exists
2429
* @param metadata custom metadata data represented as key/value map
30+
* @deprecated use {@link EventTrackerV2#trackUserLoginFailure(String, boolean, Map)}
2531
*/
2632
public void trackLoginFailureEvent(String userId, boolean exists, Map<String, String> metadata) {}
2733

@@ -31,6 +37,7 @@ public void trackLoginFailureEvent(String userId, boolean exists, Map<String, St
3137
*
3238
* @param eventName name of the custom event
3339
* @param metadata custom metadata data represented as key/value map
40+
* @deprecated use {@link EventTrackerV2#trackCustomEvent(String, Map)}
3441
*/
3542
public void trackCustomEvent(String eventName, Map<String, String> metadata) {}
3643
}

dd-trace-api/src/main/java/datadog/trace/api/GlobalTracer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ public static Tracer get() {
8585
return provider;
8686
}
8787

88+
/** @deprecated use static methods in {@link EventTrackerV2} directly */
89+
@Deprecated
8890
public static EventTracker getEventTracker() {
8991
return eventTracker;
9092
}

0 commit comments

Comments
 (0)