8000 Update login events public SDK to V2 by manuel-alvarez-alvarez · Pull Request #8620 · DataDog/dd-trace-java · GitHub
[go: up one dir, main page]

Skip to content

Update login events public SDK to V2 #8620

8000
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 28, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Fix metrics and tests
  • Loading branch information
manuel-alvarez-alvarez committed Mar 28, 2025
commit c8869f6e9511efe8237bc0c9bf24fb9499c40efc
8000
Original file line number Diff line number Diff line change
Expand Up @@ -94,38 +94,38 @@ class AppSecEventTrackerSpecification extends DDSpecification {

def 'test track login success event (SDK)'() {
when:
GlobalTracer.getEventTracker().trackLoginSuccessEvent(USER_LOGIN, ['key1': 'value1', 'key2': 'value2'])
GlobalTracer.getEventTracker().trackLoginSuccessEvent(USER_ID, ['key1': 'value1', 'key2': 'value2'])

then:
1 * traceSegment.setTagTop('usr.id', USER_LOGIN)
1 * traceSegment.setTagTop('usr', ['key1': 'value1', 'key2': 'value2'])
1 * traceSegment.setTagTop('_dd.appsec.user.collection_mode', 'sdk')
1 * traceSegment.setTagTop('appsec.events.users.login.success.usr.login', USER_LOGIN, true)
1 * traceSegment.setTagTop('usr.id', USER_ID)
1 * traceSegment.setTagTop('appsec.events.users.login.success.usr.login', USER_ID, true)
1 * traceSegment.setTagTop('appsec.events.users.login.success', ['key1': 'value1', 'key2': 'value2'], true)
1 * traceSegment.setTagTop('appsec.events.users.login.success.track', true, true)
1 * traceSegment.setTagTop('_dd.appsec.events.users.login.success.sdk', true, true)
2 * traceSegment.setTagTop('asm.keep', true)
2 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM)
1 * loginEvent.apply(_ as RequestContext, LOGIN_SUCCESS, USER_LOGIN) >> NoopFlow.INSTANCE
1 * user.apply(_ as RequestContext, USER_LOGIN) >> NoopFlow.INSTANCE
1 * traceSegment.setTagTop('asm.keep', true)
1 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM)
1 * loginEvent.apply(_ as RequestContext, LOGIN_SUCCESS, USER_ID) >> NoopFlow.INSTANCE
1 * user.apply(_ as RequestContext, USER_ID) >> NoopFlow.INSTANCE
0 * _

assertAppSecSdkEvent(LOGIN_SUCCESS, V1)
}

