Skip to content

Commit 75ceb7d

Browse files
author
Psilo
committed
Merge branch 'features/keycloak'
2 parents 93340d5 + 4e0b68d commit 75ceb7d

20 files changed

+822
-69
lines changed

.gitlab-ci.yml

Lines changed: 0 additions & 26 deletions
This file was deleted.

deploy/docker-compose.yml

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,33 @@
11
version: '3'
22
services:
3-
backend:
4-
image: gufalcon/http-server:latest
5-
restart: always
6-
depends_on:
7-
- db
8-
ports:
9-
- "1280:8080"
10-
- "12443:8443"
11-
environment:
12-
- HTTP_PORT=8080
13-
- HTTP_HOST=0.0.0.0
14-
- DB_DRIVER=mysql
15-
- DB_SERVER=db
16-
- DB_PORT=3306
17-
- DB_NAME=httpserver
18-
- DB_USER=httpserver
19-
- DB_PASSWORD=DP5V7hi7xgknaH39lDTX
20-
labels:
21-
- "traefik.enable=true"
22-
- "traefik.http-server.port=8080"
23-
- "traefik.http-server.backend=http-server"
24-
- "traefik.http-server.frontend.rule=Host:http-server.unterrainer.info"
25-
- "traefik.http-server.frontend.entryPoints=http,https"
3+
# backend:
4+
# image: gufalcon/http-server:latest
5+
# restart: always
6+
# depends_on:
7+
# - db
8+
# ports:
9+
# - "1280:8080"
10+
# - "12443:8443"
11+
# environment:
12+
# - HTTP_PORT=8080
13+
# - HTTP_HOST=0.0.0.0
14+
# - DB_DRIVER=mysql
15+
# - DB_SERVER=db
16+
# - DB_PORT=3306
17+
# - DB_NAME=httpserver
18+
# - DB_USER=httpserver
19+
# - DB_PASSWORD=DP5V7hi7xgknaH39lDTX
20+
# - KEYCLOAK_HOST=keycloak
21+
# - KEYCLOAK_REALM=nexus
22+
# labels:
23+
# - "traefik.enable=true"
24+
# - "traefik.http-server.port=8080"
25+
# - "traefik.http-server.backend=http-server"
26+
# - "traefik.http-server.frontend.rule=Host:http-server.unterrainer.info"
27+
# - "traefik.http-server.frontend.entryPoints=http,https"
2628

27-
db:
28-
image: mariadb:latest
29+
db-container:
30+
image: mysql:latest
2931
restart: always
3032
ports:
3133
- 14300:3306
@@ -37,6 +39,35 @@ services:
3739
volumes:
3840
- "/app/data/http-server/mysql-data/db:/var/lib/mysql"
3941

42+
keycloak_db:
43+
image: mariadb:latest
44+
restart: always
45+
ports:
46+
- 14310:3306
47+
environment:
48+
- MYSQL_ROOT_PASSWORD=3YazHzbLuzChlwroXLSm5I
49+
- MYSQL_DATABASE=keycloak
50+
- MYSQL_USER=keycloak
51+
- MYSQL_PASSWORD=8KNM3flMpEyCYkFw5wrGoCN3
52+
volumes:
53+
- "/app/data/keycloak/mysql-data/db:/var/lib/mysql"
54+
55+
keycloak:
56+
image: quay.io/keycloak/keycloak:latest
57+
restart: always
58+
depends_on:
59+
- keycloak_db
60+
ports:
61+
- 14888:8080
62+
environment:
63+
DB_VENDOR: mariadb
64+
DB_ADDR: keycloak_db
65+
DB_DATABASE: keycloak
66+
DB_USER: keycloak
67+
DB_PASSWORD: 8KNM3flMpEyCYkFw5wrGoCN3
68+
KEYCLOAK_USER: admin
69+
KEYCLOAK_PASSWORD: cTWJiYZDutP6tYxXnv2yg0A
70+
4071
networks:
4172
default:
4273
external:

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
<modelVersion>4.0.0</modelVersion>
1919
<artifactId>http-server</artifactId>
20-
<version>0.0.42</version>
20+
<version>0.1.0</version>
2121
<name>HttpServer</name>
2222
<packaging>jar</packaging>
2323

