# Secure DMZ adapter
# Introduction
The secure DMZ adapter serves as a proxy for a DMZ (demilitarized zone), which analyzes requests to the 4ALLPORTAL and blocks or transfers the data to the internal network. It is an Java application including an embedded Jetty server which must be installed in the DMZ.
In each response, the header Server: DMZ Adapter is set.
Possible restrictions are:
- URL
- blocking of calls with an invalid session
- blocking of logins after too many attempts
The following requests can be made:
- HTTP/HTTPS requests
- video streaming
- file upload
- file download
- AMF (Action Message Format) requests
The session of a request can be checked, so that requests with an invalid session will not be forwarded. If the access to a resource is rejected, the HTTP status code 403 (forbidden) is sent.
# Supported DAM version
This documentation implies an installed DAM version 3.4 or higher.
# Download package
You can download the dmz-adapter.zip
needed for installation from admin snap-in General system configuration/App management/DMZ adapter
.
# Clustering
The DMZ adapter does not cluster. Cookies are transferred though, so that clustering is possible via a downstream service (e.g. Apache).
# Multipart requests
If you use multipart requests, only the session from a cookie can be checked. If no cookie is set, the analysis in the DMZ will not take place.
Reading out the session from a multipart request does not work, for the request was consumed and can thus no longer be forwarded.
# Requirements
- The DMZ server and the DAM must be approached via the same URL. A different URL would cause problems with various functions, especially when sending e-mails which link to the DAM:
- welcome e-mail
- change of password
- sending an eTicket
- ...
- On the DMZ server a host entry must be set to the DAM URL of the DAM server.
- A 64-bit JavaSDK (Java version 11 or higher) must be installed.
- If you use Windows: The JRE_HOME must be set to the correct Java installation. Otherwise, the Windows service will not work.
# Installation and configuration
Unpack dmz-adapter.zip
into e.g. C:\\Program Files\\4AllPortal\\dmz
or /usr/local/4AllPortal/dmz
.
# Customize configuration
Configure the DMZ adapter in the file dmz-adapter.xml
.
- http_port: Customize or set to empty if you want to disable.
- https_port: Set if required.
- server_name: Define host for which the proxy configuration works. Only requests with this URL will be processed.
- server_alias (optional): Define additional hosts which will be processed.
- dam_url: AMF URL to DAM. Required to read the session. Example: http://example.4allportal.net:8181/service/amf
- target: URL to which the request should be forwarded to (DAM URL). Example: https://example.4allportal.net/
- redirect_http: Set enable to true if all http pages should be requested via https. http_port must be configured.
- SSL: Set enable to true, if SSL (incoming) should be supported. For further information, see https.
# Windows service
To run as a service on Windows, the commons-daemon/procrun is used. Set variables in the file install_service.cmd:
variable | description | example |
---|---|---|
DMZ_ADAPTER_HOME | path to DMZ adapter | C:\Program Files (x86)\4AllPortal\dmz |
JRE_HOME | path to JRE. If not set, use system JRE. | C:\Program Files\Java\jdk-14.0.1 |
StartParams | path to dmz-adapter config | "--config-file C:\Program Files (x86)\4AllPortal\dmz\conf\dmz-adapter.xml" |
- execute:
install_service.cmd
- start the service:
start_service.cmd
- delete the service:
sc delete dmz-adapter
# Linux service
# Service definition for Centos / RedHat - systemd service
To use the systemd service, create the file /etc/systemd/system/dmz-adapter.service
and set valid values.
Example:
[Unit]
Description=4AllPortal DMZ Adapter
[Service]
WorkingDirectory=/usr/local/4AllPortal/dmz/
ExecStart=/usr/bin/java -jar /usr/local/4AllPortal/dmz/dmz-adapter.jar --config-file=/usr/local/4AllPortal/dmz/conf/dmz-adapter.xml
Restart=always
RestartSec=0
#User=1010
LimitNOFILE=40000
LimitNPROC=40000
[Install]
WantedBy=multi-user.target
# Service definition for Centos / RedHat - init.d
You can find the old configuration in file dmz-proxy
in folder /etc/init.d
. This will still work, but probably needs to be updated later.
# Start the DMZ adapter manually
Simply execute java -jar dmz-adapter.jar
.
For debugging execute java -Xdebug -Xrunjdwp:transport=dt_socket,address=8585,server=y,suspend=n -jar dmz-adapter.jar
.
# Start parameters
Use dmz-adapter
plus the following options:
options | description |
---|---|
--config-file <arg> | Path to config file. If not set, use conf/dmz-adapter.xml. |
--ssl-info | Display infos: enabled/supported protocols and enabled/supported CipherSuites. |
--help | Display this help and exit. |
--pause <arg> | Wait for given seconds. Allow to start remote debugger. |
--version | Display version information and exit. |
# Start the DMZ adapter via docker-compose
First, create a docker-compose file.
Example :
version: '3'
services:
app:
image: registry.4allportal.net/4allportal/miscellaneous/dmz-adapter:2.0.3
restart: always
environment:
HTTP_PORT: 8080
SERVER_NAME: "localhost"
DAM_URL: "http://localhost:8383/service/amf"
TARGET: "http://localhost:8383/"
ports:
- 8080:8080
Specify the environment
-section of the configuration with the following variables:
HTTP_PORT
HTTPS_PORT
LISTEN_HTTP_PORT
LISTEN_HTTPS_PORT
SERVER_ALIAS
SERVER_NAME
DAM_URL
TARGET
DEBUG
(can be either true or false and runs internally on port 8001)
After that you have to bind the ports.
In case DEBUG
is disabled, there is no need to bind the debug port.
Finally, run the command docker compose up
to start the DMZ adapter.
# Further configuration
In case you want to do further configuration, you have to copy the conf folder under /4allportal/dmz-adapter/conf
to your local machine.
Example: docker cp container-id:/4allportal/dmz-adapter/conf
Now edit the dmz-adapter.xml configuration and mount it to the docker-compose.
Example:
version: '3'
services:
app:
image: registry.4allportal.net/4allportal/miscellaneous/dmz-adapter:2.0.3
restart: always
environment:
HTTP_PORT: 8080
SERVER_NAME: "localhost"
DAM_URL: "http://localhost:8383/service/amf"
TARGET: "http://localhost:8383/"
ports:
- 8080:8080
volumes:
- "./conf:/4allportal/dmz-adapter/conf"
Important: Use the latest release version instead of 2.0.3.
# Functions of the DMZ adapter
# HTTP
To process HTTP requests, you only need to set the port. If http and a redirection to https are not supported, the value can be set to empty.
<http_port>80</http_port>
# Listen HTTP
To listen for http requests on a different port than the request port, set this:
If not set, uses the same as http_port
.
<listen_http_port>8080</listen_http_port>
# HTTPS
SSL/HTTPS is supported both inbound and outbound.
# Inbound
To enable HTTPS, the port must be set:
<https_port>443</https_port>
To enable SSL, the path to the keystore and the passwords for keystore and keymanager must be configured. Is also possible to deactivate protocols and ciphers here. In the following example all CBC based ciphers will be disabled.
Example:
<ssl enable="true">
<key_store_path>ssl/keystore.jks</key_store_path>
<key_store_password>123456</key_store_password>
<key_manager_password>123456</key_manager_password>
<exclude_protocols>
<string>NOT_EXISTING</string>
</exclude_protocols>
<exclude_cipher_suites>
<string>^.*_(CBC)_.*$</string> <!-- deactivate all CBC cipher -->
<string>TLS_DHE.*</string>
<string>TLS_EDH.*</string>
</exclude_cipher_suites>
</ssl>
Note: If all CBC based ciphers are disabled, SSL will not work with Safari 9.
If all HTTP requests should be redirected to HTTPS, set the HTTP port and activate redirect:
<http_port>80</http_port>
<redirect_http enable="true" />
The necessary certificates including the private key must be imported to the keystore. The certificates must be stored under an alias in the following order:
- server certificate
- intermediate certificate(s)
- private key
Example:
# convert server certificate to pem
openssl x509 -in 4allportal.net.crt -out 1.pem -outform PEM
# convert intermediate certificate to pem
openssl x509 -in DigiCertCA.crt -out 2.pem -outform PEM
# convert private key (copy rear part with Vim to text file 4ap.key)
openssl rsa -text -in 4allportal.net.key -inform DER
# create bundle.pem
cat 1.pem 2.pem > bundle.pem
cat 4ap.key >> bundle.pem
# export certificate for Java
openssl pkcs12 -export -in bundle.pem -inkey 4ap.key -out 4allportal.net.p12
# generate keystore
keytool -importkeystore -srckeystore 4allportal.net.p12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS
# check if certificates are in keystore
keytool -list -v -alias 1 -storepass 123456 -keystore keystore.jks
keytool -list -rfc -alias 1 -storepass 123456 -keystore keystore.jks
# Outbound
If SSL should work outbound, the necessary certificates must be installed in the operating system. This is always necessary if one of the following URLs starts with https:
- dam_url
- target
Insert the required certificates of the certificate chain into the file cacerts of the used java version.
Example:
keytool -importcert -file server.crt -cacerts -alias "DMZ-lobdevelop.4allportal.net"
# Listen HTTPS
To listen for https requests on a different port than the request port, set this:
If not set, uses value from https_port
.
<listen_https_port>8443</listen_https_port>
# Session validation
Activate the session validation like this:
<check_4apsession>true</check_4apsession>
The system tries to read the session ID from the session cookie. If no cookie is set, the session ID is read from the request. For endpoints with checkAuthorization
true, also sessions from bearer authorization will be checked (see here). The DMZ adapter checks whether data for this session is already available. If not, it tries to get the data for the session from the DAM database.
If there is a valid session, the request will be forwarded. Otherwise, the request will be rejected.
Each time a session is accessed, the access time is stored, regardless of whether the session is valid or not. All sessions that have expired and have not been accessed for a certain time will be removed from the container. The time can be configured like this:
<remove_session_after_minutes>60</remove_session_after_minutes>
# Logout
If a logout method is executed, the session in the container will be set to expired. Logout methods are:
/service/usermanagement/logout
LoginRemoteService.logoutUser
(AMF)/api/auth/logout
In order to be able to block further calls of expired or invalid sessions, an expired session will not be removed directly.
# Limitation of login requests
The login requests can be restricted by the host. For this, the DMZ adapter must have access to the client IP. You can configure the limitation like this:
<restrict_login enable="true">
<after_logins>50</after_logins>
<tries>3</tries>
<remove_older>10</remove_older>
</restrict_login>
description | |
---|---|
enable | Set true to activate the limitation function. |
after_logins | Defines after how many logins the limitation is activated. |
tries | Defines how many logins per minute are allowed if the number set in after_logins is exceeded. |
remove_older | Removes logins which are older than X minutes. |
Note: If access to the client IP is not possible, restrict_login must be disabled (set enable to false).
# Caching
To enable caching, you need to configure like this:
<caches enable="true" time_to_live="60">
<cache>/fonts/*</cache>
<cache>/4allportal-core/*</cache>
<cache>/4allportal-essentials/*</cache>
<cache>/4allportal-dam/*</cache>
</caches>
type | required? | description | |
---|---|---|---|
enable | XML attribute | no (default: true) | Allows you to disable the cache. |
time_to_live | XML attribute | no (default: 60) | Defines how many minutes the data will remain in the cache. |
cache | XML element | yes | Defines which calls are cached. .../* defines that all sublevels are cached, otherwise, only the exact page will be cached. |
# Delete request and response headers
Deleting the request header Accept-Encoding makes it possible to e.g. deactivate compression. You can configure it like this:
<remove_request_header>
<header>Accept-Encoding</header><!-- deactivate compression -->
</remove_request_header>
<remove_response_header>
<header>...</header>
</remove_response_header>
All headers set in <header>
will be removed.
# Reloading
This method allows the configuration to be reloaded. This is only allowed for calls via localhost:
localhost/reload
Reloading works for:
- endpoints
- log_level
- dam_url
- cache clearing (If files are locked, a log entry will be created.)
Reloading works not for configurations like:
- parameters of the connection like: ports, timeouts, server name
- remove_session_after_minutes
- restrict_login
# Checking the configuration
This method allows to check the configuration. This is only allowed for calls via localhost:
localhost/reload?only_check=true
# Logging and access log
Two files are created in the logs folder for each day:
- log_yyyymmdd.log
- access_yyyymmdd.log
The log level for the file log_yyyymmdd.log can be configured in the configuration file:
<log_level>DEBUG</log_level>
Allowed log levels are:
- ERROR
- WARN
- INFO
- DEBUG
# Configuration of endpoints
All allowed requests must be configured in the configuration file in the section <endpoints>.
URLs which are not explicitly configured will be handled with a higher-level endpoint. This means that for example a call with the URL /service/amf/abc/cde would be answered by the endpoint with the configuration /service/amf.
<endpoint content_transformer="Download">
<url>/service/FileAccessDownload</url>
</endpoint>
You can configure the endpoints like this:
type | required? | description | |
---|---|---|---|
url | XML element | yes | The URL which is allowed or blocked. |
session | XML attribute | no | Attribute from which the session is to be read. For GET and POST requests. |
content_transformer | XML attribute | no | Valid values are: download and upload (see below). |
deny | XML attribute | no | Blocks explicitly this URL. |
destinations | XML element | no | Complex element to configure the handling of AMF requests (see below). |
checkAuthorization | XML attribute | no | Default: false. Set to true to activate session check for 4ALLPORTAL 3.7 endpoints. Session cookies and bearer authorization will be checked then. |
- download: Forwards the request immediately, but sets the header content-length. The file size of a download in the browser will only be displayed if more than one chunk is transferred. Otherwise, the header will be deleted automatically.
- upload: Saves the complete request before it is forwarded. Otherwise, incomplete assets and videos would be created in the DAM.
# Configuration of AMF requests
Example:
<endpoint>
<url>/service/amf</url>
<destinations>
<destination name="ActionRemoteService" type="3"/>
<destination name="AdministrationRemoteService" type="1">
<operations type="0">
<operation>getBaseConfiguration</operation>
<operation>updateBaseConfiguration</operation>
</operations>
</destination>
</destinations>
</endpoint>
# Destinations
type | required? | description | |
---|---|---|---|
name | XML attribute | yes | Name of the AMF endpoint. |
type | XML attribute | no (default: 0) | Defines the way how the session is included in the request (see below). |
pos | XML attribute | no (default: 0) | Defines in which parameter of the array the session is located. |
operations | XML element | no | Allows to define exceptions for certain operations of an AMF endpoint. If not set, the endpoint setting is used (see below). |
# Destination types
value | description |
---|---|
0 | no session |
1 | session as string |
2 | session in identVO |
3 | session in object (derived from SimpleRequestObject) |
# Operations
type | required? | description | |
---|---|---|---|
type | XML attribute | no (default: 0) | see: destinations |
pos | XML attribute | no (default: 0) | see: destinations |
access | XML attribute | no (default: true) | False will explicitly block a method. |
operation | XML elementList | yes | List of operations to which this setting applies. |
# Help
# Show server ciphers
The output depends on the supported SSL protocols and ciphers. For Linux and Mac OSX this may result in different outputs. Use one of these methods to show server ciphers:
- https://www.ssllabs.com/ssltest/ (opens new window)
nmap -p 443 --script ssl-enum-ciphers HOSTNAME
sslscan HOSTNAME
# Read out ciphers from HTTPd
#All ciphers
openssl ciphers ${cipherspec} | sed 's/:/\n/g'
#CBC ciphers
openssl ciphers ${cipherspec} | sed 's/:/\n/g' | grep CBC
# Check certificate chain
To display the certificate chain, execute:
openssl s_client -connect HOSTNAME:443
openssl s_client -verify_return_error -showcerts -connect HOSTNAME:443
The result must be: Verify return code: 0 (ok)