Skip to content

Commit 87d5ae5

Browse files
authored
Merge pull request #1 from SEPIA-Framework/dev
Update to v0.3.0: - SSL support - Settings file to configure server and path forwarding - IP filter for each path to allow/restrict access from public servers
2 parents 0b9d9da + b9a3572 commit 87d5ae5

File tree

8 files changed

+480
-34
lines changed

8 files changed

+480
-34
lines changed

pom.xml

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<modelVersion>4.0.0</modelVersion>
33
<groupId>net.b07z.sepia.proxies</groupId>
44
<artifactId>sepia-reverse-proxy</artifactId>
5-
<version>0.1.0</version>
5+
<version>0.3.0</version>
66
<packaging>jar</packaging>
77

88
<properties>
@@ -20,13 +20,13 @@
2020
<executions>
2121
<execution>
2222
<id>copy-dependencies</id>
23-
<phase>prepare-package</phase>
23+
<phase>install</phase>
2424
<goals>
2525
<goal>copy-dependencies</goal>
2626
</goals>
2727
<configuration>
2828
<outputDirectory>
29-
${project.build.directory}/libs
29+
${project.build.directory}/build/libs
3030
</outputDirectory>
3131
</configuration>
3232
</execution>
@@ -49,6 +49,46 @@
4949
<finalName>sepia-reverse-proxy-v${project.version}</finalName>
5050
</configuration>
5151
</plugin>
52+
<plugin>
53+
<artifactId>maven-resources-plugin</artifactId>
54+
<version>3.1.0</version>
55+
<executions>
56+
<execution>
57+
<id>copy-resources-1</id>
58+
<phase>install</phase>
59+
<goals>
60+
<goal>copy-resources</goal>
61+
</goals>
62+
<configuration>
63+
<outputDirectory>${project.build.directory}/build/settings</outputDirectory>
64+
<resources>
65+
<resource>
66+
<directory>settings</directory>
67+
<!--<filtering>true</filtering>-->
68+
</resource>
69+
</resources>
70+
</configuration>
71+
</execution>
72+
<execution>
73+
<id>copy-resources-2</id>
74+
<phase>install</phase>
75+
<goals>
76+
<goal>copy-resources</goal>
77+
</goals>
78+
<configuration>
79+
<outputDirectory>${project.build.directory}/build</outputDirectory>
80+
<resources>
81+
<resource>
82+
<directory>${project.build.directory}</directory>
83+
<includes>
84+
<include>*.jar</include>
85+
</includes>
86+
</resource>
87+
</resources>
88+
</configuration>
89+
</execution>
90+
</executions>
91+
</plugin>
5292
</plugins>
5393
</build>
5494

@@ -58,5 +98,11 @@
5898
<artifactId>undertow-core</artifactId>
5999
<version>2.0.1.Final</version>
60100
</dependency>
101+
102+
<dependency>
103+
<groupId>org.slf4j</groupId>
104+
<artifactId>slf4j-simple</artifactId>
105+
<version>1.7.21</version>
106+
</dependency>
61107
</dependencies>
62108
</project>

settings/proxy.properties

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Entries have to be of format: action_type_name, e.g.: redirect_path_1
2+
# Redirects must have 3 types per name: path, target, public
3+
# NOTE: The name "redirect" has to be understood in the context of proxy forwarding not 30x redirect ^^.
4+
5+
# SEPIA defaults for custom-bundle:
6+
7+
# host=localhost
8+
host=0.0.0.0
9+
port=20726
10+
11+
ssl_keystore=../letsencrypt/sepia-proxy-keystore.jks
12+
ssl_keystore_pwd=noextrapwdhere
13+
ssl_support_http=false
14+
15+
redirect_path_1=/sepia/assist
16+
redirect_target_1=http://localhost:20721
17+
redirect_public_1=true
18+
19+
redirect_path_2=/sepia/teach
20+
redirect_target_2=http://localhost:20722
21+
redirect_public_2=true
22+
23+
redirect_path_3=/sepia/chat
24+
redirect_target_3=http://localhost:20723
25+
redirect_public_3=true
Lines changed: 183 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,161 @@
11
package net.b07z.sepia.proxies;
22