@@ -57,6 +57,11 @@
5757
<artifactId>jetty-server</artifactId>
5858
<version>9.4.30.v20200611</version>
5959
</dependency>
60+
<dependency>
61+
<groupId>org.keycloak</groupId>
62+
<artifactId>keycloak-core</artifactId>
63+
<version>11.0.2</version>
64+
</dependency>
6065
</dependencies>
6166

6267
</project>

src/main/java/info/unterrainer/commons/httpserver/GenericHandlerGroup.java

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package info.unterrainer.commons.httpserver;
22

33
import java.io.IOException;
4+
import java.util.ArrayList;
5+
import java.util.LinkedHashMap;
46
import java.util.List;
7+
import java.util.Map.Entry;
58
import java.util.concurrent.ExecutorService;
69

710
import info.unterrainer.commons.httpserver.daos.BasicDao;
@@ -19,6 +22,7 @@
1922
import info.unterrainer.commons.serialization.exceptions.JsonMappingException;
2023
import info.unterrainer.commons.serialization.exceptions.JsonProcessingException;
2124
import info.unterrainer.commons.serialization.jsons.BasicJson;
25+
import io.javalin.core.security.Role;
2226
import io.javalin.http.Context;
2327
import lombok.AccessLevel;
2428
import lombok.RequiredArgsConstructor;
@@ -37,6 +41,7 @@ public class GenericHandlerGroup<P extends BasicJpa, J extends BasicJson, E> imp
3741
private final List<Endpoint> endpoints;
3842
private final List<GetListInterceptor> getListInterceptors;
3943
private final HandlerExtensions<P, J, E> extensions;
44+
private final LinkedHashMap<Endpoint, Role[]> accessRoles;
4045
private final ExecutorService executorService;
4146
private final HandlerUtils hu = new HandlerUtils();
4247

@@ -46,18 +51,42 @@ public void addHandlers(final HttpServer server) {
4651
if (!p.startsWith("/"))
4752
p = "/" + p;
4853
String pId = p + "/:" + QueryField.ID;
49-
if (endpoints.contains(Endpoint.ALL) || endpoints.contains(Endpoint.READONLY)
50-
|| endpoints.contains(Endpoint.GET_SINGLE))
51-
server.get(pId, this::getEntry);
52-
if (endpoints.contains(Endpoint.ALL) || endpoints.contains(Endpoint.READONLY)
53-
|| endpoints.contains(Endpoint.GET_LIST))
54-
server.get(p, this::getList);
55-
if (endpoints.contains(Endpoint.ALL) || endpoints.contains(Endpoint.CREATE))
56-
server.post(p, this::create);
57-
if (endpoints.contains(Endpoint.ALL) || endpoints.contains(Endpoint.UPDATE_FULL))
58-
server.put(pId, this::fullUpdate);
59-
if (endpoints.contains(Endpoint.ALL) || endpoints.contains(Endpoint.DELETE))
60-
server.delete(pId, this::delete);
54+
55+
List<Endpoint> endpointList;
56+
endpointList = List.of(Endpoint.ALL, Endpoint.READONLY, Endpoint.GET_SINGLE);
57+
if (endpointsToCreate(endpointList))
58+
server.get(pId, this::getEntry, rolesFor(endpointList));
59+
60+
endpointList = List.of(Endpoint.ALL, Endpoint.READONLY, Endpoint.GET_LIST);
61+
if (endpointsToCreate(endpointList))
62+
server.get(p, this::getList, rolesFor(endpointList));
63+
64+
endpointList = List.of(Endpoint.ALL, Endpoint.WRITEONLY, Endpoint.CREATE);
65+
if (endpointsToCreate(endpointList))
66+
server.post(p, this::create, rolesFor(endpointList));
67+
68+
endpointList = List.of(Endpoint.ALL, Endpoint.WRITEONLY, Endpoint.UPDATE_FULL);
69+
if (endpointsToCreate(endpointList))
70+
server.put(pId, this::fullUpdate, rolesFor(endpointList));
71+
72+
endpointList = List.of(Endpoint.ALL, Endpoint.WRITEONLY, Endpoint.DELETE);
73+
if (endpointsToCreate(endpointList))
74+
server.delete(pId, this::delete, rolesFor(endpointList));
75+
}
76+
77+
private boolean endpointsToCreate(final List<Endpoint> endpointList) {
78+
for (Endpoint endpoint : endpointList)
79+
if (endpoints.contains(endpoint))
80+
return true;
81+
return false;
82+
}
83+
84+
private Role[] rolesFor(final List<Endpoint> endpointList) {
85+
List<Role> roles = new ArrayList<>();
86+
for (Entry<Endpoint, Role[]> entry : accessRoles.entrySet())
87+
if (endpointList.contains(entry.getKey()))
88+
roles.addAll(List.of(entry.getValue()));
89+
return roles.toArray(new Role[0]);
6190
}
6291

