Skip to content

Commit

Permalink
Merge pull request #17 from ClaudioWaldvogel/feat/authentication
Browse files Browse the repository at this point in the history
Closes #18: feature: Add WebSecurity to EUM Server
  • Loading branch information
Heiko Holz authored Dec 16, 2022
2 parents f5cfce0 + 50d04ea commit 47ec595
Show file tree
Hide file tree
Showing 20 changed files with 1,143 additions and 6 deletions.
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

0 comments on commit 47ec595

Please sign in to comment.