Skip to content
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

Closes #18: feature: Add WebSecurity to EUM Server #17

Merged
merged 7 commits into from
Dec 16, 2022
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
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ inspectit-eum-server:
enabled: true
host: localhost
port: 8888

security:
enabled: false
authorization-header: Authorization
permitted-urls:
- "/actuator/health"
- "/boomerang/**"
auth-provider:
simple:
enabled: false
watch: true
frequency: 60s
token-directory: "" # Empty by default to force users to provide one
default-file-name: "default-token-file.yaml"
```
##### Metrics Definition
A metric is defined through the following attributes:
Expand All @@ -126,3 +140,50 @@ By now, the prometheus exporter is available. If `ènabled` is set to true, the
```bash
http://[host]:[port]/metrics
```

##### Security
Currently, the EUM Server only supports a simple API token security concept. In future, additional authentication providers
will be supported.
Security can be enabled by changing spring `application.yml`, using system properties or environment variables.

```yaml
inspectit-eum-server:
....
security:
enabled: true
authorization-header: Authorization
permitted-urls:
- "/actuator/health"
- "/boomerang/**"
auth-provider:
# List of providers
....
```

##### Simple Token Provider
The simple token provider can be enabled from config file...

```yaml
inspectit-eum-server:
...
security:
....
auth-provider:
simple:
# Enable/Disable Provider
enabled: true
# Flag indicates if the directory should be watched for changes and tokens reloaded
watch: true
# How often directory should be watched for changes
frequency: 60s
# The directory where token files are stored. Empty by default to force users to provide one
token-directory: ""
# The name of the initial token file
default-file-name: "default-token-file.yaml"
```
or via environment variables:
```bash
INSPECTIT_EUM_SERVER_SECURITY_AUTH_PROVIDER_SIMPLE_TOKEN_DIRECTORY=<my-directory>
INSPECTIT_EUM_SERVER_SECURITY_AUTH_PROVIDER_SIMPLE_ENABLED=TRUE;
INSPECTIT_EUM_SERVER_SECURITY_ENABLED=TRUE
```
10 changes: 6 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ dependencies {
"org.springframework.boot:spring-boot-starter-web",
'org.springframework.boot:spring-boot-starter-actuator',
"org.springframework.boot:spring-boot-starter-validation",
"org.springframework.security:spring-security-web:5.1.5.RELEASE",
"org.springframework.boot:spring-boot-starter-security",

// pin Prometheus client to 0.6.0 to prevent auto prefixing counter metrics with "_total"
// see: https://github.com/prometheus/client_java/issues/640, https://github.com/prometheus/client_java/pull/653
Expand All @@ -127,6 +127,7 @@ dependencies {
"io.opentelemetry:opentelemetry-proto:1.1.0-alpha",
"io.opentelemetry:opentelemetry-exporter-jaeger:1.1.0",
"io.opentelemetry:opentelemetry-sdk:1.1.0",
"com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.5",

"com.google.protobuf:protobuf-java:3.15.7",
"com.google.protobuf:protobuf-java-util:3.15.7",
Expand All @@ -135,6 +136,7 @@ dependencies {
'commons-net:commons-net:3.3',
"org.apache.commons:commons-lang3:3.+",
'org.apache.commons:commons-math3:3.6.1',
'commons-io:commons-io:2.11.0',
"org.influxdb:influxdb-java:2.15",
"rocks.inspectit:opencensus-influxdb-exporter:1.2",
)
Expand All @@ -147,16 +149,16 @@ dependencies {
"org.springframework.boot:spring-boot-starter-test",
"io.opencensus:opencensus-impl:${openCensusVersion}",
'org.apache.httpcomponents:httpclient:4.5.6',
'commons-io:commons-io:2.6',
'commons-io:commons-io:2.11.0',
"org.mockito:mockito-core:${mockitoVersion}",
'org.junit.jupiter:junit-jupiter-api:5.3.1',
'org.junit.jupiter:junit-jupiter-api:5.7.2',
'org.awaitility:awaitility:3.1.5',
'org.mockito:mockito-junit-jupiter:2.23.0',
'org.testcontainers:testcontainers:1.15.2',
'org.testcontainers:junit-jupiter:1.15.2'
)

testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.3.1"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.7.2"
}

task copyServerJar(type: Copy) {
Expand Down
36 changes: 36 additions & 0 deletions codequality/idea/code_style.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<code_scheme name="Ocelot" version="173">
<option name="LINE_SEPARATOR" value="&#xA;" />
<option name="FORMATTER_TAGS_ENABLED" value="true" />
<JavaCodeStyleSettings>
<option name="JD_ADD_BLANK_AFTER_PARM_COMMENTS" value="true" />
<option name="JD_ADD_BLANK_AFTER_RETURN" value="true" />
<option name="JD_KEEP_INVALID_TAGS" value="false" />
<option name="JD_DO_NOT_WRAP_ONE_LINE_COMMENTS" value="true" />
</JavaCodeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="RIGHT_MARGIN" value="120" />
<option name="KEEP_LINE_BREAKS" value="false" />
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="KEEP_BLANK_LINES_BETWEEN_PACKAGE_DECLARATION_AND_HEADER" value="1" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
<option name="BLANK_LINES_AROUND_FIELD" value="1" />
<option name="BLANK_LINES_AROUND_FIELD_IN_INTERFACE" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="5" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />,
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="WRAP_ON_TYPING" value="0" />
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
26 changes: 26 additions & 0 deletions codequality/idea/saveactions_settings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SaveActionSettings">
<option name="actions">
<set>
<option value="activate"/>
<option value="organizeImports"/>
<option value="reformat"/>
<option value="missingOverrideAnnotation"/>
<option value="useBlocks"/>
<option value="unnecessaryThis"/>
<option value="finalPrivateMethod"/>
<option value="unnecessaryFinalOnLocalVariableOrParameter"/>
<option value="explicitTypeCanBeDiamond"/>
<option value="suppressAnnotation"/>
<option value="unnecessarySemicolon"/>
</set>
</option>
<option name="configurationPath" value=""/>
<option name="inclusions">
<set>
<option value=".*\.java"/>
</set>
</option>
</component>
</project>
4 changes: 2 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM openjdk:11-jre-slim
FROM openjdk:19-slim-buster
COPY inspectit-ocelot-eum-server.jar /
COPY entrypoint.sh /
ENTRYPOINT ["sh", "/entrypoint.sh"]
ENTRYPOINT ["sh", "/entrypoint.sh"]
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.validation.annotation.Validated;
import rocks.inspectit.oce.eum.server.configuration.model.exporters.ExportersSettings;
import rocks.inspectit.oce.eum.server.configuration.model.metric.definition.BeaconMetricDefinitionSettings;
import rocks.inspectit.oce.eum.server.configuration.model.security.SecuritySettings;
import rocks.inspectit.oce.eum.server.configuration.model.selfmonitoring.SelfMonitoringSettings;
import rocks.inspectit.oce.eum.server.configuration.model.tags.TagsSettings;

Expand Down Expand Up @@ -55,4 +56,7 @@ public class EumServerConfiguration {
@Valid
private ResourceTimingSettings resourceTiming;

@Valid
private SecuritySettings security;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package rocks.inspectit.oce.eum.server.configuration.model.security;

import lombok.Data;
import org.springframework.validation.annotation.Validated;
import rocks.inspectit.oce.eum.server.configuration.model.security.authProvider.AuthenticationProviderSettings;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.List;

@Data
@Validated
public class SecuritySettings {

/**
* Enable/Disable Security
*/
private boolean enabled;

/**
* Name of authorization header
*/
@NotEmpty
private String authorizationHeader;

/**
* List of white listed urls which must not be secured
*/
private List<String> permittedUrls;

@Valid
private AuthenticationProviderSettings authProvider;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package rocks.inspectit.oce.eum.server.configuration.model.security.authProvider;

import lombok.Data;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;

@Data
@Validated
public class AuthenticationProviderSettings {

@Valid
private SimpleApiTokenAuthenticationProviderSettings simple;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package rocks.inspectit.oce.eum.server.configuration.model.security.authProvider;

import lombok.Data;
import org.hibernate.validator.constraints.time.DurationMin;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.AssertTrue;
import java.time.Duration;

@Data
@Validated
public class SimpleApiTokenAuthenticationProviderSettings {

/**
* Flag indicates if the {@link rocks.inspectit.oce.eum.server.security.authprovider.SimpleApiTokenAuthenticationProvider} should be enabled.
*/
private boolean enabled;

/**
* Path to directory where token provider files can be loaded from.
*/
private String tokenDirectory;

/**
* Duration how often {@link #tokenDirectory} should be checked for changes.
*/
@DurationMin(millis = 1000)
private Duration frequency;

/**
* Flag indicates if {@link #tokenDirectory} should be watched for changes.
*/
private boolean watch;

/**
* Name of the default token provider file. If the file does not already exists in the tokenDirectory, it will be created.
*/
private String defaultFileName;

@AssertTrue(message = "tokenDirectory can not be null or empty if SimpleApiTokenAuthentication is enabled")
public boolean isTokenDirectoryNotNullIfEnabled() {
return !isEnabled() || (isEnabled() && StringUtils.hasText(tokenDirectory));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package rocks.inspectit.oce.eum.server.security;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;
import java.util.Collections;

/**
* {@link Authentication} implementation for ApiToken Authentications
*/
public class ApiTokenAuthentication extends AbstractAuthenticationToken {

/**
* Default principal name for unauthorized users
*/
private static final String UNAUTHORIZED_TOKEN_USER = "unauthorized_token_user";

/**
* The current authenticated principal. {@link ApiTokenAuthentication#UNAUTHORIZED_TOKEN_USER} if not yet authorized
*/
private String principal = UNAUTHORIZED_TOKEN_USER;

/**
* The token used for authentication
*/
private String token;

/**
* Creates an unauthenticated ApiTokenAuthentication instance
*
* @param token The token used for later authentication
*/
public ApiTokenAuthentication(String token) {
super(Collections.emptyList());
this.token = token;
}

/**
* Creates an authenticated ApiTokenAuthentication instance
*
* @param principal The name of the authenticated principal
* @param authorities List of {@link GrantedAuthority}s (TODO Currently not in use)
*/
public ApiTokenAuthentication(String principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
setAuthenticated(true);
}

@Override
public Object getCredentials() {
return token;
}

@Override
public Object getPrincipal() {
return principal;
}
}
Loading