Extended security for web front end and added first rest resources

This commit is contained in:
verboomp
2026-01-21 14:08:50 +01:00
parent 47ee7c3c25
commit d2e6f5164a
29 changed files with 983 additions and 39 deletions

View File

@@ -40,6 +40,34 @@
<extension module="org.wildfly.extension.undertow"/>
</extensions>
<system-properties>
<property name="jwt.secret.key" value="-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCK1EvBSGUg/+Id
TNnlqXWkWtLypRDW5YtQ1ilT046AQfPyTCK9WGJUqqtxfiOxQ0qKVWsXZd/3JwHP
nqpgORxOlkSpCMJo4syflqSwJ/Zqg6nNEQXErNg1L2/6tM7DW3KnNfW5yujvIDm+
UJJCbmJtQ6tYaNqygQhL6nvDiP5jMwPmdAgg/dUyHJKrNOvF9znUF0360wNG8x/Q
WsmGKPddMD4k7fttA5/GRszRM/WRMbPogsz43PlERchTrYF+nY/4lnD3fNqppJ5u
uskj/G86ux4hmb/C9W+uf5NxTtURTv3H5TJW/jPZ424MoGvzQCeQa0lgNDLAIC+W
Y81e+ZT9AgMBAAECggEAOu3LbDNZLe0/4zUMZvaMB6Q/15xmbfmIrdsCNuFdoyab
sJVNx7adIphBZs7mwqcwHFEOwKNPMp9dnu4YHvkPAXK6mU+tCg1/UxyEMnv8FpFl
wbSAkM/XhJfqve4CuBz4qW53rBIr1tkEebrEoqstX3jyYfg8ILoxtdvGBiV/6cYN
Oyy01xd0NMz+JwHuk9l9ADHDqMJiPkJ1zsHqoqOsblIHSiFSyqRAJU1ns6/If/pV
DI17G2j16lqK9S+fMltJXDfEGhz0A/c9R60nvQObEOtpUCFWS0DP75oZT2AvNqkY
/7aLcBu7FPr522+zFzQrIGON1rJXS/qIBQu0x151JwKBgQDCQGAd+t3qn5Pi63xq
4GFEMZHqn3wyXhhcwg6yQFKrIr8wP3Mmr8utXC0HdncXb80bavkbV8Ii6ttItWDo
eRv3KhJe+83bS0nJc2QQtfKBt1Dg+1TBSsTwQHYKvKSThNcG3ijqtv6Juac+WqfB
H/G5lD5yI4xMquWDyuK6hRNkhwKBgQC29dKdDogFg9cdhpArChduVVGaMu0Ifvt+
oOsy3IVPeOPlXyeDIINi7tw17+WSwm3gS0TVqamcefYIhaBlmRwrYS8wHiyQiMfX
tgthWXtX5z+lw2MdUfAwW6oDRQLVf7YIsas1Loe7KZRoXEbuBeUP/XdpRO1gtUDR
gGL6e3OfWwKBgBlGJPthm6QeVTCOMSb6wM0Nog2j6JXpFkRjX2Qj6F2p7LRLXSEo
eFi7CITTDhW3jzlFBtpe5byDUDq6lrxInbHgAHnpS1SADD6wy9E8yyvDfTt4mAN6
Rft4d6NX/hXPj+at2ycG3kFvLWp4gyEmld3ugt148JU9GxW1vSBFlktbAoGAN1wO
TEN3WOPZlS+AM+WrzVC3jkbWffmeM2SRhiQ/mhpkKqUuGXkfCDJqI0/hURTPlkxw
GY5qqdQlY9K7A8LeSSnw00huB5W7kkOdEem3bpOkKI4EUXzXhmpV+QNKpjssY1kP
Ctp3a2RbaXBybdcOxlXVad7XTKnLYRjN2ii8hX0CgYEApRFzPDU+leHXGIjPZwjA
WcZ7IN+B5pdwJUfqulzx73WtOCfuf2J7HQ0pcaOkG2BOxBY1AGtgPDl7071uYvfR
hbZlR027QB9GpO8pQKZ98UquAmQNTOBI0k0RX9XZAK2ae60SM8NXFFF1TDZMoKud
eZlo8cWlAC5welD3dz1qxEo=
-----END PRIVATE KEY-----"/>
</system-properties>
<management>
@@ -299,9 +327,27 @@
<users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ManagementRealm"/>
<groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
<!-- patrick -->
<distributed-realm name="fotoDocumentationRealm" realms="fotoDocumentationJwtRealm fotoDocumentationJdbcRealm" />
<!-- patrick -->
<jdbc-realm name="fotoDocumentationRealm" >
<token-realm name="fotoDocumentationJwtRealm" principal-claim="username">
<jwt issuer="skillmatrix-jwt-issuer" audience="skillmatrix-api"
public-key="-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAitRLwUhlIP/iHUzZ5al1
pFrS8qUQ1uWLUNYpU9OOgEHz8kwivVhiVKqrcX4jsUNKilVrF2Xf9ycBz56qYDkc
TpZEqQjCaOLMn5aksCf2aoOpzREFxKzYNS9v+rTOw1typzX1ucro7yA5vlCSQm5i
bUOrWGjasoEIS+p7w4j+YzMD5nQIIP3VMhySqzTrxfc51BdN+tMDRvMf0FrJhij3
XTA+JO37bQOfxkbM0TP1kTGz6ILM+Nz5REXIU62Bfp2P+JZw93zaqaSebrrJI/xv
OrseIZm/wvVvrn+TcU7VEU79x+UyVv4z2eNuDKBr80AnkGtJYDQywCAvlmPNXvmU
/QIDAQAB
-----END PUBLIC KEY-----"
/>
</token-realm>
<!-- patrick -->
<jdbc-realm name="fotoDocumentationJdbcRealm" >
<principal-query data-source="fotoDocumentationDS" sql="select password, salt, ri.code as Role from x_user u left join user_to_right rtr on rtr.user_id_fk = u.user_id left join x_right ri on rtr.right_id_fk = ri.right_id where username = ?;">
<salted-simple-digest-mapper algorithm="password-salt-digest-sha-256" password-index="1" salt-index="2" />
<attribute-mapping>
@@ -356,7 +402,7 @@
<!-- patrick -->
<http-authentication-factory name="fotoDocumentation-http-authentication" security-domain="fotoDocumentationDomain" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="BASIC">
<mechanism mechanism-name="BEARER_TOKEN">
<mechanism-realm realm-name="fotoDocumentationRealm"/>
</mechanism>
</mechanism-configuration>