def 'test track login failure event (SDK)'() {
when:
GlobalTracer.getEventTracker().trackLoginFailureEvent(USER_LOGIN, true, ['key1': 'value1', 'key2': 'value2'])
GlobalTracer.getEventTracker().trackLoginFailureEvent(USER_ID, true, ['key1': 'value1', 'key2': 'value2'])

then:
1 * traceSegment.setTagTop('appsec.events.users.login.failure.usr.login', USER_LOGIN, true)
1 * traceSegment.setTagTop('appsec.events.users.login.failure.usr.id', USER_ID, true)
1 * traceSegment.setTagTop('appsec.events.users.login.failure.usr.login', USER_ID, true)
1 * traceSegment.setTagTop('appsec.events.users.login.failure.usr.exists', true, true)
1 * traceSegment.setTagTop('appsec.events.users.login.failure', ['key1': 'value1', 'key2': 'value2'], true)
1 * traceSegment.setTagTop('appsec.events.users.login.failure.track', true, true)
1 * traceSegment.setTagTop('_dd.appsec.events.users.login.failure.sdk', true, true)
1 * traceSegment.setTagTop('asm.keep', true)
1 * traceSegment.setTagTop('_dd.p.ts', ProductTraceSource.ASM)
1 * loginEvent.apply(_ as RequestContext, LOGIN_FAILURE, USER_LOGIN) >> NoopFlow.INSTANCE
1 * loginEvent.apply(_ as RequestContext, LOGIN_FAILURE, USER_ID) >> NoopFlow.INSTANCE
1 * user.apply(_ as RequestContext, USER_ID) >> NoopFlow.INSTANCE
0 * _

assertAppSecSdkEvent(LOGIN_FAILURE, V1)
Expand Down Expand Up @@ -153,6 +153,8 @@ class AppSecEventTrackerSpecification extends DDSpecification {
then:
1 * traceSegment.setTagTop('usr.id', USER_ID)
1 * traceSegment.setTagTop('usr', ['key1': 'value1', 'key2': 'value2'])
1 * traceSegment.setTagTop('appsec.events.users.login.success.usr.id', USER_ID, true)
1 * traceSegment.setTagTop('appsec.events.users.login.success.usr', ['key1': 'value1', 'key2': 'value2'], true)
1 * traceSegment.setTagTop('_dd.appsec.user.collection_mode', 'sdk')
1 * traceSegment.setTagTop('appsec.events.users.login.success.usr.login', USER_LOGIN, true)
1 * traceSegment.setTagTop('appsec.events.users.login.success', ['key1': 'value1', 'key2': 'value2'], true)
Expand Down Expand Up @@ -502,12 +504,15 @@ class AppSecEventTrackerSpecification extends DDSpecification {
prepareMetrics()
drain()
}
final expectedTags = ["event_type:${event.getTag()}".toString(), "sdk_version:${version.getTag()}".toString()]
assert metrics.size() == 1
final metric = metrics.find { it.metricName == 'appsec.sdk.event'}
final metric = metrics.find { it.metricName == 'sdk.event'}
assert metric != null
assert metric.namespace == 'appsec'
assert metric.type == 'count'
assert metric.value == 1
assert metric.tags.find { "event_type:${event.getTag()}" } != null
assert metric.tags.find { "sdk_version:${version.getTag()}" } != null
assert metric.tags.size() == 2
assert metric.tags.containsAll(expectedTags)
}

private static class ActionFlow<T> implements Flow<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static datadog.trace.api.telemetry.LoginEvent.CUSTOM;
import static datadog.trace.api.telemetry.LoginEvent.LOGIN_FAILURE;
import static datadog.trace.api.telemetry.LoginEvent.LOGIN_SUCCESS;
import static datadog.trace.api.telemetry.LoginVersion.AUTO;
import static datadog.trace.api.telemetry.LoginVersion.V1;
import static datadog.trace.api.telemetry.LoginVersion.V2;
import static datadog.trace.util.Strings.toHexString;
Expand All @@ -28,6 +29,7 @@
import datadog.trace.api.gateway.RequestContextSlot;
import datadog.trace.api.internal.TraceSegment;
import datadog.trace.api.telemetry.LoginEvent;
import datadog.trace.api.telemetry.LoginVersion;
import datadog.trace.api.telemetry.WafMetricCollector;
import datadog.trace.bootstrap.ActiveSubsystems;
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
Expand Down Expand Up @@ -72,7 +74,7 @@ public final void trackLoginSuccessEvent(String userId, Map<String, String> meta
throw new IllegalArgumentException("userId is null or empty");
}
WafMetricCollector.get().appSecSdkEvent(LOGIN_SUCCESS, V1);
if (handleLoginEvent(LOGIN_SUCCESS_EVENT, SDK, userId, userId, null, metadata)) {
if (handleLoginEvent(V1, LOGIN_SUCCESS_EVENT, SDK, userId, userId, null, metadata)) {
throw new BlockingException("Blocked request (for login success)");
}
}
Expand All @@ -84,7 +86,7 @@ public final void trackLoginFailureEvent(
throw new IllegalArgumentException("userId is null or empty");
}
WafMetricCollector.get().appSecSdkEvent(LOGIN_FAILURE, V1);
if (handleLoginEvent(LOGIN_FAILURE_EVENT, SDK, userId, null, exists, metadata)) {
if (handleLoginEvent(V1, LOGIN_FAILURE_EVENT, SDK, userId, userId, exists, metadata)) {
throw new BlockingException("Blocked request (for login failure)");
}
}
Expand All @@ -96,7 +98,7 @@ public void trackUserLoginSuccess(
throw new IllegalArgumentException("login is null or empty");
}
WafMetricCollector.get().appSecSdkEvent(LOGIN_SUCCESS, V2);
if (handleLoginEvent(LOGIN_SUCCESS_EVENT, SDK, login, userId, null, metadata)) {
if (handleLoginEvent(V2, LOGIN_SUCCESS_EVENT, SDK, login, userId, null, metadata)) {
throw new BlockingException("Blocked request (for login success)");
}
}
Expand All @@ -108,7 +110,7 @@ public void trackUserLoginFailure(
throw new IllegalArgumentException("login is null or empty");
}
WafMetricCollector.get().appSecSdkEvent(LOGIN_FAILURE, V2);
if (handleLoginEvent(LOGIN_FAILURE_EVENT, SDK, login, null, exists, metadata)) {
if (handleLoginEvent(V2, LOGIN_FAILURE_EVENT, SDK, login, null, exists, metadata)) {
throw new BlockingException("Blocked request (for login failure)");
}
}
Expand All @@ -120,7 +122,7 @@ public final void trackCustomEvent(String eventName, Map<String, String> metadat
throw new IllegalArgumentException("eventName is null or empty");
}
WafMetricCollector.get().appSecSdkEvent(CUSTOM, V2);
if (handleLoginEvent(eventName, SDK, null, null, null, metadata)) {
if (handleLoginEvent(V2, eventName, SDK, null, null, null, metadata)) {
throw new BlockingException("Blocked request (for custom event)");
}
}
Expand All @@ -143,7 +145,7 @@ public void onUserEvent(
}

public void onUserNotFound(final UserIdCollectionMode mode) {
if (handleLoginEvent(LOGIN_FAILURE_EVENT, mode, null, null, false, null)) {
if (handleLoginEvent(AUTO, LOGIN_FAILURE_EVENT, mode, null, null, false, null)) {
throw new BlockingException("Blocked request (for user not found)");
}
}
Expand All @@ -153,7 +155,7 @@ public void onSignupEvent(
final String login,
final String userId,
final Map<String, String> metadata) {
if (handleLoginEvent(SIGNUP_EVENT, mode, login, userId, null, metadata)) {
if (handleLoginEvent(AUTO, SIGNUP_EVENT, mode, login, userId, null, metadata)) {
throw new BlockingException("Blocked request (for signup)");
}
}
Expand All @@ -163,7 +165,7 @@ public void onLoginSuccessEvent(
final String login,
final String user,
final Map<String, String> metadata) {
if (handleLoginEvent(LOGIN_SUCCESS_EVENT, mode, login, user, null, metadata)) {
if (handleLoginEvent(AUTO, LOGIN_SUCCESS_EVENT, mode, login, user, null, metadata)) {
throw new BlockingException("Blocked request (for login success)");
}
}
Expand All @@ -173,7 +175,7 @@ public void onLoginFailureEvent(
final String login,
final Boolean exists,
final Map<String, String> metadata) {
if (handleLoginEvent(LOGIN_FAILURE_EVENT, mode, login, null, exists, metadata)) {
if (handleLoginEvent(AUTO, LOGIN_FAILURE_EVENT, mode, login, null, exists, metadata)) {
throw new BlockingException("Blocked request (for login failure)");
}
}
Expand Down Expand Up @@ -220,6 +222,7 @@ private boolean handleUser(
* blocking action
*/
private boolean handleLoginEvent(
final LoginVersion version,
final String eventName,
final UserIdCollectionMode mode,
final String login,
Expand Down Expand Up @@ -250,6 +253,7 @@ private boolean handleLoginEvent(
}
segment.setTagTop("_dd.appsec.events." + eventName + ".auto.mode", mode.fullName(), true);
}
final LoginEvent event = EVENT_MAPPING.get(eventName);
if (isNewLoginEvent(mode, segment, eventName)) {
if (finalLogin != null) {
segment.setTagTop("appsec.events." + eventName + ".usr.login", finalLogin, true);
Expand All @@ -264,15 +268,27 @@ private boolean handleLoginEvent(
segment.setTagTop(Tags.ASM_KEEP, true);
segment.setTagTop(Tags.PROPAGATED_TRACE_SOURCE, ProductTraceSource.ASM);

final LoginEvent event = EVENT_MAPPING.get(eventName);
if (finalLogin != null && event != null) {
block =
dispatch(tracer, EVENTS.loginEvent(), (ctx, cb) -> cb.apply(ctx, event, finalLogin));
}
}
if (userId != null) {
// call setUser
final boolean blockUser = handleUser(mode, userId, metadata);
boolean blockUser;
if (version == V2) {
segment.setTagTop("appsec.events." + eventName + ".usr.id", userId, true);
if (metadata != null && !metadata.isEmpty()) {
segment.setTagTop("appsec.events." + eventName + ".usr", metadata, true);
}
blockUser = handleUser(mode, userId, metadata);
} else {
if (event == LOGIN_SUCCESS) {
segment.setTagTop("usr.id", userId);
} else {
segment.setTagTop("appsec.events." + eventName + ".usr.id", userId, true);
}
blockUser = dispatch(tracer, EVENTS.user(), (ctx, cb) -> cb.apply(ctx, userId));
}
block |= blockUser;
}
return block;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package datadog.trace.api.telemetry;

public enum LoginVersion {

/** Login events generated via V1 of ATO */
V1("v1"),
/** Login event generated via V2 of ATO */
V2("v2");
V2("v2"),
AUTO(null);

private final String tag;

Expand Down
5DA3
Original file line number Diff line numberDiff line change
Expand Up @@ -448,7 +448,7 @@ public MissingUserIdMetric(long counter, String framework) {
public static class AppSecSdkEvent extends WafMetric {

public AppSecSdkEvent(long counter, String event, final String version) {
super("appsec.sdk.event", counter, "event_type:" + event, "sdk_version:" + version);
super("sdk.event", counter, "event_type:" + event, "sdk_version:" + version);
}
}

Expand Down
0