3+
import java.io.BufferedInputStream;
4+
import java.io.FileInputStream;
5+
import java.io.IOException;
6+
import java.security.KeyStore;
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import java.util.Properties;
10+
11+
import javax.net.ssl.SSLContext;
12+
13+
import net.b07z.sepia.proxies.security.SSLContextBuilder;
14+
315
/**
416
* Command-line interface to start a proxy.
517
*
618
* @author Florian Quirin
719
*
820
*/
921
public class Start {
10-
22+
23+
//Overwrite JBoss logger
24+
//private static Logger logger;
25+
static{
26+
System.setProperty("org.jboss.logging.provider", "slf4j");
27+
//logger = LoggerFactory.getLogger(Start.class);
28+
}
29+
30+
//Defaults
31+
private static String host = "localhost";
32+
private static int port = 20726;
33+
private static boolean ssl = false;
34+
private static boolean sslSupportHttp = false;
35+
private static String sslKeystore = "";
36+
private static String sslKeystorePwd = "";
37+
38+
private static String SETTINGS_FILE = "settings/proxy.properties";
39+
40+
//Command-line parameters have priority
41+
private static boolean ignoreSettingsHost = false;
42+
private static boolean ignoreSettingsPort = false;
43+
44+
public static void info(String msg){
45+
System.out.println(msg);
46+
}
47+
public static void error(String msg){
48+
//logger.error(msg);
49+
System.out.println(msg);
50+
}
51+
1152
/**
1253
* Run a proxy.
1354
* @param args
1455
* @throws Exception
1556
*/
1657
public static void main(String[] args) throws Exception {
58+
1759
String proxy = "";
1860

61+
//Check if arguments are given
62+
if (args == null || args.length == 0){
63+
error("Missing proxy-name to run, e.g. 'tiny'.");
64+
help();
65+
System.exit(1);
66+
}
67+
1968
//Proxy to run:
2069
if (args[0].equals("tiny")){
2170
proxy = "tiny";
22-
23-
//default
24-
int port = 20726;
25-
String host = "localhost";
71+
info("Starting tiny proxy ...");
2672

2773
for (String arg : args){
2874
//Port
2975
if (arg.startsWith("-port=")){
3076
port = Integer.parseInt(arg.replaceFirst(".*?=", "").trim());
77+
ignoreSettingsPort = true;
3178

3279
//Host
3380
}else if (arg.startsWith("-host=")){
3481
host = arg.replaceFirst(".*?=", "").trim();
82+
ignoreSettingsHost = true;
83+
84+
//SSL
85+
}else if (arg.startsWith("-ssl=")){
86+
ssl = Boolean.parseBoolean(arg.replaceFirst(".*?=", "").trim());
3587

3688
//Paths
3789
}else if (arg.startsWith("-defaultPaths=")){
3890
String paths = arg.replaceFirst(".*?=", "").trim();
3991
if (!paths.equals("true")){
40-
System.out.println("Sorry any other than the default paths are not yet supported via command-line interface!");
41-
return;
92+
error("Sorry any other than the default paths are not yet supported via command-line interface!");
93+
System.exit(1);
4294
}
4395
//TODO: add a way to define custom prefix-path combinations (best: load from config and give config-file here as value)
4496
}
4597
}
4698

47-
//Create tiny reverse proxy
48-
TinyReverseProxy reverseProxy = new TinyReverseProxy(host, port);
99+
//Read settings
100+
List<ProxyAction> actions = null;
101+
KeyStore ks = null;
102+
SSLContext sslContext = null;
103+
try{
104+
info("Loading settings from '" + SETTINGS_FILE + "' ...");
105+
actions = loadSettings(SETTINGS_FILE);
106+
}catch(Exception e){
107+
error("Could not read '" + SETTINGS_FILE + "' file! Error: " + e.getMessage());
108+
System.exit(1);
109+
}
110+
//Check SSL settings and keystore
111+
if (ssl && (sslKeystore.isEmpty() || sslKeystorePwd.isEmpty())){
112+
error("Missing SSL keystore and/or keystore password!");
113+
System.exit(1);
114+
}else if (ssl){
115+
try{
116+
ks = SSLContextBuilder.loadKeyStore(sslKeystore, sslKeystorePwd);
117+
}catch (Exception e){
118+
error("Could not load keystore located at: " + sslKeystore + " - check path and password!");
119+
error("Error msg.: " + e.getMessage());
120+
System.exit(1);
121+
}
122+
try{
123+
sslContext = SSLContextBuilder.create(ks, null, sslKeystorePwd);
124+
}catch (Exception e){
125+
error("Could not create SSLContext from keystore!");
126+
error("Error msg.: " + e.getMessage());
127+
System.exit(1);
128+
}
129+
}
49130

50-
//Add paths - SEPIA defaults for custom-bundle:
51-
reverseProxy.addPrefixPath("/sepia/assist", "http://localhost:20721");
52-
reverseProxy.addPrefixPath("/sepia/teach", "http://localhost:20722");
53-
reverseProxy.addPrefixPath("/sepia/chat", "http://localhost:20723");
131+
//Create tiny reverse proxy
132+
TinyReverseProxy reverseProxy = new TinyReverseProxy(host, port, ssl, sslContext);
133+
reverseProxy.setSslHttpSupport(sslSupportHttp, (port + 1)); //HTTP support is done via listener on PORT+1
134+
135+
//Add actions
136+
for (ProxyAction pa : actions){
137+
if (pa.actionType.equals("redirect")){
138+
reverseProxy.addPrefixPath(pa.redirectPath, pa.redirectTarget, pa.targetIsPublic);
139+
}
140+
}
141+
/*
142+
reverseProxy.addPrefixPath("/sepia/assist", "http://localhost:20721", true);
143+
*/
54144

55145
//Start proxy
56146
reverseProxy.start();
57147

58148
//Note
59-
System.out.println("SEPIA '" + proxy + "' reverse proxy started at: " + host + ":" + port);
149+
info("\nSEPIA '" + proxy + "' reverse proxy started as: " + host + ":" + port);
150+
info("Using SSL: " + ssl);
151+
if (ssl){
152+
info("SSL keystore: " + sslKeystore);
153+
if (sslSupportHttp){
154+
info("NOTE: All calls to simple HTTP are available at port: " + (port + 1));
155+
}else{
156+
info("NOTE: All calls to simple HTTP are deactivated when SSL is active!");
157+
}
158+
}
60159

61160
return;
62161

@@ -71,11 +170,76 @@ public static void main(String[] args) throws Exception {
71170
* Command-line interface help.
72171
*/
73172
private static void help(){
74-
System.out.println("\nUsage:");
75-
System.out.println("[proxy-name] [arguments]");
76-
System.out.println("\nProxies:");
77-
System.out.println("tiny - args: -defaultPaths=true, -port=20726, -host=localhost");
78-
System.out.println("");
173+
info("\nUsage:");
174+
info("[proxy-name] [arguments]");
175+
info("\nProxies:");
176+
info("tiny - args: -defaultPaths=true, -port=20726, -host=localhost, -ssl=true");
177+
info("\nConfiguration is done via 'settings/proxy.properties' file.");
178+
info("");
179+
}
180+
181+
/**
182+
* Class holding proxy actions loaded from settings.
183+
*/
184+
private static class ProxyAction {
185+
String redirectPath;
186+
String redirectTarget;
187+
boolean targetIsPublic = false;
188+
String actionType = "";
189+
190+
public ProxyAction(){}
191+
192+
public ProxyAction setRedirect(String path, String target, boolean isPublic){
193+
this.redirectPath = path;
194+
this.redirectTarget = target;
195+
this.targetIsPublic = isPublic;
196+
this.actionType = "redirect";
197+
return this;
198+
}
199+
}
200+
201+
/**
202+
* Load settings from properties file and return actions list.
203+
* @param configFile - path and file
204+
* @throws IOException
205+
*/
206+
private static List<ProxyAction> loadSettings(String configFile) throws IOException {
207+
BufferedInputStream stream=null;
208+
Properties config = new Properties();
209+
stream = new BufferedInputStream(new FileInputStream(configFile));
210+
config.load(stream);
211+
stream.close();
212+
List<ProxyAction> actions = new ArrayList<>();
213+
for (Object key : config.keySet()){
214+
String entry = (String) key;
215+
//has to be format: action_type_name, e.g. redirect_path_1
216+
//has to have types: path, target, public
217+
if (entry.startsWith("redirect")){
218+
String[] info = entry.split("_");
219+
if (info.length != 3){
220+
throw new RuntimeException("Settings file has invalid format in entry: " + entry);
221+
}else{
222+
String name = info[2];
223+
String path = config.getProperty("redirect_path_" + name);
224+
String target = config.getProperty("redirect_target_" + name);
225+
boolean isPublic = Boolean.parseBoolean(config.getProperty("redirect_public_" + name));
226+
actions.add(new ProxyAction().setRedirect(path, target, isPublic));
227+
}
228+
229+
}else if (entry.equals("host") && !ignoreSettingsHost){
230+
host = config.getProperty(entry);
231+
}else if (entry.equals("port") && !ignoreSettingsPort){
232+
port = Integer.parseInt(config.getProperty(entry));
233+
234+
}else if (entry.equals("ssl_keystore")){
235+
sslKeystore = config.getProperty(entry);
236+
}else if (entry.equals("ssl_keystore_pwd")){
237+
sslKeystorePwd = config.getProperty(entry);
238+
}else if (entry.equals("ssl_support_http")){
239+
sslSupportHttp = Boolean.parseBoolean(config.getProperty(entry));
240+
}
241+
}
242+
return actions;
79243
}
80244

81245
}

0 commit comments

Comments
 (0)