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

Adds security tweaks #35

Merged
merged 6 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
13 changes: 9 additions & 4 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ relp.port,601,RELP server port
relp.reconnectInterval,10000,How long to wait before reconnecting in milliseconds
relp.appName,lsh_01,Appname to use in RELP records
relp.hostname,localhost,Hostname to use in RELP records
security.tokenRequired,true,Sets whether "Authorization: SomeSecretToken" headers are required
security.token,SomeSecretToken,A token every request must contain if security.tokenRequired is enabled.
healthcheck.enabled,true,Sets if an internal healthcheck endpoint is enabled.
healthcheck.url,/healthcheck,An internal healthcheck endpoint that will always reply 200 ok regardless of security settings. Accessing this url won't generate any events.
security.authRequired,true,Sets whether Basic HTTP Authorization headers are required.
credentials.file,etc/credentials.json,A json file with array of identity:credential mappings

|===

== Limitations
Expand All @@ -51,9 +52,13 @@ Run maven on java 11

Mount configurations to `/config/` and run.

Configuration is expected to be in `/config/config.properties`
Expected files are:

- `/config/config.properties`

- `/config/credentials.json`

Custom `log4j2.xml` can be provided by placing it in `/config/log4j2.xml`, otherwise default settings will be used.
- Optional: Custom `log4j2.xml` can be provided by placing it in `/config/log4j2.xml`, otherwise default settings will be used.

For example

Expand Down
7 changes: 6 additions & 1 deletion docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ if [ ! -f /config/config.properties ]; then
exit 1;
fi;

if [ ! -f /config/credentials.json ]; then
echo "ERROR: Missing '/config/credentials.json', refusing to continue";
exit 1;
fi;

if [ -f /config/log4j2.xml ]; then
LOG4J_FILE="/config/log4j2.xml";
else
echo "INFO: Missing '/config/log4j2.xml', using default logger config";
LOG4J_FILE="/opt/teragrep/lsh_01/etc/log4j2.xml";
fi;

exec /usr/bin/java -Dproperties.file=/config/config.properties -Dlog4j2.configurationFile=file:"${LOG4J_FILE}" -jar /opt/teragrep/lsh_01/share/lsh_01.jar
exec /usr/bin/java -Dproperties.file=/config/config.properties -Dcredentials.file=/config/credentials.json -Dlog4j2.configurationFile=file:"${LOG4J_FILE}" -jar /opt/teragrep/lsh_01/share/lsh_01.jar
5 changes: 3 additions & 2 deletions etc/config.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ relp.reconnectInterval=10000
relp.appName=lsh_01
relp.hostname=localhost

security.tokenRequired=true
security.token=SomeSecretToken
security.authRequired=true

credentials.file=etc/credentials.json
6 changes: 6 additions & 0 deletions etc/credentials.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"identity": "ExampleUser",
"credential": "ExamplePassword"
}
]
12 changes: 12 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@
<artifactId>rlo_14</artifactId>
<version>${rlo_14.version}</version>
</dependency>
<!-- security -->
<dependency>
<groupId>com.teragrep</groupId>
<artifactId>jai_02</artifactId>
<version>1.0.2</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- netty -->
<dependency>
<groupId>io.netty</groupId>
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/com/teragrep/lsh_01/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@
*/
package com.teragrep.lsh_01;

import com.teragrep.lsh_01.config.InternalEndpointUrlConfig;
import com.teragrep.lsh_01.config.NettyConfig;
import com.teragrep.lsh_01.config.RelpConfig;
import com.teragrep.lsh_01.config.SecurityConfig;
import com.teragrep.lsh_01.authentication.BasicAuthentication;
import com.teragrep.lsh_01.authentication.BasicAuthenticationFactory;
import com.teragrep.lsh_01.config.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