6392
private void getEntry(final Context ctx) {

src/main/java/info/unterrainer/commons/httpserver/GenericHandlerGroupBuilder.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.ArrayList;
44
import java.util.Arrays;
5+
import java.util.LinkedHashMap;
56
import java.util.List;
67
import java.util.concurrent.ExecutorService;
78

@@ -12,6 +13,7 @@
1213
import info.unterrainer.commons.rdbutils.entities.BasicJpa;
1314
import info.unterrainer.commons.serialization.JsonMapper;
1415
import info.unterrainer.commons.serialization.jsons.BasicJson;
16+
import io.javalin.core.security.Role;
1517
import lombok.AccessLevel;
1618
import lombok.RequiredArgsConstructor;
1719
import ma.glasnost.orika.MapperFactory;
@@ -33,6 +35,7 @@ public class GenericHandlerGroupBuilder<P extends BasicJpa, J extends BasicJson,
3335
private ExecutorService executorService;
3436

3537
HandlerExtensions<P, J, E> extensions = new HandlerExtensions<>();
38+
private LinkedHashMap<Endpoint, Role[]> accessRoles = new LinkedHashMap<>();
3639

3740
public HttpServer add() {
3841
if (jsonMapper == null)
@@ -43,7 +46,7 @@ public HttpServer add() {
4346
executorService = server.executorService;
4447
GenericHandlerGroup<P, J, E> handlerGroupInstance = new GenericHandlerGroup<>(dao, jpaType, jsonType,
4548
daoTransactionManager, jsonMapper, orikaFactory.getMapperFacade(), path, endpoints, getListInterceptors,
46-
extensions, executorService);
49+
extensions, accessRoles, executorService);
4750
server.addHandlerGroup(handlerGroupInstance);
4851
return server;
4952
}
@@ -52,6 +55,11 @@ public AddonBuilder<P, J, E> extension() {
5255
return new AddonBuilder<>(this);
5356
}
5457

58+
public GenericHandlerGroupBuilder<P, J, E> addRoleFor(final Endpoint endpoint, final Role... roles) {
59+
accessRoles.put(endpoint, roles);
60+
return this;
61+
}
62+
5563
public GenericHandlerGroupBuilder<P, J, E> dao(final BasicDao<P, E> dao) {
5664
this.dao = dao;
5765
return this;

src/main/java/info/unterrainer/commons/httpserver/HttpServer.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@
1414
import org.eclipse.jetty.server.Server;
1515
import org.eclipse.jetty.server.ServerConnector;
1616

17+
import info.unterrainer.commons.httpserver.accessmanager.HttpAccessManager;
1718
import info.unterrainer.commons.httpserver.daos.DaoTransactionManager;
1819
import info.unterrainer.commons.httpserver.enums.Attribute;
20+
import info.unterrainer.commons.httpserver.enums.ResponseType;
1921
import info.unterrainer.commons.httpserver.exceptions.HttpException;
2022
import info.unterrainer.commons.httpserver.exceptions.NotFoundException;
2123
import info.unterrainer.commons.httpserver.handlers.AppNameHandler;
2224
import info.unterrainer.commons.httpserver.handlers.AppVersionHandler;
2325
import info.unterrainer.commons.httpserver.handlers.DateTimeHandler;
2426
import info.unterrainer.commons.httpserver.handlers.HealthHandler;
27+
import info.unterrainer.commons.httpserver.handlers.PostmanCollectionHandler;
2528
import info.unterrainer.commons.httpserver.jsons.MessageJson;
2629
import info.unterrainer.commons.jreutils.ShutdownHook;
2730
import info.unterrainer.commons.rdbutils.entities.BasicJpa;
@@ -95,11 +98,14 @@ private void create() {
9598
connector.setPort(config.port());
9699
server.setConnectors(new ServerConnector[] { connector });
97100

98-
javalin = Javalin.create(config -> {
99-
config.server(() -> server).enableCorsForAllOrigins();
101+
javalin = Javalin.create(c -> {
102+
c.server(() -> server)
103+
.accessManager(new HttpAccessManager(config.keycloakHost(), config.keycloakRealm()))
104+
.enableCorsForAllOrigins();
100105
}).start(config.port());
101106

102107
javalin.before(ctx -> ctx.attribute(Attribute.JAVALIN_SERVER, this));
108+
javalin.before(ctx -> ctx.attribute(Attribute.RESPONSE_TYPE, ResponseType.JSON));
103109
javalin.before(ctx -> ctx.contentType("application/json"));
104110

105111
javalin.after(ctx -> render(ctx));
@@ -119,6 +125,7 @@ private void create() {
119125
get("/version", new AppVersionHandler(appVersionFqns));
120126
get("/datetime", new DateTimeHandler());
121127
get("/health", new HealthHandler());
128+
get("/postman", new PostmanCollectionHandler());
122129

123130
registerShutdownHook();
124131
}
@@ -214,7 +221,13 @@ private void render(final Context ctx) throws IOException {
214221

215222
Object dto = ctx.attribute(Attribute.RESPONSE_OBJECT);
216223
if (dto != null)
217-
ctx.result(jsonMapper.toStringFrom(dto));
224+
switch ((ResponseType) ctx.attribute(Attribute.RESPONSE_TYPE)) {
225+
case JSON:
226+
ctx.result(jsonMapper.toStringFrom(dto));
227+
break;
228+
default:
229+
ctx.result((String) dto);
230+
}
218231

219232
Integer status = ctx.attribute(Attribute.RESPONSE_STATUS);
220233
if (status != null)

src/main/java/info/unterrainer/commons/httpserver/HttpServerConfiguration.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ private HttpServerConfiguration() {
1414

1515
private int port;
1616
private String host;
17+
private String keycloakHost;
18+
private String keycloakRealm;
1719

1820
public static HttpServerConfiguration read() {
1921
return read(null);
@@ -26,6 +28,8 @@ public static HttpServerConfiguration read(final String prefix) {
2628
HttpServerConfiguration config = new HttpServerConfiguration();
2729
config.port = Integer.parseInt(Optional.ofNullable(System.getenv(p + "HTTP_PORT")).orElse("8080"));
2830
config.host = Optional.ofNullable(System.getenv(p + "HTTP_HOST")).orElse("0.0.0.0");
31+
config.keycloakHost = Optional.ofNullable(System.getenv(p + "KEYCLOAK_HOST")).orElse("http://localhost:14888");
32+
config.keycloakRealm = Optional.ofNullable(System.getenv(p + "KEYCLOAK_REALM")).orElse("nexus");
2933
return config;
3034
}
3135
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package info.unterrainer.commons.httpserver.accessmanager;
2+
3+
import io.javalin.core.security.Role;
4+
5+
enum DefaultRole implements Role {
6+
OPEN,
7+
AUTHENTICATED;
8+
}

0 commit comments

Comments
 (0)