-
Notifications
You must be signed in to change notification settings - Fork 881
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Capture enduser attributes in Spring Security (#9777)
- Loading branch information
Showing
26 changed files
with
1,387 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
instrumentation/spring/spring-security-config-6.0/javaagent/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# OpenTelemetry Javaagent Instrumentation: Spring Security Config | ||
|
||
Javaagent automatic instrumentation to capture `enduser.*` semantic attributes | ||
from Spring Security `Authentication` objects. | ||
|
||
## Settings | ||
|
||
This module honors the [common `otel.instrumentation.common.enduser.*` properties](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/#common-instrumentation-configuration) | ||
and the following properties: | ||
|
||
| Property | Type | Default | Description | | ||
|-------------------------------------------------------------------------------|---------|----------|---------------------------------------------------------------------------------------------------------| | ||
| `otel.instrumentation.spring-security.enduser.role.granted-authority-prefix` | String | `ROLE_` | Prefix of granted authorities identifying roles to capture in the `enduser.role` semantic attribute. | | ||
| `otel.instrumentation.spring-security.enduser.scope.granted-authority-prefix` | String | `SCOPE_` | Prefix of granted authorities identifying scopes to capture in the `enduser.scopes` semantic attribute. | |
38 changes: 38 additions & 0 deletions
38
instrumentation/spring/spring-security-config-6.0/javaagent/build.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
plugins { | ||
id("otel.javaagent-instrumentation") | ||
} | ||
|
||
muzzle { | ||
pass { | ||
group.set("org.springframework.security") | ||
module.set("spring-security-config") | ||
versions.set("[6.0.0,]") | ||
|
||
extraDependency("jakarta.servlet:jakarta.servlet-api:6.0.0") | ||
extraDependency("org.springframework.security:spring-security-web:6.0.0") | ||
extraDependency("io.projectreactor:reactor-core:3.5.0") | ||
} | ||
} | ||
|
||
dependencies { | ||
implementation(project(":instrumentation:spring:spring-security-config-6.0:library")) | ||
|
||
library("org.springframework.security:spring-security-config:6.0.0") | ||
library("org.springframework.security:spring-security-web:6.0.0") | ||
library("io.projectreactor:reactor-core:3.5.0") | ||
|
||
testLibrary("org.springframework:spring-test:6.0.0") | ||
testLibrary("jakarta.servlet:jakarta.servlet-api:6.0.0") | ||
} | ||
|
||
otelJava { | ||
minJavaVersionSupported.set(JavaVersion.VERSION_17) | ||
} | ||
|
||
tasks { | ||
test { | ||
systemProperty("otel.instrumentation.common.enduser.id.enabled", "true") | ||
systemProperty("otel.instrumentation.common.enduser.role.enabled", "true") | ||
systemProperty("otel.instrumentation.common.enduser.scope.enabled", "true") | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
...gent/instrumentation/spring/security/config/v6_0/EnduserAttributesCapturerSingletons.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.security.config.v6_0; | ||
|
||
import io.opentelemetry.instrumentation.spring.security.config.v6_0.EnduserAttributesCapturer; | ||
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; | ||
import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig; | ||
|
||
public class EnduserAttributesCapturerSingletons { | ||
|
||
private static final EnduserAttributesCapturer ENDUSER_ATTRIBUTES_CAPTURER = | ||
createEndUserAttributesCapturerFromConfig(); | ||
|
||
private EnduserAttributesCapturerSingletons() {} | ||
|
||
public static EnduserAttributesCapturer enduserAttributesCapturer() { | ||
return ENDUSER_ATTRIBUTES_CAPTURER; | ||
} | ||
|
||
private static EnduserAttributesCapturer createEndUserAttributesCapturerFromConfig() { | ||
EnduserAttributesCapturer capturer = new EnduserAttributesCapturer(); | ||
capturer.setEnduserIdEnabled(CommonConfig.get().getEnduserConfig().isIdEnabled()); | ||
capturer.setEnduserRoleEnabled(CommonConfig.get().getEnduserConfig().isRoleEnabled()); | ||
capturer.setEnduserScopeEnabled(CommonConfig.get().getEnduserConfig().isScopeEnabled()); | ||
|
||
String rolePrefix = | ||
InstrumentationConfig.get() | ||
.getString( | ||
"otel.instrumentation.spring-security.enduser.role.granted-authority-prefix"); | ||
if (rolePrefix != null) { | ||
capturer.setRoleGrantedAuthorityPrefix(rolePrefix); | ||
} | ||
|
||
String scopePrefix = | ||
InstrumentationConfig.get() | ||
.getString( | ||
"otel.instrumentation.spring-security.enduser.scope.granted-authority-prefix"); | ||
if (scopePrefix != null) { | ||
capturer.setScopeGrantedAuthorityPrefix(rolePrefix); | ||
} | ||
return capturer; | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
...gent/instrumentation/spring/security/config/v6_0/servlet/HttpSecurityInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.security.config.v6_0.servlet; | ||
|
||
import static io.opentelemetry.javaagent.instrumentation.spring.security.config.v6_0.EnduserAttributesCapturerSingletons.enduserAttributesCapturer; | ||
import static net.bytebuddy.matcher.ElementMatchers.isMethod; | ||
import static net.bytebuddy.matcher.ElementMatchers.isProtected; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments; | ||
|
||
import io.opentelemetry.instrumentation.spring.security.config.v6_0.servlet.EnduserAttributesHttpSecurityCustomizer; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||
|
||
/** Instrumentation for {@link HttpSecurity}. */ | ||
public class HttpSecurityInstrumentation implements TypeInstrumentation { | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("org.springframework.security.config.annotation.web.builders.HttpSecurity"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
isMethod().and(isProtected()).and(named("performBuild")).and(takesArguments(0)), | ||
getClass().getName() + "$PerformBuildAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class PerformBuildAdvice { | ||
|
||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter(@Advice.This HttpSecurity httpSecurity) { | ||
new EnduserAttributesHttpSecurityCustomizer(enduserAttributesCapturer()) | ||
.customize(httpSecurity); | ||
} | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
...spring/security/config/v6_0/servlet/SpringSecurityConfigServletInstrumentationModule.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.security.config.v6_0.servlet; | ||
|
||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; | ||
import static java.util.Collections.singletonList; | ||
|
||
import com.google.auto.service.AutoService; | ||
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; | ||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; | ||
import java.util.List; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
/** Instrumentation module for servlet-based applications that use spring-security-config. */ | ||
@AutoService(InstrumentationModule.class) | ||
public class SpringSecurityConfigServletInstrumentationModule extends InstrumentationModule { | ||
public SpringSecurityConfigServletInstrumentationModule() { | ||
super("spring-security-config-servlet", "spring-security-config-servlet-6.0"); | ||
} | ||
|
||
@Override | ||
public boolean defaultEnabled(ConfigProperties config) { | ||
return super.defaultEnabled(config) | ||
/* | ||
* Since the only thing this module currently does is capture enduser attributes, | ||
* the module can be completely disabled if enduser attributes are disabled. | ||
* | ||
* If any functionality not related to enduser attributes is added to this module, | ||
* then this check will need to move elsewhere to only guard the enduser attributes logic. | ||
*/ | ||
&& CommonConfig.get().getEnduserConfig().isAnyEnabled(); | ||
} | ||
|
||
@Override | ||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() { | ||
/* | ||
* Ensure this module is only applied to Spring Security >= 6.0, | ||
* since Spring Security >= 6.0 uses Jakarta EE rather than Java EE, | ||
* and this instrumentation module uses Jakarta EE. | ||
*/ | ||
return hasClassesNamed( | ||
"org.springframework.security.authentication.ObservationAuthenticationManager"); | ||
} | ||
|
||
@Override | ||
public List<TypeInstrumentation> typeInstrumentations() { | ||
return singletonList(new HttpSecurityInstrumentation()); | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
...nstrumentation/spring/security/config/v6_0/webflux/ServerHttpSecurityInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.security.config.v6_0.webflux; | ||
|
||
import static io.opentelemetry.javaagent.instrumentation.spring.security.config.v6_0.EnduserAttributesCapturerSingletons.enduserAttributesCapturer; | ||
import static net.bytebuddy.matcher.ElementMatchers.isMethod; | ||
import static net.bytebuddy.matcher.ElementMatchers.isPublic; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArguments; | ||
|
||
import io.opentelemetry.instrumentation.spring.security.config.v6_0.webflux.EnduserAttributesServerHttpSecurityCustomizer; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; | ||
import net.bytebuddy.asm.Advice; | ||
import net.bytebuddy.description.type.TypeDescription; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
import org.springframework.security.config.web.server.ServerHttpSecurity; | ||
|
||
/** Instrumentation for {@link ServerHttpSecurity}. */ | ||
public class ServerHttpSecurityInstrumentation implements TypeInstrumentation { | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("org.springframework.security.config.web.server.ServerHttpSecurity"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
isMethod().and(isPublic()).and(named("build")).and(takesArguments(0)), | ||
getClass().getName() + "$BuildAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class BuildAdvice { | ||
|
||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter(@Advice.This ServerHttpSecurity serverHttpSecurity) { | ||
new EnduserAttributesServerHttpSecurityCustomizer(enduserAttributesCapturer()) | ||
.customize(serverHttpSecurity); | ||
} | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
...spring/security/config/v6_0/webflux/SpringSecurityConfigWebFluxInstrumentationModule.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.security.config.v6_0.webflux; | ||
|
||
import static java.util.Collections.singletonList; | ||
|
||
import com.google.auto.service.AutoService; | ||
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; | ||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; | ||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; | ||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; | ||
import java.util.List; | ||
|
||
/** Instrumentation module for webflux-based applications that use spring-security-config. */ | ||
@AutoService(InstrumentationModule.class) | ||
public class SpringSecurityConfigWebFluxInstrumentationModule extends InstrumentationModule { | ||
|
||
public SpringSecurityConfigWebFluxInstrumentationModule() { | ||
super("spring-security-config-webflux", "spring-security-config-webflux-6.0"); | ||
} | ||
|
||
@Override | ||
public boolean defaultEnabled(ConfigProperties config) { | ||
return super.defaultEnabled(config) | ||
/* | ||
* Since the only thing this module currently does is capture enduser attributes, | ||
* the module can be completely disabled if enduser attributes are disabled. | ||
* | ||
* If any functionality not related to enduser attributes is added to this module, | ||
* then this check will need to move elsewhere to only guard the enduser attributes logic. | ||
*/ | ||
&& CommonConfig.get().getEnduserConfig().isAnyEnabled(); | ||
} | ||
|
||
@Override | ||
public List<TypeInstrumentation> typeInstrumentations() { | ||
return singletonList(new ServerHttpSecurityInstrumentation()); | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
.../instrumentation/spring/security/config/v6_0/servlet/HttpSecurityInstrumentationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.spring.security.config.v6_0.servlet; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import io.opentelemetry.instrumentation.spring.security.config.v6_0.servlet.EnduserAttributesCapturingServletFilter; | ||
import java.util.Collections; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.mockito.Mock; | ||
import org.mockito.junit.jupiter.MockitoExtension; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.context.ApplicationContext; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.security.config.annotation.ObjectPostProcessor; | ||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | ||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||
import org.springframework.security.web.DefaultSecurityFilterChain; | ||
import org.springframework.test.context.junit.jupiter.SpringExtension; | ||
|
||
@ExtendWith(MockitoExtension.class) | ||
@ExtendWith(SpringExtension.class) | ||
class HttpSecurityInstrumentationTest { | ||
|
||
@Configuration | ||
static class TestConfiguration {} | ||
|
||
@Mock ObjectPostProcessor<Object> objectPostProcessor; | ||
|
||
/** | ||
* Ensures that {@link HttpSecurityInstrumentation} registers a {@link | ||
* EnduserAttributesCapturingServletFilter} in the filter chain. | ||
* | ||
* <p>Usage of the filter is covered in other unit tests. | ||
*/ | ||
@Test | ||
void ensureFilterRegistered(@Autowired ApplicationContext applicationContext) throws Exception { | ||
|
||
AuthenticationManagerBuilder authenticationBuilder = | ||
new AuthenticationManagerBuilder(objectPostProcessor); | ||
|
||
HttpSecurity httpSecurity = | ||
new HttpSecurity( | ||
objectPostProcessor, | ||
authenticationBuilder, | ||
Collections.singletonMap(ApplicationContext.class, applicationContext)); | ||
|
||
DefaultSecurityFilterChain filterChain = httpSecurity.build(); | ||
|
||
assertThat(filterChain.getFilters()) | ||
.filteredOn( | ||
item -> | ||
item.getClass() | ||
.getName() | ||
.endsWith(EnduserAttributesCapturingServletFilter.class.getSimpleName())) | ||
.hasSize(1); | ||
} | ||
} |
Oops, something went wrong.