Expand All @@ -34,6 +33,7 @@ public static void main(String[] args) {
NettyConfig nettyConfig = new NettyConfig();
RelpConfig relpConfig = new RelpConfig();
SecurityConfig securityConfig = new SecurityConfig();
BasicAuthentication basicAuthentication = new BasicAuthenticationFactory().create();
InternalEndpointUrlConfig internalEndpointUrlConfig = new InternalEndpointUrlConfig();
try {
nettyConfig.validate();
Expand All @@ -48,8 +48,8 @@ public static void main(String[] args) {
LOGGER.info("Got server config: <[{}]>", nettyConfig);
LOGGER.info("Got relp config: <[{}]>", relpConfig);
LOGGER.info("Got internal endpoint config: <[{}]>", internalEndpointUrlConfig);
LOGGER.info("Requires token: <[{}]>", securityConfig.tokenRequired);
RelpConversion relpConversion = new RelpConversion(relpConfig, securityConfig);
LOGGER.info("Authentication required: <[{}]>", securityConfig.authRequired);
RelpConversion relpConversion = new RelpConversion(relpConfig, securityConfig, basicAuthentication);
try (
NettyHttpServer server = new NettyHttpServer(
nettyConfig,
Expand Down
15 changes: 11 additions & 4 deletions src/main/java/com/teragrep/lsh_01/RelpConversion.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/
package com.teragrep.lsh_01;

import com.teragrep.lsh_01.authentication.BasicAuthentication;
import com.teragrep.lsh_01.config.RelpConfig;
import com.teragrep.lsh_01.config.SecurityConfig;
import com.teragrep.rlo_14.*;
Expand All @@ -41,11 +42,17 @@ public class RelpConversion implements IMessageHandler {
private boolean isConnected = false;
private final RelpConfig relpConfig;
private final SecurityConfig securityConfig;
private final BasicAuthentication basicAuthentication;

public RelpConversion(RelpConfig relpConfig, SecurityConfig securityConfig) {
public RelpConversion(
RelpConfig relpConfig,
SecurityConfig securityConfig,
BasicAuthentication basicAuthentication
) {
this.relpConfig = relpConfig;
this.securityConfig = securityConfig;
this.relpConnection = new RelpConnection();
this.basicAuthentication = basicAuthentication;
}

public boolean onNewMessage(String remoteAddress, Map<String, String> headers, String body) {
Expand All @@ -60,16 +67,16 @@ public boolean onNewMessage(String remoteAddress, Map<String, String> headers, S
}

public boolean validatesToken(String token) {
return securityConfig.token.equals(token);
return basicAuthentication.isCredentialOk(token);
}

public boolean requiresToken() {
return securityConfig.tokenRequired;
return securityConfig.authRequired;
}

public RelpConversion copy() {
LOGGER.debug("RelpConversion.copy called");
return new RelpConversion(relpConfig, securityConfig);
return new RelpConversion(relpConfig, securityConfig, basicAuthentication);
}

public Map<String, String> responseHeaders() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
logstash-http-input to syslog bridge
Copyright 2024 Suomen Kanuuna Oy

Derivative Work of Elasticsearch
Copyright 2012-2015 Elasticsearch

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.teragrep.lsh_01.authentication;

import com.teragrep.jai_02.CredentialLookup;

import java.util.Base64;

public class BasicAuthentication {

private final Base64.Decoder decoder;
private final CredentialLookup credentialLookup;

public BasicAuthentication(CredentialLookup credentialLookup) {
this.decoder = Base64.getDecoder();
this.credentialLookup = credentialLookup;
}

public boolean isCredentialOk(String token) {
if (!token.startsWith("Basic ")) {
return false;
}
try {
String tokenString = new String(decoder.decode(token.substring("Basic".length()).trim()));
if (!tokenString.contains(":")) {
return false;
}
String[] credentialPair = tokenString.split(":", 2);
if (credentialPair[0] == null || credentialPair[1] == null) {
return false;
}
return credentialPair[1].equals(credentialLookup.getCredential(credentialPair[0]));
}
catch (IllegalArgumentException e) {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
logstash-http-input to syslog bridge
Copyright 2024 Suomen Kanuuna Oy

Derivative Work of Elasticsearch
Copyright 2012-2015 Elasticsearch

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.teragrep.lsh_01.authentication;

import com.teragrep.jai_02.CredentialLookup;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;

public class BasicAuthenticationFactory {

public BasicAuthentication create() {
BufferedReader br;
String credentialsFile = System.getProperty("credentials.file", "etc/credentials.json");
try {
br = new BufferedReader(new FileReader(credentialsFile));
}
catch (FileNotFoundException e) {
throw new IllegalArgumentException(
"Can't find credentials.json from path <[" + credentialsFile + "]>: ",
e
);
}
return new BasicAuthentication(new CredentialLookup(br));
}
}
6 changes: 2 additions & 4 deletions src/main/java/com/teragrep/lsh_01/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,13 @@

public class SecurityConfig implements Validateable {

public final boolean tokenRequired;
public final String token;
public final boolean authRequired;

public SecurityConfig() {
PropertiesReaderUtilityClass propertiesReader = new PropertiesReaderUtilityClass(
System.getProperty("properties.file", "etc/config.properties")
);
tokenRequired = propertiesReader.getBooleanProperty("security.tokenRequired");
token = propertiesReader.getStringProperty("security.token");
authRequired = propertiesReader.getBooleanProperty("security.authRequired");
}

@Override
Expand Down
Loading