View File

@@ -4,6 +4,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -29,6 +31,8 @@ public abstract class AbstractRestTest extends AbstractTest {
private static final Log LOG = LogFactory.getLog(AbstractRestTest.class);
public static final String TEXT_PLAIN = "text/plain";
private static Map<String, String> bearerToken = new HashMap<>();
public HttpResponse executeRequest(Request request) throws IOException {
var executor = Executor.newInstance();
return executor.use(new BasicCookieStore()).execute(request).returnResponse();
@@ -39,6 +43,23 @@ public abstract class AbstractRestTest extends AbstractTest {
}
protected String getAuthorization(String user, String pass) {
if (!bearerToken.containsKey(user)) {
String auth = user + ":" + pass;
String encoded = Base64.getEncoder().encodeToString(auth.getBytes());
String authorization = "Basic " + encoded;
bearerToken.put(user, getBearerToken(authorization));
}
return "Bearer " + bearerToken.getOrDefault(user, "");
}
protected String getBasicHeader() {
return getBasicHeader(username, password);
}
protected String getBasicHeader(String user, String pass) {
String auth = user + ":" + pass;
String encoded = Base64.getEncoder().encodeToString(auth.getBytes());
return "Basic " + encoded;

View File

@@ -40,22 +40,24 @@ public class CustomerPictureResourceTest extends AbstractRestTest {
@Order(1)
public void doAddCustomerPicture() throws IOException {
LOG.info("doAddCustomerPicture");
String authorization = getBasicHeader();
LOG.info("authorization: " + authorization);
String path = deploymentURL + PATH;
Request request = Request.Post(path).addHeader("Accept", "application/json; charset=utf-8")
.addHeader("Authorization", getAuthorization())
.addHeader("Authorization", authorization)
.bodyFile(new File(BASE_UPLOAD + "add.json"), ContentType.APPLICATION_JSON);
HttpResponse httpResponse = executeRequest(request);
int code = httpResponse.getStatusLine().getStatusCode();
assertEquals(200, code);
}
@Test
@Order(2)
public void doAddCustomerPictureNoAuth() throws IOException {
LOG.info("doAddCustomerPicture");
LOG.info("doAddCustomerPictureNoAuth");
String path = deploymentURL + PATH;
Request request = Request.Post(path).addHeader("Accept", "application/json; charset=utf-8")
.bodyFile(new File(BASE_UPLOAD + "add.json"), ContentType.APPLICATION_JSON);
@@ -64,4 +66,14 @@ public class CustomerPictureResourceTest extends AbstractRestTest {
int code = httpResponse.getStatusLine().getStatusCode();
assertEquals(401, code);
}
public static void main(String[] args) throws IOException {
var test = new CustomerPictureResourceTest();
test.deploymentURL = "http://localhost:8080/";
test.username = "adm";
test.password = "x1t0e7Pb49";
test.doAddCustomerPicture();
}
}

View File

@@ -0,0 +1,60 @@
package marketing.heyday.hartmann.fotodocumentation.rest;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.File;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
/**
*
* <p>Copyright: Copyright (c) 2024</p>
* <p>Company: heyday Marketing GmbH</p>
* @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
* @version 1.0
*
* created: 14 Nov 2024
*/
@TestMethodOrder(OrderAnnotation.class)
public class CustomerResourceTest extends AbstractRestTest {
private static final Log LOG = LogFactory.getLog(CustomerResourceTest.class);
private static final String PATH = "api/customer";
private static final String BASE_UPLOAD = "src/test/resources/upload/";
private static final String BASE_DOWNLOAD = "json/CustomerResourceTest-";
@BeforeAll
public static void init() {
initDB();
}
@Test
@Order(1)
public void doGetAll() throws IOException {
LOG.info("doGetAll");
String authorization = getAuthorization();
LOG.info("authorization: " + authorization);
String path = deploymentURL + PATH;
Request request = Request.Get(path).addHeader("Accept", "application/json; charset=utf-8")
.addHeader("Authorization", authorization);
HttpResponse httpResponse = executeRequest(request);
int code = httpResponse.getStatusLine().getStatusCode();
assertEquals(200, code);
String text = getResponseText(httpResponse, "doGetAll");
String expected = fileToString(BASE_DOWNLOAD + "doGetAll.json");
jsonAssert(expected, text);
}
}

View File

@@ -0,0 +1,42 @@
package marketing.heyday.hartmann.fotodocumentation.rest;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
/**
*
* <p>Copyright: Copyright (c) 2024</p>
* <p>Company: heyday Marketing GmbH</p>
* @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
* @version 1.0
*
* created: 21 Jan 2026
*/
@TestMethodOrder(OrderAnnotation.class)
public class LoginResourceTest extends AbstractRestTest {
private static final Log LOG = LogFactory.getLog(LoginResourceTest.class);
@Test
@Order(2)
public void doTestLogin() {
LOG.info("doTestLogin");
String token = getBasicHeader();
assertNotNull(token);
}
public static void main(String[] args) {
var test = new LoginResourceTest();
test.deploymentURL = "http://localhost:8080/";
String token = test.getAuthorization("hartmann", "nvlev4YnTi");
System.out.println(token);
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
[
{
"name": "Meier Apotheke",
"customerNumber": "2345",
"amountOfPicture": 1
},
{
"name": "Müller Apotheke",
"customerNumber": "1234",
"amountOfPicture": 2
},
{
"name": "Schmidt Apotheke",
"customerNumber": "3456",
"amountOfPicture": 2
}
]