diff --git a/LICENSE.txt b/LICENSE
similarity index 98%
rename from LICENSE.txt
rename to LICENSE
index 9cecc1d..f288702 100644
--- a/LICENSE.txt
+++ b/LICENSE
@@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
- {one line to give the program's name and a brief idea of what it does.}
- Copyright (C) {year} {name of author}
+
+ Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -645,14 +645,14 @@ the "copyright" line and a pointer to where the full notice is found.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program. If not, see .
+ along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
- {project} Copyright (C) {year} {fullname}
+ Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
-.
+.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
-.
+.
diff --git a/README.md b/README.md
deleted file mode 100644
index 3e0f6e3..0000000
--- a/README.md
+++ /dev/null
@@ -1,579 +0,0 @@
-Nexus-Backend Service
-=====================
-
-
-## An Advanced and Secure RestApi Backend Service Gateway
-
-**The Nexus-Backend Service** acts as an intermediary between a **REST Client application** and a **Backend REST API service**.
-It forwards Requests from the client to the **Backend Service** and returns the Responses back to the client.
-The Nexus-Backend integrate a HttpFirewall and **WAF Filter** for a protection against evasion on the **Http Request Headers,
-Request Map parameters and Json BodyRequest.**
-
-**Inside a Servlet Container a Rest Controller ApiBackend and its BackendService, Secure and Replicate all the HTTP
-Requests to a RestApi Backend Server.**
-
-**All HttpRequests methods supported:** Get, Post, Post Multipart File, Put, Put Multipart File, Patch, Patch Multipart File, Delete.
-
-* Full support **Request Json Entity Object**: application/json, application/x-www-form-urlencoded
-* Full support **MultipartRequest Resources and Map parameters**, and embedded form **Json Entity Object**: multipart/form-data
-* Full support **Response in Json Entity Object**: application/json
-* Full support **Response in ByteArray Resource file**: application/octet-stream
-* Full support **Streaming Http Response Json Entity Object**: application/octet-stream, accept header Range bytes
-* Full support **Cookie manage** during a redirection Http status 3xx
-
-**Tomcat Servlet Containers under Servlet version 4.x**
-
-**Examples forwarded requests and responses through the Nexus-Backend Service:**
-
-| REST Clients | RestApi Nexus-Backend Service | Backend Server Services |
-|-----------------------|:---------------------------------------------------|:------------------------------------------------|
-| Ajax / XMLHttpRequest | http://localhost:8082/nexus-backend/api/** | https://secure.jservlet.com:9092/api/v1/service |
-| HttpClient | https://front.jservlet.com:80/nexus-backend/api/** | https://secure.jservlet.com:9092/api/v1/service |
-| FeedService | https://intra.jservlet.com:80/nexus-backend/api/** | https://10.100.100.50:9092/api/v1/service |
-
-***An Ajax Single Page Application communicate through the Rest Controller ApiBackend and its BackendService to a RestApi Backend Server.***
-
-
-### Ability to Secure all RestApi Request to a Backend Server
-
- * Implements a **BackendService**, ability to request typed response Object class or ParameterizedTypeReference, requested on all HTTP methods to a RestApi Backend Server.
- * Implements an **EntityBackend** Json Object or Resource, transfer back headers, manage error HttpStatus 400, 401, 405 or 500 coming from the Backend Server.
- * Implements a **HttpFirewall** filter protection against evasion, rejected any suspicious Requests, Headers, Parameters, and log IP address at fault.
- * Implements a **WAF** filter protection against evasion on the Http Json BodyRequest, and log IP address at fault.
- * Implements a **CORS Security Request** filter, authorize request based on Origin Domains and Methods.
- * Implements a **Content Security Policy** filter, define your own policy rules CSP.
- * Implements a **RateLimit** interceptor, allows 1000 requests per minutes and per-IP-address.
- * Implements a **Fingerprint** for each Http header Request, generate a unique trackable Token APP-REQUEST-ID in the access logs.
- * Implements a **Method Override** filter, PUT or PATCH request can be switched in POST or DELETE switched in GET with header X-HTTP-Method-Override.
- * Implements a **Forwarded Header** filter, set removeOnly at true by default, remove "Forwarded" and "X-Forwarded-*" headers.
- * Implements a **FormContent** filter, parses form data for Http PUT, PATCH, and DELETE requests and exposes it as Servlet request parameters.
- * Implements a **Compressing** filter Gzip compression for the Http Responses.
- * Implements a **CharacterEncoding** filter, UTF-8 default encoding for requests.
-
-
-### Specials config Http Headers
-
- * **HTTP headers:** reset all Headers, remove host or origin header.
- * **Basic Authentication:** set any security ACL **Access Control List**
- * **Bearer Authorization:** set any security **Bearer Token**.
- * **Cookie:** set any **security session Cookie**.
- * **CORS:** Bypass locally all **CORS Security** (Cross-origin resource sharing) from a Navigator,
- not restricted to accessing resources from the same origin through what is known as same-origin policy.
-
-
-### The Nexus Backend application can be configured by the following keys SpringBoot and Settings properties
-
- **SpringBoot keys application.properties:**
-
-| **Keys** | **Default value** | **Descriptions** |
-|--------------------------------------------------|:------------------|:---------------------------------------------------|
-| nexus.api.backend.enabled | true | Activated the Nexus-Backend Service |
-| nexus.api.backend.filter.waf.enabled | true | Activated the WAF filter Json RequestBody |
-| nexus.api.backend.listener.requestid.enabled | true | Activated the Fingerprint for each Http Request |
-| nexus.api.backend.filter.httpoverride.enabled | true | Activated the Http Override Method |
-| nexus.api.backend.interceptor.ratelimit.enabled | true | Activated the RateLimit |
-| nexus.backend.filter.forwardedHeader.enabled | true | Activated the ForwardedHeader filter |
-| nexus.backend.filter.gzip.enabled | true | Activated the Gzip compression filter |
-| spring.mvc.formcontent.filter.enabled | true | Activated the FormContent parameterMap Support |
-| nexus.backend.tomcat.connector.https.enable | false | Activated a Connector TLS/SSL in a Embedded Tomcat |
-| nexus.backend.tomcat.accesslog.valve.enable | false | Activated an Accesslog in a Embedded Tomcat |
-
-#### Noted the Spring config location can be overridden
-
-* -Dspring.config.location=/your/config/dir/
-* -Dspring.config.name=spring.properties
-
-
-### The Nexus-Backend Url Server and miscellaneous options can be configured by the following keys Settings
-
- **Settings keys settings.properties:**
-
-| **Keys** | **Default value** | **Example value** | **Descriptions** |
-|-------------------------------------------------|:-------------------------|:--------------------------------|:----------------------------------------------------|
-| **nexus.backend.url** | https://postman-echo.com | https://nexus6.jservlet.com/api | The API Backend Server targeted |
-| **nexus.backend.uri.alive** | /get | /health/info | The endpoint alive Backend Server |
-| nexus.backend.http.response.truncated | false | true | Truncated the Json output in the logs |
-| nexus.backend.http.response.truncated.maxLength | 1000 | 100 | MaxLength truncated |
-| **WAF** | | | |
-| nexus.api.backend.filter.waf.reactive.mode | STRICT | PASSIVE | Default Strict HttpFirewall + Json RequestBody |
-| nexus.api.backend.filter.waf.deepscan.cookie | false | true | Activated Deep Scan Cookie |
-| **Headers** | | | |
-| nexus.backend.header.remove | **true** | true | Remove all Headers |
-| nexus.backend.header.host.remove | false | false | Remove just host Header |
-| nexus.backend.header.origin.remove | false | false | Remove just origin Header |
-| nexus.backend.header.cookie | - | XSession=0XX1YY2ZZ3XX4YY5ZZ6XX | Set a Cookie Request Header |
-| nexus.backend.header.bearer | - | eyJhbGciO | Activated Bearer Authorization request |
-| nexus.backend.header.user-agent | JavaNexus | Apache HttpClient/4.5 | User Agent header |
-| nexus.backend.header.authorization.username | - | XUsername | Activated Basic Authorization request |
-| nexus.backend.header.authorization.password | - | XPassword | " |
-| **Backend Headers** | | | |
-| nexus.api.backend.transfer.headers | test | test,Link,Content-Range | Headers list back from Backend Server |
-| **Mapper** | | | |
-| nexus.backend.mapper.indentOutput | false | true | Indent Output Json |
-| **Debug** | | | |
-| nexus.spring.web.security.debug | false | true | Debug the Spring FilterChain |
-
-**Noted**: About the list HttpHeaders transfer back, the CORS can expose these Headers see key security.cors.exposedHeaders
-
-#### Noted the settings.properties can be overridden by a file Path config.properties
-
-* **${user.home}**/conf-global/config.properties
-* **${user.home}**/conf/config.properties
-* **${user.home}**/cfg/**${servletContextPath}**/config.properties
-
-### The ApiBackend Configuration Json Entity Object or a ByteArray Resource
-
-**ApiBackend ResponseType** can be now a **ByteArray Resource.**
-
-**Download** any content in a **ByteArray** included commons extensions files (see **[MediaTypes](#The-MediaTypes-safe-extensions-configuration)** section)
-
-The **ResourceMatchers** Config can be configured on specific ByteArray Resources path
-and on specific Methods **GET, POST, PUT, PATCH** and Ant Path pattern:
-
-**Settings keys settings.properties:**
-
-| **Keys Methods** and **Keys Path pattern** | **Default value** | **Content-Type** |
-|---------------------------------------------------------------|:-----------------------|:-------------------------|
-| nexus.backend.api-backend-resource.matchers.1.method | GET | |
-| nexus.backend.api-backend-resource.matchers.1.pattern | /api/encoding/** | text/html;charset=utf-8 |
-| nexus.backend.api-backend-resource.matchers.2.method | GET | |
-| nexus.backend.api-backend-resource.matchers.2.pattern | /api/streaming/** | application/octet-stream |
-| nexus.backend.api-backend-resource.matchers.3.method | GET | |
-| nexus.backend.api-backend-resource.matchers.3.pattern | /api/time/now | text/html;charset=utf-8 |
-| nexus.backend.api-backend-resource.matchers.{name}[X].method | Methods | |
-| nexus.backend.api-backend-resource.matchers.{name}[X].pattern | Patterns | |
-
-**Http Responses** are considerate as **Resources**, the Http header **"Accept-Ranges: bytes"** is injected and allow you to use
-the Http header **'Range: bytes=1-100'** in the request and grabbed only range of Bytes desired.
-And the Http Responses didn't come back with a HttpHeader **"Transfer-Encoding: chunked"** cause the header **Content-Length**.
-
-
-**Noted:** For configure **all the Responses** in **Resource** put an empty Method and use the path pattern=/api/**
-
-| **Keys Methods** and **Keys Path pattern** | **Default value** |
-|---------------------------------------------------------------|:------------------|
-| nexus.backend.api-backend-resource.matchers.matchers1.method | |
-| nexus.backend.api-backend-resource.matchers.matchers1.pattern | /api/** |
-
-**Noted bis:** For remove the Http header **"Transfer-Encoding: chunked"** the header Content-Length need to be calculated.
-
-Enable the **ShallowEtagHeader Filter** in the configuration for force to calculate the header **Content-Length**
-for all the **Response Json Entity Object**, no more HttpHeader **"Transfer-Encoding: chunked"**.
-
-### The MediaTypes safe extensions configuration
-
-**MediaTypes safe extensions**
-
-The Spring ContentNegotiation load the safe extensions files that can be extended.
-A commons MediaTypes properties file is loaded [resources/mime/MediaTypes_commons.properties](https://github.com/javaguru/nexus-backend/blob/master/src/main/resources/mime/MediaTypes_commons.properties)
-and can be disabled:
-
-**Settings keys settings.properties:**
-
-Default Header ContentNegotiation Strategy:
-
-| **ContentNegotiation Strategy** | **Default value** | **Descriptions Strategy** |
-|---------------------------------------------------------------|:------------------|:----------------------------|
-| **Header Strategy** | | |
-| nexus.backend.content.negotiation.ignoreAcceptHeader | false | Header Strategy Enabled |
-| **Parameter Strategy** | | |
-| nexus.backend.content.negotiation.favorParameter | false | Parameter Strategy Disabled |
-| nexus.backend.content.negotiation.parameterName | mediaType | |
-| **Registered Extensions** | | |
-| nexus.backend.content.negotiation.useRegisteredExtensionsOnly | true | Registered Only Enabled |
-| **Load commons MediaTypes** | | |
-| nexus.backend.content.negotiation.commonMediaTypes | true | Enabled |
-
-
-### The CORS Security configuration
-
-**CORS Security configuration, allow Control Request on Domains and Methods**
-
-**Settings keys settings.properties:**
-
-The default Cors Configuration:
-
-| **Cors Configuration** | **Default value** | **Example value** | **Descriptions** |
-|---------------------------------------------------|:---------------------------------------------------------------------------|:---------------------------------------------------|:-----------------------|
-| nexus.backend.security.cors.credentials | false | true | Enable credentials |
-| nexus.backend.security.cors.allowedHttpMethods | GET,POST,PUT ,OPTIONS,HEAD, DELETE,PATCH | GET,POST,PUT,OPTIONS | List Http Methods |
-| nexus.backend.security.cors.allowedOriginPatterns | | | Regex Patterns domains |
-| nexus.backend.security.cors.allowedOrigins | * | http://localhost:4042, http://localhost:4083 | List domains |
-| nexus.backend.security.cors.allowedHeaders | Authorization,Cache-Control, Content-Type, X-Requested-With,Accept | Authorization, Cache-Control, Content-Type | List Allowed Headers |
-| nexus.backend.security.cors.exposedHeaders | | Link,X-Custom-Header | List Exposed Headers |
-| nexus.backend.security.cors.maxAge | 3600 | 1800 | Max Age cached |
-
-**Noted:** allowedOrigins cannot be a wildcard '*' if credentials is at true, a list of domains need to be provided.
-
-Exposed headers
-
-### The RateLimit Configuration
-
-**Rate limit** 1000 per minutes and per-IP-address.
-
-**SpringBoot key** *nexus.api.backend.interceptor.ratelimit.enabled* at **true** for activated the RateLimit.
-
-**Settings keys settings.properties:**
-
-The default Cors Configuration:
-
-| **Cors Configuration** | **Default value** | **Example value** | **Descriptions** |
-|--------------------------------------------------------|:------------------|:------------------|:-----------------|
-| nexus.backend.interceptor.ratelimit.refillToken | 1000 | 100 | Filled tokens |
-| nexus.backend.interceptor.ratelimit.refillMinutes | 1 | 1 | Duration minutes |
-| nexus.backend.interceptor.ratelimit.bandwidthCapacity | 1000 | 100 | Bucket capacity |
-
-
-### The Nexus-Backend provides a full support MultipartRequest and Map parameters inside a form-data HttpRequest
-
-#### MultipartConfig
-
-**SpringBoot keys application.properties:**
-
-| **Keys** | **Default value** | **Example value** | **Descriptions** |
-|----------------------------------------------|:------------------|:------------------|:--------------------|
-| spring.servlet.multipart.enabled | true | true | Enabled multipart |
-| spring.servlet.multipart.file-size-threshold | 2MB | 5MB | File size threshold |
-| spring.servlet.multipart.max-file-size | 15MB | 150MB | Max file size |
-| spring.servlet.multipart.max-request-size | 15MB | 150MB | Max request size |
-
-**Noted** All the HttpRequests with a **Content-Type multipart/form-data** will be managed by a temporary **BackendResource**.
-
-~~This BackendResource can convert a **MultipartFile** to a temporary **Resource**, ready to be sent to the **Backend Server**.~~
-
-Since version 1.0.24 no more BackendResource and temporary file, all is in memory.
-
-### The BackendService HttpFactory Client Configuration
-
- **Settings keys settings.properties:**
-
-| **Keys** | **Default value** | **Example value** | **Descriptions** |
-|-----------------------------------------------------|:------------------|:------------------|:-------------------------------|
-| nexus.backend.client.header.user-agent | JavaNexus | curl | User Agent Header |
-| nexus.backend.client.connectTimeout | 10 | 5 | Connection timeout in second |
-| nexus.backend.client.requestTimeout | 20 | 10 | Request timeout in second |
-| nexus.backend.client.socketTimeout | 10 | 5 | Socket timeout in second |
-| nexus.backend.client.max_connections_per_route | 20 | 30 | Max Connections per route |
-| nexus.backend.client.max_connections | 100 | 300 | Max Connections in the Pool |
-| nexus.backend.client.close_idle_connections_timeout | 0 | 0 | Close idle connections timeout |
-| nexus.backend.client.validate_after_inactivity | 2 | 2 | Validate after inactivity |
-| nexus.backend.client.requestSentRetryEnabled | false | true | Request Sent Retry Enabled |
-| nexus.backend.client.retryCount | 3 | 2 | Retry Count |
-| nexus.backend.client.redirectsEnabled | true | true | Redirects enabled |
-| nexus.backend.client.maxRedirects | 5 | 2 | Maximum redirections |
-| nexus.backend.client.authenticationEnabled | false | true | Authentication enabled |
-| nexus.backend.client.circularRedirectsAllowed | false | true | Circular redirections allowed |
-
-
-### The Nexus-Backend Firewall and the WAF Filter Configuration
-
-The **Nexus-Backend** implements a **HttpFirewall** protection against evasion and rejected any suspicious Http Request
-on the Headers and Cookies, the Parameters, the keys and Values.
-
-The **WAF Filter** implements a secure WAF protection against evasion on a **Json Http RequestBody**.
-
-**Un-normalized** Http requests are automatically rejected by the **StrictHttpFirewall**,
-and path parameters and duplicate slashes are removed for matching purposes.
-
-**Noted** the valid characters are defined in **RFC 7230** and **RFC 3986** are checked
-by the **Apache Coyote http11 processor** (see coyote Error parsing HTTP request header)
-
-All the Http request with **Cookies, Headers, Parameters and RequestBody** will be filtered and the suspicious **IP address** in fault will be logged.
-
- **Settings keys settings.properties:**
-
-| **Keys** | **Default value** | **Descriptions** |
-|------------------------------------------------------------|:--------------------------------------------|:--------------------------------------|
-| nexus.backend.security.allowedHttpMethods | GET,POST,PUT,OPTIONS, HEAD,DELETE,PATCH | Allowed Http Methods |
-| nexus.backend.security.allowSemicolon | false | Allowed Semi Colon |
-| nexus.backend.security.allowUrlEncodedSlash | false | Allow url encoded Slash |
-| nexus.backend.security.allowUrlEncodedDoubleSlash | false | Allow url encoded double Slash |
-| nexus.backend.security.allowUrlEncodedPeriod | false | Allow url encoded Period |
-| nexus.backend.security.allowBackSlash | false | Allow BackSlash |
-| nexus.backend.security.allowNull | false | Allow Null |
-| nexus.backend.security.allowUrlEncodedPercent | false | Allow url encoded Percent |
-| nexus.backend.security.allowUrlEncodedCarriageReturn | false | Allow url encoded Carriage Return |
-| nexus.backend.security.allowUrlEncodedLineFeed | false | Allow url encoded Line Feed |
-| nexus.backend.security.allowUrlEncodedParagraphSeparator | false | Allow url encoded Paragraph Separator |
-| nexus.backend.security.allowUrlEncodedLineSeparator | false | Allow url encoded Line Separator |
-
-**The WAF Utilities Predicates checked for potential evasion:**
-
-* XSS script injection
-* SQL injection
-* Google injection
-* Command injection
-* File injection
-* Link injection
-
-**Implements a WAF Predicate for potential evasion by Headers or Parameters:**
-
- * Header Names / Header Values
- * Parameter Names / Parameter Values
- * Hostnames
- * UserAgent
-
-**And check for Buffer Overflow evasion by the Length:**
-
- * Parameter Names 255 characters max. / Values 1000000 characters max.
- * Header Names 255 characters max. / Values 25000 characters max.
- * Hostnames 255 characters max.
-
- **The WAF Reactive mode configuration:**
-
- * **STRICT**: Strict HttpFirewall + Json RequestBody
- * **PASSIVE**: Strict HttpFirewall + Clean Json RequestBody and Parameters Map
- * **UNSAFE**: Strict HttpFirewall + No check Json RequestBody!
-
-**Settings keys settings.properties:** Define a max length for Keys/Values Headers or Parameters
-
-| **Keys** | **Default value** | **Descriptions** |
-|----------------------------------------------------------|:------------------|:--------------------------------|
-| nexus.backend.security.predicate.parameterNamesLength | 255 | Parameter names length max |
-| nexus.backend.security.predicate.parameterValuesLength | 1000000 | Parameter values length max |
-| nexus.backend.security.predicate.headerNamesLength | 255 | Header names length max |
-| nexus.backend.security.predicate.headerNamesValuesLength | 25000 | Header values length max |
-| nexus.backend.security.predicate.hostNamesLength | 255 | Host names length max |
-| nexus.backend.security.predicate.hostName.pattern | | Hostname pattern filter |
-| nexus.backend.security.predicate.userAgent.blocked | false | Active Scanner UserAgent filter |
-| nexus.backend.security.predicate.aiUserAgent.blocked | true | Active AI UserAgent filter |
-
-
-### Activated the Mutual Authentication or mTLS connection on the HttpFactory Client
-
- **Settings keys settings.properties:** *nexus.backend.client.ssl.mtls.enable* at **true** for activated the mTLS connection
-
-| **Keys** | **Default value** | **Descriptions** |
-|---------------------------------------------|:-----------------------|:--------------------------|
-| nexus.backend.client.ssl.mtls.enable | **false** | Activated the Mutual TLS |
-| nexus.backend.client.ssl.key-store | nexus-default.jks | Path to the Java KeyStore |
-| nexus.backend.client.ssl.key-store-password | changeit | The password |
-| nexus.backend.client.ssl.certificate.alias | key_server | The certificate alias |
-| nexus.backend.client.ssl.https.protocols | TLSv1.3 | The protocols |
-| nexus.backend.client.ssl.https.cipherSuites | TLS_AES_256_GCM_SHA384 | The Cipher Suites |
-
-
-### Activated Tomcat Catalina Connector TLS/SSL on a wildcard domain Certificate
-
- **Settings keys settings.properties:**
-
- **SpringBoot key** *nexus.backend.tomcat.connector.https.enable* at **true** for activated the TLS/SSL protocol
-
-| **Keys** | **Default value** | **Descriptions** |
-|-------------------------------------------------------|:---------------------|:--------------------------|
-| nexus.backend.tomcat.ssl.keystore-path | /home/root/.keystore | Path to the Java KeyStore |
-| nexus.backend.tomcat.ssl.keystore-password | changeit | The password |
-| nexus.backend.tomcat.ssl.certificate.alias | key_server | The certificate alias |
-| nexus.backend.tomcat.ssl.https.port | 8443 | The Https port |
-| nexus.backend.tomcat.ssl.ajp.connector.enable | false | Start the Ajp connector |
-| nexus.backend.tomcat.ssl.ajp.connector.port | 8009 | The Ajp port |
-| nexus.backend.tomcat.ssl.ajp.connector.protocol | AJP/1.3 | AJP version 1.3 |
-| nexus.backend.tomcat.ssl.ajp.connector.secretRequired | false | A secret is Required |
-
-
-### Activated Tomcat Catalina Extended AccessLog Valve
-
- **Settings keys settings.properties:**
-
- **SpringBoot key** *nexus.backend.tomcat.accesslog.valve.enable* at **true** for activated the Accesslogs
-
-| **Keys** | **Default value** | **Descriptions** |
-|-----------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------|
-| nexus.backend.tomcat.accesslog.directory | /tmp/logs/tomcat-nexus | Directory access log |
-| nexus.backend.tomcat.accesslog.suffix | .log | The suffix |
-| nexus.backend.tomcat.accesslog.encoding | UTF-8 | The suffix |
-| nexus.backend.tomcat.accesslog.pattern | date time x-threadname c-ip cs-method cs-uri sc-status bytes x-H(contentLength)time-taken x-H(authType) cs(Authorization) cs(User-Agent) | The pattern |
-| nexus.backend.tomcat.accesslog.checkExists | true | Check if file exists |
-| nexus.backend.tomcat.accesslog.asyncSupported | true | Support async requests |
-| nexus.backend.tomcat.accesslog.renameOnRotate | true | Rename on rotate |
-| nexus.backend.tomcat.accesslog.throwOnFailure | true | Throw on failure |
-| nexus.backend.tomcat.accesslog.maxDay | -1 | Max day file retention |
-
-**Noted** the Full access logs are available with the **CommonsRequestLoggingFilter**, included the **RequestBody**.
-
-Already initialized, activated by setting the logback.xml at **level="DEBUG"**.
-
-
-## Build Nexus-Backend
-
-[SpringBoot](https://projects.spring.io/spring-boot/)
-
-### Build requirements
-
- * Java 13
- * SpringBoot 2.7.18
- * Tomcat 9.0.116 & Servlet 4.0.1
- * Maven 3.9.x
-
-### Build war external Tomcat 9
-
-with the profile withoutTomcat:
-
-* `mvn clean compile -P withoutTomcat`
-* `mvn clean package -P withoutTomcat`
-* `mvn clean install -P withoutTomcat`
-
-and look for the jar at `target/nexus-backend-{version}.war`
-
-### Build jar embedded Tomcat 9
-
-with the profile withTomcat:
-
-* `mvn clean compile -P withTomcat`
-* `mvn clean install -P withTomcat`
-* `mvn clean package -P withTomcat`
-
-and look for the jar at `target/nexus-backend-{version}.jar`
-
-### Get javadoc
-
-`mvn javadoc:javadoc`
-
-### Run SpringBoot App
-
-with maven:
-
-`mvn spring-boot:run -P withTomcat`
-
-### The Configuration
-
-By default, it uses `8082` port and the Servlet Context `/nexus-backend`.
-
-The default SpringBoot config is in `/src/main/resources/application.properties` file.
-
-The default NexusBackend config in `/src/main/resources/settings.properties` file.
-
-The Config keys and values can be modified or override by external path files, here:
-
- * file `{user.home}/conf-global/config.properties`
- * file `{user.home}/conf/config.properties`
- * file `{user.home}/cfg/nexus-backend/config.properties`
-
-### Swagger Tests environment
-
-See RestControllerTest is in interaction with the MockController, run the tests with a local Tomcat running on localhost:8082/nexus-backend
-
-The Swagger Mock-Api is only available in Dev mode, added in JVM Options: -Denvironment=development
-
-## The BackendService API Implementation
-
-This API implementation is used for the communication to a backend server.
-It provides methods for all supported http protocols on the backend side.
-Normally, it communicates to an API interface Backend.
-
-### Available HTTP methods:
-
- * Get
- * Post
- * Post Multipart File
- * Put
- * Put Multipart File
- * Patch
- * Patch Multipart File
- * Delete
-
-### Sample BackendService API
-
-#### Prerequisites:
-
-* **RestOperations** should be configured with an Apache-HttpClient and a Pooling connection should be properly configured.
-* **HttpMessageConverter** are also mandatory, StringHttp, FormHttp, ByteArrayHttp, ResourceHttp and MappingJackson2Http are the minimal.
-* **Typed Response** parameter Class Object or a ParameterizedTypeReference are mandatory
-* **Object.class** cannot be converted in a Resource or ByteArray directly without a minimal support Typed Response.
-
-#### Initialize the RestApi BackendService
-
-```
-BackendService backendService = new BackendServiceImpl();
-backendService.setBackendURL("https://internal.domain.com:9094");
-backendService.setRestOperations(new RestTemplate());
-backendService.setObjectMapper(new ObjectMapper());
-```
-
-#### Get Data
-
-```
-Data data = backendService.get("/mock/v1/data", backendService.createResponseType(Data.class));
-```
-
-#### Get List Data
-
-```
-ResponseType> typeReference = backendService.createResponseType(new ParameterizedTypeReference<>(){});
-List list = backendService.get("/mock/v1/dataList", typeReference);
-```
-
-#### Get Resource File
-
-```
-Resource image = backendService.getFile("/static/images/logo-marianne.svg");
-FileUtils.copyInputStreamToFile(image.getInputStream(), new File(System.getProperty("java.io.tmpdir") + "/logo-marianne.svg"));
-```
-
-
-#### Do Request List Data
-```
-ResponseType> typeReference = backendService.createResponseType(new ParameterizedTypeReference<>(){});
-Object obj = backendService.doRequest("/mock/v1/dataList", HttpMethod.GET, typeReference, null, null);
-System.out.println(obj);
-```
-
-#### Do Request Resource
-```
-Resource resource = backendService.doRequest("/mock/v1/datafile", HttpMethod.GET,
-backendService.createResponseType(Resource.class), null, headers); // WARN mandatory typed Resource.class
-String data = StreamUtils.copyToString(resource.getInputStream(), Charset.defaultCharset());
-System.out.println(data);
-```
-
-#### Do Request Byte Array
-```
-ResponseType typeReference = backendService.createResponseType(byte[].class)
-byte[] bytes = backendService.doRequest("/mock/v1/dataBytes", HttpMethod.GET, typeReference , null, null); // WARN mandatory typed byte[].class
-System.out.println(new String(bytes, StandardCharsets.UTF_8));
-```
-
-
-## Last News
-* Last version **1.0.25**, released at 22/03/2026 Modern WAF Defense, XSS, SQL, Google, Command, File, Java RCE, XXE, AI User-Agent
-* Version **1.0.24**, released at 01/09/2025 Forwarded headers Client and Transfer headers Backend Server, Cors headers exposed
-* Version **1.0.23**, released at 22/08/2025 Reorganize WAFFilter Multipart, CorsConfiguration, Cookie client stateful
-* Version **1.0.22**, released at 31/07/2025 Fix Security RateLimit, Content Security Policy and Referrer-Policy
-* Version **1.0.21**, released at 29/07/2025 Fix Predicate for Hostnames, Shared CookieRedirectInterceptor, Postman-Echo performance
-* Version **1.0.20**, released at 26/07/2025 Fix Spring Security dependencies, Improve security WAFFilter and WAFPredicate - Bis
-* Version **1.0.19**, released at 26/07/2025 Fix Spring Security dependencies, Improve security WAFFilter and WAFPredicate
-* Version **1.0.18**, released at 10/05/2025 Fix manage Cookie during a redirection 3xx
-* Version **1.0.17**, released at 04/05/2025 Fix manage Cookie, Gateway is stateless!
-* Version **1.0.16**, released at 03/11/2024 Fix CORS Security configuration Spring 5/6
-* Version **1.0.15**, released at 23/10/2024 Fix missing method addCorsMappings
-* Version **1.0.14**, released at 14/10/2024 Support Backend Headers and Support ContentNegotiation Header Strategy for Resources
-* Version **1.0.13**, released at 06/10/2024 Full support Response in ByteArray Resource and Streaming Http Response Range Bytes
-* Version **1.0.12**, released at 02/10/2024 Fix ApiBase error Message super.getResponseEntity
-* Version **1.0.11**, released at 30/09/2024 Does not encode the URI template!
-* Version **1.0.10**, released at 29/09/2024 Add full support MultipartRequest content type multipart/form-data
-* Version **1.0.9**, released at 24/09/2024 Fix replicate requests ApiBackend.requestEntity
-* Version **1.0.8**, released at 13/08/2024 Re-encoding HttpUrl, Special Characters are re-interpreted
-* Version **1.0.7**, released at 03/08/2024 All is Bytes.
-* Version **1.0.6**, released at 14/07/2024 Clarify Byte Array deserialization.
-* Version **1.0.5**, released at 13/07/2024 Optimize build war/jar.
-* Version **1.0.4**, released at 08/07/2024.
-* Version **1.0.3**, released at 23/06/2024 Reinit project.
-* Version **1.0.2** released at 28/04/2024.
-* Version **1.0.1** released at 21/11/2022.
-* Initial release **1.0.0** at 03/06/2021.
-
-## Support
-If you need help using Nexus-Backend Service feel free to drop an email or create an issue in GitHub.com (preferred).
-
-## Contributions
-To help **Nexus-Backend / ApiBackend / BackendService** development you are encouraged to
-* Provide suggestion/feedback/Issue
-* pull requests for new features
-* Star :star2: the project
-
-## License
-
-This project is an Open Source Software released under the [GPL-3.0 license](https://github.com/javaguru/nexus-backend/blob/master/LICENSE.txt).
-
-Copyright (c) 2001-2025 JServlet.com [Franck ANDRIANO.](http://jservlet.com)
-
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index 1e2bfa1..0000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Security Policy
-
-## Supported Versions
-
-| Version | Supported |
-|---------|---------------------|
-| 1.0.24 | :white_check_mark: |
-
-## Reporting a Vulnerability
diff --git a/pom.xml b/pom.xml
deleted file mode 100644
index d278be7..0000000
--- a/pom.xml
+++ /dev/null
@@ -1,726 +0,0 @@
-
-
- 4.0.0
-
- com.jservlet.nexus.backend
- nexus-backend
- ${packaging}
- 1.0.25
-
- nexus-backend
- The Java Nexus BackendService, an advanced and secure Rest Backend Gateway
- https://github.com/javaguru/nexus-backend
-
-
- JServlet.com
- https://github.com/javaguru
-
- 2020
-
-
-
- GNU General Public License (GPL) version 3.0
- https://www.gnu.org/licenses/gpl-3.0.txt
- repo
-
-
-
-
-
- fan
- Franck Andriano.
- franck@jservlet.com
- JServlet.com
- https://www.jservlet.com
-
- architect
- developer
-
-
-
-
-
- scm:git:git://github.com/javaguru/nexus-backend.git
- scm:git:git@github.com:javaguru/nexus-backend.git
- https://github.com/javaguru/nexus-backend
- HEAD
-
-
-
-
- ossrh
- Sonatype Nexus Snapshots
- https://oss.sonatype.org/content/repositories/snapshots
-
-
- ossrh
- Nexus Release Repository
- https://oss.sonatype.org/service/local/staging/deploy/maven2/
-
-
-
-
- Github
- https://github.com/javaguru/nexus-backend/issues
-
-
-
- SNAPSHOT
- NOW
- NOW
- unknown
- unknown
- unknown
-
- 13
- UTF-8
- UTF-8
-
- exec
- com.jservlet.nexus.config.Application
-
-
- 9.0.116
-
-
- 2.7.18
- 5.3.44
- 5.3.39
- 5.3.39
- 5.8.16
- 4.0.1
-
- 3.0.0
- 1.8.0
- 2.21.1
- 2.4.1
-
- 3.8.1
- 2.22.2
- 3.3.1
-
- 3.4.0
- 3.4.1
- 3.0.1
- 3.7.0
- 2.0.0
-
- 2.5.3
- 2.8.2
- 1.6.7
-
- 1.6
- 1.11.2
-
-
-
-
-
-
- release-sign-artifacts
-
- jar
-
-
-
- performRelease
- true
-
-
-
-
-
- org.apache.maven.plugins
- maven-gpg-plugin
- ${maven-gpg-plugin.version}
-
-
- sign-artifacts
- verify
-
- sign
-
-
-
-
-
-
-
-
-
- withoutTomcat
-
- war
- withoutTomcat
-
-
-
-
- org.springframework.boot
- spring-boot-starter-web
- ${spring-boot.version}
- provided
-
-
- spring-boot-starter-tomcat
- org.springframework.boot
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-war-plugin
- ${maven-war-plugin.version}
-
- src/main/webapp
- false
-
-
-
- true
- lib/
- ${mainClass}
-
-
- ${project.groupId}
- ${project.artifactId}
- ${project.version}
- ${project.url}
- development
-
-
-
-
-
-
-
-
-
- withTomcat
-
- true
-
-
- jar
- withTomcat
-
-
-
-
- org.springframework.boot
- spring-boot-starter-web
- ${spring-boot.version}
-
-
- org.springframework.boot
- spring-boot-starter-tomcat
- ${spring-boot.version}
- provided
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
-
-
- copy-dependencies
- prepare-package
-
- copy-dependencies
-
-
- ${project.build.outputDirectory}/lib
- false
- false
- true
-
-
-
-
-
-
-
-
-
-
- ${project.artifactId}
-
-
-
- src/main/resources
-
- **/*.properties
-
- true
-
-
-
- src/main/resources
-
- logback.xml
- logo-marianne.svg
- persistence.xml
- api-ui/api-docs.yaml
- mime/*.properties
- META-INF/services/javax.servlet.ServletContainerInitializer
-
- false
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
- ${spring-boot.version}
-
-
-
- repackage
-
-
- ${packageClassifier}
- true
- ${mainClass}
- ${project.build.directory}/docker
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- ${maven-compiler-plugin.version}
-
- ${project.build.sourceEncoding}
- ${java.version}
- ${java.version}
- true
- -Xlint:unchecked
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- ${maven-surefire-plugin.version}
-
-
-
- org.apache.maven.plugins
- maven-resources-plugin
- ${maven-resources-plugin.version}
-
- ISO-8859-1
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- ${maven-jar-plugin.version}
-
-
-
-
- true
- lib/
- ${mainClass}
-
-
- ${project.groupId}
- ${project.artifactId}
- ${project.version}
- ${project.url}
- development
- lib/
-
-
-
-
-
-
- package
-
- jar
-
-
-
-
- true
- lib/
- ${mainClass}
-
-
- ${project.groupId}
- ${project.artifactId}
- ${project.version}
- ${project.url}
- shared
- lib/
-
-
- shared
-
- settings.properties
- logback.xml
- com/jservlet/nexus/config/**/*.*
- com/jservlet/nexus/controller/**/*.*
-
-
- /META-INF/*.properties
- /META-INF/*.MF
- com/jservlet/nexus/shared/**/*.class
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-source-plugin
- ${maven-source-plugin.version}
-
-
- attach-sources
-
- jar
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- ${maven-javadoc-plugin.version}
-
- UTF-8
- false
- ${java.home}/bin/javadoc
-
-
-
-
- attach-javadoc
-
- jar
-
-
-
-
-
- org.apache.maven.plugins
- maven-release-plugin
- ${maven-release-plugin.version}
-
- true
- false
- forked-path
- -Dgpg.passphrase=${gpg.passphrase}
-
-
-
- org.apache.maven.scm
- maven-scm-provider-gitexe
- ${maven-scm-provider-gitexe.version}
-
-
-
-
- org.codehaus.mojo
- buildnumber-maven-plugin
- 1.4
-
-
- validate
-
- create
-
-
-
-
- gitRevision
- buildtime
- {0,date,yyyy-MM-dd HH:mm:ss}
- gitBranch
-
-
-
- maven-deploy-plugin
- ${maven-deploy-plugin.version}
-
-
- default-deploy
- deploy
-
- deploy
-
-
-
-
-
- org.sonatype.plugins
- nexus-staging-maven-plugin
- ${nexus-staging-maven-plugin.version}
- true
-
- ossrh
- https://oss.sonatype.org/
- true
-
-
-
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-starter
- ${spring-boot.version}
- pom
- import
-
-
- org.springframework
- spring-framework-bom
- ${spring.bom.version}
- pom
- import
-
-
- org.springframework.security
- spring-security-bom
- ${spring.security.version}
- pom
- import
-
-
-
-
-
-
-
- org.apache.tomcat.embed
- tomcat-embed-jasper
- ${tomcat.version}
-
-
-
-
- org.yaml
- snakeyaml
- 2.0
-
-
-
-
- ch.qos.logback
- logback-classic
- 1.5.25
-
-
- ch.qos.logback
- logback-core
- 1.5.25
-
-
-
-
- org.springframework.boot
- spring-boot-configuration-processor
- ${spring-boot.version}
-
-
-
-
- org.springframework.boot
- spring-boot-starter-validation
- ${spring-boot.version}
-
-
-
-
- org.springframework.boot
- spring-boot-starter-actuator
- ${spring-boot.version}
-
-
-
-
- com.giffing.bucket4j.spring.boot.starter
- bucket4j-spring-boot-starter
- 0.9.0
-
-
-
-
- org.springframework
- spring-context-support
- ${spring.context.version}
-
-
-
-
- org.springframework.security
- spring-security-web
- ${spring.security.version}
-
-
- org.springframework.security
- spring-security-config
- ${spring.security.version}
-
-
-
-
- javax.annotation
- javax.annotation-api
- 1.3.2
-
-
-
-
- javax.servlet
- javax.servlet-api
- ${servlet.api.version}
- provided
-
-
-
- javax.servlet
- jstl
- 1.2
-
-
-
-
- io.swagger.parser.v3
- swagger-parser
- 2.1.39
-
-
-
-
- org.codehaus.janino
- janino
- 2.6.1
-
-
-
-
- org.springdoc
- springdoc-openapi-ui
- ${springdoc-openapi.version}
-
-
- org.springdoc
- springdoc-openapi-security
- ${springdoc-openapi.version}
-
-
-
-
- com.fasterxml.jackson.core
- jackson-core
- ${jackson.version}
-
-
-
-
- org.apache.logging.log4j
- log4j-to-slf4j
- 2.19.0
-
-
-
-
- commons-io
- commons-io
- 2.16.1
-
-
- org.apache.commons
- commons-collections4
- 4.5.0-M1
-
-
-
- commons-codec
- commons-codec
- 1.17.0
-
-
-
- org.apache.commons
- commons-lang3
- 3.18.0
-
-
-
-
- com.github.ziplet
- ziplet
- ${ziplet.version}
-
-
-
-
- junit
- junit
- 4.13.2
- test
-
-
- org.springframework
- spring-test
- test
-
-
-
-
-
diff --git a/src/license/gnu/header.txt b/src/license/gnu/header.txt
deleted file mode 100644
index 46306d8..0000000
--- a/src/license/gnu/header.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Copyright (C) 2001-2024 JServlet.com Franck Andriano.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
diff --git a/src/main/java/com/jservlet/nexus/config/Application.java b/src/main/java/com/jservlet/nexus/config/Application.java
deleted file mode 100644
index 83889fb..0000000
--- a/src/main/java/com/jservlet/nexus/config/Application.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2001-2024 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config;
-
-import io.swagger.v3.oas.annotations.OpenAPIDefinition;
-import org.springframework.boot.Banner;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
-import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
-import org.springframework.boot.builder.SpringApplicationBuilder;
-import org.springframework.boot.web.servlet.ServletComponentScan;
-import org.springframework.context.annotation.Import;
-
-/**
- * SpringBoot Application
- */
-
-//@OpenAPIDefinition(servers = {@Server(url = "/nexus-backend", description = "Default Server URL")})
-@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class})
-@ServletComponentScan // Scan all @WebListener, @WebServlet or @WebFilter!
-@Import({
- ApplicationConfig.class
-})
-public class Application {
-
- /**
- * -Denvironment=development -Dserver.servlet.context-path=/nexus-backend -Dserver.port=8082
- *
- * @param args {@link String[]}
- */
- public static void main(String[] args) {
- //System.setProperty("spring.devtools.restart.enabled", "false");
-
- // Fix ClassNotFoundException: org.slf4j.impl.StaticLoggerBinder
- System.setProperty("org.springframework.boot.logging.LoggingSystem", "none");
- // Swagger is only available in dev!
- String env = System.getProperty("environment", "development");
- if ("development".equals(env)) System.setProperty("springdoc.swagger-ui.enabled", "true");
- // Server path and port
- System.setProperty("server.servlet.context-path", System.getProperty("server.servlet.context-path", "/nexus-backend"));
- System.setProperty("server.port", System.getProperty("server.port", "8082"));
- new SpringApplicationBuilder(Application.class).bannerMode(Banner.Mode.CONSOLE).run(args);
- }
-
-}
diff --git a/src/main/java/com/jservlet/nexus/config/ApplicationConfig.java b/src/main/java/com/jservlet/nexus/config/ApplicationConfig.java
deleted file mode 100644
index 7362d44..0000000
--- a/src/main/java/com/jservlet/nexus/config/ApplicationConfig.java
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2001-2024 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.databind.*;
-import com.jservlet.nexus.config.web.WebConfig;
-import com.jservlet.nexus.config.web.WebSecurityConfig;
-import com.jservlet.nexus.config.web.tomcat.ssl.TomcatConnectorConfig;
-import com.jservlet.nexus.shared.config.annotation.ConfigProperties;
-import com.jservlet.nexus.shared.service.backend.BackendService;
-import com.jservlet.nexus.shared.service.backend.BackendServiceImpl;
-import com.jservlet.nexus.shared.web.controller.api.ApiBackend;
-import com.jservlet.nexus.shared.web.interceptor.CookieRedirectInterceptor;
-import org.apache.http.Header;
-import org.apache.http.HttpResponse;
-import org.apache.http.ParseException;
-import org.apache.http.client.config.CookieSpecs;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.HttpConnectionFactory;
-import org.apache.http.conn.ManagedHttpClientConnection;
-import org.apache.http.conn.routing.HttpRoute;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.DefaultConnectionReuseStrategy;
-import org.apache.http.impl.DefaultHttpResponseFactory;
-import org.apache.http.impl.client.*;
-import org.apache.http.impl.conn.DefaultHttpResponseParserFactory;
-import org.apache.http.impl.conn.ManagedHttpClientConnectionFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.impl.io.DefaultHttpRequestWriterFactory;
-import org.apache.http.message.BasicHeader;
-import org.apache.http.message.BasicLineParser;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.ssl.PrivateKeyDetails;
-import org.apache.http.ssl.PrivateKeyStrategy;
-import org.apache.http.ssl.SSLContexts;
-import org.apache.http.util.CharArrayBuffer;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
-import org.springframework.http.*;
-import org.springframework.http.client.*;
-import org.springframework.http.converter.*;
-import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
-import org.springframework.web.client.*;
-import org.springframework.web.util.DefaultUriBuilderFactory;
-
-import javax.net.ssl.SSLContext;
-import java.io.*;
-import java.net.Socket;
-import java.security.KeyStore;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-/**
- * Application Config Nexus Backend Application
- * Loader ConfigProperties file "classpath:settings.properties"
- */
-@Configuration
-@ConfigProperties("classpath:settings.properties")
-@Import({
- WebConfig.class,
- WebSecurityConfig.class,
- TomcatConnectorConfig.class
-})
-@EnableConfigurationProperties(ApiBackend.ResourceMatchersConfig.class)
-public class ApplicationConfig {
-
- @Bean
- public BackendService backendService(@Value("${nexus.backend.url}") String backendUrl,
- RestOperations restOperations,
- ObjectMapper objectMapper) {
- final BackendServiceImpl backendService = new BackendServiceImpl(true); // return a Generics Object!
- backendService.setBackendURL(backendUrl);
- backendService.setRestOperations(restOperations);
- backendService.setObjectMapper(objectMapper);
- return backendService;
- }
-
- @Bean
- public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
- return new MappingJackson2HttpMessageConverter(objectMapper);
- }
-
- @Value("${nexus.backend.mapper.indentOutput:false}")
- private boolean indentOutput;
-
-
- @Bean
- public ObjectMapper objectMapper() {
- return new Jackson2ObjectMapperBuilder()
- // fields not null globally!
- .serializationInclusion(JsonInclude.Include.NON_NULL)
- // to allow serialization of "empty" POJOs (no properties to serialize)
- .failOnEmptyBeans(false)
- // to prevent exception when encountering unknown property:
- .failOnUnknownProperties(false)
-
- // disable, not thrown an exception if an unknown property
- .featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
-
- // to enable standard indentation ("pretty-printing"):
- .indentOutput(indentOutput)
- .build();
- }
-
-
- @Bean
- public RestOperations backendRestOperations(MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter,
- ClientHttpRequestFactory httpRequestFactory) throws Exception {
-
- RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
- restTemplate.setInterceptors(List.of(new CookieRedirectInterceptor(maxRedirects)));
-
- // Does not encode the URI template, prevent to re-encode again the Uri with percent encoded in %25
- DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory();
- uriFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);
- restTemplate.setUriTemplateHandler(uriFactory);
-
- // MediaType.ALL now! Json + Json wildcard, pdf, gif etc...
- mappingJackson2HttpMessageConverter.setSupportedMediaTypes(List.of(MediaType.ALL));
-
- // List HttpMessage Converters
- restTemplate.setMessageConverters(Arrays.asList(
- new StringHttpMessageConverter(UTF_8), // String
- new FormHttpMessageConverter(), // Form x-www-form-urlencoded, multipart/form-data multipart/mixed
- new ByteArrayHttpMessageConverter(), // byte[] octet-stream
- new ResourceHttpMessageConverter(), // Resource, ByteArrayResource
- mappingJackson2HttpMessageConverter // JSON
- ));
- return restTemplate;
- }
-
-
- @Value("${nexus.backend.client.connectTimeout:10}")
- private int connectTimeout;
- @Value("${nexus.backend.client.requestTimeout:20}")
- private int requestTimeout;
- @Value("${nexus.backend.client.socketTimeout:10}")
- private int socketTimeout;
-
- @Value("${nexus.backend.client.max_connections_per_route:20}")
- private int defaultMaxConnectionsPerRoute;
-
- @Value("${nexus.backend.client.max_connections:100}")
- private int maxConnections;
-
- @Value("${nexus.backend.client.close_idle_connections_timeout:0}")
- private int closeIdleConnectionsTimeout;
-
- @Value("${nexus.backend.client.validate_after_inactivity:2}")
- private int validateAfterInactivity;
-
- @Value("${nexus.backend.client.retryCount:3}")
- private int retryCount;
- @Value("${nexus.backend.client.requestSentRetryEnabled:false}")
- private boolean requestSentRetryEnabled;
-
- @Value("${nexus.backend.client.redirectsEnabled:false}")
- private boolean redirectsEnabled;
- @Value("${nexus.backend.client.maxRedirects:5}")
- private int maxRedirects;
- @Value("${nexus.backend.client.authenticationEnabled:false}")
- private boolean authenticationEnabled;
- @Value("${nexus.backend.client.circularRedirectsAllowed:false}")
- private boolean circularRedirectsAllowed;
-
-
- /**
- * User-Agent
- */
- @Value("${nexus.backend.client.header.user-agent:JavaNexus}")
- private String userAgent;
-
-
- /**
- * Activated the Mutual Authentication or mTLS, default protocol TLSv1.3
- */
- @Value("${nexus.backend.client.ssl.mtls.enable:false}")
- private boolean isMTLS;
-
- @Value("${nexus.backend.client.ssl.key-store:nexus-default.jks}")
- private String pathJKS;
- @Value("${nexus.backend.client.ssl.key-store-password:changeit}")
- private String keyStorePassword;
- @Value("${nexus.backend.client.ssl.certificate.alias:key_server}")
- private String certificateAlias;
- /**
- * SpEL reads allow method delimited with a comma and splits into a List of Strings
- */
- @Value("#{'${nexus.backend.client.ssl.https.protocols:TLSv1.3}'.split(',')}")
- private List httpsProtocols;
- @Value("#{'${nexus.backend.client.ssl.https.cipherSuites:TLS_AES_256_GCM_SHA384}'.split(',')}")
- private List httpsCipherSuites;
-
- @Bean
- public ClientHttpRequestFactory httpRequestFactory() throws Exception {
-
- final DefaultConnectionKeepAliveStrategy myStrategy = new DefaultConnectionKeepAliveStrategy() {
- @Override
- public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
- return super.getKeepAliveDuration(response, context);
- }
- };
-
- final HttpConnectionFactory connFactory =
- new ManagedHttpClientConnectionFactory(
- new DefaultHttpRequestWriterFactory(),
- new DefaultHttpResponseParserFactory(
- new CompliantLineParser(), new DefaultHttpResponseFactory()));
-
- final PoolingHttpClientConnectionManager cm;
-
- if (isMTLS) {
- final KeyStore identityKeyStore = KeyStore.getInstance("jks");
- final FileInputStream identityKeyStoreFile = new FileInputStream(pathJKS);
- identityKeyStore.load(identityKeyStoreFile, keyStorePassword.toCharArray());
-
- final KeyStore trustKeyStore = KeyStore.getInstance("jks");
- final FileInputStream trustKeyStoreFile = new FileInputStream(pathJKS);
- trustKeyStore.load(trustKeyStoreFile, keyStorePassword.toCharArray());
-
- final SSLContext sslContext = SSLContexts.custom()
- // load identity keystore
- .loadKeyMaterial(identityKeyStore, keyStorePassword.toCharArray(), new PrivateKeyStrategy() {
- @Override
- public String chooseAlias(Map aliases, Socket socket) {
- return certificateAlias;
- }
- })
- // load trust keystore
- .loadTrustMaterial(trustKeyStore, null)
- .build();
-
- // WARN only protocol TLSv1.3, Not a mix with TLSv1.2,TLSv1.1 cause SSLSocket duplex close failed!!!
- // WARN only CipherSuites TLS_AES_256_GCM_SHA384 or TLS_AES_128_GCM_SHA256
- final SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
- httpsProtocols.toArray(new String[0]),
- httpsCipherSuites.toArray(new String[0]), // TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256
- SSLConnectionSocketFactory.getDefaultHostnameVerifier());
-
- // WARN Not set a sslConnectionSocketFactory cause a HandshakeContext with a dummy KeyManager!!!
- cm = new PoolingHttpClientConnectionManager(RegistryBuilder.create()
- .register("http", PlainConnectionSocketFactory.getSocketFactory())
- .register("https", sslConnectionSocketFactory)
- .build(), connFactory);
- } else {
- cm = new PoolingHttpClientConnectionManager(connFactory);
- }
-
- cm.setDefaultMaxPerRoute(defaultMaxConnectionsPerRoute);
- cm.setMaxTotal(maxConnections);
- cm.setValidateAfterInactivity(validateAfterInactivity * 1000);
- cm.closeIdleConnections(closeIdleConnectionsTimeout, TimeUnit.SECONDS);
-
- return new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create()
- .setUserAgent(userAgent)
- .setConnectionManager(cm)
- .setDefaultRequestConfig(RequestConfig.custom()
- .setCookieSpec(CookieSpecs.STANDARD) // Optional specs standard!
- .setConnectTimeout(connectTimeout * 1000)
- .setConnectionRequestTimeout(requestTimeout * 1000)
- .setSocketTimeout(socketTimeout * 1000)
- .setRedirectsEnabled(redirectsEnabled) // mandatory disabled by default!
- .setMaxRedirects(maxRedirects)
- .setAuthenticationEnabled(authenticationEnabled)
- .setCircularRedirectsAllowed(circularRedirectsAllowed)
- .build())
- .setConnectionReuseStrategy(new DefaultConnectionReuseStrategy())
- .setKeepAliveStrategy(myStrategy)
- .setRedirectStrategy(new LaxRedirectStrategy())
- .setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, requestSentRetryEnabled))
- .disableRedirectHandling()
- // Cookie client stateful managed, the Gateway is Stateless! Session state is temporary and only affects the transaction!
- //.disableCookieManagement()
- .disableAuthCaching()
- .disableConnectionState()
- .build());
- }
-
- /**
- * Force HttpClient into accepting malformed response heads in order to salvage the content of the messages.
- * (Deal non-standard and non-compliant behaviours!)
- */
- static class CompliantLineParser extends BasicLineParser {
- @Override
- public Header parseHeader(CharArrayBuffer buffer) throws ParseException {
- try {
- return super.parseHeader(buffer);
- } catch (ParseException ex) {
- // Suppress ParseException exception
- return new BasicHeader(buffer.toString(), null);
- }
- }
- }
-
-}
diff --git a/src/main/java/com/jservlet/nexus/config/JServletBanner.java b/src/main/java/com/jservlet/nexus/config/JServletBanner.java
deleted file mode 100644
index 53616d1..0000000
--- a/src/main/java/com/jservlet/nexus/config/JServletBanner.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2001-2024 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config;
-
-import org.springframework.boot.Banner;
-import org.springframework.boot.ansi.AnsiBackground;
-import org.springframework.boot.ansi.AnsiColor;
-import org.springframework.boot.ansi.AnsiOutput;
-import org.springframework.boot.ansi.AnsiStyle;
-import org.springframework.context.ResourceLoaderAware;
-import org.springframework.core.env.Environment;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.lang.NonNull;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.MissingResourceException;
-import java.util.Properties;
-
-/**
- * JServlet NexusBackend Banner
- */
-@Component
-public class JServletBanner implements Banner, ResourceLoaderAware {
-
- private ResourceLoader resourceLoader;
- private String VERSION;
-
- @PostConstruct
- public void postConstruct() throws IOException {
- Resource resource = resourceLoader.getResource("classpath:META-INF/version.properties");
- if (!resource.exists())
- throw new MissingResourceException("Unable to find \"version.properties\" on classpath!",
- getClass().getName(), "version.properties");
-
- Properties properties = new Properties();
- properties.load(resource.getInputStream());
- VERSION = properties.getProperty("version");
- }
-
- private final String[] BANNER = { "", // line break!
- " _ _ ___ _ _ \n" +
- " | \\| | ___ ____ _ _ ___ | _ ) __ _ __ | |__ ___ _ _ __| |\n" +
- " | .` |/ -_)\\ \\ /| || |(_-< | _ \\/ _` |/ _|| / // -_)| ' \\ / _` |\n" +
- " |_|\\_|\\___|/_\\_\\ \\_,_| /__/|___/\\__,_|\\__||_\\_\\\\___||_||_|\\__,_| "
- };
-
- private static final String NEXUS_BACKEND = " :: NexusBackend :: Secure RestApi Backend Gateway";
- private static final int STRAP_LINE_SIZE = 63;
-
- @Override
- public void printBanner(Environment environment, Class> sourceClass, PrintStream printStream) {
- for (String line : BANNER) {
- printStream.println(AnsiOutput.toString(AnsiColor.CYAN, AnsiBackground.DEFAULT, AnsiStyle.BOLD, line));
- }
- String version = " (v" + VERSION + ")";
- StringBuilder padding = new StringBuilder();
- while (padding.length() < STRAP_LINE_SIZE - (version.length() + NEXUS_BACKEND.length())) {
- padding.append(" ");
- }
- printStream.println(AnsiOutput.toString(AnsiColor.GREEN, NEXUS_BACKEND, AnsiColor.DEFAULT, padding.toString(),
- AnsiStyle.FAINT, version));
- printStream.println();
- }
-
- @Override
- public void setResourceLoader(@NonNull ResourceLoader resourceLoader) {
- this.resourceLoader = resourceLoader;
- }
-}
diff --git a/src/main/java/com/jservlet/nexus/config/JServletContainerInitializer.java b/src/main/java/com/jservlet/nexus/config/JServletContainerInitializer.java
deleted file mode 100644
index b90d59d..0000000
--- a/src/main/java/com/jservlet/nexus/config/JServletContainerInitializer.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2001-2024 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config;
-
-import org.springframework.web.WebApplicationInitializer;
-
-import javax.servlet.ServletContainerInitializer;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.annotation.HandlesTypes;
-import java.util.*;
-
-/**
- * JServlet Container Initializer only with an external Tomcat (Not embedded)
- */
-@HandlesTypes(WebApplicationInitializer.class)
-public class JServletContainerInitializer implements ServletContainerInitializer {
-
- @Override
- public void onStartup(Set>> c, ServletContext ctx) throws ServletException {
- // All Servlets Initializer
- System.out.println();
- System.out.println("Started Servlets Container Initializer:");
- for (Class> clazz : c) {
- System.out.println("- " + clazz);
- }
- }
-}
-
diff --git a/src/main/java/com/jservlet/nexus/config/JServletContextListener.java b/src/main/java/com/jservlet/nexus/config/JServletContextListener.java
deleted file mode 100644
index 09f3a4f..0000000
--- a/src/main/java/com/jservlet/nexus/config/JServletContextListener.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2001-2024 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config;
-
-import ch.qos.logback.classic.LoggerContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.boot.ansi.AnsiColor;
-import org.springframework.boot.ansi.AnsiOutput;
-import org.springframework.context.ApplicationContext;
-import org.springframework.lang.NonNull;
-import org.springframework.stereotype.Component;
-import org.springframework.web.context.ConfigurableWebApplicationContext;
-import org.springframework.web.context.ContextCleanupListener;
-import org.springframework.web.context.support.WebApplicationContextUtils;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-
-/**
- * NexusBackend ServletContext Listener
- */
-@Component
-public class JServletContextListener extends ContextCleanupListener {
-
- private final static Logger logger = LoggerFactory.getLogger(JServletContextListener.class);
-
- private final JServletBanner jServletBanner;
-
- public JServletContextListener(JServletBanner jServletBanner) {
- this.jServletBanner = jServletBanner;
- }
-
- @Override
- public void contextInitialized(@NonNull ServletContextEvent event) {
- logger.info("Starting NexusBackend ServletContext Listener");
- // Banner
- jServletBanner.printBanner(null, null, System.out);
-
- if (logger.isInfoEnabled()) {
- System.out.println(" Started NexusBackend ServletContext");
- ServletContext servletContext = event.getServletContext();
- ApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
- // Server Info
- System.out.println(" ServerInfo: " +
- AnsiOutput.toString(AnsiColor.GREEN, servletContext.getServerInfo()));
- System.out.println(" ServletApi: " +
- AnsiOutput.toString(AnsiColor.GREEN, "Specifications v" + servletContext.getMajorVersion() + "."+ servletContext.getMinorVersion()));
- System.out.println();
- }
- }
-
- @Override
- public void contextDestroyed(ServletContextEvent event) {
-
- // Assume SLF4J is bound to logback-classic in the current environment
- LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
- loggerContext.stop();
-
- /*ClassLoader webAppClassLoader = this.getClass().getClassLoader();
- Class clazz = null;
- try {
- clazz = Class.forName("com..xxx.XMLRequestInterface",false, webAppClassLoader);
- } catch (ClassNotFoundException ignore) {
- //log exception or ignore
- }
-
- if (clazz != null) {
- if ((clazz.getClassLoader() == webAppClassLoader)) {
- XMLRequestInterface.clearStaticTableCache();
- }
- }*/
-
- // Close webapp context
- closeWebApplicationContext(event.getServletContext());
-
- // Call super destroy
- super.contextDestroyed(event);
-
- // console logs, no more logs!
- System.out.println("Nexus-Backend ServletContext destroyed");
- }
-
- private void closeWebApplicationContext(ServletContext servletContext) {
- if (servletContext instanceof ConfigurableWebApplicationContext) {
- ((ConfigurableWebApplicationContext) servletContext).close();
- }
- }
-
-}
diff --git a/src/main/java/com/jservlet/nexus/config/JServletInitializer.java b/src/main/java/com/jservlet/nexus/config/JServletInitializer.java
deleted file mode 100644
index 355fef8..0000000
--- a/src/main/java/com/jservlet/nexus/config/JServletInitializer.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2001-2025 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config;
-
-import org.springframework.boot.builder.SpringApplicationBuilder;
-import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
-import org.springframework.context.annotation.Profile;
-
-/**
- * SpringBoot Tomcat Container ServletInitializer
- * Only a Spring profile 'withoutTomcat' (or 'withTomcat' with a Tomcat Embedded by SpringBoot!)
- */
-@Profile("withoutTomcat")
-public class JServletInitializer extends SpringBootServletInitializer {
-
- @Override
- protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
- // Swagger is only available in dev!
- String env = System.getProperty("environment", "development");
- if ("development".equals(env)) System.setProperty("springdoc.swagger-ui.enabled", "true");
- // run app
- return application.sources(Application.class);
- }
-}
diff --git a/src/main/java/com/jservlet/nexus/config/web/SwaggerConfig.java b/src/main/java/com/jservlet/nexus/config/web/SwaggerConfig.java
deleted file mode 100644
index 0e3eca1..0000000
--- a/src/main/java/com/jservlet/nexus/config/web/SwaggerConfig.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2001-2024 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config.web;
-
-import io.swagger.v3.oas.models.info.*;
-import io.swagger.v3.oas.models.Components;
-import io.swagger.v3.oas.models.OpenAPI;
-import io.swagger.v3.oas.models.info.Info;
-import io.swagger.v3.parser.OpenAPIV3Parser;
-import org.springdoc.core.GroupedOpenApi;
-import org.springdoc.core.customizers.OpenApiCustomiser;
-import org.springframework.context.ResourceLoaderAware;
-import org.springframework.context.annotation.*;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.core.type.AnnotatedTypeMetadata;
-import org.springframework.lang.NonNull;
-
-import javax.annotation.PostConstruct;
-import java.io.IOException;
-import java.util.MissingResourceException;
-import java.util.Properties;
-
-/**
- * Swagger mock-api only available in Dev mode, added in JVM Options: -Denvironment=development
- */
-@Conditional(SwaggerConfig.IsDevEnvCondition.class)
-@Configuration
-public class SwaggerConfig implements ResourceLoaderAware {
-
- private ResourceLoader resourceLoader;
-
- private String VERSION;
-
- @PostConstruct
- public void postConstruct() throws IOException {
- Resource resource = resourceLoader.getResource("classpath:META-INF/version.properties");
- if (!resource.exists())
- throw new MissingResourceException("Unable to find \"version.properties\" on classpath!",
- getClass().getName(), "version.properties");
- Properties properties = new Properties();
- properties.load(resource.getInputStream());
- VERSION = properties.getProperty("version");
- //System.getProperties().list(System.out);
- }
-
- @Override
- public void setResourceLoader(@NonNull ResourceLoader resourceLoader) {
- this.resourceLoader = resourceLoader;
- }
-
- @Bean
- public GroupedOpenApi mockOpenApi() {
- return GroupedOpenApi.builder()
- .group("mock-api")
- .packagesToScan("com.jservlet.nexus.controller")
- .addOpenApiCustomiser(new OpenApiCustomised("api-ui/api-docs.yaml"))
- .build();
- }
-
- /**
- * OpenApi customised config with the file api-ui/api-docs.yaml
- */
- private class OpenApiCustomised implements OpenApiCustomiser {
-
- private final String specLocation;
-
- public OpenApiCustomised(String specLocation) {
- this.specLocation = specLocation;
- }
-
- @Override
- public void customise(OpenAPI openApi) {
-
- // Load raw data from file format openapi 3.0.1
- OpenAPI api = new OpenAPIV3Parser().read(specLocation);
-
- // Keep all the existing schemas..
- Components components = openApi.getComponents();
-
- // Get the component that we just parse, but not securitySchemes!
- Components componentsApi = api.getComponents();
- if (componentsApi != null) {
- componentsApi.schemas(components.getSchemas());
- componentsApi.headers(components.getHeaders());
- componentsApi.extensions(components.getExtensions());
- componentsApi.callbacks(components.getCallbacks());
- componentsApi.links(components.getLinks());
- //componentsApi.securitySchemes(components.getSecuritySchemes());
-
- // Set the customised Components Security Schemes
- openApi.setComponents(componentsApi);
- }
-
- // Set the customised Security, see https://swagger.io/docs/specification/authentication/
- openApi.setSecurity(api.getSecurity());
-
- // Apply the info now!
- openApi.setInfo(apiInfo());
-
- // not, in all case, let the scan package do it for us!
- //openApi.setPaths(api.getPaths());
-
- // not used!
- openApi.setExtensions(api.getExtensions());
- openApi.setExternalDocs(api.getExternalDocs());
- openApi.setServers(api.getServers());
- openApi.setTags(api.getTags());
- }
- }
-
-
- private Info apiInfo() {
- return new Info()
- .title("Mock Test API")
- .description( "The Mock Test Api Nexus Backend Application\n" +
- "- 1 Test GET, POST, PUT, PATCH, DELETE\n" +
- "- 2 Test POST, PUT, PATCH file\n" +
- "- 3 Test Error 400, 401 and 500\n" +
- "- 4 Test Security GET and POST XSS data\n")
- .version(VERSION)
- .contact(new Contact().name("Franck Andriano.").email("franck@jservlet.com"))
- .license(new License().name("Copyright (c) JServlet.com").url("https://jservlet.com"));
- }
-
- static class IsDevEnvCondition implements Condition {
- @Override
- public boolean matches(ConditionContext context, @NonNull AnnotatedTypeMetadata metadata) {
- final String env = context.getEnvironment().getProperty("environment");
- if (env == null || env.isEmpty()) {
- return false;
- }
- return env.contains("development");
- }
- }
-
-}
diff --git a/src/main/java/com/jservlet/nexus/config/web/WebConfig.java b/src/main/java/com/jservlet/nexus/config/web/WebConfig.java
deleted file mode 100644
index 1915435..0000000
--- a/src/main/java/com/jservlet/nexus/config/web/WebConfig.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2001-2025 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config.web;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.jservlet.nexus.shared.web.interceptor.RateLimitInterceptor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.env.OriginTrackedMapPropertySource;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.*;
-import org.springframework.lang.NonNull;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/*
- * Web App Configuration
- */
-@Configuration
-@ComponentScan({
- "com.jservlet.nexus.controller",
- // Scan from shared server components
- "com.jservlet.nexus.shared.web.controller",
- "com.jservlet.nexus.shared.web.filter",
- "com.jservlet.nexus.shared.web.listener"
-})
-public class WebConfig implements ApplicationContextAware {
-
- private final static Logger logger = LoggerFactory.getLogger(WebConfig.class);
-
- private static ApplicationContext appContext;
-
- private final Environment env;
-
- private final ObjectMapper objectMapper;
-
- public WebConfig(Environment env, ObjectMapper objectMapper) {
- this.env = env;
- this.objectMapper = objectMapper;
- }
-
- @Override
- public synchronized void setApplicationContext(@NonNull ApplicationContext ac) {
- logger.info("SpringBoot set ApplicationContext -> ac: ['{}']", ac.getId());
- WebConfig.appContext = ac;
-
- if (logger.isInfoEnabled()) {
- Map map = getApplicationProperties(env);
- // Debug also log system out!
- logger.info("*** SpringBoot ApplicationProperties ***");
- for (Map.Entry entry : map.entrySet()) {
- logger.info("{} = {}", entry.getKey(), entry.getValue());
- }
- }
- }
-
- /**
- * Get the current ApplicationContext
- * @return ApplicationContext
- */
- public static synchronized ApplicationContext getApplicationContext() {
- return appContext;
- }
-
- /* Stuff, get loaded SpringBoot Application Properties */
- private static Map getApplicationProperties(Environment env) {
- Map map = new LinkedHashMap<>(); // keep order!
- if (env instanceof ConfigurableEnvironment) {
- for (PropertySource> propertySource : ((ConfigurableEnvironment) env).getPropertySources()) {
- // WARN all tracked SpringBoot config file *.properties!
- if (propertySource instanceof OriginTrackedMapPropertySource) {
- for (String key : ((EnumerablePropertySource>) propertySource).getPropertyNames()) {
- map.put(key, propertySource.getProperty(key));
- }
- }
- // Include Spring devtools
- if (propertySource instanceof MapPropertySource && "devtools".equals(propertySource.getName())) {
- for (String key : ((MapPropertySource) propertySource).getPropertyNames()) {
- map.put(key, propertySource.getProperty(key));
- }
- }
- }
- }
- return map;
- }
-
-
- @Value("${nexus.backend.interceptor.ratelimit.refillToken:1000}")
- private int refillToken;
- @Value("${nexus.backend.interceptor.ratelimit.refillMinutes:1}")
- private int refillMinutes;
- @Value("${nexus.backend.interceptor.ratelimit.bandwidthCapacity:1000}")
- private int bandwidthCapacity;
-
- /**
- * Rate Limit interceptor checks incoming requests against a rate limit defined on a per-IP-address basis.
- * @return RateLimitInterceptor
- */
- @Bean
- @ConditionalOnProperty(value = "nexus.api.backend.interceptor.ratelimit.enabled")
- public RateLimitInterceptor limitInterceptor() {
- RateLimitInterceptor limitInterceptor = new RateLimitInterceptor();
- limitInterceptor.setObjectMapper(objectMapper);
- limitInterceptor.setRefillToken(refillToken);
- limitInterceptor.setRefillMinutes(refillMinutes);
- limitInterceptor.setBandwidthCapacity(bandwidthCapacity);
- return limitInterceptor;
- }
-}
diff --git a/src/main/java/com/jservlet/nexus/config/web/WebConstants.java b/src/main/java/com/jservlet/nexus/config/web/WebConstants.java
deleted file mode 100644
index 795e04f..0000000
--- a/src/main/java/com/jservlet/nexus/config/web/WebConstants.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2001-2024 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config.web;
-
-/*
- * Web Constants
- */
-public interface WebConstants {
- /**
- * CONSTANTS RESPONSE
- */
- String $200 = "200";
- String $201 = "201";
- String $204 = "204";
-
- String $400 = "400";
- String $401 = "401";
- String $403 = "403";
- String $404 = "404";
- String $405 = "405";
- String $415 = "415";
- String $422 = "422";
-
- String $500 = "500";
-
- String REQ_SUCCESSFULLY = "Request executed successfully, returning the requested item(s)";
- String REQ_NOT_CORRECTLY = "Request is not formed correctly";
- String USER_NOT_AUTH = "User not authenticated";
- String INTERNAL_SERVER = "Internal server error, see error code and documentation for more details";
-
- String PERM_DENIED = "Permission denied for this resource";
- String HTTP_NOT_ALLOWED = "HTTP Method (GET, POST, ...) not allowed for this resource";
- String REQ_SUCC_EMPTY_RESP = "Request executed successfully, returning an empty response";
- String ITEM_NOT_FOUND = "Requested item not found, see error code and documentation for more details";
- String PERMISSION_DENIED = "Permission denied for this resource";
- String UNSUPPORTED_MEDIA_TYPE = "Unsupported Media Type";
- String VALIDATION_ERROR = "Error while validating request's content, see error code and documentation for more details";
-
-}
diff --git a/src/main/java/com/jservlet/nexus/config/web/WebFilterConfig.java b/src/main/java/com/jservlet/nexus/config/web/WebFilterConfig.java
deleted file mode 100644
index 63af2f8..0000000
--- a/src/main/java/com/jservlet/nexus/config/web/WebFilterConfig.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.jservlet.nexus.config.web;
-
-import com.github.ziplet.filter.compression.CompressingFilter;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.annotation.Order;
-import org.springframework.core.env.Environment;
-import org.springframework.lang.NonNull;
-import org.springframework.web.context.ServletContextAware;
-import org.springframework.web.filter.CommonsRequestLoggingFilter;
-import org.springframework.web.filter.ForwardedHeaderFilter;
-
-import javax.servlet.Filter;
-import javax.servlet.ServletContext;
-
-/*
- * Web Filter Chain Configuration
- */
-@Configuration
-public class WebFilterConfig implements ServletContextAware {
-
- private ServletContext servletContext;
- private final Environment env;
-
- @Value("${nexus.backend.filter.forwardedHeader.removeOnly:true}")
- private boolean forwardedHeaderRemoveOnly;
-
- public WebFilterConfig(Environment env) {
- this.env = env;
- }
-
- @Override
- public void setServletContext(@NonNull ServletContext servletContext) {
- this.servletContext = servletContext;
- }
-
- /**
- * Forwarded Header Filter, see rfc7239
- * RemoveOnly at true, discard and ignore forwarded headers
- *
- * @return Forwarded Filter Bean
- */
- @Bean
- @Order(1)
- @ConditionalOnProperty(value="nexus.backend.filter.forwardedHeader.enabled")
- public FilterRegistrationBean forwardedInfoFilter() {
- FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
- ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
- filter.setRemoveOnly(forwardedHeaderRemoveOnly);
- registrationBean.setFilter(filter);
- registrationBean.setOrder(1);
- return registrationBean;
- }
-
- /**
- * Generally use gzip for all resources !
- *
- * @return a gzip implementation (only response)
- */
- @Bean
- @Order(2)
- @ConditionalOnProperty(value="nexus.backend.filter.gzip.enabled")
- public FilterRegistrationBean gzipFilter() {
- FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
- registrationBean.setFilter(new CompressingFilter());
- registrationBean.setOrder(2);
- return registrationBean;
- }
-
-
- /**
- * The full logs request with payload!
- *
- * @return The Logging filter
- */
- @Bean
- public CommonsRequestLoggingFilter logFilter() {
- CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
- filter.setIncludeClientInfo(true);
- filter.setIncludeQueryString(true);
- filter.setIncludePayload(true);
- filter.setIncludeHeaders(true);
- filter.setHeaderPredicate(header -> !header.equalsIgnoreCase("authorization"));
- filter.setMaxPayloadLength(10000);
- filter.setBeforeMessagePrefix("INCOMING REQUEST : ");
- filter.setAfterMessagePrefix("OUTGOING REQUEST : ");
- filter.setServletContext(servletContext);
- filter.setEnvironment(env);
- return filter;
- }
-
-}
diff --git a/src/main/java/com/jservlet/nexus/config/web/WebMvcConfig.java b/src/main/java/com/jservlet/nexus/config/web/WebMvcConfig.java
deleted file mode 100644
index c677ac3..0000000
--- a/src/main/java/com/jservlet/nexus/config/web/WebMvcConfig.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package com.jservlet.nexus.config.web;
-
-import com.jservlet.nexus.shared.web.interceptor.RateLimitInterceptor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.web.server.WebServerFactoryCustomizer;
-import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
-import org.springframework.context.ResourceLoaderAware;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
-import org.springframework.core.env.Environment;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.MediaType;
-import org.springframework.lang.NonNull;
-import org.springframework.util.StringUtils;
-import org.springframework.web.multipart.MultipartResolver;
-import org.springframework.web.multipart.support.StandardServletMultipartResolver;
-import org.springframework.web.servlet.config.annotation.*;
-import org.springframework.web.servlet.view.InternalResourceViewResolver;
-
-import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
-import java.util.EnumSet;
-import java.util.Optional;
-import java.util.Properties;
-import java.util.Set;
-
-/*
- * Web Mvc Configuration
- */
-@Configuration
-@EnableWebMvc
-@Import(SwaggerConfig.class)
-public class WebMvcConfig implements WebMvcConfigurer, ResourceLoaderAware {
-
- private final static Logger logger = LoggerFactory.getLogger(WebMvcConfig.class);
- private ResourceLoader resourceLoader;
-
- private final Environment env;
- private static final String ENV_VAR = "environment";
-
- private final RateLimitInterceptor rateLimitInterceptor;
-
- public WebMvcConfig(Optional rateLimitInterceptor, Environment env) {
- this.rateLimitInterceptor = rateLimitInterceptor.orElse(null);
- this.env = env;
- }
-
- @Override
- public void setResourceLoader(@NonNull ResourceLoader resourceLoader) {
- this.resourceLoader = resourceLoader;
- }
-
- @Override
- public void addInterceptors(@NonNull InterceptorRegistry registry) {
- if (rateLimitInterceptor != null) {
- registry.addInterceptor(rateLimitInterceptor).addPathPatterns("/api/**");
- }
- }
-
- @Override
- public void configureViewResolvers(ViewResolverRegistry registry) {
- InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
- viewResolver.setPrefix("/WEB-INF/views/");
- viewResolver.setSuffix(".jsp");
- registry.viewResolver(viewResolver);
- }
-
- @Override
- public void addResourceHandlers(@NonNull ResourceHandlerRegistry registry) {
- if ("development".equals(env.getProperty(ENV_VAR))) {
- registry.addResourceHandler("/swagger-ui/**").resourceChain(false);
- }
- registry.addResourceHandler("/resources/api-ui/**").addResourceLocations("/resources/");
- registry.addResourceHandler("/static/**").addResourceLocations("/static/");
- }
-
- @Override
- public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
- configurer.enable();
- }
-
- @Value("${nexus.backend.content.negotiation.favorParameter:false}")
- private boolean favorParameter;
- @Value("${nexus.backend.content.negotiation.parameterName:mediaType}")
- private String parameterName;
-
- @Value("${nexus.backend.content.negotiation.ignoreAcceptHeader:false}")
- private boolean ignoreAcceptHeader;
-
- @Value("${nexus.backend.content.negotiation.useRegisteredExtensionsOnly:true}")
- private boolean useRegisteredExtensionsOnly;
-
- @Value("${nexus.backend.content.negotiation.commonMediaTypes:true}")
- private boolean commonMediaTypes;
-
-
- /**
- * Configure a default ContentNegotiation with a default HeaderContentNegotiationStrategy (ignoreAcceptHeader at false)
- * Force the defaultContentType by application/octet-stream
- * @see org.springframework.web.accept.ContentNegotiationManagerFactoryBean
- *
- * @param configurer The current ContentNegotiationConfigurer
- */
- @Override
- public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
- configurer // JSON Mandatory forced for Resource 404 not found from the Backend
- .defaultContentType(MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM)
- //.defaultContentTypeStrategy(new HeaderContentNegotiationStrategy())
- .favorParameter(favorParameter)
- .parameterName(parameterName)
- .ignoreAcceptHeader(ignoreAcceptHeader)
- .useRegisteredExtensionsOnly(useRegisteredExtensionsOnly)
- .mediaType("pdf", MediaType.APPLICATION_PDF); // Add pdf as safe extensions by default!
-
- if (commonMediaTypes) {
- extractedMediaTypes(configurer, "classpath:mime/MediaTypes_commons.properties");
- }
- }
-
- @SuppressWarnings("SameParameterValue")
- private void extractedMediaTypes(ContentNegotiationConfigurer configurer, String classpath) {
- Resource resource = resourceLoader.getResource(classpath);
- if (resource.exists()) {
- try {
- Properties properties = new Properties();
- properties.load(resource.getInputStream());
- properties.forEach((key, value) ->
- configurer.mediaType(key.toString(), MediaType.parseMediaType(value.toString())));
- } catch (IOException e) {
- logger.error("Failed to load '{}' media types {}", classpath, e.getMessage());
- }
- }
- }
-
-
- /**
- * Use Servlet 4 style MultipartResolver: StandardServletMultipartResolver
- * Strict Servlet compliance only multipart/form-data
- * @return the MultipartResolver,
- */
- @Bean
- public MultipartResolver multipartResolver() {
- return new StandardServletMultipartResolver() {
- private final Set SUPPORTED_METHODS = EnumSet.of(HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH);
- @Override
- public boolean isMultipart(@NonNull HttpServletRequest request) {
- if (!SUPPORTED_METHODS.contains(HttpMethod.resolve(request.getMethod()))) return false;
- return StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.MULTIPART_FORM_DATA_VALUE);
- }
- };
- }
-
- /**
- * Springboot only, WebServerFactory register Servlet (and Jsp!)
- * @return the factory
- */
- @Bean
- public WebServerFactoryCustomizer enableDefaultServlet() {
- return (factory) -> factory.setRegisterDefaultServlet(true);
- }
-
-}
diff --git a/src/main/java/com/jservlet/nexus/config/web/WebSecurityConfig.java b/src/main/java/com/jservlet/nexus/config/web/WebSecurityConfig.java
deleted file mode 100644
index 64cb839..0000000
--- a/src/main/java/com/jservlet/nexus/config/web/WebSecurityConfig.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 2001-2025 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config.web;
-
-import com.jservlet.nexus.shared.web.filter.WAFPredicate;
-import com.jservlet.nexus.shared.web.security.WebHttpFirewall;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-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.configuration.WebSecurityCustomizer;
-import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
-import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
-import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.web.SecurityFilterChain;
-import org.springframework.security.web.firewall.*;
-import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.CorsConfigurationSource;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
-
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.util.List;
-import java.util.regex.Pattern;
-
-/*
- * Web Security Configuration: HttpFirewall, FilterChain and Customizer
- */
-@Configuration
-@EnableWebSecurity //(debug = true)
-public class WebSecurityConfig {
-
- private final static Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class);
-
- private final ServletContext servletContext;
-
- @Value("${nexus.spring.web.security.debug:false}")
- private boolean webSecurityDebug;
-
- public WebSecurityConfig(ServletContext servletContext) {
- this.servletContext = servletContext;
- }
-
- // WARN no UserDetailsServiceAutoConfiguration
-
-
- /**
- * Performs some WebSecurity customizations:
- * - debug
- * - httpFirewall
- * - servletContext
- * @param webHttpFirewall The HttpFirewall
- * @return A WebSecurity customizer!
- */
- @Bean
- public WebSecurityCustomizer webSecurityCustomizer(HttpFirewall webHttpFirewall) {
- return (web) -> web.debug(webSecurityDebug).httpFirewall(webHttpFirewall)
- .setServletContext(servletContext);
- }
-
- @Value("${nexus.spring.web.security.csp.policy:default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'; object-src 'none';}")
- private String cspPolicyDirectives;
-
- @Value("${nexus.spring.web.security.hsts.maxAgeInSeconds:31536000}")
- private long maxAgeInSeconds;
- @Value("${nexus.spring.web.security.hsts.includeSubDomains:false}")
- private boolean includeSubDomains;
-
- @Value("${nexus.spring.web.security.referrer.policy:NO_REFERRER}")
- private String referrerPolicy;
-
- /**
- * SecurityFilterChain
- *
- * @param http The HttpSecurity
- * @param corsConfigurationSource The Cors config
- * @throws Exception An exception
- * @return SecurityFilterChain A WebSecurity customizer!
- */
- @Bean
- public SecurityFilterChain filterChain(HttpSecurity http, CorsConfigurationSource corsConfigurationSource) throws Exception {
- // cors config, csrf disable
- http.cors(c -> c.configurationSource(corsConfigurationSource))
- .csrf(AbstractHttpConfigurer::disable);
- // session STATELESS
- http.sessionManagement(session ->
- session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
- // authorize HttpRequests
- http.authorizeHttpRequests(auth -> auth
- .requestMatchers(
- // Use AntPathRequestMatcher for remove ambiguity with Servlet/JSP
- new AntPathRequestMatcher("/"),
- new AntPathRequestMatcher("/mock/**"),
- new AntPathRequestMatcher("/static/**"),
- new AntPathRequestMatcher("/actuator/**"),
- new AntPathRequestMatcher("/swagger-ui/index.html"),
- new AntPathRequestMatcher("/api/**"),
- new AntPathRequestMatcher("/error")
- ).permitAll()
- );
-
- // security headers
- http.headers(headers -> {
- headers.contentTypeOptions(); // X-Content-Type-Options: nosniff
- headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin); // X-Frame-Options: SAMEORIGIN
- headers.cacheControl(); // Cache-Control: no-cache, no-store, max-age=0, must-revalidate
- headers.xssProtection(); // X-XSS-Protection: 1; mode=block
- if (!cspPolicyDirectives.isEmpty()) { // Content Security Policy: default-src 'none'; frame-ancestors 'none';
- headers.contentSecurityPolicy(csp -> csp
- .policyDirectives(cspPolicyDirectives)
- );
- }
- headers.httpStrictTransportSecurity(
- hsts -> { // Strict-Transport-Security: max-age=31536000; includeSubDomains
- hsts.maxAgeInSeconds(maxAgeInSeconds);
- hsts.includeSubDomains(includeSubDomains);
- }
- );
- // Referrer-Policy: no-referrer
- headers.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.valueOf(referrerPolicy));
- });
- return http.build();
- }
-
-
- /**
- * Spring EL reads allow method delimited with a comma and splits into a List of Strings (or an empty List)
- */
- // Provide a List of HttpMethods
- @Value("#{T(java.util.Arrays).asList('${nexus.backend.security.cors.allowedHttpMethods:GET,POST,PUT,OPTION,HEAD,DELETE,PATCH}')}")
- private List allowedCorsHttpMethods;
- // Provide a Regex Patterns domains
- @Value("${nexus.backend.security.cors.allowedOriginPatterns:#{null}")
- private String allowedOriginPatterns;
- // Provide a List of domains
- @Value("#{T(java.util.Arrays).asList('${nexus.backend.security.cors.allowedOrigins:*}')}")
- private List allowedOrigins;
- // Headers: Authorization,Cache-Control,Content-Type,X-Requested-With,Accept
- @Value("#{T(java.util.Arrays).asList('${nexus.backend.security.cors.allowedHeaders:Authorization,Cache-Control,Content-Type,X-Requested-With,Accept}')}")
- private List allowedHeaders;
- // At true Origin cannot be a wildcard '*' a list of domains need to be provided.
- @Value("${nexus.backend.security.cors.credentials:false}")
- private boolean credentials;
- // Headers: Authorization
- @Value("#{T(java.util.Arrays).asList('${nexus.backend.security.cors.exposedHeaders:}')}")
- private List exposedHeaders;
- // Max age in second
- @Value("${nexus.backend.security.cors.maxAge:3600}")
- private Long maxAgeCors;
-
- /*
- * CORS Security configuration, allow Control Request by Headers
- * Access-Control-Allow-Origin: *
- * Access-Control-Allow-Methods: GET,POST,PUT,OPTION,HEAD,DELETE,PATCH
- * Access-Control-Max-Age: 3600
- * Test OPTIONS request on the local domain:
- *
- * curl -v -H "Access-Control-Request-Method: GET" -H "Origin: http://localhost:8082" -X OPTIONS http://localhost:8082/nexus-backend/api/get
- * or -H "Origin: http://localhost:4200"
- */
- @Bean
- public CorsConfigurationSource corsConfigurationSource() {
- final CorsConfiguration configuration = new CorsConfiguration();
- if (allowedOriginPatterns != null && !allowedOriginPatterns.isEmpty()) configuration.addAllowedOriginPattern(allowedOriginPatterns);
- if (allowedOrigins != null && !allowedOrigins.isEmpty()) configuration.setAllowedOrigins(allowedOrigins);
- if (allowedCorsHttpMethods != null && !allowedCorsHttpMethods.isEmpty()) configuration.setAllowedMethods(allowedCorsHttpMethods);
- // setAllowCredentials(true) is important, otherwise:
- // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
- configuration.setAllowCredentials(credentials);
- // setAllowedHeaders is important! Without it, OPTIONS preflight request will fail with 403 Invalid CORS request
- if (allowedHeaders != null && !allowedHeaders.isEmpty()) configuration.setAllowedHeaders(allowedHeaders); // "Authorization", "Cache-Control", "Content-Type"
- if (exposedHeaders != null && !exposedHeaders.isEmpty()) configuration.setExposedHeaders(exposedHeaders); // "Authorization"
- configuration.setMaxAge(maxAgeCors);
- // register source Cors pattern
- final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
- source.registerCorsConfiguration("/api/**", configuration);
- return source;
- }
-
-
- @Value("${nexus.backend.security.allowSemicolon:false}")
- public boolean isAllowSemicolon;
- @Value("${nexus.backend.security.allowUrlEncodedSlash:false}")
- public boolean isAllowUrlEncodedSlash;
- @Value("${nexus.backend.security.allowUrlEncodedDoubleSlash:false}")
- public boolean isAllowUrlEncodedDoubleSlash;
- @Value("${nexus.backend.security.allowUrlEncodedPeriod:false}")
- public boolean isAllowUrlEncodedPeriod;
- @Value("${nexus.backend.security.allowBackSlash:false}")
- public boolean isAllowBackSlash;
- @Value("${nexus.backend.security.allowNull:false}")
- public boolean isAllowNull;
- @Value("${nexus.backend.security.allowUrlEncodedPercent:false}")
- public boolean isAllowUrlEncodedPercent;
- @Value("${nexus.backend.security.allowUrlEncodedCarriageReturn:false}")
- public boolean isAllowUrlEncodedCarriageReturn;
- @Value("${nexus.backend.security.allowUrlEncodedLineFeed:false}")
- public boolean isAllowUrlEncodedLineFeed;
- @Value("${nexus.backend.security.allowUrlEncodedParagraphSeparator:false}")
- public boolean isAllowUrlEncodedParagraphSeparator;
- @Value("${nexus.backend.security.allowUrlEncodedLineSeparator:false}")
- public boolean isAllowUrlEncodedLineSeparator;
-
- /**
- * SpEL reads allow method delimited with a comma and splits into a List of Strings
- */
- @Value("#{'${nexus.backend.security.allowedHttpMethods:GET,POST,PUT,OPTIONS,HEAD,DELETE,PATCH}'.split(',')}")
- private List allowedHttpMethods;
-
- @Value("${nexus.backend.security.predicate.parameterNamesLength:255}")
- private int parameterNamesLength = 255;
- @Value("${nexus.backend.security.predicate.parameterValuesLength:1000000}")
- private int parameterValuesLength = 1000000;
- @Value("${nexus.backend.security.predicate.headerNamesLength:255}")
- private int headerNamesLength = 255;
- @Value("${nexus.backend.security.predicate.headerNamesValuesLength:25000}")
- private int headerNamesValuesLength = 25000;
- @Value("${nexus.backend.security.predicate.hostNamesLength:255}")
- private int hostNamesLength = 255;
- @Value("${nexus.backend.security.predicate.hostName.pattern:}") // "^(www\\.)?nexus\\.jservlet\\.com(:[0-9]+)?$"
- private String hostNamesPattern;
- @Value("${nexus.backend.security.predicate.userAgent.blocked:false}")
- private boolean userAgentBlocked;
- @Value("${nexus.backend.security.predicate.aiUserAgent.blocked:true}")
- private boolean aiUserAgentBlocked;
-
- @Bean
- public WAFPredicate wafPredicate() {
- WAFPredicate wafPredicate = new WAFPredicate();
- wafPredicate.setParameterNamesLength(parameterNamesLength);
- wafPredicate.setParameterValuesLength(parameterValuesLength);
- wafPredicate.setHeaderNamesLength(headerNamesLength);
- wafPredicate.setHeaderValuesLength(headerNamesValuesLength);
- wafPredicate.setHostNamesLength(hostNamesLength);
-
- if (hostNamesPattern.isEmpty()) {
- wafPredicate.setAllowedHostnames(Pattern.compile(hostNamesPattern,Pattern.CASE_INSENSITIVE | Pattern.DOTALL));
- }
-
- //
- wafPredicate.setBlockDisallowedUserAgents(userAgentBlocked);
- wafPredicate.setBlockDisallowedAIUserAgents(aiUserAgentBlocked);
-
- return wafPredicate;
- }
-
- /**
- * Web HttpFirewall, allow semicolon by example
- * @param waf WAFPredicate
- * @return HttpFirewall
- */
- @Bean
- public HttpFirewall webHttpFirewall(WAFPredicate waf) {
- WebHttpFirewall firewall = new WebHttpFirewall();
-
- firewall.setAllowedHttpMethods(allowedHttpMethods);
-
- firewall.setAllowSemicolon(isAllowSemicolon);
- firewall.setAllowUrlEncodedSlash(isAllowUrlEncodedSlash);
- firewall.setAllowUrlEncodedDoubleSlash(isAllowUrlEncodedDoubleSlash);
- firewall.setAllowUrlEncodedPeriod(isAllowUrlEncodedPeriod);
- firewall.setAllowBackSlash(isAllowBackSlash);
- firewall.setAllowNull(isAllowNull);
- firewall.setAllowUrlEncodedPercent(isAllowUrlEncodedPercent);
- firewall.setAllowUrlEncodedCarriageReturn(isAllowUrlEncodedCarriageReturn);
- firewall.setAllowUrlEncodedLineFeed(isAllowUrlEncodedLineFeed);
- firewall.setAllowUrlEncodedParagraphSeparator(isAllowUrlEncodedParagraphSeparator);
- firewall.setAllowUrlEncodedLineSeparator(isAllowUrlEncodedLineSeparator);
-
- // Predicate Parameter Name/Value
- firewall.setAllowedParameterNames(waf.getWAFParameterNames());
- firewall.setAllowedParameterValues(waf.getWAFParameterValues());
-
- // Predicate Header Name/Value
- firewall.setAllowedHeaderNames(waf.getWAFHeaderNames());
- firewall.setAllowedHeaderValues(waf.getWAFHeaderValues());
-
- // Predicate Hostnames
- firewall.setAllowedHostnames(waf.getWAFHostnames());
-
- return firewall;
- }
-
-
- /**
- * A simple implementation of {@link RequestRejectedHandler} that sends an error with configurable status code
- * @return RequestRejectedHandler
- */
- @Bean
- public RequestRejectedHandler requestRejectedHandler() {
- return new HttpStatusRequestRejectedHandler() {
- @Override
- public void handle(HttpServletRequest request, HttpServletResponse response, RequestRejectedException requestRejectedException) throws IOException {
- String message = (String) request.getAttribute("javax.servlet.error.message");
- String uri = (String) request.getAttribute("javax.servlet.error.request_uri");
- // WARN path /error can be reject cause can also contained the reject parameter..
- if (message != null && uri != null) {
- logger.error("Rejecting request due to: {} uri: {}", requestRejectedException.getMessage(), uri);
- }
- response.sendError(HttpServletResponse.SC_BAD_REQUEST, message); // msg never displayed !?
- }
- };
- }
-
-}
diff --git a/src/main/java/com/jservlet/nexus/config/web/tomcat/TomcatCustomContainer.java b/src/main/java/com/jservlet/nexus/config/web/tomcat/TomcatCustomContainer.java
deleted file mode 100644
index e215f48..0000000
--- a/src/main/java/com/jservlet/nexus/config/web/tomcat/TomcatCustomContainer.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2001-2025 JServlet.com Franck Andriano.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program. If not, see
- * .
- */
-
-package com.jservlet.nexus.config.web.tomcat;
-
-import org.apache.catalina.authenticator.BasicAuthenticator;
-import org.apache.catalina.realm.MemoryRealm;
-import org.apache.catalina.valves.ErrorReportValve;
-import org.apache.catalina.valves.ExtendedAccessLogValve;
-import org.apache.tomcat.util.descriptor.web.LoginConfig;
-import org.apache.tomcat.util.descriptor.web.SecurityCollection;
-import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
-import org.springframework.boot.web.server.WebServerFactoryCustomizer;
-import org.springframework.context.annotation.Profile;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.stereotype.Component;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
-
-/**
- * Custom Container with an Embedded Tomcat:
- * - Customizes Connector Http
- * - Extended Access Log Valve
- * - Error ReportValve
- * - Configuration ACL / Security constraint
- *
- *
- * server.xml
- *