1
0

migrate from CAS to Oauth2-JWT Auth (#197)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/197
Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
Michael Hoennig
2025-09-08 15:27:28 +02:00
parent bc06001ce9
commit d7a78d0a79
125 changed files with 1537 additions and 1549 deletions
+10 -6
View File
@@ -74,11 +74,15 @@ function importLegacyData() {
alias gw-importHostingAssets='importLegacyData importHostingAssets' alias gw-importHostingAssets='importLegacyData importHostingAssets'
function gradlewBootRun() { function gradlewBootRun() {
local port=${1:-8080} local serverPort=${1:-8080}; shift
shift local managementPort=${2:-$((serverPort + 1))}; shift
local additional_args="$@" local additional_args="$@"
echo gw bootRun --args="--spring.profiles.active=dev,fakeCasAuthenticator,complete,test-data --server.port=${port} ${additional_args}" unset HSADMINNG_JWT_ISSUER
./gradlew bootRun --args="--spring.profiles.active=dev,fakeCasAuthenticator,complete,test-data --server.port=${port} ${additional_args}" unset HSADMINNG_JWT_JWKS_URL
unset HSADMINNG_JWT_TOKEN_URL
set -x
./gradlew bootRun --args="--spring.profiles.active=dev,fake-jwt,complete,test-data --server.port=${serverPort} --management.server.port=${managementPort} ${additional_args}"
set +x
} }
alias gw-bootRun=gradlewBootRun alias gw-bootRun=gradlewBootRun
@@ -97,7 +101,7 @@ alias pg-sql-restore='gunzip --stdout | docker exec -i hsadmin-ng-postgres psql
alias fp='grep -r '@Accepts' src | sed -e 's/^.*@/@/g' | sort -u | wc -l' alias fp='grep -r '@Accepts' src | sed -e 's/^.*@/@/g' | sort -u | wc -l'
alias gw-spotless='./gradlew spotlessApply -x pitest -x test -x :processResources' alias gw-spotless='./gradlew compile spotlessApply -x pitest -x test -x :processResources'
alias gw-check='. .aliases; . .tc-environment; gw test check -x pitest' alias gw-check='. .aliases; . .tc-environment; gw test check -x pitest'
# HOWTO: run all 'normal' tests (by default without scenario+import-tests): `gw-test` # HOWTO: run all 'normal' tests (by default without scenario+import-tests): `gw-test`
@@ -143,7 +147,7 @@ function _gwTest() {
alias gw-test=_gwTest alias gw-test=_gwTest
alias howto=bin/howto alias howto=bin/howto
alias cas-curl=bin/cas-curl alias jwt-curl=bin/jwt-curl
# etc/docker-compose.yml limits CPUs+MEM and includes a PostgreSQL config for analysing slow queries # etc/docker-compose.yml limits CPUs+MEM and includes a PostgreSQL config for analysing slow queries
alias gw-importHostingAssets-in-docker-compose=' alias gw-importHostingAssets-in-docker-compose='
+2 -1
View File
@@ -3,6 +3,7 @@ source .unset-environment
export HSADMINNG_POSTGRES_RESTRICTED_USERNAME=restricted export HSADMINNG_POSTGRES_RESTRICTED_USERNAME=restricted
export HSADMINNG_POSTGRES_ADMIN_USERNAME=admin export HSADMINNG_POSTGRES_ADMIN_USERNAME=admin
export HSADMINNG_SUPERUSER=import-superuser@hostsharing.net export HSADMINNG_SUPERUSER=import-superuser@hostsharing.net
export HSADMINNG_CAS_SERVER= export HSADMINNG_OFFICE_DATA_SQL_FILE
export HSADMINNG_JWT_TOKEN_URL=http://localhost:8080/fake-jwt/token
export LANG=en_US.UTF-8 export LANG=en_US.UTF-8
+6 -1
View File
@@ -5,5 +5,10 @@ unset HSADMINNG_POSTGRES_RESTRICTED_USERNAME
unset HSADMINNG_SUPERUSER unset HSADMINNG_SUPERUSER
unset HSADMINNG_MIGRATION_DATA_PATH unset HSADMINNG_MIGRATION_DATA_PATH
unset HSADMINNG_OFFICE_DATA_SQL_FILE unset HSADMINNG_OFFICE_DATA_SQL_FILE
unset HSADMINNG_CAS_SERVER=
unset HSADMINNG_JWT_ISSUER
unset HSADMINNG_JWT_JWKS_URL
unset HSADMINNG_JWT_USERNAME
unset HSADMINNG_JWT_PASSWORD
unset HSADMINNG_JWT_TOKEN_URL
+61 -35
View File
@@ -87,13 +87,10 @@ If you have at least Docker and the Java JDK installed in appropriate versions a
# if the container has been built already and you want to keep the data, run this: # if the container has been built already and you want to keep the data, run this:
pg-sql-start pg-sql-start
Next, compile and run the application on `localhost:8080` and the management server on `localhost:8081`: Next, compile and run the application with in dev-mode with all modules, test-data and fake-JWT-authentication::
# this disables CAS-authentication, for using the REST-API with CAS-authentication, see `bin/cas-curl`. # on `localhost:8080` and the management server on `localhost:8081`:
export HSADMINNG_CAS_SERVER= gw-bootRun
# this runs the application with test-data and all modules:
gw bootRun --args='--spring.profiles.active=dev,fakeCasAuthenticator,complete,test-data'
# there is also an alias which takes an optional port as an argument: # there is also an alias which takes an optional port as an argument:
gw-bootRun 8888 gw-bootRun 8888
@@ -101,53 +98,75 @@ Next, compile and run the application on `localhost:8080` and the management ser
The meaning of these profiles is: The meaning of these profiles is:
- **dev**: the PostgreSQL users are created via Liquibase - **dev**: the PostgreSQL users are created via Liquibase
- **fakeCasAuthenticator**: The username is simply taken from whatever is after "Bearer " in the "Authorization" header. - **fake-jwt**: the app starts with a build-in fake OAuth2/JWT server
- **complete**: all modules are started - **complete**: all modules are started
- **test-data**: some test data inserted - **test-data**: some test data inserted
Now we can access the REST API, e.g. using curl: Now we can access the REST API, e.g. using curl. But you need to use JWT authentication.
To make this a bit easier to handle, we use `bin/jwt-curl` (or `jwt-curl` alias).
# the following command should reply with "pong": Make sure you replace `8080` with the port you used to run the application.`
curl -f -s http://localhost:8080/api/ping
# the following command does not need authentication and should reply with "pinged ...".
curl http://localhost:8080/api/ping
# but when you try endpoints which need authentication, you will get a 401 error:
curl http://localhost:8080/api/pong
# For the follinging commands we need to be authenticated by a valid JWT token.
# To make JWT handling a bit easier, there is a wrapper scropt `jwt-curl`.
# Make sure the following variable is set to the fake JWT issuer:
export HSADMINNG_JWT_TOKEN_URL=http://localhost:8080/fake-jwt/token
# optionally, you can set the username and password to in env-vars as well:
export HSADMINNG_JWT_USERNAME=superuser-alex@hostsharing.net
export HSADMINNG_JWT_PASSWORD=whatever-as-its-not-checked-by-fake-jwt-auth
# also optionally, you can login explicitly:
jwt-curl login
# now, the following command should reply with "ponged ... superuser-alex@hostsharing.net":
jwt-curl GET http://localhost:8080/api/pong
# the following command should return a JSON array with just all customers: # the following command should return a JSON array with just all customers:
curl -f -s\ jwt-curl GET http://localhost:8080/api/test/customers \
-H 'Authorization: Bearer superuser-alex@hostsharing.net' \
http://localhost:8080/api/test/customers \
| jq # just if `jq` is installed, to prettyprint the output | jq # just if `jq` is installed, to prettyprint the output
# the following command should return a JSON array with just all packages visible for the admin of the customer yyy: # the following command should return a JSON array with just all packages visible for the admin of the customer yyy:
curl -f -s\ jwt-curl ASSUME 'rbactest.customer#yyy:ADMIN'
-H 'Authorization: Bearer superuser-alex@hostsharing.net' -H 'assumed-roles: rbactest.customer#yyy:ADMIN' \ jwt-curl GET http://localhost:8080/api/test/packages \
http://localhost:8080/api/test/packages \
| jq | jq
jwt-curl UNASSUME
# add a new customer # add a new customer
curl -f -s\ jwt-curl POST \
-H 'Authorization: Bearer superuser-alex@hostsharing.net' -H "Content-Type: application/json" \
-d '{ "prefix":"ttt", "reference":80001, "adminUserName":"admin@ttt.example.com" }' \ -d '{ "prefix":"ttt", "reference":80001, "adminUserName":"admin@ttt.example.com" }' \
-X POST http://localhost:8080/api/test/customers \ http://localhost:8080/api/test/customers \
| jq | jq
If you wonder who 'superuser-alex@hostsharing.net' and 'superuser-fran@hostsharing.net' are and where the data comes from: If you wonder who 'superuser-alex@hostsharing.net' and 'superuser-fran@hostsharing.net' are and where the data comes from:
Mike and Sven are just example global admin accounts as part of the example data which is automatically inserted in Testcontainers and Development environments. Alex and Fran are just example global admin accounts as part of the example data which is automatically inserted in Testcontainers and Development environments.
Also try for example 'admin@xxx.example.com' or 'unknown@example.org'. Also, for example, try 'admin@xxx.example.com' or 'unknown@example.org'.
If you want a formatted JSON output, you can pipe the result to `jq` or similar. If you want a formatted JSON output, you can pipe the result to `jq` or similar.
And to see the full, currently implemented, API, open http://localhost:8080/swagger-ui/index.html). And to see the full, currently implemented, API, open http://localhost:8080/swagger-ui/index.html.
For a locally running app without CAS-authentication (export HSADMINNG_CAS_SERVER=''),
authorize using the name of the subject (e.g. "superuser-alex@hostsharing.net" in case of test-data).
Otherwise, use a valid CAS-ticket.
If you want to run the application with real CAS-Authentication: If you want to run the application with real (OAuth2) JWT-authentication:
# set the CAS-SERVER-Root, also see `bin/cas-curl`. # set the JWT-issuer URI, e.g.
export HSADMINNG_CAS_SERVER=https://login.hostsharing.net # or whatever your CAS-Server-URL you want to use export HSADMINNG_JWT_ISSUER=https://login.hshsngdev.hs-example.de/realms/HSAdminDEV
# run the application against the real CAS authenticator # and the JWT JWKS callback URI:
gw bootRun --args='--spring.profiles.active=dev,realCasAuthenticator,complete,test-data' export HSADMINNG_JWT_JWKS_URL=https://login.hshsngdev.hs-example.de/realms/HSAdminDEV/.well-known/openid-configuration
# as well as the JWT token endpoint URI:
export HSADMINNG_JWT_TOKEN_URL=https://login.hshsngdev.hs-example.de/realms/HSAdminDEV/protocol/openid-connect/token
# run the application against the specified JWT authenticator, do NOT add the 'fake-jwt' profile:
gw bootRun --args='--spring.profiles.active=dev,complete,test-data'
Also run `bin/jwt-curl` (or the alias `jwt-curl`) without any parameters to see the available commands.
### PostgreSQL Server ### PostgreSQL Server
@@ -156,7 +175,7 @@ You might amend the port and user settings in `src/main/resources/application.ym
But the easiest way to run PostgreSQL is via Docker. But the easiest way to run PostgreSQL is via Docker.
Initially, pull an image compatible to current PostgreSQL version of Hostsharing: Initially, pull an image compatible to the current PostgreSQL version of Hostsharing:
docker pull postgres:15.5-bookworm docker pull postgres:15.5-bookworm
@@ -674,7 +693,7 @@ howto
Add `--args='--spring.profiles.active=...` with the wanted profile selector: Add `--args='--spring.profiles.active=...` with the wanted profile selector:
```sh ```sh
gw bootRun --args='--spring.profiles.active=fakeCasAuthenticator,external-db,only-prod-schema,without-test-data' gw bootRun --args='--spring.profiles.active=external-db,only-prod-schema,without-test-data'
``` ```
These profiles mean: These profiles mean:
@@ -712,7 +731,7 @@ If it's selected, just hit the *bug*-symbol next to it.
If you frequently need to run with a fresh database and a clean build, you can use this: If you frequently need to run with a fresh database and a clean build, you can use this:
```sh ```sh
export HSADMINNG_CAS_SERVER= # replace `gw bootRun` by the proper command as described above
gw clean && pg-sql-reset && sleep 5 && gw bootRun' 2>&1 | tee log gw clean && pg-sql-reset && sleep 5 && gw bootRun' 2>&1 | tee log
``` ```
@@ -851,9 +870,16 @@ This port can be changed in
Or on the command line, add ` --server.port=...` to the `--args` parameter of the `bootRun` task, e.g.: Or on the command line, add ` --server.port=...` to the `--args` parameter of the `bootRun` task, e.g.:
```sh ```sh
gw bootRun --args='--spring.profiles.active=dev,fakeCasAuthenticator,complete,test-data --server.port=8888' gw bootRun --args='--spring.profiles.active=dev,fake-jwt,complete,test-data --server.port=8888'
``` ```
or, for local development, simply:
```sh
gw-bootRun 8888
```
### How to Use a Persistent Database for Integration Tests? ### How to Use a Persistent Database for Integration Tests?
Usually, the `DataJpaTest` integration tests run against a database in a temporary docker container. Usually, the `DataJpaTest` integration tests run against a database in a temporary docker container.
@@ -888,7 +914,7 @@ Therefore, during initial development, it's good approach just to amend the exis
```shell ```shell
pg-sql-reset pg-sql-reset
gw bootRun gw bootRun # with the proper command line arguments
``` ```
<big>**&#9888;**</big> <big>**&#9888;**</big>
-261
View File
@@ -1,261 +0,0 @@
#!/bin/bash
if [ "$2" == "--show-password" ]; then
HSADMINNG_CAS_SHOW_PASSWORD=yes
shift
else
HSADMINNG_CAS_SHOW_PASSWORD=
fi
if [ "$1" == "--trace" ]; then
function trace() {
echo "$*" >&2
}
function doCurl() {
set -x
if [ -z "$HSADMINNG_CAS_ASSUME" ]; then
curl --fail-with-body \
--header "Authorization: $HSADMINNG_CAS_TICKET" \
"$@"
else
curl --fail-with-body \
--header "Authorization: $HSADMINNG_CAS_TICKET" \
--header "assumed-roles: $HSADMINNG_CAS_ASSUME" \
"$@"
fi
set +x
}
shift
else
function trace() {
: # noop
}
function doCurl() {
curl --fail-with-body --header "Authorization: $HSADMINNG_CAS_TICKET" "$@"
}
fi
export HSADMINNG_CAS_ASSUME_HEADER
if [ -f ~/.cas-curl-assume ]; then
HSADMINNG_CAS_ASSUME="$(cat ~/.cas-curl-assume)"
else
HSADMINNG_CAS_ASSUME=
fi
if [ -z "$HSADMINNG_CAS_LOGIN" ] || [ -z "$HSADMINNG_CAS_VALIDATE" ] || \
[ -z "$HSADMINNG_CAS_SERVICE_ID" ]; then
cat >&2 <<EOF
ERROR: environment incomplete
please set the following environment variables:
export HSADMINNG_CAS_LOGIN=https://login.hostsharing.net/cas/v1/tickets
export HSADMINNG_CAS_VALIDATE=https://login.hostsharing.net/cas/proxyValidate
export HSADMINNG_CAS_USERNAME=<<optionally, your username, or leave empty after '='>>
export HSADMINNG_CAS_PASSWORD=<<optionally, your password, or leave empty after '='>>
export HSADMINNG_CAS_SERVICE_ID=https://hsadminng.hostsharing.net:443/
EOF
exit 1
fi
function casCurlDocumentation() {
cat <<EOF
curl-wrapper utilizing CAS-authentication for hsadmin-ng
usage: $0 [--trace] [--show-password] <<command>> [parameters]
commands:
EOF
# filters out help texts (containing double-# and following lines with leading single-#) from the commands itself
# (the '' makes sure that this line is not found, just the lines with actual help texts)
sed -n '/#''#/ {x; p; x; s/#''#//; p; :a; n; /^[[:space:]]*#/!b; s/^[[:space:]]*#//; p; ba}' <$0
}
function casLogin() {
# ticket granting ticket exists and not expired?
if find ~/.cas-login-tgt -type f -size +0c -mmin -60 2>/dev/null | grep -q .; then
return
fi
if [ -z "$HSADMINNG_CAS_USERNAME" ]; then
read -e -p "Username: " HSADMINNG_CAS_USERNAME
fi
if [ -z "$HSADMINNG_CAS_PASSWORD" ]; then
read -s -e -p "Password: " HSADMINNG_CAS_PASSWORD
fi
if [ "$HSADMINNG_CAS_SHOW_PASSWORD" == "--show-password" ]; then
HSADMINNG_CAS_PASSWORD_DISPLAY=$HSADMINNG_CAS_PASSWORD
else
HSADMINNG_CAS_PASSWORD_DISPLAY="<<password hidden - use --show-password to show>>"
fi
# Do NOT use doCurl here! We do neither want to print the password nor pass a CAS service ticket.
trace "+ curl --fail-with-body -s -i -X POST \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d \"username=$HSADMINNG_CAS_USERNAME&password=$HSADMINNG_CAS_PASSWORD_DISPLAY\" \
$HSADMINNG_CAS_LOGIN -o ~/.cas-login-tgt.response -D -"
HSADMINNG_CAS_TGT=`curl --fail-with-body -s -i -X POST \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "username=$HSADMINNG_CAS_USERNAME&password=$HSADMINNG_CAS_PASSWORD" \
$HSADMINNG_CAS_LOGIN -o ~/.cas-login-tgt.response -D - \
| grep -i "^Location: " | sed -e 's/^Location: //' -e 's/\\r//'`
if [ -z "$HSADMINNG_CAS_TGT" ]; then
echo "ERROR: could not get ticket granting ticket" >&2
cat ~/.cas-login-tgt.response >&2
exit 1
fi
echo "$HSADMINNG_CAS_TGT" >~/.cas-login-tgt
trace "$HSADMINNG_CAS_TGT"
}
function casLogout() {
rm -f ~/.cas-login-tgt
}
function casTicket() {
HSADMINNG_CAS_TGT=$(<~/.cas-login-tgt)
if [[ -z "$HSADMINNG_CAS_TGT" ]]; then
echo "ERROR: cannot get CAS ticket granting ticket for $HSADMINNG_CAS_USERNAME" >&2
exit 1
fi
trace "CAS-TGT: $HSADMINNG_CAS_TGT"
trace "fetching CAS service ticket"
trace "curl -s -d \"service=$HSADMINNG_CAS_SERVICE_ID\" $HSADMINNG_CAS_TGT"
HSADMINNG_CAS_TICKET=$(curl -s -d "service=$HSADMINNG_CAS_SERVICE_ID" $HSADMINNG_CAS_TGT)
if [[ -z "$HSADMINNG_CAS_TICKET" ]]; then
echo "ERROR: cannot get CAS service ticket" >&2
exit 1
fi
echo $HSADMINNG_CAS_TICKET
}
function casTgt() {
HSADMINNG_CAS_TGT=$(<~/.cas-login-tgt)
if [[ -z "$HSADMINNG_CAS_TGT" ]]; then
echo "ERROR: cannot get CAS ticket granting ticket for $HSADMINNG_CAS_USERNAME" >&2
exit 1
fi
echo "CAS-TGT: $HSADMINNG_CAS_TGT"
}
function casValidate() {
HSADMINNG_CAS_TICKET=`casTicket`
trace "validating CAS-TICKET: $HSADMINNG_CAS_TICKET"
# Do NOT use doCurl here! We do not pass a CAS service ticket.
trace curl -i -s $HSADMINNG_CAS_VALIDATE?ticket=${HSADMINNG_CAS_TICKET}\&service=${HSADMINNG_CAS_SERVICE_ID}
HSADMINNG_CAS_USER=`curl -i -s $HSADMINNG_CAS_VALIDATE?ticket=${HSADMINNG_CAS_TICKET}\&service=${HSADMINNG_CAS_SERVICE_ID} | grep -oPm1 "(?<=<cas:user>)[^<]+"`
if [ -z "$HSADMINNG_CAS_USER" ]; then
echo "validation failed" >&2
exit 1
fi
echo "CAS-User: $HSADMINNG_CAS_USER"
}
case "${1,,}" in
# -- generic commands --------------------------------------------------------------------------
""|"-h"|"--help"|"help") ## prints documentation about commands and options
casCurlDocumentation
exit
;;
"env") ## prints all related HSADMINNG_CAS_... environment variables; use '--show-password' to show the password as well
# example: cas-curl env --show-password
echo "HSADMINNG_CAS_LOGIN: $HSADMINNG_CAS_LOGIN"
echo "HSADMINNG_CAS_VALIDATE: $HSADMINNG_CAS_VALIDATE"
echo "HSADMINNG_CAS_USERNAME: $HSADMINNG_CAS_USERNAME"
if [ "$2" == "--show-password" ]; then
echo "HSADMINNG_CAS_PASSWORD: $HSADMINNG_CAS_PASSWORD"
elif [ -z "$HSADMINNG_CAS_PASSWORD" ]; then
echo "HSADMINNG_CAS_PASSWORD: <<not given>>"
else
echo "HSADMINNG_CAS_PASSWORD: <<given, but hidden - add --show-password to show>>"
fi
echo "HSADMINNG_CAS_SERVICE_ID: $HSADMINNG_CAS_SERVICE_ID"
;;
# --- authentication-related commands ------------------------------------------------------------
"login") ## reads username+password and fetches ticket granting ticket (bypasses HSADMINNG_CAS_USERNAME+HSADMINNG_CAS_PASSWORD)
# example: cas-curl login
casLogout
export HSADMINNG_CAS_USERNAME=
export HSADMINNG_CAS_PASSWORD=
casLogin
;;
"assume") ## assumes the given comma-separated roles
# example using object-id-name: cas-curl assume 'hs_office.relation#ExampleMandant-with-PARTNER-ExamplePartner:AGENT'
# example using object-uuid: cas-curl assume 'hs_office.relation#1d3bc468-c5c8-11ef-9d0d-4751ecfda2b7:AGENT'
shift
if [ -z "$1" ]; then
echo "ERROR: requires comma-separated list of roles to assume" >&2
exit 1
fi
echo "$1" >~/.cas-curl-assume
;;
"unassume") ## do not assume any particular role anymore, use the plain user as RBAC subject
rm ~/.cas-curl-assume
;;
"tgt") ## prints the current ticket granting ticket
casTgt
;;
"validate") ## validates current ticket granting ticket and prints currently logged in user
casValidate
;;
"logout") ## logout, deletes ticket granting ticket
casLogout
;;
# --- HTTP-commands ----------------------------------------------------------------------
"get") ## HTTP GET, add URL as parameter
# example: cas-curl GET http://localhost:8080/api/hs/office/partners/P-10003 | jq
# hint: '| jq' is just for human-readable formatted JSON output
shift
casLogin
HSADMINNG_CAS_TICKET=`casTicket`
doCurl "$*"
;;
"post") ## HTTP POST, add curl options to specify the request body and the URL as last parameter
# example: cas-curl POST \
# -d '{ "prefix":"ttt", "reference":80001, "adminUserName":"admin@ttt.example.com" }' \
# http://localhost:8080/api/test/customers | jq
# hint: '| jq' is just for human-readable formatted JSON output
shift
casLogin
HSADMINNG_CAS_TICKET=`casTicket`
doCurl --header "Content-Type: application/json" -X POST "$@"
;;
"patch") ## HTTP PATCH, add curl options to specify the request body and the URL as last parameterparameter
# example: cas-curl PATCH \
# -d '{ "reference":80002 }' \
# http://localhost:8080/api/test/customers/ae90ac2a-4728-4ca9-802e-a0d0108b2324 | jq
# hint: '| jq' is just for human-readable formatted JSON output
shift
casLogin
HSADMINNG_CAS_TICKET=`casTicket`
doCurl --header "Content-Type: application/json" -X POST "$*"
;;
"delete") ## HTTP DELETE, add curl options to specify the request body and the URL as last parameter
# example: cas-curl DELETE http://localhost:8080/api/hs/office/persons/ae90ac2a-4728-4ca9-802e-a0d0108b2324
shift
casLogin
HSADMINNG_CAS_TICKET=`casTicket`
curl -X POST "$@"
;;
*)
cat >&2 <<EOF
unknown command: '$1'
valid commands: help, login, logout, validate, get, post, patch, delete
EOF
exit 1
;;
esac
Executable
+279
View File
@@ -0,0 +1,279 @@
#!/bin/bash
if [ "$1" == "--show-password" ]; then
HSADMINNG_JWT_SHOW_PASSWORD=yes
shift
else
HSADMINNG_JWT_SHOW_PASSWORD=
fi
if [ "$1" == "--trace" ]; then
function trace() {
echo "$*" >&2
}
function doCurl() {
set -x
if [ -z "$HSADMINNG_JWT_ASSUME" ]; then
curl --fail-with-body \
--header "Authorization: Bearer $HSADMINNG_JWT_TOKEN" \
"$@"
else
curl --fail-with-body \
--header "Authorization: Bearer $HSADMINNG_JWT_TOKEN" \
--header "assumed-roles: $HSADMINNG_JWT_ASSUME" \
"$@"
fi
set +x
echo
}
shift
else
function trace() {
: # noop
}
function doCurl() {
if [ -z "$HSADMINNG_JWT_ASSUME" ]; then
curl --fail-with-body --header "Authorization: Bearer $HSADMINNG_JWT_TOKEN" "$@"
else
curl --fail-with-body \
--header "Authorization: Bearer $HSADMINNG_JWT_TOKEN" \
--header "assumed-roles: $HSADMINNG_JWT_ASSUME" \
"$@"
echo
fi
}
fi
export HSADMINNG_JWT_ASSUME_HEADER
if [ -f ~/.cas-curl-assume ]; then
HSADMINNG_JWT_ASSUME="$(cat ~/.cas-curl-assume)"
else
HSADMINNG_JWT_ASSUME=
fi
if [ -z "$HSADMINNG_JWT_TOKEN_URL" ]; then
cat >&2 <<EOF
ERROR: environment incomplete
please set the following environment variables:
export HSADMINNG_JWT_TOKEN_URL=https://login.hostsharing.net/oauth/token
export HSADMINNG_JWT_USERNAME=<<optionally, your username, or leave empty after '='>>
export HSADMINNG_JWT_PASSWORD=<<optionally, your password, or leave empty after '='>>
EOF
exit 1
fi
function jwtCurlDocumentation() {
cat <<EOF
curl-wrapper utilizing JWT-authentication for hsadmin-ng
usage: $0 [--trace] [--show-password] <<command>> [parameters]
commands:
EOF
# filters out help texts (containing double-# and following lines with leading single-#) from the commands itself
# (the '' makes sure that this line is not found, just the lines with actual help texts)
sed -n '/#''#/ {x; p; x; s/#''#//; p; :a; n; /^[[:space:]]*#/!b; s/^[[:space:]]*#//; p; ba}' <$0
}
function jwtLogin() {
# JWT token exists and not expired?
if [ -f ~/.jwt-token ]; then
# Check if token is still valid (simple expiry check - you might want to add JWT parsing for more precise validation)
if find ~/.jwt-token -type f -size +0c -mmin -55 2>/dev/null | grep -q .; then
HSADMINNG_JWT_TOKEN=$(<~/.jwt-token)
return
fi
fi
if [ -z "$HSADMINNG_JWT_USERNAME" ]; then
read -e -p "Username: " HSADMINNG_JWT_USERNAME
fi
if [ -z "$HSADMINNG_JWT_PASSWORD" ]; then
read -s -e -p "Password: " HSADMINNG_JWT_PASSWORD
fi
if [ "$HSADMINNG_JWT_SHOW_PASSWORD" == "yes" ]; then
HSADMINNG_JWT_PASSWORD_DISPLAY=$HSADMINNG_JWT_PASSWORD
else
HSADMINNG_JWT_PASSWORD_DISPLAY="<<password hidden - use --show-password to show>>"
fi
# OAuth2 Resource Owner Password Credentials Grant (public client)
trace "+ curl --fail-with-body --show-error -X POST \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d \"grant_type=password&username=$HSADMINNG_JWT_USERNAME&password=$HSADMINNG_JWT_PASSWORD_DISPLAY\" \
$HSADMINNG_JWT_TOKEN_URL -o ~/.jwt-token.response"
JWT_RESPONSE=$(curl --fail-with-body --show-error -X POST \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "grant_type=password&username=$HSADMINNG_JWT_USERNAME&password=$HSADMINNG_JWT_PASSWORD" \
$HSADMINNG_JWT_TOKEN_URL 2>&1 | tee ~/.jwt-token.response)
# Extract access token from JSON response
HSADMINNG_JWT_TOKEN=$(echo "$JWT_RESPONSE" | grep -o '"access_token":"[^"]*' | cut -d'"' -f4)
if [ -z "$HSADMINNG_JWT_TOKEN" ]; then
echo "ERROR: could not get JWT access token: $JWT_RESPONSE" >&2
echo >&2
exit 1
fi
echo "$HSADMINNG_JWT_TOKEN" > ~/.jwt-token
trace "JWT Token acquired (length: ${#HSADMINNG_JWT_TOKEN})"
}
function jwtLogout() {
rm -f ~/.jwt-token ~/.jwt-token.response
}
function jwtValidate() {
if [ ! -f ~/.jwt-token ]; then
echo "ERROR: no JWT token found, please login first" >&2
exit 1
fi
HSADMINNG_JWT_TOKEN=$(<~/.jwt-token)
# Simple JWT validation - decode payload (base64 decode the middle part)
JWT_PAYLOAD=$(echo "$HSADMINNG_JWT_TOKEN" | cut -d'.' -f2)
# Add padding if needed for base64 decoding
case $((${#JWT_PAYLOAD} % 4)) in
2) JWT_PAYLOAD="${JWT_PAYLOAD}==" ;;
3) JWT_PAYLOAD="${JWT_PAYLOAD}=" ;;
esac
if command -v base64 >/dev/null 2>&1; then
JWT_DECODED=$(echo "$JWT_PAYLOAD" | base64 -d 2>/dev/null)
if [ $? -eq 0 ]; then
OAUTH_USER=$(echo "$JWT_DECODED" | grep -o '"sub":"[^"]*' | cut -d'"' -f4)
if [ -z "$OAUTH_USER" ]; then
OAUTH_USER=$(echo "$JWT_DECODED" | grep -o '"preferred_username":"[^"]*' | cut -d'"' -f4)
fi
if [ -z "$OAUTH_USER" ]; then
OAUTH_USER=$(echo "$JWT_DECODED" | grep -o '"username":"[^"]*' | cut -d'"' -f4)
fi
if [ -n "$OAUTH_USER" ]; then
echo "OAuth User: $OAUTH_USER"
# Check expiry
EXP=$(echo "$JWT_DECODED" | grep -o '"exp":[0-9]*' | cut -d':' -f2)
if [ -n "$EXP" ]; then
CURRENT_TIME=$(date +%s)
if [ "$EXP" -lt "$CURRENT_TIME" ]; then
echo "WARNING: JWT token has expired" >&2
else
echo "Token expires: $(date -d "@$EXP" 2>/dev/null || date -r "$EXP" 2>/dev/null || echo "unknown")"
fi
fi
else
echo "Could not extract user from JWT token" >&2
fi
else
echo "Could not decode JWT token" >&2
fi
else
echo "JWT token present but cannot validate (base64 command not available)" >&2
fi
}
function jwtToken() {
if [ ! -f ~/.jwt-token ]; then
echo "ERROR: no JWT token found, please login first" >&2
exit 1
fi
HSADMINNG_JWT_TOKEN=$(<~/.jwt-token)
echo "$HSADMINNG_JWT_TOKEN"
}
case "${1,,}" in
# -- generic commands --------------------------------------------------------------------------
""|"-h"|"--help"|"help") ## prints documentation about commands and options
jwtCurlDocumentation
exit
;;
"env") ## prints all related HSADMINNG_JWT_... environment variables; use '--show-password' to show the password as well
# example: jwt-curl -show-password env
echo "export HSADMINNG_JWT_TOKEN_URL=$HSADMINNG_JWT_TOKEN_URL"
echo "export HSADMINNG_JWT_USERNAME=$HSADMINNG_JWT_USERNAME"
if [ "$HSADMINNG_JWT_SHOW_PASSWORD" == "yes" ]; then
echo "export HSADMINNG_JWT_PASSWORD=$HSADMINNG_JWT_PASSWORD"
elif [ -z "$HSADMINNG_JWT_PASSWORD" ]; then
echo "export HSADMINNG_JWT_PASSWORD=#<<not given>>"
else
echo "export HSADMINNG_JWT_PASSWORD=#<<given, but hidden - add --show-password to show>>"
fi
;;
# --- authentication-related commands ------------------------------------------------------------
"login") ## reads username+password and fetches JWT access token (bypasses HSADMINNG_JWT_USERNAME+HSADMINNG_JWT_PASSWORD)
# example: jwt-curl login
jwtLogout
export HSADMINNG_JWT_USERNAME=
export HSADMINNG_JWT_PASSWORD=
jwtLogin
;;
"assume") ## assumes the given comma-separated roles
# example using object-id-name: jwt-curl assume 'hs_office.relation#ExampleMandant-with-PARTNER-ExamplePartner:AGENT'
# example using object-uuid: jwt-curl assume 'hs_office.relation#1d3bc468-c5c8-11ef-9d0d-4751ecfda2b7:AGENT'
shift
if [ -z "$1" ]; then
echo "ERROR: requires comma-separated list of roles to assume" >&2
exit 1
fi
echo "$1" >~/.cas-curl-assume
;;
"unassume") ## do not assume any particular role anymore, use the plain user as RBAC subject
rm -f ~/.cas-curl-assume
;;
"token") ## prints the current JWT access token
jwtToken
;;
"validate") ## validates current JWT token and prints currently logged in user
jwtValidate
;;
"logout") ## logout, deletes JWT token
jwtLogout
;;
# --- HTTP-commands ----------------------------------------------------------------------
"get") ## HTTP GET, add URL as parameter
# example: jwt-curl GET http://localhost:8080/api/hs/office/partners/P-10003 | jq
# hint: '| jq' is just for human-readable formatted JSON output
shift
jwtLogin
doCurl "$*"
;;
"post") ## HTTP POST, add curl options to specify the request body and the URL as last parameter
# example: jwt-curl POST \
# -d '{ "prefix":"ttt", "reference":80001, "adminUserName":"admin@ttt.example.com" }' \
# http://localhost:8080/api/test/customers | jq
# hint: '| jq' is just for human-readable formatted JSON output
shift
jwtLogin
doCurl --header "Content-Type: application/json" -X POST "$@"
;;
"patch") ## HTTP PATCH, add curl options to specify the request body and the URL as last parameterparameter
# example: jwt-curl PATCH \
# -d '{ "reference":80002 }' \
# http://localhost:8080/api/test/customers/ae90ac2a-4728-4ca9-802e-a0d0108b2324 | jq
# hint: '| jq' is just for human-readable formatted JSON output
shift
jwtLogin
doCurl --header "Content-Type: application/json" -X POST "$*"
;;
# --- unknown command --------------------------------------------------------------------
*)
cat >&2 <<EOF
unknown command: '$1'
valid commands: help, login, logout, validate, get, post, patch, delete
EOF
exit 1
;;
esac
+4
View File
@@ -92,6 +92,7 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-validation") implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-actuator") implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6")
implementation("com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.11.0") implementation("com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.11.0")
implementation("org.postgresql:postgresql") implementation("org.postgresql:postgresql")
@@ -346,6 +347,9 @@ configure<JacocoPluginExtension> {
tasks.named<JacocoReport>("jacocoTestReport") { tasks.named<JacocoReport>("jacocoTestReport") {
dependsOn(tasks.named("test")) // Depends on the main test task dependsOn(tasks.named("test")) // Depends on the main test task
dependsOn(tasks.named("compileJava")) // Add explicit dependency on compileJava
dependsOn(tasks.named("openApiGenerate")) // Add explicit dependency on openApiGenerate
reports { reports {
xml.required.set(true) // Common requirement for CI/CD xml.required.set(true) // Common requirement for CI/CD
csv.required.set(false) csv.required.set(false)
@@ -0,0 +1,78 @@
package net.hostsharing.hsadminng.config;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.web.SecurityFilterChain;
import jakarta.servlet.http.HttpServletResponse;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.RSA_KEY;
@Configuration
@EnableWebSecurity
// securitySchemes should work in OpenAPI yaml, but the Spring templates seem not to support it
@SecurityScheme(
name = "bearerAuth",
type = SecuritySchemeType.HTTP,
scheme = "bearer",
bearerFormat = "JWT"
)
public abstract class BaseWebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(final HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(
// only list endpoints implemented in libraries here
"/swagger-ui/**",
"/v3/api-docs/**",
"/actuator/**",
"/fake-jwt/**"
// otherwise use @PreAuthorize annotation at the controller class / endpoint method level
).permitAll()
.requestMatchers("/api/**").permitAll() // controlled at method level
.anyRequest().denyAll()
)
.oauth2ResourceServer(oauth ->
oauth.jwt(Customizer.withDefaults()))
.csrf(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.exceptionHandling(exception -> exception
.authenticationEntryPoint((request, response, authException) ->
// For unknown reason Spring security returns 403 FORBIDDEN for a BadCredentialsException.
// But it should return 401 UNAUTHORIZED.
response.sendError(HttpServletResponse.SC_UNAUTHORIZED)
)
)
.build();
}
@Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri:http://localhost:${server.port}/fake-jwt/.well-known/jwks.json}")
private String jwkSetUri;
@Bean
@Profile("!fake-jwt")
public JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
}
@Bean
@Profile("fake-jwt")
@SneakyThrows
public JwtDecoder fakeJwtDecoder() {
// For fake-jwt profile, use the same RSA key as JwtFakeBearer
return NimbusJwtDecoder.withPublicKey(RSA_KEY.toRSAPublicKey()).build();
}
}
@@ -1,36 +0,0 @@
package net.hostsharing.hsadminng.config;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
// Do NOT use @Component (or similar) here, this would register the filter directly.
// But we need to register it in the SecurityFilterChain created by WebSecurityConfig.
// The bean gets created in net.hostsharing.hsadminng.config.WebSecurityConfig.authenticationFilter.
@AllArgsConstructor
public class CasAuthenticationFilter extends OncePerRequestFilter {
private CasAuthenticator authenticator;
@Override
@SneakyThrows
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
if (request.getHeader("authorization") != null) {
final var authenticatedRequest = new AuthenticatedHttpServletRequestWrapper(request);
final var currentSubject = authenticator.authenticate(request);
final var authentication = new UsernamePasswordAuthenticationToken(currentSubject, null, null);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(authenticatedRequest, response);
} else {
filterChain.doFilter(request, response);
}
}
}
@@ -1,8 +0,0 @@
package net.hostsharing.hsadminng.config;
import jakarta.servlet.http.HttpServletRequest;
public interface CasAuthenticator {
String authenticate(final HttpServletRequest httpRequest);
}
@@ -1,14 +0,0 @@
package net.hostsharing.hsadminng.config;
import lombok.SneakyThrows;
import jakarta.servlet.http.HttpServletRequest;
public class FakeCasAuthenticator implements CasAuthenticator {
@Override
@SneakyThrows
public String authenticate(final HttpServletRequest httpRequest) {
return httpRequest.getHeader("Authorization").replaceAll("^Bearer ", "");
}
}
@@ -0,0 +1,40 @@
package net.hostsharing.hsadminng.config;
import io.micrometer.core.annotation.Timed;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Profile;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@Profile("fake-jwt")
@NoSecurityRequirement
@Slf4j
public class FakeJwtController {
@PostMapping(value = "/fake-jwt/token", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@Timed("app.config.jwt.token")
public ResponseEntity<Map<String, Object>> token(
@RequestParam String username,
@RequestParam String password,
@RequestParam(defaultValue = "openid profile") String scope) {
log.info("Fake JWT: Issuing token for user: {}", username);
// Accept any username/password for local testing
String token = JwtFakeBearer.bearer(username).replace("Bearer ", "");
return ResponseEntity.ok(Map.of(
"access_token", token,
"token_type", "Bearer",
"expires_in", 3600,
"scope", scope
));
}
}
@@ -11,18 +11,16 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@Configuration @Configuration
public class JsonObjectMapperConfiguration { public class JsonObjectMapperConfiguration {
public static ObjectMapper build() { public static ObjectMapper build() {
return new JsonObjectMapperConfiguration().customObjectMapper().build(); return new JsonObjectMapperConfiguration().customObjectMapper();
} }
@Bean @Bean
@Primary @Primary
public Jackson2ObjectMapperBuilder customObjectMapper() { public ObjectMapper customObjectMapper() {
// HOWTO: add JSON converters and specify other JSON mapping configurations
return new Jackson2ObjectMapperBuilder() return new Jackson2ObjectMapperBuilder()
.modules(new JsonNullableModule(), new JavaTimeModule()) .modules(new JsonNullableModule(), new JavaTimeModule())
.featuresToEnable( .featuresToEnable(
@@ -30,6 +28,7 @@ public class JsonObjectMapperConfiguration {
DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS,
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
) )
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build();
} }
} }
@@ -0,0 +1,42 @@
package net.hostsharing.hsadminng.config;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import lombok.SneakyThrows;
import lombok.val;
import java.util.Date;
/**
* Provides a fake JWT bearer generator.
*/
public class JwtFakeBearer {
public static final RSAKey RSA_KEY = generateRSAKey(2048, "test-key");
@SneakyThrows
public static String bearer(final String subject) {
val claims = new JWTClaimsSet.Builder()
.subject(subject)
.issuer("http://test-issuer")
.audience("api")
.expirationTime(new Date(System.currentTimeMillis() + 3600_000))
.build();
val signed = new SignedJWT(
new JWSHeader.Builder(JWSAlgorithm.RS256)
.keyID(RSA_KEY.getKeyID()).build(), claims);
signed.sign(new RSASSASigner(RSA_KEY.toPrivateKey()));
return "Bearer " + signed.serialize();
}
@SneakyThrows
private static RSAKey generateRSAKey(final int size, final String keyID) {
return new RSAKeyGenerator(size).keyID(keyID).generate();
}
}
@@ -1,86 +0,0 @@
package net.hostsharing.hsadminng.config;
import io.micrometer.core.annotation.Timed;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import jakarta.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
// HOWTO add logger
@Slf4j
@RequiredArgsConstructor
public class RealCasAuthenticator implements CasAuthenticator {
@Value("${hsadminng.cas.server}")
private String casServerUrl;
@Value("${hsadminng.cas.service}")
private String serviceUrl;
private final MessageTranslator messageTranslator;
private final RestTemplate restTemplate = new RestTemplate();
@SneakyThrows
@Timed("app.cas.authenticate")
public String authenticate(final HttpServletRequest httpRequest) {
final var ticket = httpRequest.getHeader("authorization").replaceAll("^Bearer ", "");
final var serviceTicket = ticket.startsWith("TGT-")
? fetchServiceTicket(ticket)
: ticket;
final var userName = extractUserName(verifyServiceTicket(serviceTicket));
// HOWTO log some message for a certain log level (trace, debug, info, warn, error)
log.debug("CAS-user: {}", userName);
return userName;
}
private String fetchServiceTicket(final String ticketGrantingTicket) {
final var tgtUrl = casServerUrl + "/cas/v1/tickets/" + ticketGrantingTicket;
final var restTemplate = new RestTemplate();
final var formData = new LinkedMultiValueMap<String, String>();
formData.add("service", serviceUrl);
return restTemplate.postForObject(tgtUrl, formData, String.class);
}
private Document verifyServiceTicket(final String serviceTicket) throws SAXException, IOException, ParserConfigurationException {
if ( !serviceTicket.startsWith("ST-") ) {
throwBadCredentialsException("auth.unknown-authorization-ticket");
}
final var url = casServerUrl + "/cas/p3/serviceValidate" +
"?service=" + serviceUrl +
"&ticket=" + serviceTicket;
final var response = restTemplate.getForObject(url, String.class);
return DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(new java.io.ByteArrayInputStream(response.getBytes()));
}
private String extractUserName(final Document verification) {
if (verification.getElementsByTagName("cas:authenticationSuccess").getLength() == 0) {
throwBadCredentialsException("auth.cas-service-ticket-could-not-be-verified");
}
return verification.getElementsByTagName("cas:user").item(0).getTextContent();
}
private void throwBadCredentialsException(final String messageKey) {
final var translatedMessage = messageTranslator.translate(messageKey);
throw new BadCredentialsException(translatedMessage);
}
}
@@ -1,77 +1,12 @@
package net.hostsharing.hsadminng.config; package net.hostsharing.hsadminng.config;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFilter;
import jakarta.servlet.http.HttpServletResponse;
@Configuration @Configuration
@EnableWebSecurity @Profile("!test")
@EnableMethodSecurity(prePostEnabled = true) // Add this annotation @EnableMethodSecurity // this does not work with @WebMvcTest, see WebSecurityConfigForWebMvcTests
// TODO.impl: securitySchemes should work in OpenAPI yaml, but the Spring templates seem not to support it public class WebSecurityConfig extends BaseWebSecurityConfig {
@SecurityScheme(type = SecuritySchemeType.HTTP, name = "casTicket", scheme = "bearer", bearerFormat = "CAS ticket", description = "CAS ticket", in = SecuritySchemeIn.HEADER)
public class WebSecurityConfig {
@Lazy
@Autowired
private CasAuthenticationFilter authenticationFilter;
@Autowired
private MessageTranslator messageTranslator;
@Bean
@Profile("!test")
public SecurityFilterChain securityFilterChain(final HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(
// only list endpoints implemented in libraries here
"/swagger-ui/**",
"/v3/api-docs/**",
"/actuator/**"
// otherwise use @PreAuthorize annotation at the controller class / endpoint method level
).permitAll()
.requestMatchers("/api/**").permitAll() // controlled at method level
.anyRequest().denyAll()
)
.addFilterBefore(authenticationFilter, AuthenticationFilter.class)
.csrf(AbstractHttpConfigurer::disable)
.exceptionHandling(exception -> exception
.authenticationEntryPoint((request, response, authException) ->
// For unknown reasons Spring security returns 403 FORBIDDEN for a BadCredentialsException.
// But it should return 401 UNAUTHORIZED.
response.sendError(HttpServletResponse.SC_UNAUTHORIZED)
)
)
.build();
}
@Bean
@Profile("realCasAuthenticator")
public CasAuthenticator realCasServiceTicketValidator() {
return new RealCasAuthenticator(messageTranslator);
}
@Bean
@Profile("fakeCasAuthenticator")
public CasAuthenticator fakeCasServiceTicketValidator() {
return new FakeCasAuthenticator();
}
@Bean
public CasAuthenticationFilter authenticationFilter(final CasAuthenticator authenticator) {
return new CasAuthenticationFilter(authenticator);
}
} }
@@ -5,19 +5,17 @@ import java.util.List;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import lombok.val; import lombok.val;
import net.hostsharing.hsadminng.config.NoSecurityRequirement; import net.hostsharing.hsadminng.config.NoSecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.accounts.generated.api.v1.api.ContextsApi; import net.hostsharing.hsadminng.accounts.generated.api.v1.api.ContextsApi;
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.ContextResource; import net.hostsharing.hsadminng.accounts.generated.api.v1.model.ContextResource;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@PreAuthorize("isAuthenticated()")
@NoSecurityRequirement @NoSecurityRequirement
public class HsCredentialsContextsController implements ContextsApi { public class HsCredentialsContextsController implements ContextsApi {
@@ -33,7 +31,6 @@ public class HsCredentialsContextsController implements ContextsApi {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Timed("app.credentials.contexts.getListOfLoginContexts") @Timed("app.credentials.contexts.getListOfLoginContexts")
@PreAuthorize("permitAll()")
public ResponseEntity<List<ContextResource>> getListOfContexts(final String assumedRoles) { public ResponseEntity<List<ContextResource>> getListOfContexts(final String assumedRoles) {
if (SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) { if (SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
context.assumeRoles(assumedRoles); context.assumeRoles(assumedRoles);
@@ -14,7 +14,7 @@ import net.hostsharing.hsadminng.accounts.generated.api.v1.model.ContextResource
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.CurrentLoginUserResource; import net.hostsharing.hsadminng.accounts.generated.api.v1.model.CurrentLoginUserResource;
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.RbacSubjectResource; import net.hostsharing.hsadminng.accounts.generated.api.v1.model.RbacSubjectResource;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.accounts.generated.api.v1.api.CredentialsApi; import net.hostsharing.hsadminng.accounts.generated.api.v1.api.CredentialsApi;
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.CredentialsInsertResource; import net.hostsharing.hsadminng.accounts.generated.api.v1.model.CredentialsInsertResource;
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.CredentialsPatchResource; import net.hostsharing.hsadminng.accounts.generated.api.v1.model.CredentialsPatchResource;
@@ -42,7 +42,7 @@ import static java.util.Optional.of;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsCredentialsController implements CredentialsApi { public class HsCredentialsController implements CredentialsApi {
@Autowired @Autowired
@@ -4,7 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.api.HsBookingItemsApi; import net.hostsharing.hsadminng.hs.booking.generated.api.v1.api.HsBookingItemsApi;
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemInsertResource; import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemInsertResource;
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemPatchResource; import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemPatchResource;
@@ -35,7 +35,7 @@ import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateR
@RestController @RestController
@Profile("!only-prod-schema") @Profile("!only-prod-schema")
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsBookingItemController implements HsBookingItemsApi { public class HsBookingItemController implements HsBookingItemsApi {
@Autowired @Autowired
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.booking.project;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorRepository; import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorRepository;
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.api.HsBookingProjectsApi; import net.hostsharing.hsadminng.hs.booking.generated.api.v1.api.HsBookingProjectsApi;
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingProjectInsertResource; import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingProjectInsertResource;
@@ -25,7 +25,7 @@ import java.util.function.BiConsumer;
@RestController @RestController
@Profile("!only-prod-schema") @Profile("!only-prod-schema")
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsBookingProjectController implements HsBookingProjectsApi { public class HsBookingProjectController implements HsBookingProjectsApi {
@Autowired @Autowired
@@ -7,7 +7,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityS
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityValidatorRegistry; import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityValidatorRegistry;
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetsApi; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetsApi;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetInsertResource; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetInsertResource;
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetPatchResource; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetPatchResource;
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetResource; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetResource;
@@ -32,7 +32,7 @@ import java.util.function.BiConsumer;
@RestController @RestController
@Profile("!only-prod-schema") @Profile("!only-prod-schema")
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsHostingAssetController implements HsHostingAssetsApi { public class HsHostingAssetController implements HsHostingAssetsApi {
@Autowired @Autowired
@@ -7,7 +7,6 @@ import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetP
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetTypeResource; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetTypeResource;
import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.Profile;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
@@ -16,12 +15,10 @@ import java.util.Map;
@RestController @RestController
@Profile("!only-prod-schema") @Profile("!only-prod-schema")
@PreAuthorize("isAuthenticated()")
@NoSecurityRequirement @NoSecurityRequirement
public class HsHostingAssetPropsController implements HsHostingAssetPropsApi { public class HsHostingAssetPropsController implements HsHostingAssetPropsApi {
@Override @Override
@PreAuthorize("permitAll()")
@Timed("app.hosting.assets.api.getListOfHostingAssetTypes") @Timed("app.hosting.assets.api.getListOfHostingAssetTypes")
public ResponseEntity<List<String>> getListOfHostingAssetTypes() { public ResponseEntity<List<String>> getListOfHostingAssetTypes() {
final var resource = HostingAssetEntityValidatorRegistry.types().stream() final var resource = HostingAssetEntityValidatorRegistry.types().stream()
@@ -31,7 +28,6 @@ public class HsHostingAssetPropsController implements HsHostingAssetPropsApi {
} }
@Override @Override
@PreAuthorize("permitAll()")
@Timed("app.hosting.assets.api.getListOfHostingAssetTypeProps") @Timed("app.hosting.assets.api.getListOfHostingAssetTypeProps")
public ResponseEntity<List<Object>> getListOfHostingAssetTypeProps( public ResponseEntity<List<Object>> getListOfHostingAssetTypeProps(
final HsHostingAssetTypeResource assetType) { final HsHostingAssetTypeResource assetType) {
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.office.bankaccount;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeBankAccountsApi; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeBankAccountsApi;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeBankAccountInsertResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeBankAccountInsertResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeBankAccountResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeBankAccountResource;
@@ -21,7 +21,7 @@ import java.util.UUID;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsOfficeBankAccountController implements HsOfficeBankAccountsApi { public class HsOfficeBankAccountController implements HsOfficeBankAccountsApi {
@Autowired @Autowired
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.contact;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeContactsApi; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeContactsApi;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeContactInsertResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeContactInsertResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeContactPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeContactPatchResource;
@@ -23,7 +23,7 @@ import static net.hostsharing.hsadminng.errors.Validate.validate;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsOfficeContactController implements HsOfficeContactsApi { public class HsOfficeContactController implements HsOfficeContactsApi {
@Autowired @Autowired
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.coopassets;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.errors.MultiValidationException; import net.hostsharing.hsadminng.errors.MultiValidationException;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopAssetsApi; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopAssetsApi;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopAssetsTransactionInsertResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopAssetsTransactionInsertResource;
@@ -40,7 +40,7 @@ import static net.hostsharing.hsadminng.lambda.WithNonNull.withNonNull;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAssetsApi { public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAssetsApi {
@Autowired @Autowired
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.coopshares;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.errors.MultiValidationException; import net.hostsharing.hsadminng.errors.MultiValidationException;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopSharesApi; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopSharesApi;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopSharesTransactionInsertResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopSharesTransactionInsertResource;
@@ -31,7 +31,7 @@ import static net.hostsharing.hsadminng.hs.validation.UuidResolver.resolve;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopSharesApi { public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopSharesApi {
@Autowired @Autowired
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.office.debitor;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeDebitorsApi; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeDebitorsApi;
@@ -35,7 +35,7 @@ import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsOfficeDebitorController implements HsOfficeDebitorsApi { public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
@Autowired @Autowired
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.office.membership;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeMembershipsApi; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeMembershipsApi;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipInsertResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipInsertResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource;
@@ -27,7 +27,7 @@ import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsOfficeMembershipController implements HsOfficeMembershipsApi { public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
@Autowired @Autowired
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.partner;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.errors.ReferenceNotFoundException; import net.hostsharing.hsadminng.errors.ReferenceNotFoundException;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactFromResourceConverter; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactFromResourceConverter;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
@@ -39,7 +39,7 @@ import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsOfficePartnerController implements HsOfficePartnersApi { public class HsOfficePartnerController implements HsOfficePartnersApi {
@Autowired @Autowired
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.person;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficePersonsApi; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficePersonsApi;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePersonInsertResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePersonInsertResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePersonPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePersonPatchResource;
@@ -20,7 +20,7 @@ import java.util.UUID;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsOfficePersonController implements HsOfficePersonsApi { public class HsOfficePersonController implements HsOfficePersonsApi {
@Autowired @Autowired
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.office.relation;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.errors.Validate; import net.hostsharing.hsadminng.errors.Validate;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
@@ -29,7 +29,7 @@ import static net.hostsharing.hsadminng.mapper.KeyValueMap.from;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsOfficeRelationController implements HsOfficeRelationsApi { public class HsOfficeRelationController implements HsOfficeRelationsApi {
@Autowired @Autowired
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.office.sepamandate;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeSepaMandatesApi; import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeSepaMandatesApi;
@@ -27,7 +27,7 @@ import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateR
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi { public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi {
@Autowired @Autowired
@@ -6,19 +6,16 @@ import net.hostsharing.hsadminng.config.NoSecurityRequirement;
import net.hostsharing.hsadminng.generated.api.v1.api.TestApi; import net.hostsharing.hsadminng.generated.api.v1.api.TestApi;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@PreAuthorize("isAuthenticated()")
@NoSecurityRequirement @NoSecurityRequirement
public class PingController implements TestApi { public class PingController implements TestApi {
@Autowired @Autowired
private MessageTranslator messageTranslator; private MessageTranslator messageTranslator;
@PreAuthorize("permitAll()")
@Timed("app.api.ping") @Timed("app.api.ping")
public ResponseEntity<String> ping() { public ResponseEntity<String> ping() {
// HOWTO translate text with placeholders - also see in resource files i18n/messages_*.properties. // HOWTO translate text with placeholders - also see in resource files i18n/messages_*.properties.
@@ -26,7 +23,6 @@ public class PingController implements TestApi {
return ResponseEntity.ok(translatedMessage + "\n"); return ResponseEntity.ok(translatedMessage + "\n");
} }
@PreAuthorize("isAuthenticated()")
@Timed("app.api.pong") @Timed("app.api.pong")
public ResponseEntity<String> pong() { public ResponseEntity<String> pong() {
final var userName = SecurityContextHolder.getContext().getAuthentication().getName(); final var userName = SecurityContextHolder.getContext().getAuthentication().getName();
@@ -1,7 +1,8 @@
package net.hostsharing.hsadminng.context; package net.hostsharing.hsadminng.rbac.context;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.val;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
@@ -9,6 +10,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import jakarta.persistence.EntityExistsException;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@@ -74,7 +76,7 @@ public class Context {
"""); """);
query.setParameter("currentTask", shortenToMaxLength(currentTask, 127)); query.setParameter("currentTask", shortenToMaxLength(currentTask, 127));
query.setParameter("currentRequest", currentRequest); query.setParameter("currentRequest", currentRequest);
query.setParameter("currentSubject", currentSubject); query.setParameter("currentSubject", subjectName(currentSubject));
query.setParameter("assumedRoles", assumedRoles != null ? assumedRoles : ""); query.setParameter("assumedRoles", assumedRoles != null ? assumedRoles : "");
query.executeUpdate(); query.executeUpdate();
} }
@@ -119,6 +121,27 @@ public class Context {
.orElse("unknown"); .orElse("unknown");
} }
private String subjectName(final String nameOrUuid) {
if (nameOrUuid == null) {
return null;
}
// TODO.impl: maybe it should be the other way around: UUID as the default and just optionally the name
try {
val authenticatedUuid = UUID.fromString(nameOrUuid);
val subjectName = findSubjectNameByUuid(authenticatedUuid)
.orElseThrow(() -> new EntityExistsException("Subject not found"));
return subjectName;
} catch (final IllegalArgumentException e) {
return nameOrUuid;
}
}
private Optional<String> findSubjectNameByUuid(final UUID authenticatedUuid) {
return Optional.ofNullable(em.createNativeQuery("SELECT name FROM rbac.subject s WHERE s.uuid=:uuid")
.setParameter("uuid", authenticatedUuid)
.getSingleResult()).map(Object::toString);
}
private String toTask(final HttpServletRequest request) { private String toTask(final HttpServletRequest request) {
if (isRequestScopeAvailable()) { if (isRequestScopeAvailable()) {
return request.getMethod() + " " + request.getRequestURI(); return request.getMethod() + " " + request.getRequestURI();
@@ -2,7 +2,6 @@ package net.hostsharing.hsadminng.rbac.context;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacContextApi; import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacContextApi;
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacContextResource; import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacContextResource;
@@ -23,7 +22,7 @@ import java.util.UUID;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class RbacContextController implements RbacContextApi { public class RbacContextController implements RbacContextApi {
@Autowired @Autowired
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.rbac.grant;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacGrantsApi; import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacGrantsApi;
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacGrantResource; import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacGrantResource;
@@ -20,7 +20,7 @@ import java.util.UUID;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class RbacGrantController implements RbacGrantsApi { public class RbacGrantController implements RbacGrantsApi {
@Autowired @Autowired
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.rbac.grant; package net.hostsharing.hsadminng.rbac.grant;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.rbac.role;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacRolesApi; import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacRolesApi;
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacRoleResource; import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacRoleResource;
@@ -16,7 +16,7 @@ import java.util.List;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class RbacRoleController implements RbacRolesApi { public class RbacRoleController implements RbacRolesApi {
@Autowired @Autowired
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.rbac.subject;
import io.micrometer.core.annotation.Timed; import io.micrometer.core.annotation.Timed;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacSubjectsApi; import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacSubjectsApi;
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacSubjectPermissionResource; import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacSubjectPermissionResource;
@@ -19,7 +19,7 @@ import java.util.UUID;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class RbacSubjectController implements RbacSubjectsApi { public class RbacSubjectController implements RbacSubjectsApi {
@Autowired @Autowired
@@ -1,7 +1,7 @@
package net.hostsharing.hsadminng.rbac.test.cust; package net.hostsharing.hsadminng.rbac.test.cust;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.test.generated.api.v1.api.TestCustomersApi; import net.hostsharing.hsadminng.test.generated.api.v1.api.TestCustomersApi;
import net.hostsharing.hsadminng.test.generated.api.v1.model.TestCustomerResource; import net.hostsharing.hsadminng.test.generated.api.v1.model.TestCustomerResource;
@@ -18,7 +18,7 @@ import java.util.List;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class TestCustomerController implements TestCustomersApi { public class TestCustomerController implements TestCustomersApi {
@Autowired @Autowired
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.rbac.test.pac;
import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.mapper.OptionalFromJson; import net.hostsharing.hsadminng.mapper.OptionalFromJson;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.test.generated.api.v1.api.TestPackagesApi; import net.hostsharing.hsadminng.test.generated.api.v1.api.TestPackagesApi;
import net.hostsharing.hsadminng.test.generated.api.v1.model.TestPackageResource; import net.hostsharing.hsadminng.test.generated.api.v1.model.TestPackageResource;
import net.hostsharing.hsadminng.test.generated.api.v1.model.TestPackageUpdateResource; import net.hostsharing.hsadminng.test.generated.api.v1.model.TestPackageUpdateResource;
@@ -18,7 +18,7 @@ import java.util.UUID;
@RestController @RestController
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@SecurityRequirement(name = "casTicket") @SecurityRequirement(name = "bearerAuth")
public class TestPackageController implements TestPackagesApi { public class TestPackageController implements TestPackagesApi {
@Autowired @Autowired
@@ -147,15 +147,11 @@ public final class Stringify<B> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
PropertyValue(final B object, final Property<B, ?> prop) { PropertyValue(final B object, final Property<B, ?> prop) {
// FIXME: simplify this.prop = (Property<B, V>) prop;
final var typedProp = (Property<B, V>) prop; this.value = (V) this.prop.getValue(object);
final var value = typedProp.getValue(object); this.stringValue = this.value instanceof Stringifyable s
final var stringifiedValue = value instanceof Stringifyable stringifyable ? s.toShortString()
? stringifyable.toShortString() : Objects.toString(this.value);
: Objects.toString(value);
this.prop = typedProp;
this.value = (V) value;
this.stringValue = stringifiedValue;
} }
boolean notNullAndNotEmpty() { boolean notNullAndNotEmpty() {
+21 -3
View File
@@ -54,12 +54,16 @@ spring:
liquibase: liquibase:
contexts: ${spring.profiles.active} contexts: ${spring.profiles.active}
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ${HSADMINNG_JWT_ISSUER:}
jwk-set-uri: ${HSADMINNG_JWT_JWKS_URL:}
hsadminng: hsadminng:
postgres: postgres:
leakproof: leakproof:
cas:
server: https://login.hostsharing.net/cas # use empty string to bypass CAS-validation and directly use current-subject
service: https://hsadminng.hostsharing.net:443 # TODO.conf: deployment target + matching CAS service ID
metrics: metrics:
distribution: distribution:
@@ -78,3 +82,17 @@ logging:
# HOWTO configure logging, e.g. logging to a separate file, see: # HOWTO configure logging, e.g. logging to a separate file, see:
# https://docs.spring.io/spring-boot/reference/features/logging.html # https://docs.spring.io/spring-boot/reference/features/logging.html
---
spring:
config:
activate:
on-profile: fake-jwt
security:
oauth2:
resourceserver:
jwt:
issuer-uri: "http://localhost:${server.port}/fake-jwt"
jwk-set-uri: "http://localhost:${server.port}/fake-jwt/.well-known/jwks.json"
@@ -384,6 +384,7 @@ public class ArchitectureTest {
classes().that(belongToProductionClasses() classes().that(belongToProductionClasses()
.and(are(annotatedWith(RestController.class)))) .and(are(annotatedWith(RestController.class))))
.should(havePreAuthorizeWithValue("isAuthenticated()")) .should(havePreAuthorizeWithValue("isAuthenticated()"))
.orShould().beAnnotatedWith(NoSecurityRequirement.class)
.because("Every REST controller should require authentication by default, use @PreAuthorize(...) to override this at the endpoint method level."); .because("Every REST controller should require authentication by default, use @PreAuthorize(...) to override this at the endpoint method level.");
private static ArchCondition<JavaClass> havePreAuthorizeWithValue(String expectedValue) { private static ArchCondition<JavaClass> havePreAuthorizeWithValue(String expectedValue) {
@@ -1,109 +0,0 @@
package net.hostsharing.hsadminng.config;
import com.github.tomakehurst.wiremock.WireMockServer;
import net.hostsharing.hsadminng.test.LogbackLogPattern;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static java.util.Map.entry;
import static net.hostsharing.hsadminng.config.HttpHeadersBuilder.headers;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {
"server.port=0",
"hsadminng.cas.server=http://localhost:8088",
"logging.level.root=DEBUG"
})
@ActiveProfiles({"wiremock", "realCasAuthenticator"}) // IMPORTANT: To test prod config, do NOT use test profile!
@Tag("generalIntegrationTest")
@ExtendWith(OutputCaptureExtension.class)
class CasAuthenticationFilterIntegrationTest {
@Value("${local.server.port}")
private int serverPort;
@Value("${hsadminng.cas.service}")
private String serviceUrl;
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private WireMockServer wireMockServer;
@Test
public void shouldAcceptRequestWithValidCasTicket(final CapturedOutput capturedOutput) {
// given
final var username = "test-user-" + randomAlphanumeric(4);
wireMockServer.stubFor(get(urlEqualTo("/cas/p3/serviceValidate?service=" + serviceUrl + "&ticket=ST-valid"))
.willReturn(aResponse()
.withStatus(200)
.withBody("""
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user>%{username}</cas:user>
</cas:authenticationSuccess>
</cas:serviceResponse>
""".replace("%{username}", username)
)));
// when
final var result = restTemplate.exchange(
"http://localhost:" + this.serverPort + "/api/pong",
HttpMethod.GET,
new HttpEntity<>(null, headers(entry("Authorization", "ST-valid"))),
String.class
);
// then
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getBody()).startsWith("ponged " + username);
// HOWTO assert log messages
assertThat(capturedOutput.getOut()).containsPattern(
LogbackLogPattern.of(LogLevel.DEBUG, RealCasAuthenticator.class, "CAS-user: " + username));
}
@Test
public void shouldRejectRequestWithInvalidCasTicket() {
// given
wireMockServer.stubFor(get(urlEqualTo("/cas/p3/serviceValidate?service=" + serviceUrl + "&ticket=invalid"))
.willReturn(aResponse()
.withStatus(200)
.withBody("""
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationFailure code="INVALID_REQUEST"></cas:authenticationFailure>
</cas:serviceResponse>
""")));
// when
final var result = restTemplate.exchange(
"http://localhost:" + this.serverPort + "/api/ping",
HttpMethod.GET,
new HttpEntity<>(null, headers(entry("Authorization", "invalid"))),
String.class
);
// then
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
}
}
@@ -10,12 +10,11 @@ import org.springframework.test.context.ActiveProfiles;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
@Tag("generalIntegrationTest")
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class } classes = HsadminNgApplication.class)
) @ActiveProfiles("fake-jwt")
@ActiveProfiles("test")
@Tag("generalIntegrationTest")
class CustomActuatorEndpointAcceptanceTest { class CustomActuatorEndpointAcceptanceTest {
@LocalManagementPort @LocalManagementPort
@@ -1,27 +0,0 @@
package net.hostsharing.hsadminng.config;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;
@TestConfiguration
public class DisableSecurityConfig {
@Bean
@Profile("test")
public SecurityFilterChain securityFilterChain(final HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
@Bean
@Profile("test")
public CasAuthenticator fakeAuthenticator() {
return new FakeCasAuthenticator();
}
}
@@ -0,0 +1,77 @@
package net.hostsharing.hsadminng.config;
import lombok.val;
import net.hostsharing.hsadminng.HsadminNgApplication;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import static java.util.Map.entry;
import static net.hostsharing.hsadminng.config.HttpHeadersBuilder.headers;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static org.assertj.core.api.Assertions.assertThat;
@Tag("generalIntegrationTest")
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class)
@TestPropertySource(properties = {
"server.port=0",
"logging.level.root=DEBUG"
})
@ActiveProfiles("fake-jwt")
@ExtendWith(OutputCaptureExtension.class)
class JwtAuthenticationFilterIntegrationTest {
@Value("${local.server.port}")
private int serverPort;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void shouldAcceptRequestWithValidJwt() {
// given
val givenSubject = "some-subject";
val bearer = bearer(givenSubject);
// when
final var result = restTemplate.exchange(
"http://localhost:" + this.serverPort + "/api/pong",
HttpMethod.GET,
new HttpEntity<>(null, headers(entry("Authorization", bearer))),
String.class
);
// then
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getBody()).startsWith("ponged " + givenSubject);
}
@Test
public void shouldRejectRequestWithInvalidJwt() {
// given
val givenInvalidBearer = "Bearer invalid";
// when
final var result = restTemplate.exchange(
"http://localhost:" + this.serverPort + "/api/pong",
HttpMethod.GET,
new HttpEntity<>(null, headers(entry("Authorization", givenInvalidBearer))),
String.class
);
// then
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
}
}
@@ -7,11 +7,8 @@ import org.junit.jupiter.params.provider.EnumSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import net.hostsharing.hsadminng.context.Context;
import java.util.Locale; import java.util.Locale;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@@ -29,9 +26,6 @@ class MessageTranslatorIntegrationTest {
@Autowired @Autowired
private WebApplicationContext webApplicationContext; private WebApplicationContext webApplicationContext;
@MockitoBean
private Context contextMock; // avoiding dependency issues
@AllArgsConstructor @AllArgsConstructor
enum TestCases { enum TestCases {
ENGLISH_KNOWN(Locale.ENGLISH, "test.ponged-{0}--in-your-language", ENGLISH_KNOWN(Locale.ENGLISH, "test.ponged-{0}--in-your-language",
@@ -0,0 +1,13 @@
package net.hostsharing.hsadminng.config;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Profile;
@TestConfiguration
// @EnableMethodSecurity breaks RestTests, endpoints won't be reachable anymore, all return 404
// that's the reason why this class even exists in the first place
@Profile("test")
public class WebSecurityConfigForWebMvcTests extends BaseWebSecurityConfig {
}
@@ -1,12 +1,9 @@
package net.hostsharing.hsadminng.config; package net.hostsharing.hsadminng.config;
import java.util.Map; import lombok.val;
import org.jetbrains.annotations.NotNull;
import com.github.tomakehurst.wiremock.WireMockServer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@@ -18,134 +15,57 @@ import org.springframework.http.HttpStatus;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.TestPropertySource;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import java.util.Map;
import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static java.util.Map.entry; import static java.util.Map.entry;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {"management.port=0", "server.port=0", "hsadminng.cas.server=http://localhost:8088"})
@ActiveProfiles({"wiremock", "realCasAuthenticator"}) // IMPORTANT: To test prod config, do NOT use test profile!
@Tag("generalIntegrationTest") @Tag("generalIntegrationTest")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = { "management.port=0", "server.port=0" })
@ActiveProfiles("fake-jwt") // IMPORTANT: In this test, want to test the prod config, do NOT use test profile!
class WebSecurityConfigIntegrationTest { class WebSecurityConfigIntegrationTest {
public static final String GIVEN_FAKE_SUBJECT = "fake-user-name";
@Value("${local.server.port}") @Value("${local.server.port}")
private int serverPort; private int serverPort;
@Value("${local.management.port}") @Value("${local.management.port}")
private int managementPort; private int managementPort;
@Value("${hsadminng.cas.service}")
private String serviceUrl;
@Autowired @Autowired
private TestRestTemplate restTemplate; private TestRestTemplate restTemplate;
@Autowired
private WireMockServer wireMockServer;
@BeforeEach
void setUp() {
wireMockServer.stubFor(get(anyUrl())
.willReturn(aResponse()
.withStatus(200)
.withBody("""
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationFailure/>
</cas:serviceResponse>
""")));
}
@Test @Test
void accessToApiWithValidServiceTicketSouldBePermitted() { void accessToApiWithValidJwtShouldBePermitted() {
// given
givenCasTicketValidationResponse("ST-fake-cas-ticket", "fake-user-name");
// http request
final var result = restTemplate.exchange(
"http://localhost:" + this.serverPort + "/api/pong",
HttpMethod.GET,
httpHeaders(entry("Authorization", "Bearer ST-fake-cas-ticket")),
String.class
);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getBody()).startsWith("ponged fake-user-name");
}
@Test
void accessToApiWithValidTicketGrantingTicketShouldBePermitted() {
// given
givenCasServiceTicketForTicketGrantingTicket("TGT-fake-cas-ticket", "ST-fake-cas-ticket");
givenCasTicketValidationResponse("ST-fake-cas-ticket", "fake-user-name");
// http request
final var result = restTemplate.exchange(
"http://localhost:" + this.serverPort + "/api/pong",
HttpMethod.GET,
httpHeaders(entry("Authorization", "Bearer TGT-fake-cas-ticket")),
String.class
);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getBody()).startsWith("ponged fake-user-name");
}
@Test
void accessToOpenApiWithInvalidTicketGrantingTicketShouldBePermitted() {
// given
givenCasServiceTicketForTicketGrantingTicket("TGT-fake-cas-ticket", "ST-fake-cas-ticket");
givenCasTicketValidationResponse("ST-fake-cas-ticket", "fake-user-name");
// http request
final var result = restTemplate.exchange(
"http://localhost:" + this.serverPort + "/api/ping",
HttpMethod.GET,
httpHeaders(entry("Authorization", "Bearer TGT-WRONG-cas-ticket")),
String.class
);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
}
@Test
void accessToOpenApiWithoutTokenShouldBePermitted() {
final var result = this.restTemplate.getForEntity(
"http://localhost:" + this.serverPort + "/api/ping", String.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
}
@Test
void accessToProtectedApiWithValidTokenShouldBePermitted() {
// given
givenCasTicketValidationResponse("ST-fake-cas-ticket", "fake-user-name");
// when // when
final var result = restTemplate.exchange( val result = restTemplate.exchange(
"http://localhost:" + this.serverPort + "/api/pong", serverUrl("/api/pong"),
HttpMethod.GET, HttpMethod.GET,
httpHeaders(entry("Authorization", "Bearer ST-fake-cas-ticket")), httpHeaders(entry("Authorization", bearer(GIVEN_FAKE_SUBJECT))),
String.class String.class
); );
// then // then
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getBody()).startsWith("ponged " + GIVEN_FAKE_SUBJECT);
}
@Test
void accessToOpenApiWithoutTokenShouldBePermitted() {
val result = this.restTemplate.getForEntity(
serverUrl("/api/ping"), String.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
} }
@Test @Test
void accessToProtectedApiWithInvalidTokenShouldBeDenied() { void accessToProtectedApiWithInvalidTokenShouldBeDenied() {
// given
givenCasTicketValidationResponse("ST-fake-cas-ticket", "fake-user-name");
// when // when
final var result = restTemplate.exchange( val result = restTemplate.exchange(
"http://localhost:" + this.serverPort + "/api/pong", serverUrl("/api/pong"),
HttpMethod.GET, HttpMethod.GET,
httpHeaders(entry("Authorization", "Bearer ST-WRONG-cas-ticket")), httpHeaders(entry("Authorization", "Bearer INVALID-JWT")),
String.class String.class
); );
@@ -155,59 +75,42 @@ class WebSecurityConfigIntegrationTest {
@Test @Test
void accessToActuatorShouldBePermitted() { void accessToActuatorShouldBePermitted() {
final var result = this.restTemplate.getForEntity( val result = this.restTemplate.getForEntity(
"http://localhost:" + this.managementPort + "/actuator", Map.class); "http://localhost:" + this.managementPort + "/actuator", Map.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
} }
@Test @Test
void accessToSwaggerUiShouldBePermitted() { void accessToSwaggerUiShouldBePermitted() {
final var result = this.restTemplate.getForEntity( val result = this.restTemplate.getForEntity(
"http://localhost:" + this.serverPort + "/swagger-ui/index.html", String.class); serverUrl("/swagger-ui/index.html"), String.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
} }
@Test @Test
void accessToApiDocsEndpointShouldBePermitted() { void accessToApiDocsEndpointShouldBePermitted() {
final var result = this.restTemplate.getForEntity( val result = this.restTemplate.getForEntity(
"http://localhost:" + this.serverPort + "/v3/api-docs/swagger-config", String.class); serverUrl("/v3/api-docs/swagger-config"), String.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getBody()).contains("\"configUrl\":\"/v3/api-docs/swagger-config\""); assertThat(result.getBody()).contains("\"configUrl\":\"/v3/api-docs/swagger-config\"");
} }
@Test @Test
void accessToActuatorEndpointShouldBePermitted() { void accessToActuatorEndpointShouldBePermitted() {
final var result = this.restTemplate.getForEntity( val result = this.restTemplate.getForEntity(
"http://localhost:" + this.managementPort + "/actuator/health", Map.class); "http://localhost:" + this.managementPort + "/actuator/health", Map.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getBody().get("status")).isEqualTo("UP"); assertThat(result.getBody().get("status")).isEqualTo("UP");
} }
private void givenCasServiceTicketForTicketGrantingTicket(final String ticketGrantingTicket, final String serviceTicket) { private @NotNull String serverUrl(final String path) {
wireMockServer.stubFor(post(urlEqualTo("/cas/v1/tickets/" + ticketGrantingTicket)) return "http://localhost:" + this.serverPort + path;
.withFormParam("service", equalTo(serviceUrl))
.willReturn(aResponse()
.withStatus(201)
.withBody(serviceTicket)));
}
private void givenCasTicketValidationResponse(final String casToken, final String userName) {
wireMockServer.stubFor(get(urlEqualTo("/cas/p3/serviceValidate?service=" + serviceUrl + "&ticket=" + casToken))
.willReturn(aResponse()
.withStatus(200)
.withBody("""
<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
<cas:authenticationSuccess>
<cas:user>${userName}</cas:user>
</cas:authenticationSuccess>
</cas:serviceResponse>
""".replace("${userName}", userName))));
} }
@SafeVarargs @SafeVarargs
private HttpEntity<?> httpHeaders(final Map.Entry<String, String>... headerValues) { private HttpEntity<?> httpHeaders(final Map.Entry<String, String>... headerValues) {
final var headers = new HttpHeaders(); val headers = new HttpHeaders();
for ( Map.Entry<String, String> headerValue: headerValues ) { for (Map.Entry<String, String> headerValue : headerValues) {
headers.add(headerValue.getKey(), headerValue.getValue()); headers.add(headerValue.getKey(), headerValue.getValue());
} }
return new HttpEntity<>(headers); return new HttpEntity<>(headers);
@@ -1,9 +1,8 @@
package net.hostsharing.hsadminng.errors; package net.hostsharing.hsadminng.errors;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration; import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import org.junit.jupiter.api.Tag; import net.hostsharing.hsadminng.config.WebSecurityConfigForWebMvcTests;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
@@ -21,9 +20,12 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(controllers = RestResponseEntityExceptionHandlerRestTest.TestController.class) @WebMvcTest(controllers = RestResponseEntityExceptionHandlerRestTest.TestController.class)
@Import({JsonObjectMapperConfiguration.class, MessageTranslator.class, DisableSecurityConfig.class, RestResponseEntityExceptionHandler.class, RestResponseEntityExceptionHandlerRestTest.TestConfig.class}) @Import({ JsonObjectMapperConfiguration.class,
@Tag("generalIntegrationTest") MessageTranslator.class,
@ActiveProfiles("test") RestResponseEntityExceptionHandler.class,
RestResponseEntityExceptionHandlerRestTest.TestConfig.class,
WebSecurityConfigForWebMvcTests.class })
@ActiveProfiles({"fake-jwt", "test"})
class RestResponseEntityExceptionHandlerRestTest { class RestResponseEntityExceptionHandlerRestTest {
@TestConfiguration @TestConfiguration
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.accounts; package net.hostsharing.hsadminng.hs.accounts;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.context.ContextBasedTest; import net.hostsharing.hsadminng.rbac.context.ContextBasedTest;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Tag;
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.accounts; package net.hostsharing.hsadminng.hs.accounts;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.context.ContextBasedTest; import net.hostsharing.hsadminng.rbac.context.ContextBasedTest;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Tag;
@@ -1,6 +1,7 @@
package net.hostsharing.hsadminng.hs.accounts; package net.hostsharing.hsadminng.hs.accounts;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@@ -13,12 +14,13 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import net.hostsharing.hsadminng.config.DisableSecurityConfig; import net.hostsharing.hsadminng.config.WebSecurityConfigForWebMvcTests;
import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration; import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -37,8 +39,11 @@ import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.SynchronizationType; import jakarta.persistence.SynchronizationType;
@WebMvcTest(HsCredentialsContextsController.class) @WebMvcTest(HsCredentialsContextsController.class)
@Import({ StrictMapper.class, JsonObjectMapperConfiguration.class, DisableSecurityConfig.class, MessageTranslator.class}) @Import({ StrictMapper.class,
@ActiveProfiles("test") MessageTranslator.class,
JsonObjectMapperConfiguration.class,
WebSecurityConfigForWebMvcTests.class })
@ActiveProfiles({"fake-jwt", "test"})
class HsCredentialsContextsControllerRestTest { class HsCredentialsContextsControllerRestTest {
@Autowired @Autowired
@@ -85,7 +90,7 @@ class HsCredentialsContextsControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/accounts/contexts") .get("/api/hs/accounts/contexts")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(print()) .andDo(print())
@@ -105,7 +110,7 @@ class HsCredentialsContextsControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/accounts/contexts") .get("/api/hs/accounts/contexts")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("Bearer superuser-alex@hostsharing.net"))
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(print()) .andDo(print())
@@ -147,7 +152,7 @@ class HsCredentialsContextsControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/accounts/contexts") .get("/api/hs/accounts/contexts")
.header("Authorization", "Bearer drew@hostsharing.org") .header("Authorization", bearer("drew@hostsharing.org"))
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
.andDo(print()) .andDo(print())
@@ -3,9 +3,7 @@ package net.hostsharing.hsadminng.hs.accounts;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import lombok.val; import lombok.val;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.accounts.HsCredentialsEntity.HsCredentialsEntityBuilder; import net.hostsharing.hsadminng.hs.accounts.HsCredentialsEntity.HsCredentialsEntityBuilder;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
@@ -31,6 +29,7 @@ import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.LEGAL_PERSON; import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.LEGAL_PERSON;
import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.NATURAL_PERSON; import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.NATURAL_PERSON;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
@@ -41,18 +40,17 @@ import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
@Tag("generalIntegrationTest")
@Transactional @Transactional
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class }
) )
@ActiveProfiles("test") @ActiveProfiles("fake-jwt")
@Tag("generalIntegrationTest")
// too complex database interaction for just a RestTest, thus a fully integrated test // too complex database interaction for just a RestTest, thus a fully integrated test
class HsCredentialsControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsCredentialsControllerAcceptanceTest extends ContextBasedTestWithCleanup {
@LocalServerPort @LocalServerPort
private Integer port; Integer port;
@Autowired @Autowired
Context context; Context context;
@@ -93,7 +91,7 @@ class HsCredentialsControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/accounts/current") .get("http://localhost/api/hs/accounts/current")
@@ -120,7 +118,7 @@ class HsCredentialsControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer " + credentialsEntity.getSubject().getName()) .header("Authorization", bearer(credentialsEntity.getSubject().getName()))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/accounts/credentials/" + credentialsEntity.getUuid()) .get("http://localhost/api/hs/accounts/credentials/" + credentialsEntity.getUuid())
@@ -188,7 +186,7 @@ class HsCredentialsControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -228,7 +226,7 @@ class HsCredentialsControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -268,7 +266,7 @@ class HsCredentialsControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -314,7 +312,7 @@ class HsCredentialsControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -350,7 +348,7 @@ class HsCredentialsControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -388,7 +386,7 @@ class HsCredentialsControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.post("http://localhost/api/hs/accounts/credentials/" + credentialsEntity.getUuid() + "/used") .post("http://localhost/api/hs/accounts/credentials/" + credentialsEntity.getUuid() + "/used")
@@ -1,9 +1,8 @@
package net.hostsharing.hsadminng.hs.accounts; package net.hostsharing.hsadminng.hs.accounts;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity;
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType;
@@ -1,43 +1,19 @@
package net.hostsharing.hsadminng.hs.accounts.scenarios; package net.hostsharing.hsadminng.hs.accounts.scenarios;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import net.hostsharing.hsadminng.hs.scenarios.Produces; import net.hostsharing.hsadminng.hs.scenarios.Produces;
import net.hostsharing.hsadminng.hs.scenarios.Requires; import net.hostsharing.hsadminng.hs.scenarios.Requires;
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest; import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
import net.hostsharing.hsadminng.mapper.Array; import net.hostsharing.hsadminng.mapper.Array;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.test.IgnoreOnFailureExtension;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.ClassOrderer;
import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestClassOrder;
import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
@Tag("scenarioTest")
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class },
properties = {
"spring.datasource.url=${HSADMINNG_POSTGRES_JDBC_URL:jdbc:tc:postgresql:15.5-bookworm:///scenariosTC}",
"spring.datasource.username=${HSADMINNG_POSTGRES_ADMIN_USERNAME:ADMIN}",
"spring.datasource.password=${HSADMINNG_POSTGRES_ADMIN_PASSWORD:password}",
"hsadminng.superuser=${HSADMINNG_SUPERUSER:superuser-alex@hostsharing.net}"
}
)
@ActiveProfiles("test")
@TestClassOrder(ClassOrderer.OrderAnnotation.class)
@ExtendWith(IgnoreOnFailureExtension.class)
class CredentialsScenarioTests extends ScenarioTest { class CredentialsScenarioTests extends ScenarioTest {
@SneakyThrows @SneakyThrows
@@ -105,7 +81,8 @@ class CredentialsScenarioTests extends ScenarioTest {
.given("smsNumber", "+49123456789") .given("smsNumber", "+49123456789")
.given("globalUid", 21011) .given("globalUid", 21011)
.given("globalGid", 21011) .given("globalGid", 21011)
.given("contexts", Array.of( .given(
"contexts", Array.of(
Pair.of("HSADMIN", "prod") Pair.of("HSADMIN", "prod")
)) ))
.given("onboardingToken", "fake-unboarding-token") .given("onboardingToken", "fake-unboarding-token")
@@ -126,7 +103,8 @@ class CredentialsScenarioTests extends ScenarioTest {
.given("emailAddress", "susan.firby@example.org") .given("emailAddress", "susan.firby@example.org")
.given("phonePassword", "securePass987") .given("phonePassword", "securePass987")
.given("smsNumber", "+49987654321") .given("smsNumber", "+49987654321")
.given("contexts", Array.of( .given(
"contexts", Array.of(
Pair.of("HSADMIN", "prod"), Pair.of("HSADMIN", "prod"),
Pair.of("SSH", "internal") Pair.of("SSH", "internal")
)) ))
@@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
import static io.restassured.http.ContentType.JSON; import static io.restassured.http.ContentType.JSON;
import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.bearerTemplate;
import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.resolve; import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.resolve;
import static net.hostsharing.hsadminng.hs.scenarios.TemplateResolver.Resolver.DROP_COMMENTS; import static net.hostsharing.hsadminng.hs.scenarios.TemplateResolver.Resolver.DROP_COMMENTS;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@@ -33,7 +34,7 @@ public class CurrentLoginUser extends UseCase<CurrentLoginUser> {
"Current Login User", () -> "Current Login User", () ->
httpGet( httpGet(
"/api/hs/accounts/current", req -> req "/api/hs/accounts/current", req -> req
.header("Authorization", resolve("Bearer %{subjectName}", DROP_COMMENTS)) .header("Authorization", bearerTemplate("%{subjectName}"))
) )
.expecting(OK).expecting(JSON).expectObject() .expecting(OK).expecting(JSON).expectObject()
.extractValue("subject.name", "returnedSubjectName") .extractValue("subject.name", "returnedSubjectName")
@@ -7,6 +7,7 @@ import net.hostsharing.hsadminng.hs.scenarios.UseCase;
import java.util.List; import java.util.List;
import static io.restassured.http.ContentType.JSON; import static io.restassured.http.ContentType.JSON;
import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.bearerTemplate;
import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.resolve; import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.resolve;
import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.resolveJsonArray; import static net.hostsharing.hsadminng.hs.scenarios.ScenarioTest.resolveJsonArray;
import static net.hostsharing.hsadminng.hs.scenarios.TemplateResolver.Resolver.DROP_COMMENTS; import static net.hostsharing.hsadminng.hs.scenarios.TemplateResolver.Resolver.DROP_COMMENTS;
@@ -27,7 +28,7 @@ public class FetchRbacContext extends UseCase<FetchRbacContext> {
"RBAC Context", () -> "RBAC Context", () ->
httpGet( httpGet(
"/api/rbac/context", req -> req "/api/rbac/context", req -> req
.header("Authorization", resolve("Bearer %{subjectName}", DROP_COMMENTS)) .header("Authorization", bearerTemplate("%{subjectName}"))
.header("assumed-roles", resolve("%{assumedRoles}", DROP_COMMENTS)) .header("assumed-roles", resolve("%{assumedRoles}", DROP_COMMENTS))
) )
.expecting(OK).expecting(JSON).expectObject() .expecting(OK).expecting(JSON).expectObject()
@@ -12,7 +12,6 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetRealRepository;
import net.hostsharing.hsadminng.hs.hosting.asset.validators.Dns; import net.hostsharing.hsadminng.hs.hosting.asset.validators.Dns;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.ClassOrderer; import org.junit.jupiter.api.ClassOrderer;
@@ -36,6 +35,7 @@ import java.util.UUID;
import static java.util.Map.entry; import static java.util.Map.entry;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_WEBSPACE; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_WEBSPACE;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.UNIX_USER; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.UNIX_USER;
@@ -43,14 +43,13 @@ import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.matchesRegex; import static org.hamcrest.Matchers.matchesRegex;
@Tag("bookingIntegrationTest")
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class} classes = HsadminNgApplication.class)
) @ActiveProfiles("fake-jwt")
@ActiveProfiles("test")
@Transactional
@TestClassOrder(ClassOrderer.OrderAnnotation.class) // fail early on fetching problems @TestClassOrder(ClassOrderer.OrderAnnotation.class) // fail early on fetching problems
@Tag("bookingIntegrationTest") @Transactional
class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup {
@LocalServerPort @LocalServerPort
@@ -87,7 +86,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/booking/items?projectUuid=" + givenProject.getUuid()) .get("http://localhost/api/hs/booking/items?projectUuid=" + givenProject.getUuid())
@@ -151,7 +150,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -201,7 +200,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -271,7 +270,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -361,7 +360,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -454,7 +453,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/booking/items/" + givenBookingItemUuid) .get("http://localhost/api/hs/booking/items/" + givenBookingItemUuid)
@@ -488,7 +487,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/booking/items/" + givenBookingItemUuid) .get("http://localhost/api/hs/booking/items/" + givenBookingItemUuid)
@@ -506,7 +505,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("assumed-roles", "hs_booking.project#D-1000313-D-1000313defaultproject:ADMIN") .header("assumed-roles", "hs_booking.project#D-1000313-D-1000313defaultproject:ADMIN")
.port(port) .port(port)
.when() .when()
@@ -550,7 +549,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("assumed-roles", "hs_booking.project#D-1000111-D-1000111defaultproject:AGENT") .header("assumed-roles", "hs_booking.project#D-1000111-D-1000111defaultproject:AGENT")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -605,7 +604,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/booking/items/" + givenBookingItem.getUuid()) .delete("http://localhost/api/hs/booking/items/" + givenBookingItem.getUuid())
@@ -624,7 +623,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/booking/items/" + givenBookingItem.getUuid()) .delete("http://localhost/api/hs/booking/items/" + givenBookingItem.getUuid())
@@ -3,25 +3,25 @@ package net.hostsharing.hsadminng.hs.booking.item;
import io.hypersistence.utils.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration; import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.config.WebSecurityConfigForWebMvcTests;
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemInsertResource; import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemInsertResource;
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemResource; import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemResource;
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealEntity; import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealEntity;
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealRepository; import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealRepository;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
import net.hostsharing.hsadminng.config.DisableSecurityConfig; import net.hostsharing.hsadminng.rbac.context.Context;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@@ -32,20 +32,24 @@ import java.time.LocalDate;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.matchesRegex; import static org.hamcrest.Matchers.matchesRegex;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(HsBookingItemController.class) @WebMvcTest(HsBookingItemController.class)
@Import({StrictMapper.class, JsonObjectMapperConfiguration.class, DisableSecurityConfig.class, MessageTranslator.class}) @Import({StrictMapper.class,
@ActiveProfiles("test") JsonObjectMapperConfiguration.class,
MessageTranslator.class,
WebSecurityConfigForWebMvcTests.class })
@ActiveProfiles({"fake-jwt", "test"})
class HsBookingItemControllerRestTest { class HsBookingItemControllerRestTest {
@Autowired @Autowired
@@ -77,7 +81,6 @@ class HsBookingItemControllerRestTest {
public EntityManager entityManager() { public EntityManager entityManager() {
return mock(EntityManager.class); return mock(EntityManager.class);
} }
} }
@BeforeEach @BeforeEach
@@ -107,7 +110,7 @@ class HsBookingItemControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/booking/items") .post("/api/hs/booking/items")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
@@ -158,7 +161,7 @@ class HsBookingItemControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/booking/items") .post("/api/hs/booking/items")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
@@ -1,7 +1,7 @@
package net.hostsharing.hsadminng.hs.booking.item; package net.hostsharing.hsadminng.hs.booking.item;
import io.hypersistence.utils.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealRepository; import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRealRepository;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository; import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository;
@@ -6,7 +6,6 @@ import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorRepository; import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorRepository;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -20,17 +19,17 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.matchesRegex; import static org.hamcrest.Matchers.matchesRegex;
@Tag("bookingIntegrationTest")
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class } classes = HsadminNgApplication.class)
)
@ActiveProfiles("test")
@Transactional @Transactional
@Tag("bookingIntegrationTest") @ActiveProfiles("fake-jwt")
class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithCleanup {
@LocalServerPort @LocalServerPort
@@ -62,7 +61,7 @@ class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/booking/projects?debitorUuid=" + givenDebitor.getUuid()) .get("http://localhost/api/hs/booking/projects?debitorUuid=" + givenDebitor.getUuid())
@@ -93,7 +92,7 @@ class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithClean
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -133,7 +132,7 @@ class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/booking/projects/" + givenBookingProjectUuid) .get("http://localhost/api/hs/booking/projects/" + givenBookingProjectUuid)
@@ -156,7 +155,7 @@ class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/booking/projects/" + givenBookingProjectUuid) .get("http://localhost/api/hs/booking/projects/" + givenBookingProjectUuid)
@@ -172,7 +171,7 @@ class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer person-TuckerJack@example.com") .header("Authorization", bearer("person-TuckerJack@example.com"))
.header("assumed-roles", "hs_booking.project#D-1000313-D-1000313defaultproject:AGENT") .header("assumed-roles", "hs_booking.project#D-1000313-D-1000313defaultproject:AGENT")
.port(port) .port(port)
.when() .when()
@@ -198,7 +197,7 @@ class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -237,7 +236,7 @@ class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/booking/projects/" + givenBookingProject.getUuid()) .delete("http://localhost/api/hs/booking/projects/" + givenBookingProject.getUuid())
@@ -255,7 +254,7 @@ class HsBookingProjectControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/booking/projects/" + givenBookingProject.getUuid()) .delete("http://localhost/api/hs/booking/projects/" + givenBookingProject.getUuid())
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.booking.project; package net.hostsharing.hsadminng.hs.booking.project;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorRepository; import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorRepository;
import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository; import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository;
import net.hostsharing.hsadminng.rbac.role.RawRbacRoleRepository; import net.hostsharing.hsadminng.rbac.role.RawRbacRoleRepository;
@@ -14,7 +14,6 @@ import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.ClassOrderer; import org.junit.jupiter.api.ClassOrderer;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
@@ -34,6 +33,7 @@ import java.util.UUID;
import java.util.function.Supplier; import java.util.function.Supplier;
import static java.util.Map.entry; import static java.util.Map.entry;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.EMAIL_ALIAS; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.EMAIL_ALIAS;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
@@ -43,14 +43,13 @@ import static net.hostsharing.hsadminng.test.JsonMatcher.strictlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.matchesRegex; import static org.hamcrest.Matchers.matchesRegex;
@Tag("hostingIntegrationTest")
@Transactional @Transactional
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, DisableSecurityConfig.class, JpaAttempt.class } classes = HsadminNgApplication.class)
) @ActiveProfiles("fake-jwt")
@ActiveProfiles("test")
@TestClassOrder(ClassOrderer.OrderAnnotation.class) // fail early on fetching problems @TestClassOrder(ClassOrderer.OrderAnnotation.class) // fail early on fetching problems
@Tag("hostingIntegrationTest")
class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup {
@LocalServerPort @LocalServerPort
@@ -90,7 +89,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/hosting/assets?projectUuid=" + givenProject.getUuid() + "&type=MANAGED_WEBSPACE") .get("http://localhost/api/hs/hosting/assets?projectUuid=" + givenProject.getUuid() + "&type=MANAGED_WEBSPACE")
@@ -118,7 +117,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("assumed-roles", "hs_hosting.asset#fir01:AGENT") .header("assumed-roles", "hs_hosting.asset#fir01:AGENT")
.port(port) .port(port)
.when() .when()
@@ -154,7 +153,8 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
void globalAdmin_canAddBookedAsset() { void globalAdmin_canAddBookedAsset() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenBookingItem = newBookingItem("D-1000111 default project", final var givenBookingItem = newBookingItem(
"D-1000111 default project",
HsBookingItemType.MANAGED_WEBSPACE, "separate ManagedWebspace BI", HsBookingItemType.MANAGED_WEBSPACE, "separate ManagedWebspace BI",
Map.ofEntries( Map.ofEntries(
entry("SSD", 50), entry("SSD", 50),
@@ -166,7 +166,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -206,7 +206,8 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
toCleanup(HsHostingAssetRbacEntity.class, newWebspaceUuid); toCleanup(HsHostingAssetRbacEntity.class, newWebspaceUuid);
// and a default user got created // and a default user got created
final var webspaceUnixUser = em.createQuery("SELECT ha FROM HsHostingAssetRealEntity ha WHERE ha.parentAsset.uuid=:webspaceUUID") final var webspaceUnixUser = em.createQuery(
"SELECT ha FROM HsHostingAssetRealEntity ha WHERE ha.parentAsset.uuid=:webspaceUUID")
.setParameter("webspaceUUID", newWebspaceUuid) .setParameter("webspaceUUID", newWebspaceUuid)
.getSingleResult(); .getSingleResult();
assertThat(webspaceUnixUser).isNotNull().extracting(Object::toString) assertThat(webspaceUnixUser).isNotNull().extracting(Object::toString)
@@ -227,7 +228,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("assumed-roles", "hs_hosting.asset#vm1011:ADMIN") .header("assumed-roles", "hs_hosting.asset#vm1011:ADMIN")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -281,7 +282,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -327,7 +328,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -364,12 +365,13 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
assertThat(givenHostingAsset.getBookingItem().getResources().get("Multi")) assertThat(givenHostingAsset.getBookingItem().getResources().get("Multi"))
.as("precondition failed") .as("precondition failed")
.isEqualTo(1); .isEqualTo(1);
final var preExistingUnixUserCount = realAssetRepo.findAllByCriteria(null, givenHostingAsset.getUuid(), UNIX_USER).size(); final var preExistingUnixUserCount = realAssetRepo.findAllByCriteria(null, givenHostingAsset.getUuid(), UNIX_USER)
.size();
final var UNIX_USER_PER_MULTI_OPTION = 25; final var UNIX_USER_PER_MULTI_OPTION = 25;
jpaAttempt.transacted(() -> { jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
for (int n = 0; n < UNIX_USER_PER_MULTI_OPTION-preExistingUnixUserCount; ++n) { for (int n = 0; n < UNIX_USER_PER_MULTI_OPTION - preExistingUnixUserCount; ++n) {
toCleanup(realAssetRepo.save( toCleanup(realAssetRepo.save(
HsHostingAssetRealEntity.builder() HsHostingAssetRealEntity.builder()
.type(UNIX_USER) .type(UNIX_USER)
@@ -382,7 +384,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -421,7 +423,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/hosting/assets/" + givenAssetUuid) .get("http://localhost/api/hs/hosting/assets/" + givenAssetUuid)
@@ -446,7 +448,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/hosting/assets/" + givenAssetUuid) .get("http://localhost/api/hs/hosting/assets/" + givenAssetUuid)
@@ -463,7 +465,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer person-TuckerJack@example.com") .header("Authorization", bearer("person-TuckerJack@example.com"))
.header("assumed-roles", "hs_booking.project#D-1000313-D-1000313defaultproject:AGENT") .header("assumed-roles", "hs_booking.project#D-1000313-D-1000313defaultproject:AGENT")
.port(port) .port(port)
.when() .when()
@@ -508,7 +510,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -581,7 +583,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
//.header("assumed-roles", "hs_hosting.asset#vm2001:ADMIN") //.header("assumed-roles", "hs_hosting.asset#vm2001:ADMIN")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -664,7 +666,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
.build()); .build());
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/hosting/assets/" + givenAsset.getUuid()) .delete("http://localhost/api/hs/hosting/assets/" + givenAsset.getUuid())
@@ -696,7 +698,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
.build()); .build());
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/hosting/assets/" + givenAsset.getUuid()) .delete("http://localhost/api/hs/hosting/assets/" + givenAsset.getUuid())
@@ -739,7 +741,8 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var project = realProjectRepo.findByCaption(projectCaption).getFirst(); final var project = realProjectRepo.findByCaption(projectCaption).getFirst();
final var resources = switch (bookingItemType) { final var resources = switch (bookingItemType) {
case MANAGED_SERVER -> Map.<String, Object>ofEntries(entry("CPU", 1), case MANAGED_SERVER -> Map.<String, Object>ofEntries(
entry("CPU", 1),
entry("RAM", 20), entry("RAM", 20),
entry("SSD", 25), entry("SSD", 25),
entry("Traffic", 250)); entry("Traffic", 250));
@@ -783,9 +786,8 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
}).returnedValue(); }).returnedValue();
} }
private Integer nextUnixUserId() { private Integer nextUnixUserId() {
final Object result = em.createNativeQuery("SELECT nextval('hs_hosting.asset_unixuser_system_id_seq')", Integer.class) final Object result = em.createNativeQuery("select nextval('hs_hosting.asset_unixuser_system_id_seq')", Integer.class)
.getSingleResult(); .getSingleResult();
return (Integer) result + 1; return (Integer) result + 1;
} }
@@ -7,12 +7,12 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration; import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.config.WebSecurityConfigForWebMvcTests;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealRepository; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealRepository;
import net.hostsharing.hsadminng.mapper.Array; import net.hostsharing.hsadminng.mapper.Array;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
import net.hostsharing.hsadminng.config.DisableSecurityConfig; import net.hostsharing.hsadminng.rbac.context.Context;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
@@ -38,6 +38,7 @@ import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static java.util.Map.entry; import static java.util.Map.entry;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.CLOUD_SERVER_BOOKING_ITEM_REAL_ENTITY; import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.CLOUD_SERVER_BOOKING_ITEM_REAL_ENTITY;
import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.MANAGED_SERVER_BOOKING_ITEM_REAL_ENTITY; import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.MANAGED_SERVER_BOOKING_ITEM_REAL_ENTITY;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetTestEntities.MANAGED_SERVER_HOSTING_ASSET_REAL_TEST_ENTITY; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetTestEntities.MANAGED_SERVER_HOSTING_ASSET_REAL_TEST_ENTITY;
@@ -49,13 +50,16 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(HsHostingAssetController.class) @WebMvcTest(HsHostingAssetController.class)
@Import({ StrictMapper.class, JsonObjectMapperConfiguration.class, DisableSecurityConfig.class, MessageTranslator.class }) @Import({ StrictMapper.class,
@ActiveProfiles("test") JsonObjectMapperConfiguration.class,
MessageTranslator.class,
WebSecurityConfigForWebMvcTests.class })
@ActiveProfiles({"fake-jwt", "test"})
public class HsHostingAssetControllerRestTest { public class HsHostingAssetControllerRestTest {
@Autowired @Autowired
@@ -592,7 +596,7 @@ public class HsHostingAssetControllerRestTest {
// when // when
final var result = mockMvc.perform(MockMvcRequestBuilders final var result = mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/hosting/assets?type="+testCase.name()) .get("/api/hs/hosting/assets?type="+testCase.name())
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
// then // then
@@ -662,7 +666,7 @@ public class HsHostingAssetControllerRestTest {
// when // when
final var result = mockMvc.perform(MockMvcRequestBuilders final var result = mockMvc.perform(MockMvcRequestBuilders
.patch("/api/hs/hosting/assets/" + givenDomainHttpSetupUuid) .patch("/api/hs/hosting/assets/" + givenDomainHttpSetupUuid)
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
@@ -2,8 +2,6 @@ package net.hostsharing.hsadminng.hs.hosting.asset;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@@ -12,12 +10,11 @@ import org.springframework.test.context.ActiveProfiles;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
@Tag("hostingIntegrationTest")
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class } classes = HsadminNgApplication.class)
) @ActiveProfiles("fake-jwt")
@ActiveProfiles("test")
@Tag("hostingIntegrationTest")
class HsHostingAssetPropsControllerAcceptanceTest { class HsHostingAssetPropsControllerAcceptanceTest {
@LocalServerPort @LocalServerPort
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.hosting.asset; package net.hostsharing.hsadminng.hs.hosting.asset;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealRepository; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealRepository;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
@@ -56,7 +56,7 @@ class DomainSetupHostingAssetFactoryUnitTest {
private EntityManagerWrapper emw = emwFake; private EntityManagerWrapper emw = emwFake;
@Spy @Spy
private ObjectMapper jsonMapper = new JsonObjectMapperConfiguration().customObjectMapper().build(); private ObjectMapper jsonMapper = new JsonObjectMapperConfiguration().customObjectMapper();
@Spy @Spy
private StrictMapper StrictMapper = new StrictMapper(emw); private StrictMapper StrictMapper = new StrictMapper(emw);
@@ -39,7 +39,7 @@ class HsBookingItemCreatedListenerUnitTest {
private EntityManagerWrapper emw = emwFake; private EntityManagerWrapper emw = emwFake;
@Spy @Spy
private ObjectMapper jsonMapper = new JsonObjectMapperConfiguration().customObjectMapper().build(); private ObjectMapper jsonMapper = new JsonObjectMapperConfiguration().customObjectMapper();
@Spy @Spy
private StrictMapper StrictMapper = new StrictMapper(emw); private StrictMapper StrictMapper = new StrictMapper(emw);
@@ -52,7 +52,7 @@ class ManagedWebspaceHostingAssetFactoryUnitTest {
private EntityManagerWrapper emw = emwFake; private EntityManagerWrapper emw = emwFake;
@Spy @Spy
private ObjectMapper jsonMapper = new JsonObjectMapperConfiguration().customObjectMapper().build(); private ObjectMapper jsonMapper = new JsonObjectMapperConfiguration().customObjectMapper();
@Spy @Spy
private StrictMapper StrictMapper = new StrictMapper(emw); private StrictMapper StrictMapper = new StrictMapper(emw);
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.migration;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hash.HashGenerator; import net.hostsharing.hsadminng.hash.HashGenerator;
import net.hostsharing.hsadminng.hash.HashGenerator.Algorithm; import net.hostsharing.hsadminng.hash.HashGenerator.Algorithm;
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorEntity; import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorEntity;
@@ -3,13 +3,17 @@ package net.hostsharing.hsadminng.hs.office.bankaccount;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.json.JSONException; import org.json.JSONException;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.boot.test.web.server.LocalServerPort;
@@ -20,19 +24,19 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.startsWith;
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class }
)
@ActiveProfiles("test")
@Transactional @Transactional
@Tag("officeIntegrationTest") @Tag("officeIntegrationTest")
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class)
@ActiveProfiles("fake-jwt")
class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCleanup {
@LocalServerPort @LocalServerPort
@@ -58,7 +62,7 @@ class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/bankaccounts") .get("http://localhost/api/hs/office/bankaccounts")
@@ -124,7 +128,7 @@ class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCl
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -163,7 +167,7 @@ class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/bankaccounts/" + givenBankAccountUuid) .get("http://localhost/api/hs/office/bankaccounts/" + givenBankAccountUuid)
@@ -184,7 +188,7 @@ class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/bankaccounts/" + givenBankAccountUuid) .get("http://localhost/api/hs/office/bankaccounts/" + givenBankAccountUuid)
@@ -200,7 +204,7 @@ class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer bankaccount-admin@firstbankaccount.example.com") .header("Authorization", bearer("bankaccount-admin@firstbankaccount.example.com"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/bankaccounts/" + givenBankAccountUuid) .get("http://localhost/api/hs/office/bankaccounts/" + givenBankAccountUuid)
@@ -228,7 +232,7 @@ class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCl
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -266,7 +270,7 @@ class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/bankaccounts/" + givenBankAccount.getUuid()) .delete("http://localhost/api/hs/office/bankaccounts/" + givenBankAccount.getUuid())
@@ -283,7 +287,7 @@ class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-test-user@hostsharing.org") .header("Authorization", bearer("selfregistered-test-user@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/bankaccounts/" + givenBankAccount.getUuid()) .delete("http://localhost/api/hs/office/bankaccounts/" + givenBankAccount.getUuid())
@@ -304,7 +308,7 @@ class HsOfficeBankAccountControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/bankaccounts/" + givenBankAccount.getUuid()) .delete("http://localhost/api/hs/office/bankaccounts/" + givenBankAccount.getUuid())
@@ -1,27 +1,29 @@
package net.hostsharing.hsadminng.hs.office.bankaccount; package net.hostsharing.hsadminng.hs.office.bankaccount;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.config.WebSecurityConfigForWebMvcTests;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.config.DisableSecurityConfig; import net.hostsharing.hsadminng.rbac.context.Context;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.EnumSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(HsOfficeBankAccountController.class) @WebMvcTest(HsOfficeBankAccountController.class)
@Import({DisableSecurityConfig.class, MessageTranslator.class}) @Import({ MessageTranslator.class,
@ActiveProfiles("test") WebSecurityConfigForWebMvcTests.class })
@ActiveProfiles({"fake-jwt", "test"})
class HsOfficeBankAccountControllerRestTest { class HsOfficeBankAccountControllerRestTest {
@Autowired @Autowired
@@ -69,7 +71,7 @@ class HsOfficeBankAccountControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/bankaccounts") .post("/api/hs/office/bankaccounts")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
@@ -116,7 +118,7 @@ class HsOfficeBankAccountControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/bankaccounts") .post("/api/hs/office/bankaccounts")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.bankaccount; package net.hostsharing.hsadminng.hs.office.bankaccount;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository; import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository;
import net.hostsharing.hsadminng.rbac.role.RawRbacRoleRepository; import net.hostsharing.hsadminng.rbac.role.RawRbacRoleRepository;
@@ -3,10 +3,9 @@ package net.hostsharing.hsadminng.hs.office.contact;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.json.JSONException; import org.json.JSONException;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
@@ -27,6 +26,7 @@ import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import static java.util.Map.entry; import static java.util.Map.entry;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@@ -34,13 +34,12 @@ import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.startsWith;
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class }
)
@ActiveProfiles("test")
@Transactional @Transactional
@Tag("officeIntegrationTest") @Tag("officeIntegrationTest")
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class)
@ActiveProfiles("fake-jwt")
class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanup {
@LocalServerPort @LocalServerPort
@@ -69,7 +68,7 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/contacts") .get("http://localhost/api/hs/office/contacts")
@@ -107,7 +106,7 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -156,7 +155,7 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/contacts/" + givenContactUuid) .get("http://localhost/api/hs/office/contacts/" + givenContactUuid)
@@ -177,7 +176,7 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/contacts/" + givenContactUuid) .get("http://localhost/api/hs/office/contacts/" + givenContactUuid)
@@ -192,7 +191,7 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer contact-admin@firstcontact.example.com") .header("Authorization", bearer("contact-admin@firstcontact.example.com"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/contacts/" + givenContactUuid) .get("http://localhost/api/hs/office/contacts/" + givenContactUuid)
@@ -224,7 +223,7 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -282,7 +281,7 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -328,7 +327,7 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/contacts/" + givenContact.getUuid()) .delete("http://localhost/api/hs/office/contacts/" + givenContact.getUuid())
@@ -348,7 +347,7 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-test-user@hostsharing.org") .header("Authorization", bearer("selfregistered-test-user@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/contacts/" + givenContact.getUuid()) .delete("http://localhost/api/hs/office/contacts/" + givenContact.getUuid())
@@ -369,7 +368,7 @@ class HsOfficeContactControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/contacts/" + givenContact.getUuid()) .delete("http://localhost/api/hs/office/contacts/" + givenContact.getUuid())
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.contact; package net.hostsharing.hsadminng.hs.office.contact;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.mapper.Array; import net.hostsharing.hsadminng.mapper.Array;
import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository; import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository;
import net.hostsharing.hsadminng.rbac.role.RawRbacRoleRepository; import net.hostsharing.hsadminng.rbac.role.RawRbacRoleRepository;
@@ -3,13 +3,10 @@ package net.hostsharing.hsadminng.hs.office.coopassets;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.config.MessagesResourceConfig;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository;
import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
@@ -27,6 +24,7 @@ import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionType.DEPOSIT; import static net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionType.DEPOSIT;
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
@@ -34,14 +32,12 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.startsWith;
@Tag("officeIntegrationTest")
@Transactional
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class, classes = HsadminNgApplication.class)
MessagesResourceConfig.class, MessageTranslator.class} @ActiveProfiles("fake-jwt")
)
@ActiveProfiles("test")
@Transactional
@Tag("officeIntegrationTest")
class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBasedTestWithCleanup {
@LocalServerPort @LocalServerPort
@@ -70,14 +66,14 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopassetstransactions") .get("http://localhost/api/hs/office/coopassetstransactions")
.then().log().all().assertThat() .then().log().all().assertThat()
.statusCode(200) .statusCode(200)
.contentType("application/json") .contentType("application/json")
.body("", hasSize(3*6)); // @formatter:on .body("", hasSize(3 * 6)); // @formatter:on
} }
@Test @Test
@@ -88,7 +84,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopassetstransactions?membershipUuid="+givenMembership.getUuid()) .get("http://localhost/api/hs/office/coopassetstransactions?membershipUuid="+givenMembership.getUuid())
@@ -211,7 +207,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopassetstransactions?membershipUuid=" .get("http://localhost/api/hs/office/coopassetstransactions?membershipUuid="
@@ -244,7 +240,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -301,7 +297,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -357,7 +353,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -398,7 +394,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
LocalDate.of(2010, 3, 15)).get(0).getUuid(); LocalDate.of(2010, 3, 15)).get(0).getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given().header("Authorization", "Bearer superuser-alex@hostsharing.net") .given().header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid) .get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid)
@@ -421,7 +417,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
LocalDate.of(2010, 3, 15)).get(0).getUuid(); LocalDate.of(2010, 3, 15)).get(0).getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given().header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .given().header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid) .get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid)
@@ -439,7 +435,7 @@ class HsOfficeCoopAssetsTransactionControllerAcceptanceTest extends ContextBased
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer person-FirstGmbH@example.com") .header("Authorization", bearer("person-FirstGmbH@example.com"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid) .get("http://localhost/api/hs/office/coopassetstransactions/" + givenCoopAssetTransactionUuid)
@@ -2,15 +2,16 @@ package net.hostsharing.hsadminng.hs.office.coopassets;
import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration; import net.hostsharing.hsadminng.config.JsonObjectMapperConfiguration;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealEntity;
import net.hostsharing.hsadminng.config.MessagesResourceConfig; import net.hostsharing.hsadminng.config.MessagesResourceConfig;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
import net.hostsharing.hsadminng.rbac.test.JsonBuilder; import net.hostsharing.hsadminng.rbac.test.JsonBuilder;
import net.hostsharing.hsadminng.config.DisableSecurityConfig; import net.hostsharing.hsadminng.config.WebSecurityConfigForWebMvcTests;
import net.hostsharing.hsadminng.test.TestUuidGenerator; import net.hostsharing.hsadminng.test.TestUuidGenerator;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -37,6 +38,7 @@ import static net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsT
import static net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionType.DISBURSAL; import static net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionType.DISBURSAL;
import static net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionType.REVERSAL; import static net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionType.REVERSAL;
import static net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionType.TRANSFER; import static net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionType.TRANSFER;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.rbac.test.JsonBuilder.jsonObject; import static net.hostsharing.hsadminng.rbac.test.JsonBuilder.jsonObject;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@@ -54,8 +56,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
MessagesResourceConfig.class, MessagesResourceConfig.class,
MessageTranslator.class, MessageTranslator.class,
JsonObjectMapperConfiguration.class, JsonObjectMapperConfiguration.class,
DisableSecurityConfig.class }) WebSecurityConfigForWebMvcTests.class })
@ActiveProfiles("test") @ActiveProfiles({"fake-jwt", "test"})
class HsOfficeCoopAssetsTransactionControllerRestTest { class HsOfficeCoopAssetsTransactionControllerRestTest {
// If you need to run just a single test-case in this data-driven test-method, set SINGLE_TEST_CASE_EXECUTION to true! // If you need to run just a single test-case in this data-driven test-method, set SINGLE_TEST_CASE_EXECUTION to true!
@@ -662,7 +664,7 @@ class HsOfficeCoopAssetsTransactionControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/coopassetstransactions") .post("/api/hs/office/coopassetstransactions")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(testCase.givenRequestBody()) .content(testCase.givenRequestBody())
@@ -838,7 +840,7 @@ class HsOfficeCoopAssetsTransactionControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/coopassetstransactions") .post("/api/hs/office/coopassetstransactions")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(testCase.givenRequestBody()) .content(testCase.givenRequestBody())
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
@@ -857,7 +859,7 @@ class HsOfficeCoopAssetsTransactionControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/coopassetstransactions/" + SOME_REVERTED_TRANSFER_ASSET_TX_ENTITY.getUuid()) .get("/api/hs/office/coopassetstransactions/" + SOME_REVERTED_TRANSFER_ASSET_TX_ENTITY.getUuid())
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON)) .contentType(MediaType.APPLICATION_JSON))
// then // then
@@ -873,7 +875,7 @@ class HsOfficeCoopAssetsTransactionControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/coopassetstransactions/" + UNAVAILABLE_UUID) .get("/api/hs/office/coopassetstransactions/" + UNAVAILABLE_UUID)
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON)) .contentType(MediaType.APPLICATION_JSON))
// then // then
@@ -899,7 +901,7 @@ class HsOfficeCoopAssetsTransactionControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/coopassetstransactions") .get("/api/hs/office/coopassetstransactions")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON)) .contentType(MediaType.APPLICATION_JSON))
// then // then
@@ -950,5 +952,4 @@ class HsOfficeCoopAssetsTransactionControllerRestTest {
private String suffixOf(final String memberNumber) { private String suffixOf(final String memberNumber) {
return memberNumber.substring("M-".length() + 5); return memberNumber.substring("M-".length() + 5);
} }
} }
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.coopassets; package net.hostsharing.hsadminng.hs.office.coopassets;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository; import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository;
@@ -3,12 +3,10 @@ package net.hostsharing.hsadminng.hs.office.coopshares;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository;
import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
@@ -22,21 +20,22 @@ import org.springframework.transaction.annotation.Transactional;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.startsWith;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = {HsadminNgApplication.class, DisableSecurityConfig.class, MessageTranslator.class, JpaAttempt.class})
@ActiveProfiles("test")
@Transactional @Transactional
@Tag("officeIntegrationTest") @Tag("officeIntegrationTest")
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class)
@ActiveProfiles("fake-jwt")
class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBasedTestWithCleanup {
@Autowired @Autowired
@@ -76,7 +75,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopsharestransactions") .get("http://localhost/api/hs/office/coopsharestransactions")
@@ -94,7 +93,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopsharestransactions?membershipUuid=" + givenMembership.getUuid()) .get("http://localhost/api/hs/office/coopsharestransactions?membershipUuid=" + givenMembership.getUuid())
@@ -158,7 +157,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopsharestransactions?membershipUuid=" + givenMembership.getUuid() + "&fromValueDate=2020-01-01&toValueDate=2021-12-31") .get("http://localhost/api/hs/office/coopsharestransactions?membershipUuid=" + givenMembership.getUuid() + "&fromValueDate=2020-01-01&toValueDate=2021-12-31")
@@ -191,7 +190,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(ContentType.JSON).body(""" .contentType(ContentType.JSON).body("""
{ {
@@ -251,7 +250,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -307,7 +306,7 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -344,11 +343,14 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased
@Test @Test
void globalAdmin_withoutAssumedRole_canGetArbitraryCoopShareTransaction() { void globalAdmin_withoutAssumedRole_canGetArbitraryCoopShareTransaction() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid(); final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
null,
LocalDate.of(2010, 3, 15),
LocalDate.of(2010, 3, 15)).get(0).getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid) .get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid)
@@ -366,11 +368,14 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased
@Test @Test
void normalUser_canNotGetUnrelatedCoopShareTransaction() { void normalUser_canNotGetUnrelatedCoopShareTransaction() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid(); final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
null,
LocalDate.of(2010, 3, 15),
LocalDate.of(2010, 3, 15)).get(0).getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid) .get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid)
.then().log().body() .then().log().body()
@@ -381,11 +386,14 @@ class HsOfficeCoopSharesTransactionControllerAcceptanceTest extends ContextBased
@Test @Test
void partnerPersonUser_canGetRelatedCoopShareTransaction() { void partnerPersonUser_canGetRelatedCoopShareTransaction() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(null, LocalDate.of(2010, 3, 15), LocalDate.of(2010, 3, 15)).get(0).getUuid(); final var givenCoopShareTransactionUuid = coopSharesTransactionRepo.findCoopSharesTransactionByOptionalMembershipUuidAndDateRange(
null,
LocalDate.of(2010, 3, 15),
LocalDate.of(2010, 3, 15)).get(0).getUuid();
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer person-FirstGmbH@example.com") .header("Authorization", bearer("person-FirstGmbH@example.com"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid) .get("http://localhost/api/hs/office/coopsharestransactions/" + givenCoopShareTransactionUuid)
@@ -2,11 +2,12 @@ package net.hostsharing.hsadminng.hs.office.coopshares;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.config.MessagesResourceConfig; import net.hostsharing.hsadminng.config.MessagesResourceConfig;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.rbac.test.JsonBuilder; import net.hostsharing.hsadminng.rbac.test.JsonBuilder;
import net.hostsharing.hsadminng.config.DisableSecurityConfig; import net.hostsharing.hsadminng.config.WebSecurityConfigForWebMvcTests;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.EnumSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -21,6 +22,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.rbac.test.JsonBuilder.jsonObject; import static net.hostsharing.hsadminng.rbac.test.JsonBuilder.jsonObject;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@@ -28,10 +30,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(HsOfficeCoopSharesTransactionController.class) @WebMvcTest(HsOfficeCoopSharesTransactionController.class)
@Import({DisableSecurityConfig.class, @Import({ MessagesResourceConfig.class,
MessagesResourceConfig.class, MessageTranslator.class,
MessageTranslator.class}) WebSecurityConfigForWebMvcTests.class })
@ActiveProfiles("test") @ActiveProfiles({"fake-jwt", "test"})
class HsOfficeCoopSharesTransactionControllerRestTest { class HsOfficeCoopSharesTransactionControllerRestTest {
@Autowired @Autowired
@@ -126,7 +128,7 @@ class HsOfficeCoopSharesTransactionControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/coopsharestransactions") .post("/api/hs/office/coopsharestransactions")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(testCase.givenRequestBody()) .content(testCase.givenRequestBody())
@@ -138,5 +140,4 @@ class HsOfficeCoopSharesTransactionControllerRestTest {
.andExpect(jsonPath("statusPhrase", is("Bad Request"))) .andExpect(jsonPath("statusPhrase", is("Bad Request")))
.andExpect(jsonPath("message", containsString(testCase.expectedErrorMessage))); .andExpect(jsonPath("message", containsString(testCase.expectedErrorMessage)));
} }
} }
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.coopshares; package net.hostsharing.hsadminng.hs.office.coopshares;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipRepository;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository; import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository;
@@ -3,16 +3,15 @@ package net.hostsharing.hsadminng.hs.office.debitor;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRbacRepository; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRbacRepository;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity;
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealRepository; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealRepository;
import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
@@ -28,6 +27,7 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.DEBITOR; import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.DEBITOR;
import static net.hostsharing.hsadminng.rbac.role.RbacRoleType.ADMIN; import static net.hostsharing.hsadminng.rbac.role.RbacRoleType.ADMIN;
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
@@ -38,13 +38,12 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.startsWith;
@Tag("officeIntegrationTest")
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class } classes = HsadminNgApplication.class)
) @ActiveProfiles({ "fake-jwt"})
@ActiveProfiles("test")
@Transactional @Transactional
@Tag("officeIntegrationTest")
class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanup {
private static final int LOWEST_TEMP_DEBITOR_SUFFIX = 90; private static final int LOWEST_TEMP_DEBITOR_SUFFIX = 90;
@@ -93,7 +92,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid()) .get("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid())
@@ -120,7 +119,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/debitors/D-1000212") .get("http://localhost/api/hs/office/debitors/D-1000212")
@@ -151,7 +150,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/debitors") .get("http://localhost/api/hs/office/debitors")
@@ -306,7 +305,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/debitors?partnerNumber=P-10002") .get("http://localhost/api/hs/office/debitors?partnerNumber=P-10002")
@@ -351,7 +350,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -396,7 +395,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -447,7 +446,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -482,7 +481,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -513,7 +512,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/debitors/" + givenDebitorUuid) .get("http://localhost/api/hs/office/debitors/" + givenDebitorUuid)
@@ -578,7 +577,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/debitors/" + givenDebitorUuid) .get("http://localhost/api/hs/office/debitors/" + givenDebitorUuid)
@@ -593,7 +592,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer contact-admin@firstcontact.example.com") .header("Authorization", bearer("contact-admin@firstcontact.example.com"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/debitors/" + givenDebitorUuid) .get("http://localhost/api/hs/office/debitors/" + givenDebitorUuid)
@@ -623,7 +622,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -705,7 +704,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
// @formatter:on // @formatter:on
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("assumed-roles", givenDebitor.getDebitorRel().getContact().roleId(ADMIN) ) .header("assumed-roles", givenDebitor.getDebitorRel().getContact().roleId(ADMIN) )
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -734,7 +733,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid()) .delete("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid())
@@ -753,7 +752,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer contact-admin@tenthcontact.example.com") .header("Authorization", bearer("contact-admin@tenthcontact.example.com"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid()) .delete("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid())
@@ -772,7 +771,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid()) .delete("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid())
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.debitor; package net.hostsharing.hsadminng.hs.office.debitor;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealRepository; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealRepository;
@@ -4,11 +4,10 @@ import io.hypersistence.utils.hibernate.type.range.Range;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealRepository; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealRepository;
import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.json.JSONException; import org.json.JSONException;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
@@ -25,20 +24,22 @@ import jakarta.persistence.PersistenceContext;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipStatus.ACTIVE; import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipStatus.ACTIVE;
import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipStatus.CANCELLED; import static net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipStatus.CANCELLED;
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
@Tag("officeIntegrationTest")
@Transactional
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class } classes = HsadminNgApplication.class)
) @ActiveProfiles("fake-jwt")
@ActiveProfiles("test")
@Transactional
@Tag("officeIntegrationTest")
class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCleanup {
private static final String TEMP_MEMBER_NUMBER_SUFFIX = "90"; private static final String TEMP_MEMBER_NUMBER_SUFFIX = "90";
@@ -72,7 +73,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/memberships") .get("http://localhost/api/hs/office/memberships")
@@ -118,7 +119,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.queryParam("partnerUuid", partner.getUuid() ) .queryParam("partnerUuid", partner.getUuid() )
@@ -146,7 +147,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.queryParam("partnerNumber", "P-10002" ) .queryParam("partnerNumber", "P-10002" )
@@ -183,7 +184,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -226,7 +227,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/memberships/" + givenMembershipUuid) .get("http://localhost/api/hs/office/memberships/" + givenMembershipUuid)
@@ -252,7 +253,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/memberships/" + givenMembershipUuid) .get("http://localhost/api/hs/office/memberships/" + givenMembershipUuid)
@@ -267,7 +268,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("assumed-roles", "hs_office.relation#HostsharingeG-with-PARTNER-ThirdOHG:AGENT") .header("assumed-roles", "hs_office.relation#HostsharingeG-with-PARTNER-ThirdOHG:AGENT")
.port(port) .port(port)
.when() .when()
@@ -299,7 +300,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -343,7 +344,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
// when // when
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("assumed-roles", givenPartnerAdmin) .header("assumed-roles", givenPartnerAdmin)
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
@@ -378,7 +379,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/memberships/" + givenMembership.getUuid()) .delete("http://localhost/api/hs/office/memberships/" + givenMembership.getUuid())
@@ -396,7 +397,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("assumed-roles", "hs_office.relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT") .header("assumed-roles", "hs_office.relation#HostsharingeG-with-PARTNER-FirstGmbH:AGENT")
.port(port) .port(port)
.when() .when()
@@ -415,7 +416,7 @@ class HsOfficeMembershipControllerAcceptanceTest extends ContextBasedTestWithCle
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/memberships/" + givenMembership.getUuid()) .delete("http://localhost/api/hs/office/memberships/" + givenMembership.getUuid())
@@ -3,14 +3,15 @@ package net.hostsharing.hsadminng.hs.office.membership;
import io.hypersistence.utils.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.config.MessagesResourceConfig; import net.hostsharing.hsadminng.config.MessagesResourceConfig;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionRepository; import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionRepository;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRbacEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRbacEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealRepository; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealRepository;
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
import net.hostsharing.hsadminng.config.DisableSecurityConfig; import net.hostsharing.hsadminng.config.WebSecurityConfigForWebMvcTests;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
@@ -30,6 +31,7 @@ import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static io.hypersistence.utils.hibernate.type.range.Range.localDateRange; import static io.hypersistence.utils.hibernate.type.range.Range.localDateRange;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
@@ -42,8 +44,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(HsOfficeMembershipController.class) @WebMvcTest(HsOfficeMembershipController.class)
@Import({ StrictMapper.class, DisableSecurityConfig.class, MessagesResourceConfig.class, MessageTranslator.class}) @Import({ StrictMapper.class, MessagesResourceConfig.class, MessageTranslator.class,
@ActiveProfiles("test") WebSecurityConfigForWebMvcTests.class })
@ActiveProfiles({"fake-jwt", "test"})
public class HsOfficeMembershipControllerRestTest { public class HsOfficeMembershipControllerRestTest {
private static final HsOfficePartnerRealEntity PARTNER_12345 = HsOfficePartnerRealEntity.builder() private static final HsOfficePartnerRealEntity PARTNER_12345 = HsOfficePartnerRealEntity.builder()
@@ -112,7 +115,7 @@ public class HsOfficeMembershipControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/memberships?partnerNumber=P-12345") .get("/api/hs/office/memberships?partnerNumber=P-12345")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
// then // then
@@ -134,7 +137,7 @@ public class HsOfficeMembershipControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/memberships?partnerNumber=P-12345") .get("/api/hs/office/memberships?partnerNumber=P-12345")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
@@ -199,7 +202,7 @@ public class HsOfficeMembershipControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/memberships/" + givenUuid) .get("/api/hs/office/memberships/" + givenUuid)
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
// then // then
@@ -218,7 +221,7 @@ public class HsOfficeMembershipControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/memberships/" + UUID.randomUUID()) .get("/api/hs/office/memberships/" + UUID.randomUUID())
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
// then // then
@@ -236,7 +239,7 @@ public class HsOfficeMembershipControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/memberships/M-1234501") .get("/api/hs/office/memberships/M-1234501")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
// then // then
@@ -255,7 +258,7 @@ public class HsOfficeMembershipControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/memberships/M-0000000") .get("/api/hs/office/memberships/M-0000000")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
// then // then
@@ -273,7 +276,7 @@ public class HsOfficeMembershipControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/memberships") .post("/api/hs/office/memberships")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
@@ -303,7 +306,7 @@ public class HsOfficeMembershipControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/memberships") .post("/api/hs/office/memberships")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
@@ -331,7 +334,7 @@ public class HsOfficeMembershipControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/memberships") .post("/api/hs/office/memberships")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
@@ -366,5 +369,4 @@ public class HsOfficeMembershipControllerRestTest {
} }
} }
} }
} }
@@ -1,7 +1,7 @@
package net.hostsharing.hsadminng.hs.office.membership; package net.hostsharing.hsadminng.hs.office.membership;
import io.hypersistence.utils.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealRepository; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRealRepository;
import net.hostsharing.hsadminng.mapper.Array; import net.hostsharing.hsadminng.mapper.Array;
@@ -13,8 +13,10 @@ import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealReposito
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.boot.test.web.server.LocalServerPort;
@@ -23,18 +25,20 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.EX_PARTNER; import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.EX_PARTNER;
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
@Tag("officeIntegrationTest")
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class } classes = HsadminNgApplication.class)
) @ActiveProfiles("fake-jwt")
@ActiveProfiles("test")
@Tag("officeIntegrationTest")
class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanup {
private static final UUID GIVEN_NON_EXISTING_UUID = UUID.fromString("00000000-0000-0000-0000-000000000000"); private static final UUID GIVEN_NON_EXISTING_UUID = UUID.fromString("00000000-0000-0000-0000-000000000000");
@@ -66,7 +70,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/partners") .get("http://localhost/api/hs/office/partners")
@@ -94,13 +98,19 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
void globalAdmin_withoutAssumedRole_canPostNewPartner() { void globalAdmin_withoutAssumedRole_canPostNewPartner() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMandantPerson = personRealRepo.findPersonByOptionalNameLike("Hostsharing eG").stream().findFirst().orElseThrow(); final var givenMandantPerson = personRealRepo.findPersonByOptionalNameLike("Hostsharing eG")
.stream()
.findFirst()
.orElseThrow();
final var givenPerson = personRealRepo.findPersonByOptionalNameLike("Winkler").stream().findFirst().orElseThrow(); final var givenPerson = personRealRepo.findPersonByOptionalNameLike("Winkler").stream().findFirst().orElseThrow();
final var givenContact = contactRealRepo.findContactByOptionalCaptionLike("fourth").stream().findFirst().orElseThrow(); final var givenContact = contactRealRepo.findContactByOptionalCaptionLike("fourth")
.stream()
.findFirst()
.orElseThrow();
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -159,7 +169,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -195,7 +205,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -238,7 +248,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/partners/" + givenPartnerUuid) .get("http://localhost/api/hs/office/partners/" + givenPartnerUuid)
@@ -270,7 +280,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/partners/" + givenPartnerUuid) .get("http://localhost/api/hs/office/partners/" + givenPartnerUuid)
@@ -285,7 +295,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer contact-admin@firstcontact.example.com") .header("Authorization", bearer("contact-admin@firstcontact.example.com"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/partners/" + givenPartnerUuid) .get("http://localhost/api/hs/office/partners/" + givenPartnerUuid)
@@ -316,7 +326,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -384,7 +394,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -411,7 +421,12 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
// and an ex-partner-relation got created // and an ex-partner-relation got created
final var newPartnerPersonUuid = givenPartner.getPartnerRel().getHolder().getUuid(); final var newPartnerPersonUuid = givenPartner.getPartnerRel().getHolder().getUuid();
assertThat(relationRepo.findRelationRelatedToPersonUuidRelationTypeMarkPersonAndContactData(newPartnerPersonUuid, EX_PARTNER, null, null, null)) assertThat(relationRepo.findRelationRelatedToPersonUuidRelationTypeMarkPersonAndContactData(
newPartnerPersonUuid,
EX_PARTNER,
null,
null,
null))
.map(HsOfficeRelation::toShortString) .map(HsOfficeRelation::toShortString)
.contains("rel(anchor='NP Winkler, Paul', type=EX_PARTNER, holder='UF Erben Bessler')"); .contains("rel(anchor='NP Winkler, Paul', type=EX_PARTNER, holder='UF Erben Bessler')");
} }
@@ -424,7 +439,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -449,7 +464,9 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
// finally, the partner details and only the partner details are actually updated // finally, the partner details and only the partner details are actually updated
assertThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent().get() assertThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent().get()
.matches(partner -> { .matches(partner -> {
assertThat(partner.getPartnerRel().getContact().getCaption()).isEqualTo(givenPartner.getPartnerRel().getContact().getCaption()); assertThat(partner.getPartnerRel().getContact().getCaption()).isEqualTo(givenPartner.getPartnerRel()
.getContact()
.getCaption());
assertThat(partner.getDetails().getRegistrationOffice()).isEqualTo("Temp Registergericht Leer"); assertThat(partner.getDetails().getRegistrationOffice()).isEqualTo("Temp Registergericht Leer");
assertThat(partner.getDetails().getRegistrationNumber()).isEqualTo("333333"); assertThat(partner.getDetails().getRegistrationNumber()).isEqualTo("333333");
assertThat(partner.getDetails().getBirthName()).isEqualTo("Maja Schmidt"); assertThat(partner.getDetails().getBirthName()).isEqualTo("Maja Schmidt");
@@ -472,7 +489,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/partners/" + givenPartner.getUuid()) .delete("http://localhost/api/hs/office/partners/" + givenPartner.getUuid())
@@ -492,7 +509,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer contact-admin@fourthcontact.example.com") .header("Authorization", bearer("contact-admin@fourthcontact.example.com"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/partners/" + givenPartner.getUuid()) .delete("http://localhost/api/hs/office/partners/" + givenPartner.getUuid())
@@ -511,7 +528,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/partners/" + givenPartner.getUuid()) .delete("http://localhost/api/hs/office/partners/" + givenPartner.getUuid())
@@ -528,9 +545,18 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
final String contactName) { final String contactName) {
return jpaAttempt.transacted(() -> { return jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMandantPerson = personRealRepo.findPersonByOptionalNameLike("Hostsharing eG").stream().findFirst().orElseThrow(); final var givenMandantPerson = personRealRepo.findPersonByOptionalNameLike("Hostsharing eG")
final var givenPerson = personRealRepo.findPersonByOptionalNameLike(partnerHolderName).stream().findFirst().orElseThrow(); .stream()
final var givenContact = contactRealRepo.findContactByOptionalCaptionLike(contactName).stream().findFirst().orElseThrow(); .findFirst()
.orElseThrow();
final var givenPerson = personRealRepo.findPersonByOptionalNameLike(partnerHolderName)
.stream()
.findFirst()
.orElseThrow();
final var givenContact = contactRealRepo.findContactByOptionalCaptionLike(contactName)
.stream()
.findFirst()
.orElseThrow();
final var partnerRel = new HsOfficeRelationRealEntity(); final var partnerRel = new HsOfficeRelationRealEntity();
partnerRel.setType(HsOfficeRelationType.PARTNER); partnerRel.setType(HsOfficeRelationType.PARTNER);
@@ -541,6 +567,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
return partnerRel; return partnerRel;
}).assertSuccessful().returnedValue(); }).assertSuccessful().returnedValue();
} }
private HsOfficePartnerRbacEntity givenSomeTemporaryPartnerBessler(final Integer partnerNumber) { private HsOfficePartnerRbacEntity givenSomeTemporaryPartnerBessler(final Integer partnerNumber) {
return jpaAttempt.transacted(() -> { return jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
@@ -1,8 +1,8 @@
package net.hostsharing.hsadminng.hs.office.partner; package net.hostsharing.hsadminng.hs.office.partner;
import net.hostsharing.hsadminng.config.DisableSecurityConfig; import net.hostsharing.hsadminng.config.WebSecurityConfigForWebMvcTests;
import net.hostsharing.hsadminng.config.MessageTranslator; import net.hostsharing.hsadminng.config.MessageTranslator;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactFromResourceConverter; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactFromResourceConverter;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRbacEntity; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRbacEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity;
@@ -11,6 +11,7 @@ import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealReposito
import net.hostsharing.hsadminng.mapper.StrictMapper; import net.hostsharing.hsadminng.mapper.StrictMapper;
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper; import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
import net.hostsharing.hsadminng.config.MessagesResourceConfig; import net.hostsharing.hsadminng.config.MessagesResourceConfig;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -32,6 +33,7 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@@ -46,8 +48,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
MessagesResourceConfig.class, MessagesResourceConfig.class,
MessageTranslator.class, MessageTranslator.class,
HsOfficeContactFromResourceConverter.class, HsOfficeContactFromResourceConverter.class,
DisableSecurityConfig.class }) WebSecurityConfigForWebMvcTests.class })
@ActiveProfiles("test") @ActiveProfiles({"fake-jwt", "test"})
class HsOfficePartnerControllerRestTest { class HsOfficePartnerControllerRestTest {
static final UUID GIVEN_MANDANTE_UUID = UUID.randomUUID(); static final UUID GIVEN_MANDANTE_UUID = UUID.randomUUID();
@@ -112,7 +114,7 @@ class HsOfficePartnerControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/partners") .post("/api/hs/office/partners")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.header("Accept-Language", "de") .header("Accept-Language", "de")
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
@@ -147,7 +149,7 @@ class HsOfficePartnerControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/partners") .post("/api/hs/office/partners")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.content(""" .content("""
{ {
@@ -190,7 +192,7 @@ class HsOfficePartnerControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/partners/P-12345") .get("/api/hs/office/partners/P-12345")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
@@ -207,7 +209,7 @@ class HsOfficePartnerControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.get("/api/hs/office/partners/P-12345") .get("/api/hs/office/partners/P-12345")
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
@@ -235,7 +237,7 @@ class HsOfficePartnerControllerRestTest {
// when // when
mockMvc.perform(MockMvcRequestBuilders mockMvc.perform(MockMvcRequestBuilders
.delete("/api/hs/office/partners/" + givenPartnerUuid) .delete("/api/hs/office/partners/" + givenPartnerUuid)
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)) .accept(MediaType.APPLICATION_JSON))
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.partner; package net.hostsharing.hsadminng.hs.office.partner;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRealEntity;
@@ -3,10 +3,9 @@ package net.hostsharing.hsadminng.hs.office.person;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
@@ -22,17 +21,19 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
@Tag("officeIntegrationTest")
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class } classes = HsadminNgApplication.class)
) @ActiveProfiles("fake-jwt")
@ActiveProfiles("test")
@Tag("officeIntegrationTest")
class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup {
@LocalServerPort @LocalServerPort
@@ -61,7 +62,7 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/persons") .get("http://localhost/api/hs/office/persons")
@@ -81,7 +82,7 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -119,7 +120,7 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/persons/" + givenPersonUuid) .get("http://localhost/api/hs/office/persons/" + givenPersonUuid)
@@ -142,7 +143,7 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/persons/" + givenPersonUuid) .get("http://localhost/api/hs/office/persons/" + givenPersonUuid)
@@ -159,7 +160,7 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer person-ErbenBesslerMelBessler@example.com") .header("Authorization", bearer("person-ErbenBesslerMelBessler@example.com"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/persons/" + givenPersonUuid) .get("http://localhost/api/hs/office/persons/" + givenPersonUuid)
@@ -188,7 +189,7 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -230,7 +231,7 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -274,7 +275,7 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/persons/" + givenPerson.getUuid()) .delete("http://localhost/api/hs/office/persons/" + givenPerson.getUuid())
@@ -293,7 +294,7 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-test-user@hostsharing.org") .header("Authorization", bearer("selfregistered-test-user@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/persons/" + givenPerson.getUuid()) .delete("http://localhost/api/hs/office/persons/" + givenPerson.getUuid())
@@ -313,7 +314,7 @@ class HsOfficePersonControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/persons/" + givenPerson.getUuid()) .delete("http://localhost/api/hs/office/persons/" + givenPerson.getUuid())
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.person; package net.hostsharing.hsadminng.hs.office.person;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository; import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository;
import net.hostsharing.hsadminng.rbac.role.RawRbacRoleRepository; import net.hostsharing.hsadminng.rbac.role.RawRbacRoleRepository;
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.person; package net.hostsharing.hsadminng.hs.office.person;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.mapper.Array; import net.hostsharing.hsadminng.mapper.Array;
import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository; import net.hostsharing.hsadminng.rbac.grant.RawRbacGrantRepository;
import net.hostsharing.hsadminng.rbac.role.RawRbacRoleRepository; import net.hostsharing.hsadminng.rbac.role.RawRbacRoleRepository;
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.relation; package net.hostsharing.hsadminng.hs.office.relation;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
@@ -2,14 +2,13 @@ package net.hostsharing.hsadminng.hs.office.relation;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeRelationTypeResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeRelationTypeResource;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -22,19 +21,20 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class }
)
@ActiveProfiles("test")
@Transactional @Transactional
@Tag("officeIntegrationTest") @Tag("officeIntegrationTest")
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = HsadminNgApplication.class)
@ActiveProfiles("fake-jwt")
class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithCleanup {
public static final UUID GIVEN_NON_EXISTING_HOLDER_PERSON_UUID = UUID.fromString("00000000-0000-0000-0000-000000000000"); public static final UUID GIVEN_NON_EXISTING_HOLDER_PERSON_UUID = UUID.fromString("00000000-0000-0000-0000-000000000000");
@@ -68,7 +68,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/relations?personUuid=%s&relationType=%s" .get("http://localhost/api/hs/office/relations?personUuid=%s&relationType=%s"
@@ -126,7 +126,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/relations?personUuid=%s" .get("http://localhost/api/hs/office/relations?personUuid=%s"
@@ -183,7 +183,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/relations?personData=firby&contactData=Contact-Admin@FirstContact.Example.COM") .get("http://localhost/api/hs/office/relations?personData=firby&contactData=Contact-Admin@FirstContact.Example.COM")
@@ -235,7 +235,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -280,7 +280,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -348,7 +348,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -380,7 +380,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -413,7 +413,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -447,7 +447,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/relations/" + givenRelationUuid) .get("http://localhost/api/hs/office/relations/" + givenRelationUuid)
@@ -470,7 +470,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/relations/" + givenRelationUuid) .get("http://localhost/api/hs/office/relations/" + givenRelationUuid)
@@ -486,7 +486,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer contact-admin@firstcontact.example.com") .header("Authorization", bearer("contact-admin@firstcontact.example.com"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/relations/" + givenRelation.getUuid()) .get("http://localhost/api/hs/office/relations/" + givenRelation.getUuid())
@@ -529,7 +529,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -572,7 +572,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/relations/" + givenRelation.getUuid()) .delete("http://localhost/api/hs/office/relations/" + givenRelation.getUuid())
@@ -591,7 +591,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer contact-admin@seventhcontact.example.com") .header("Authorization", bearer("contact-admin@seventhcontact.example.com"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/relations/" + givenRelation.getUuid()) .delete("http://localhost/api/hs/office/relations/" + givenRelation.getUuid())
@@ -610,7 +610,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/relations/" + givenRelation.getUuid()) .delete("http://localhost/api/hs/office/relations/" + givenRelation.getUuid())
@@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.relation; package net.hostsharing.hsadminng.hs.office.relation;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.rbac.context.Context;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
import net.hostsharing.hsadminng.lambda.Reducer; import net.hostsharing.hsadminng.lambda.Reducer;
@@ -1,7 +1,6 @@
package net.hostsharing.hsadminng.hs.office.scenarios; package net.hostsharing.hsadminng.hs.office.scenarios;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRbacEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRbacEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRbacRepository; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRbacRepository;
import net.hostsharing.hsadminng.hs.office.scenarios.contact.AddPhoneNumberToContactData; import net.hostsharing.hsadminng.hs.office.scenarios.contact.AddPhoneNumberToContactData;
@@ -43,39 +42,16 @@ import net.hostsharing.hsadminng.hs.scenarios.Produces;
import net.hostsharing.hsadminng.hs.scenarios.Requires; import net.hostsharing.hsadminng.hs.scenarios.Requires;
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest; import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
import net.hostsharing.hsadminng.lambda.Reducer; import net.hostsharing.hsadminng.lambda.Reducer;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import net.hostsharing.hsadminng.test.IgnoreOnFailureExtension;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.ClassOrderer;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestClassOrder;
import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
@Tag("scenarioTest")
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class },
properties = {
"spring.datasource.url=${HSADMINNG_POSTGRES_JDBC_URL:jdbc:tc:postgresql:15.5-bookworm:///scenariosTC}",
"spring.datasource.username=${HSADMINNG_POSTGRES_ADMIN_USERNAME:ADMIN}",
"spring.datasource.password=${HSADMINNG_POSTGRES_ADMIN_PASSWORD:password}",
"hsadminng.superuser=${HSADMINNG_SUPERUSER:superuser-alex@hostsharing.net}"
}
)
@ActiveProfiles("test")
@TestClassOrder(ClassOrderer.OrderAnnotation.class)
@ExtendWith(IgnoreOnFailureExtension.class)
class HsOfficeScenarioTests extends ScenarioTest { class HsOfficeScenarioTests extends ScenarioTest {
@Autowired @Autowired
@@ -702,7 +678,8 @@ class HsOfficeScenarioTests extends ScenarioTest {
@Test @Test
@Order(6010) @Order(6010)
@Requires("Debitor: D-3101100 - Michelle Matthieu") // which should also get updated @Requires("Debitor: D-3101100 - Michelle Matthieu")
// which should also get updated
void shouldReplaceDeceasedPartnerByCommunityOfHeirs() { void shouldReplaceDeceasedPartnerByCommunityOfHeirs() {
new ReplaceDeceasedPartnerWithCommunityOfHeirs(scenarioTest) new ReplaceDeceasedPartnerWithCommunityOfHeirs(scenarioTest)
.given("partnerNumber", "P-31011") .given("partnerNumber", "P-31011")
@@ -8,7 +8,6 @@ import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountReposi
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup; import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt; import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import net.hostsharing.hsadminng.config.DisableSecurityConfig;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
@@ -26,18 +25,20 @@ import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.config.JwtFakeBearer.bearer;
import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid; import static net.hostsharing.hsadminng.rbac.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals; import static net.hostsharing.hsadminng.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
@Tag("officeIntegrationTest")
@Transactional
@SpringBootTest( @SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, DisableSecurityConfig.class, JpaAttempt.class } classes = HsadminNgApplication.class)
) @ActiveProfiles("fake-jwt")
@ActiveProfiles("test")
@Transactional
@Tag("officeIntegrationTest")
class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCleanup { class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCleanup {
@LocalServerPort @LocalServerPort
@@ -66,7 +67,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/sepamandates") .get("http://localhost/api/hs/office/sepamandates")
@@ -107,7 +108,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/sepamandates?iban=DE02120300000000202051") .get("http://localhost/api/hs/office/sepamandates?iban=DE02120300000000202051")
@@ -145,7 +146,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -186,7 +187,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -211,7 +212,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -241,7 +242,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -275,7 +276,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/sepamandates/" + givenSepaMandateUuid) .get("http://localhost/api/hs/office/sepamandates/" + givenSepaMandateUuid)
@@ -305,7 +306,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/sepamandates/" + givenSepaMandateUuid) .get("http://localhost/api/hs/office/sepamandates/" + givenSepaMandateUuid)
@@ -322,7 +323,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer bankaccount-admin@FirstGmbH.example.com") .header("Authorization", bearer("bankaccount-admin@FirstGmbH.example.com"))
.port(port) .port(port)
.when() .when()
.get("http://localhost/api/hs/office/sepamandates/" + givenSepaMandateUuid) .get("http://localhost/api/hs/office/sepamandates/" + givenSepaMandateUuid)
@@ -354,7 +355,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -383,7 +384,8 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent().get() assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent().get()
.matches(mandate -> { .matches(mandate -> {
assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(D-1000111: rel(anchor='LP First GmbH', type=DEBITOR, holder='LP First GmbH'), fir)"); assertThat(mandate.getDebitor().toString()).isEqualTo(
"debitor(D-1000111: rel(anchor='LP First GmbH', type=DEBITOR, holder='LP First GmbH'), fir)");
assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH"); assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH");
assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z - patched"); assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z - patched");
assertThat(mandate.getValidFrom()).isEqualTo("2020-06-05"); assertThat(mandate.getValidFrom()).isEqualTo("2020-06-05");
@@ -400,7 +402,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -425,7 +427,8 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent().get() assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent().get()
.matches(mandate -> { .matches(mandate -> {
assertThat(mandate.getDebitor().toString()) assertThat(mandate.getDebitor().toString())
.isEqualTo("debitor(D-1000111: rel(anchor='LP First GmbH', type=DEBITOR, holder='LP First GmbH'), fir)"); .isEqualTo(
"debitor(D-1000111: rel(anchor='LP First GmbH', type=DEBITOR, holder='LP First GmbH'), fir)");
assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH"); assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH");
assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z"); assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z");
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2023-01-01)"); assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2023-01-01)");
@@ -441,7 +444,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@@ -475,7 +478,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer superuser-alex@hostsharing.net") .header("Authorization", bearer("superuser-alex@hostsharing.net"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/sepamandates/" + givenSepaMandate.getUuid()) .delete("http://localhost/api/hs/office/sepamandates/" + givenSepaMandate.getUuid())
@@ -493,7 +496,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer bankaccount-admin@FirstGmbH.example.com") .header("Authorization", bearer("bankaccount-admin@FirstGmbH.example.com"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/sepamandates/" + givenSepaMandate.getUuid()) .delete("http://localhost/api/hs/office/sepamandates/" + givenSepaMandate.getUuid())
@@ -511,7 +514,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("Authorization", "Bearer selfregistered-user-drew@hostsharing.org") .header("Authorization", bearer("selfregistered-user-drew@hostsharing.org"))
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/sepamandates/" + givenSepaMandate.getUuid()) .delete("http://localhost/api/hs/office/sepamandates/" + givenSepaMandate.getUuid())

Some files were not shown because too many files have changed in this diff Show More