Merge pull request #194 from apache/dependabot/maven/slf4j.version-1.7.32
Bump slf4j.version from 1.7.31 to 1.7.32
diff --git a/modules/json/src/org/apache/axis2/json/gson/JsonFormatter.java b/modules/json/src/org/apache/axis2/json/gson/JsonFormatter.java
index 776674f..6c42c44 100644
--- a/modules/json/src/org/apache/axis2/json/gson/JsonFormatter.java
+++ b/modules/json/src/org/apache/axis2/json/gson/JsonFormatter.java
@@ -101,7 +101,7 @@
try {
GsonBuilder gsonBuilder = new GsonBuilder();
// XSS protection, encode JSON Strings as HTML
- gsonBuilder.registerTypeAdapter(String.class, new JsonHtmlXssSerializer());
+ gsonBuilder.registerTypeAdapter(String.class, new JsonHtmlEncoder());
Gson gson = gsonBuilder.create();
jsonWriter.beginObject();
jsonWriter.name(JsonConstant.RESPONSE);
diff --git a/modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java b/modules/json/src/org/apache/axis2/json/gson/JsonHtmlEncoder.java
similarity index 94%
rename from modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java
rename to modules/json/src/org/apache/axis2/json/gson/JsonHtmlEncoder.java
index 619c1ae..0b76443 100644
--- a/modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java
+++ b/modules/json/src/org/apache/axis2/json/gson/JsonHtmlEncoder.java
@@ -27,7 +27,7 @@
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
-public class JsonHtmlXssSerializer implements JsonSerializer<String> {
+public class JsonHtmlEncoder implements JsonSerializer<String> {
@Override
public JsonElement serialize(String src, Type typeOfSrc,
diff --git a/modules/json/src/org/apache/axis2/json/moshi/JsonFormatter.java b/modules/json/src/org/apache/axis2/json/moshi/JsonFormatter.java
index 941451e..1936873 100644
--- a/modules/json/src/org/apache/axis2/json/moshi/JsonFormatter.java
+++ b/modules/json/src/org/apache/axis2/json/moshi/JsonFormatter.java
@@ -60,7 +60,7 @@
String msg;
try {
- Moshi moshi = new Moshi.Builder().add(String.class, new JsonHtmlXssSerializer()).add(Date.class, new Rfc3339DateJsonAdapter()).build();
+ Moshi moshi = new Moshi.Builder().add(String.class, new JsonHtmlEncoder()).add(Date.class, new Rfc3339DateJsonAdapter()).build();
JsonAdapter<Object> adapter = moshi.adapter(Object.class);
BufferedSink sink = Okio.buffer(Okio.sink(outputStream));
jsonWriter = JsonWriter.of(sink);
diff --git a/modules/json/src/org/apache/axis2/json/moshi/JsonHtmlXssSerializer.java b/modules/json/src/org/apache/axis2/json/moshi/JsonHtmlEncoder.java
similarity index 95%
rename from modules/json/src/org/apache/axis2/json/moshi/JsonHtmlXssSerializer.java
rename to modules/json/src/org/apache/axis2/json/moshi/JsonHtmlEncoder.java
index 241a96e..3a7c906 100644
--- a/modules/json/src/org/apache/axis2/json/moshi/JsonHtmlXssSerializer.java
+++ b/modules/json/src/org/apache/axis2/json/moshi/JsonHtmlEncoder.java
@@ -26,7 +26,7 @@
import org.owasp.encoder.Encode;
-public final class JsonHtmlXssSerializer extends JsonAdapter<String> {
+public final class JsonHtmlEncoder extends JsonAdapter<String> {
@Override
public synchronized String fromJson(JsonReader reader) throws IOException {
diff --git a/modules/samples/userguide/README.txt b/modules/samples/userguide/README.txt
index 0a38736..cf4d8d1 100644
--- a/modules/samples/userguide/README.txt
+++ b/modules/samples/userguide/README.txt
@@ -8,6 +8,9 @@
The sample explains how to write a Web service and Web service client with
Apache Axis2 using XML based client APIs (Axis2's Primary APIs).
+For new applications, json-springboot-userguide.html brings Axis2 into
+modern API's and contemporary servers.
+
Introduction
============
@@ -41,7 +44,7 @@
Pre-Requisites
==============
-Apache Ant 1.6.2 or later
+Apache Ant 1.8.0 or later
Building the Service
====================
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/pom.xml b/modules/samples/userguide/src/userguide/springbootdemo/pom.xml
new file mode 100644
index 0000000..731fdec
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/pom.xml
@@ -0,0 +1,405 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>userguide.springboot</groupId>
+ <artifactId>axis2-json-api</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>war</packaging>
+ <name>axis2-json-api</name>
+ <description>Spring Boot with Axis2 demo</description>
+
+ <parent>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-parent</artifactId>
+ <version>2.5.2</version>
+ <relativePath/> <!-- lookup parent from repository -->
+ </parent>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <java.version>1.8</java.version>
+ <spring-boot.version>2.5.2</spring-boot.version>
+ <forceHttps>false</forceHttps>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <!-- Required in this userguide for
+ org.springframework.dao.DataAccessException
+ -->
+ <artifactId>spring-boot-starter-data-jpa</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>com.zaxxer</groupId>
+ <artifactId>HikariCP</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.12.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.mail</groupId>
+ <artifactId>jakarta.mail</artifactId>
+ <version>1.6.7</version>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.activation</groupId>
+ <artifactId>jakarta.activation-api</artifactId>
+ <version>1.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jaxb</groupId>
+ <artifactId>jaxb-runtime</artifactId>
+ <version>2.3.4</version>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.xml.bind</groupId>
+ <artifactId>jakarta.xml.bind-api</artifactId>
+ <version>2.3.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-log4j2</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-jul</artifactId>
+ <version>2.14.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-devtools</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-collections4</artifactId>
+ <version>4.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-configuration-processor</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-validation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-logging</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>3.1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ <version>2.5.2</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.11.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.15</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.6</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-validator</groupId>
+ <artifactId>commons-validator</artifactId>
+ <version>1.7</version>
+ </dependency>
+ <!-- axis2 -->
+ <dependency>
+ <groupId>commons-fileupload</groupId>
+ <artifactId>commons-fileupload</artifactId>
+ <version>1.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-ws-metadata_2.0_spec</artifactId>
+ <version>1.1.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jaxws_2.2_spec</artifactId>
+ <version>1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.axis2</groupId>
+ <artifactId>axis2-kernel</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.axis2</groupId>
+ <artifactId>axis2-transport-http</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.axis2</groupId>
+ <artifactId>axis2-transport-local</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.axis2</groupId>
+ <artifactId>axis2-json</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.axis2</groupId>
+ <artifactId>axis2-ant-plugin</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.axis2</groupId>
+ <artifactId>axis2-adb</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.axis2</groupId>
+ <artifactId>axis2-java2wsdl</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.axis2</groupId>
+ <artifactId>axis2-metadata</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.axis2</groupId>
+ <artifactId>axis2-spring</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.axis2</groupId>
+ <artifactId>axis2-jaxws</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.neethi</groupId>
+ <artifactId>neethi</artifactId>
+ <version>3.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>wsdl4j</groupId>
+ <artifactId>wsdl4j</artifactId>
+ <version>1.6.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.woodstox</groupId>
+ <artifactId>woodstox-core-asl</artifactId>
+ <version>4.4.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ws.xmlschema</groupId>
+ <artifactId>xmlschema-core</artifactId>
+ <version>2.2.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.woodstox</groupId>
+ <artifactId>stax2-api</artifactId>
+ <version>4.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>jaxen</groupId>
+ <artifactId>jaxen</artifactId>
+ <version>1.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.woden</groupId>
+ <artifactId>woden-core</artifactId>
+ <version>1.0M10</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ws.commons.axiom</groupId>
+ <artifactId>axiom-api</artifactId>
+ <version>1.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ws.commons.axiom</groupId>
+ <artifactId>axiom-dom</artifactId>
+ <version>1.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ws.commons.axiom</groupId>
+ <artifactId>axiom-impl</artifactId>
+ <version>1.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.owasp.esapi</groupId>
+ <artifactId>esapi</artifactId>
+ <version>2.2.3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.5.13</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore</artifactId>
+ <version>4.4.13</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>3.2.0</version>
+ <executions>
+ <execution>
+ <id>unpack</id>
+ <phase>package</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>userguide.springboot</groupId>
+ <artifactId>axis2-json-api</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <type>war</type>
+ <overWrite>false</overWrite>
+ <outputDirectory>${project.build.directory}/deploy/axis2-json-api.war</outputDirectory>
+ <includes>**/*.class,**/*.xml</includes>
+ <excludes>**/*test.class</excludes>
+ </artifactItem>
+ </artifactItems>
+ <includes>**/*.java</includes>
+ <excludes>**/*.properties</excludes>
+ <overWriteReleases>true</overWriteReleases>
+ <overWriteSnapshots>true</overWriteSnapshots>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>install</id>
+ <phase>install</phase>
+ <configuration>
+ <tasks>
+ <!-- used for local deploys, ignored otherwise -->
+ <touch file="target/deploy/axis2-json-api.war.dodeploy">
+ </touch>
+ <jar jarfile="${project.build.directory}/deploy/axis2-json-api.war/WEB-INF/services/Login.aar">
+ <metainf file="resources-axis2/login_resources/services.xml"/>
+ </jar>
+ <jar jarfile="${project.build.directory}/deploy/axis2-json-api.war/WEB-INF/services/testws.aar">
+ <metainf file="resources-axis2/test_service_resources/services.xml"/>
+ </jar>
+ <copy todir="${project.build.directory}/deploy/axis2-json-api.war/WEB-INF/conf">
+ <fileset dir="resources-axis2/conf">
+ <include name="axis2.xml"/>
+ </fileset>
+ </copy>
+ <unzip src="${project.build.directory}/axis2-json-api-0.0.1-SNAPSHOT.war" dest="${project.build.directory}/exploded"/>
+ <jar jarfile="${project.build.directory}/exploded/WEB-INF/services/Login.aar">
+ <metainf file="resources-axis2/login_resources/services.xml"/>
+ </jar>
+ <jar jarfile="${project.build.directory}/exploded/WEB-INF/services/testws.aar">
+ <metainf file="resources-axis2/test_service_resources/services.xml"/>
+ </jar>
+ <copy todir="${project.build.directory}/exploded/WEB-INF/conf">
+ <fileset dir="resources-axis2/conf">
+ <include name="axis2.xml"/>
+ </fileset>
+ </copy>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <version>3.3.1</version>
+ <configuration>
+ <webResources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <includes>
+ <include>**/*.xml</include>
+ <include>**/application.properties</include>
+ </includes>
+ <targetPath>WEB-INF/classes</targetPath>
+ <filtering>true</filtering>
+ </resource>
+ </webResources>
+ <webappDirectory>${project.build.directory}/deploy/axis2-json-api.war</webappDirectory>
+ </configuration>
+ <executions>
+ <execution>
+ <id>enforce-java</id>
+ <goals>
+ <goal>exploded</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+
+ </build>
+
+</project>
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/conf/axis2.xml b/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/conf/axis2.xml
new file mode 100644
index 0000000..dd06722
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/conf/axis2.xml
@@ -0,0 +1,539 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<axisconfig name="AxisJava2.0">
+ <!-- ================================================= -->
+ <!-- Parameters -->
+ <!-- ================================================= -->
+ <parameter name="hotdeployment">true</parameter>
+ <parameter name="hotupdate">false</parameter>
+ <parameter name="enableMTOM">false</parameter>
+ <parameter name="enableSwA">false</parameter>
+
+ <!--Uncomment if you want to enable file caching for attachments -->
+ <!--parameter name="cacheAttachments">true</parameter>
+ <parameter name="attachmentDIR"></parameter>
+ <parameter name="sizeThreshold">4000</parameter-->
+
+ <parameter name="EnableChildFirstClassLoading">false</parameter>
+
+ <!--
+ The exposeServiceMetadata parameter decides whether the metadata (WSDL, schema, policy) of
+ the services deployed on Axis2 should be visible when ?wsdl, ?wsdl2, ?xsd, ?policy requests
+ are received.
+ This parameter can be defined in the axi2.xml file, in which case this will be applicable
+ globally, or in the services.xml files, in which case, it will be applicable to the
+ Service groups and/or services, depending on the level at which the parameter is declared.
+ This value of this parameter defaults to true.
+ -->
+ <parameter name="exposeServiceMetadata">true</parameter>
+
+
+ <!--Uncomment if you want to plugin your own attachments lifecycle implementation -->
+ <!--<attachmentsLifecycleManager class="org.apache.axiom.attachments.lifecycle.impl.LifecycleManagerImpl"/>-->
+
+
+ <!--Uncomment if you want to enable the reduction of the in-memory cache of WSDL definitions -->
+ <!--In some server environments, the available memory heap is limited and can fill up under load -->
+ <!--Since in-memory copies of WSDL definitions can be large, some steps can be taken-->
+ <!--to reduce the memory needed for the cached WSDL definitions. -->
+ <!--parameter name="reduceWSDLMemoryCache">true</parameter-->
+
+ <!--This will give out the timout of the configuration contexts, in milliseconds-->
+ <parameter name="ConfigContextTimeoutInterval">30000</parameter>
+
+ <!--During a fault, stack trace can be sent with the fault message. The following flag will control -->
+ <!--that behavior.-->
+ <parameter name="sendStacktraceDetailsWithFaults">false</parameter>
+
+ <!--If there aren't any information available to find out the fault reason, we set the message of the exception-->
+ <!--as the faultreason/Reason. But when a fault is thrown from a service or some where, it will be -->
+ <!--wrapped by different levels. Due to this the initial exception message can be lost. If this flag-->
+ <!--is set, then Axis2 tries to get the first exception and set its message as the faultreason/Reason.-->
+ <parameter name="DrillDownToRootCauseForFaultReason">false</parameter>
+
+ <parameter name="userName">admin</parameter>
+ <parameter name="password">axis2</parameter>
+
+ <!--To override repository/services you need to uncomment following parameter and value SHOULD be absolute file path.-->
+ <!--ServicesDirectory only works on the following cases-->
+ <!---File based configurator and in that case the value should be a file URL (http:// not allowed)-->
+ <!---When creating URL Based configurator with URL file:// -->
+ <!--- War based configurator with expanded case , -->
+
+ <!--All the other scenarios it will be ignored.-->
+ <!--<parameter name="ServicesDirectory">service</parameter>-->
+ <!--To override repository/modules you need to uncomment following parameter and value SHOULD be absolute file path-->
+ <!--<parameter name="ModulesDirectory">modules</parameter>-->
+
+
+ <!--Following params will set the proper context paths for invocations. All the endpoints will have a commons context-->
+ <!--root which can configured using the following contextRoot parameter-->
+ <!--<parameter name="contextRoot">axis2</parameter>-->
+
+ <!--Our HTTP endpoints can handle both REST and SOAP. Following parameters can be used to distinguiush those endpoints-->
+ <!--In case of a servlet, if you change this you have to manually change the settings of your servlet container to map this -->
+ <!--context path to proper Axis2 servlets-->
+ <!--<parameter name="servicePath">services</parameter>-->
+ <!--<parameter name="restPath">rest</parameter>-->
+
+ <!-- Following parameter will completely disable REST handling in Axis2-->
+ <parameter name="disableREST" locked="false">false</parameter>
+
+ <!-- Following parameter will suppress generation of SOAP 1.2 bindings in auto-generated WSDL files -->
+ <parameter name="disableSOAP12" locked="true">false</parameter>
+
+ <!-- ================================================= -->
+ <!-- Deployers -->
+ <!-- ================================================= -->
+
+ <!--Service deployer , this will alow users to deploy AAR or exploded AAR as axis2 services-->
+ <deployer extension=".aar" directory="services" class="org.apache.axis2.deployment.ServiceDeployer">
+ <serviceBuilderExtension name ="jwsbuilderExt" class="org.apache.axis2.jaxws.framework.JAXWSServiceBuilderExtension"/>
+ <serviceBuilderExtension name ="wsdlbuilderExt" class="org.apache.axis2.deployment.WSDLServiceBuilderExtension"/>
+ </deployer>
+
+ <!--POJO deployer , this will alow users to drop .class file and make that into a service-->
+ <deployer extension=".class" directory="pojo" class="org.apache.axis2.deployment.POJODeployer"/>
+ <deployer extension=".jar" directory="servicejars"
+ class="org.apache.axis2.jaxws.framework.JAXWSDeployer"/>
+ <deployer extension=".jar" directory="transports"
+ class="org.apache.axis2.deployment.TransportDeployer"/>
+
+ <!--CORBA deployer , this will alow users to invoke remote CORBA services through Axis2-->
+ <!--<deployer extension=".xml" directory="corba" class="org.apache.axis2.corba.deployer.CorbaDeployer"/>-->
+
+ <!--<deployer extension=".jsa" directory="rmiservices" class="org.apache.axis2.rmi.deploy.RMIServiceDeployer"/>-->
+
+
+ <!-- Following parameter will set the host name for the epr-->
+ <!--<parameter name="hostname" locked="true">myhost.com</parameter>-->
+
+ <!-- If you have a front end host which exposes this webservice using a different public URL -->
+ <!-- use this parameter to override autodetected url -->
+ <!--<parameter name="httpFrontendHostUrl">https://someotherhost/context</parameter>-->
+
+ <!--By default, JAXWS services are created by reading annotations. WSDL and schema are generated-->
+ <!--using a separate WSDL generator only when ?wsdl is called. Therefore, even if you engage-->
+ <!--policies etc.. to AxisService, it doesn't appear in the WSDL. By setting the following property-->
+ <!--to true, you can create the AxisService using the generated WSDL and remove the need for a-->
+ <!--WSDL generator. When ?wsdl is called, WSDL is generated in the normal way.-->
+ <parameter name="useGeneratedWSDLinJAXWS">false</parameter>
+
+ <!-- The way of adding listener to the system-->
+ <!-- <listener class="org.apache.axis2.ObserverIMPL">-->
+ <!-- <parameter name="RSS_URL">http://127.0.0.1/rss</parameter>-->
+ <!-- </listener>-->
+
+ <threadContextMigrators>
+ <threadContextMigrator listId="JAXWS-ThreadContextMigrator-List"
+ class="org.apache.axis2.jaxws.addressing.migrator.EndpointContextMapMigrator"/>
+ </threadContextMigrators>
+
+ <!-- ================================================= -->
+ <!-- Message Receivers -->
+ <!-- ================================================= -->
+ <!--This is the default MessageReceiver for the system , if you want to have MessageReceivers for -->
+ <!--all the other MEP implement it and add the correct entry to here , so that you can refer from-->
+ <!--any operation -->
+ <!--Note : You can override this for a particular service by adding the same element with your requirement-->
+ <messageReceivers>
+ <messageReceiver mep="http://www.w3.org/ns/wsdl/in-out"
+ class="org.apache.axis2.json.moshi.rpc.JsonRpcMessageReceiver" />
+ <messageReceiver mep="http://www.w3.org/ns/wsdl/in-only"
+ class="org.apache.axis2.json.moshi.rpc.JsonInOnlyRPCMessageReceiver"/>
+ </messageReceivers>
+
+ <!-- ================================================= -->
+ <!-- Message Formatter -->
+ <!-- ================================================= -->
+ <!--Following content type to message formatter mapping can be used to implement support for different message -->
+ <!--format serialization in Axis2. These message formats are expected to be resolved based on the content type. -->
+ <messageFormatters>
+ <messageFormatter contentType="application/x-www-form-urlencoded"
+ class="org.apache.axis2.transport.http.XFormURLEncodedFormatter"/>
+ <messageFormatter contentType="multipart/form-data"
+ class="org.apache.axis2.transport.http.MultipartFormDataFormatter"/>
+ <messageFormatter contentType="application/xml"
+ class="org.apache.axis2.transport.http.ApplicationXMLFormatter"/>
+ <messageFormatter contentType="text/xml"
+ class="org.apache.axis2.transport.http.SOAPMessageFormatter"/>
+ <messageFormatter contentType="application/soap+xml"
+ class="org.apache.axis2.transport.http.SOAPMessageFormatter"/>
+ <messageFormatter contentType="application/json"
+ class="org.apache.axis2.json.moshi.JsonFormatter"/>
+ </messageFormatters>
+
+ <!-- ================================================= -->
+ <!-- Message Builders -->
+ <!-- ================================================= -->
+ <!--Following content type to builder mapping can be used to implement support for different message -->
+ <!--formats in Axis2. These message formats are expected to be resolved based on the content type. -->
+ <messageBuilders>
+ <messageBuilder contentType="application/xml"
+ class="org.apache.axis2.builder.ApplicationXMLBuilder"/>
+ <messageBuilder contentType="application/x-www-form-urlencoded"
+ class="org.apache.axis2.builder.XFormURLEncodedBuilder"/>
+ <messageBuilder contentType="multipart/form-data"
+ class="org.apache.axis2.builder.MultipartFormDataBuilder"/>
+ <messageBuilder contentType="application/json"
+ class="org.apache.axis2.json.moshi.JsonBuilder"/>
+ </messageBuilders>
+
+ <!-- ================================================= -->
+ <!-- Transport Ins -->
+ <!-- ================================================= -->
+ <transportReceiver name="http"
+ class="org.apache.axis2.transport.http.SimpleHTTPServer">
+ <parameter name="port">8080</parameter>
+ <!-- Here is the complete list of supported parameters (see example settings further below):
+ port: the port to listen on (default 6060)
+ hostname: if non-null, url prefix used in reply-to endpoint references (default null)
+ originServer: value of http Server header in outgoing messages (default "Simple-Server/1.1")
+ requestTimeout: value in millis of time that requests can wait for data (default 20000)
+ requestTcpNoDelay: true to maximize performance and minimize latency (default true)
+ false to minimize bandwidth consumption by combining segments
+ requestCoreThreadPoolSize: number of threads available for request processing (unless queue fills up) (default 25)
+ requestMaxThreadPoolSize: number of threads available for request processing if queue fills up (default 150)
+ note that default queue never fills up: see HttpFactory
+ threadKeepAliveTime: time to keep threads in excess of core size alive while inactive (default 180)
+ note that no such threads can exist with default unbounded request queue
+ threadKeepAliveTimeUnit: TimeUnit of value in threadKeepAliveTime (default SECONDS) (default SECONDS)
+ -->
+ <!-- <parameter name="hostname">http://www.myApp.com/ws</parameter> -->
+ <!-- <parameter name="originServer">My-Server/1.1</parameter> -->
+ <!-- <parameter name="requestTimeout">10000</parameter> -->
+ <!-- <parameter name="requestTcpNoDelay">false</parameter> -->
+ <!-- <parameter name="requestCoreThreadPoolSize">50</parameter> -->
+ <!-- <parameter name="requestMaxThreadPoolSize">100</parameter> -->
+ <!-- <parameter name="threadKeepAliveTime">240000</parameter> -->
+ <!-- <parameter name="threadKeepAliveTimeUnit">MILLISECONDS</parameter> -->
+ </transportReceiver>
+
+ <!-- This is where you'd put custom transports. See the transports project -->
+ <!-- for more. http://ws.apache.org/commons/transport -->
+
+ <!-- ================================================= -->
+ <!-- Transport Outs -->
+ <!-- ================================================= -->
+
+ <transportSender name="local"
+ class="org.apache.axis2.transport.local.LocalTransportSender"/>
+ <transportSender name="http"
+ class="org.apache.axis2.transport.http.impl.httpclient4.HTTPClient4TransportSender">
+ <parameter name="PROTOCOL">HTTP/1.1</parameter>
+ <parameter name="Transfer-Encoding">chunked</parameter>
+
+ <!-- If following is set to 'true', optional action part of the Content-Type will not be added to the SOAP 1.2 messages -->
+ <!-- <parameter name="OmitSOAP12Action">true</parameter> -->
+ </transportSender>
+
+ <transportSender name="https"
+ class="org.apache.axis2.transport.http.impl.httpclient4.HTTPClient4TransportSender">
+ <parameter name="PROTOCOL">HTTP/1.1</parameter>
+ <parameter name="Transfer-Encoding">chunked</parameter>
+ </transportSender>
+
+ <!-- Please enable this if you need the java transport -->
+ <!-- <transportSender name="java"
+ class="org.apache.axis2.transport.java.JavaTransportSender"/> -->
+
+ <!-- ================================================= -->
+ <!-- Global Modules -->
+ <!-- ================================================= -->
+ <!-- Comment this to disable Addressing -->
+ <!-- commented out for the Axis2 spring boot demo that uses JSON -->
+ <!-- <module ref="addressing"/> -->
+
+ <!--Configuring module , providing parameters for modules whether they refer or not-->
+ <!--<moduleConfig name="addressing">-->
+ <!--<parameter name="addressingPara">N/A</parameter>-->
+ <!--</moduleConfig>-->
+
+ <!-- ================================================= -->
+ <!-- Clustering -->
+ <!-- ================================================= -->
+ <!--
+ To enable clustering for this node, set the value of "enable" attribute of the "clustering"
+ element to "true". The initialization of a node in the cluster is handled by the class
+ corresponding to the "class" attribute of the "clustering" element. It is also responsible for
+ getting this node to join the cluster.
+ -->
+ <clustering class="org.apache.axis2.clustering.tribes.TribesClusteringAgent" enable="false">
+
+ <!--
+ This parameter indicates whether the cluster has to be automatically initalized
+ when the AxisConfiguration is built. If set to "true" the initialization will not be
+ done at that stage, and some other party will have to explictly initialize the cluster.
+ -->
+ <parameter name="AvoidInitiation">true</parameter>
+
+ <!--
+ The membership scheme used in this setup. The only values supported at the moment are
+ "multicast" and "wka"
+
+ 1. multicast - membership is automatically discovered using multicasting
+ 2. wka - Well-Known Address based multicasting. Membership is discovered with the help
+ of one or more nodes running at a Well-Known Address. New members joining a
+ cluster will first connect to a well-known node, register with the well-known node
+ and get the membership list from it. When new members join, one of the well-known
+ nodes will notify the others in the group. When a member leaves the cluster or
+ is deemed to have left the cluster, it will be detected by the Group Membership
+ Service (GMS) using a TCP ping mechanism.
+ -->
+ <parameter name="membershipScheme">multicast</parameter>
+
+ <!--
+ The clustering domain/group. Nodes in the same group will belong to the same multicast
+ domain. There will not be interference between nodes in different groups.
+ -->
+ <parameter name="domain">wso2.carbon.domain</parameter>
+
+ <!--
+ When a Web service request is received, and processed, before the response is sent to the
+ client, should we update the states of all members in the cluster? If the value of
+ this parameter is set to "true", the response to the client will be sent only after
+ all the members have been updated. Obviously, this can be time consuming. In some cases,
+ such this overhead may not be acceptable, in which case the value of this parameter
+ should be set to "false"
+ -->
+ <parameter name="synchronizeAll">true</parameter>
+
+ <!--
+ The maximum number of times we need to retry to send a message to a particular node
+ before giving up and considering that node to be faulty
+ -->
+ <parameter name="maxRetries">10</parameter>
+
+ <!-- The multicast address to be used -->
+ <parameter name="mcastAddress">228.0.0.4</parameter>
+
+ <!-- The multicast port to be used -->
+ <parameter name="mcastPort">45564</parameter>
+
+ <!-- The frequency of sending membership multicast messages (in ms) -->
+ <parameter name="mcastFrequency">500</parameter>
+
+ <!-- The time interval within which if a member does not respond, the member will be
+ deemed to have left the group (in ms)
+ -->
+ <parameter name="memberDropTime">3000</parameter>
+
+ <!--
+ The IP address of the network interface to which the multicasting has to be bound to.
+ Multicasting would be done using this interface.
+ -->
+ <parameter name="mcastBindAddress">127.0.0.1</parameter>
+
+ <!-- The host name or IP address of this member -->
+ <parameter name="localMemberHost">127.0.0.1</parameter>
+
+ <!--
+ The TCP port used by this member. This is the port through which other nodes will
+ contact this member
+ -->
+ <parameter name="localMemberPort">4000</parameter>
+
+ <!--
+ Preserve message ordering. This will be done according to sender order.
+ -->
+ <parameter name="preserveMessageOrder">true</parameter>
+
+ <!--
+ Maintain atmost-once message processing semantics
+ -->
+ <parameter name="atmostOnceMessageSemantics">true</parameter>
+
+ <!--
+ Properties specific to this member
+ -->
+ <parameter name="properties">
+ <property name="backendServerURL" value="https://${hostName}:${httpsPort}/services/"/>
+ <property name="mgtConsoleURL" value="https://${hostName}:${httpsPort}/"/>
+ </parameter>
+
+ <!--
+ The list of static or well-known members. These entries will only be valid if the
+ "membershipScheme" above is set to "wka"
+ -->
+ <members>
+ <member>
+ <hostName>127.0.0.1</hostName>
+ <port>4000</port>
+ </member>
+ <member>
+ <hostName>127.0.0.1</hostName>
+ <port>4001</port>
+ </member>
+ </members>
+
+ <!--
+ Enable the groupManagement entry if you need to run this node as a cluster manager.
+ Multiple application domains with different GroupManagementAgent implementations
+ can be defined in this section.
+ -->
+ <groupManagement enable="false">
+ <applicationDomain name="apache.axis2.application.domain"
+ description="Axis2 group"
+ agent="org.apache.axis2.clustering.management.DefaultGroupManagementAgent"/>
+ </groupManagement>
+
+ <!--
+ This interface is responsible for handling management of a specific node in the cluster
+ The "enable" attribute indicates whether Node management has been enabled
+ -->
+ <nodeManager class="org.apache.axis2.clustering.management.DefaultNodeManager"
+ enable="true"/>
+
+ <!--
+ This interface is responsible for handling state replication. The property changes in
+ the Axis2 context hierarchy in this node, are propagated to all other nodes in the cluster.
+
+ The "excludes" patterns can be used to specify the prefixes (e.g. local_*) or
+ suffixes (e.g. *_local) of the properties to be excluded from replication. The pattern
+ "*" indicates that all properties in a particular context should not be replicated.
+
+ The "enable" attribute indicates whether context replication has been enabled
+ -->
+ <stateManager class="org.apache.axis2.clustering.state.DefaultStateManager"
+ enable="true">
+ <replication>
+ <defaults>
+ <exclude name="local_*"/>
+ <exclude name="LOCAL_*"/>
+ </defaults>
+ <context class="org.apache.axis2.context.ConfigurationContext">
+ <exclude name="local_*"/>
+ </context>
+ <context class="org.apache.axis2.context.ServiceGroupContext">
+ <exclude name="local_*"/>
+ </context>
+ <context class="org.apache.axis2.context.ServiceContext">
+ <exclude name="local_*"/>
+ </context>
+ </replication>
+ </stateManager>
+ </clustering>
+
+ <!-- ================================================= -->
+ <!-- Phases -->
+ <!-- ================================================= -->
+ <phaseOrder type="InFlow">
+ <!-- System predefined phases -->
+ <phase name="Transport">
+ <handler name="RequestURIBasedDispatcher"
+ class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher">
+ <order phase="Transport"/>
+ </handler>
+ <handler name="SOAPActionBasedDispatcher"
+ class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher">
+ <order phase="Transport"/>
+ </handler>
+ <handler name="JSONMessageHandler"
+ class="org.apache.axis2.json.moshi.JSONMessageHandler">
+ <order phase="Transport"/>
+ </handler>
+ </phase>
+ <phase name="Addressing">
+ <handler name="AddressingBasedDispatcher"
+ class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
+ <order phase="Addressing"/>
+ </handler>
+ </phase>
+ <phase name="Security"/>
+ <phase name="PreDispatch"/>
+ <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
+ <handler name="RequestURIBasedDispatcher"
+ class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
+ <handler name="SOAPActionBasedDispatcher"
+ class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
+ <handler name="RequestURIOperationDispatcher"
+ class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
+ <handler name="SOAPMessageBodyBasedDispatcher"
+ class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
+ <handler name="HTTPLocationBasedDispatcher"
+ class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
+ <handler name="GenericProviderDispatcher"
+ class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
+ <handler name="MustUnderstandValidationDispatcher"
+ class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
+ </phase>
+ <phase name="RMPhase"/>
+ <!-- System predefined phases -->
+ <!-- After Postdispatch phase module author or service author can add any phase he want -->
+ <phase name="OperationInPhase">
+ <handler name="MustUnderstandChecker"
+ class="org.apache.axis2.jaxws.dispatchers.MustUnderstandChecker">
+ <order phase="OperationInPhase"/>
+ </handler>
+ </phase>
+ <phase name="soapmonitorPhase"/>
+ </phaseOrder>
+ <phaseOrder type="OutFlow">
+ <!-- user can add his own phases to this area -->
+ <phase name="soapmonitorPhase"/>
+ <phase name="OperationOutPhase"/>
+ <!--system predefined phase-->
+ <!--these phase will run irrespective of the service-->
+ <phase name="RMPhase"/>
+ <phase name="PolicyDetermination"/>
+ <phase name="MessageOut"/>
+ <phase name="Security"/>
+ </phaseOrder>
+ <phaseOrder type="InFaultFlow">
+ <phase name="Addressing">
+ <handler name="AddressingBasedDispatcher"
+ class="org.apache.axis2.dispatchers.AddressingBasedDispatcher">
+ <order phase="Addressing"/>
+ </handler>
+ </phase>
+ <phase name="Security"/>
+ <phase name="PreDispatch"/>
+ <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">
+ <handler name="RequestURIBasedDispatcher"
+ class="org.apache.axis2.dispatchers.RequestURIBasedDispatcher"/>
+ <handler name="SOAPActionBasedDispatcher"
+ class="org.apache.axis2.dispatchers.SOAPActionBasedDispatcher"/>
+ <handler name="RequestURIOperationDispatcher"
+ class="org.apache.axis2.dispatchers.RequestURIOperationDispatcher"/>
+ <handler name="SOAPMessageBodyBasedDispatcher"
+ class="org.apache.axis2.dispatchers.SOAPMessageBodyBasedDispatcher"/>
+ <handler name="HTTPLocationBasedDispatcher"
+ class="org.apache.axis2.dispatchers.HTTPLocationBasedDispatcher"/>
+ <handler name="GenericProviderDispatcher"
+ class="org.apache.axis2.jaxws.dispatchers.GenericProviderDispatcher"/>
+ <handler name="MustUnderstandValidationDispatcher"
+ class="org.apache.axis2.jaxws.dispatchers.MustUnderstandValidationDispatcher"/>
+ </phase>
+ <phase name="RMPhase"/>
+ <!-- user can add his own phases to this area -->
+ <phase name="OperationInFaultPhase"/>
+ <phase name="soapmonitorPhase"/>
+ </phaseOrder>
+ <phaseOrder type="OutFaultFlow">
+ <!-- user can add his own phases to this area -->
+ <phase name="soapmonitorPhase"/>
+ <phase name="OperationOutFaultPhase"/>
+ <phase name="RMPhase"/>
+ <phase name="PolicyDetermination"/>
+ <phase name="MessageOut"/>
+ <phase name="Security"/>
+ </phaseOrder>
+</axisconfig>
+
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/login_resources/services.xml b/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/login_resources/services.xml
new file mode 100755
index 0000000..64812c7
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/login_resources/services.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<service name="loginService">
+ <description>
+ Login Resources
+ </description>
+ <parameter name="ServiceObjectSupplier">org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier</parameter>
+ <parameter name="SpringBeanName">loginService</parameter>
+ <operation name="doLogin">
+ <messageReceivers>
+ <messageReceiver mep="http://www.w3.org/ns/wsdl/in-out"
+ class="org.apache.axis2.json.moshi.rpc.JsonRpcMessageReceiver" />
+ <messageReceiver mep="http://www.w3.org/ns/wsdl/in-only"
+ class="org.apache.axis2.json.moshi.rpc.JsonInOnlyRPCMessageReceiver"/>
+ </messageReceivers>
+ </operation>
+</service>
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/test_service_resources/services.xml b/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/test_service_resources/services.xml
new file mode 100755
index 0000000..6a202ff
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/test_service_resources/services.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<service name="testws">
+ <description>
+ testws Resources
+ </description>
+ <parameter name="ServiceObjectSupplier">org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier</parameter>
+ <parameter name="SpringBeanName">testwsService</parameter>
+ <operation name="doTestws">
+ <messageReceivers>
+ <messageReceiver mep="http://www.w3.org/ns/wsdl/in-out"
+ class="org.apache.axis2.json.moshi.rpc.JsonRpcMessageReceiver" />
+ <messageReceiver mep="http://www.w3.org/ns/wsdl/in-only"
+ class="org.apache.axis2.json.moshi.rpc.JsonInOnlyRPCMessageReceiver"/>
+ </messageReceivers>
+ </operation>
+</service>
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java
new file mode 100644
index 0000000..7aefd00
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/Axis2Application.java
@@ -0,0 +1,468 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.Filter;
+
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.util.*;
+
+import org.springframework.context.annotation.Bean;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.security.access.AccessDecisionManager;
+import org.springframework.security.access.AccessDecisionVoter;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.access.vote.AffirmativeBased;
+import org.springframework.security.access.vote.RoleVoter;
+import org.springframework.security.access.SecurityConfig;
+import org.springframework.security.authentication.InsufficientAuthenticationException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.access.AccessDeniedHandler;
+
+import org.springframework.security.web.access.ExceptionTranslationFilter;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+import org.springframework.security.web.context.HttpRequestResponseHolder;
+import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
+import org.springframework.security.web.firewall.HttpFirewall;
+import org.springframework.security.web.firewall.StrictHttpFirewall;
+import org.springframework.security.web.header.HeaderWriter;
+import org.springframework.security.web.header.HeaderWriterFilter;
+import org.springframework.security.web.session.SessionManagementFilter;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.FilterChainProxy;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.HttpStatusEntryPoint;
+import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.security.authentication.ProviderManager;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.filter.DelegatingFilterProxy;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+
+import static org.springframework.http.HttpStatus.FORBIDDEN;
+
+import userguide.springboot.security.webservices.WSLoginFilter;
+import userguide.springboot.security.webservices.JWTAuthenticationFilter;
+import userguide.springboot.security.webservices.JWTAuthenticationProvider;
+import userguide.springboot.security.webservices.HTTPPostOnlyRejectionFilter;
+import userguide.springboot.security.webservices.RequestAndResponseValidatorFilter;
+import userguide.springboot.security.webservices.RestAuthenticationEntryPoint;
+
+@SpringBootApplication
+@EnableAutoConfiguration
+@Configuration
+public class Axis2Application extends SpringBootServletInitializer {
+
+ private static final Logger logger = LogManager.getLogger(Axis2Application.class);
+ public static volatile boolean isRunning = false;
+
+ @Configuration
+ @EnableWebSecurity
+ @Order(1)
+ @PropertySource("classpath:application.properties")
+ public static class SecurityConfigurationTokenWebServices extends WebSecurityConfigurerAdapter {
+ private static final Logger logger = LogManager.getLogger(SecurityConfigurationTokenWebServices.class);
+
+ public SecurityConfigurationTokenWebServices() {
+ super(true);
+ String logPrefix = "SecurityConfigurationTokenWebServices , ";
+ logger.debug(logPrefix + "inside constructor, defaults disabled via super(true) ...");
+ }
+
+ class AnonRequestMatcher implements RequestMatcher {
+
+ @Override
+ public boolean matches(HttpServletRequest request) {
+ String logPrefix = "AnonRequestMatcher.matches , ";
+ boolean result = request.getRequestURI().contains(
+ "/services/loginService");
+ logger.debug(logPrefix
+ + "inside AnonRequestMatcher.matches, will return result: "
+ + result + " , on request.getRequestURI() : "
+ + request.getRequestURI() + " , request.getMethod() : "
+ + request.getMethod());
+ return result;
+ }
+
+ }
+
+ class AuthorizationFailHandler implements AccessDeniedHandler {
+
+ @Override
+ public void handle(final HttpServletRequest request, final HttpServletResponse response, final AccessDeniedException accessDeniedException)
+ throws IOException, ServletException {
+ String logPrefix = "AuthorizationFailHandler.handle() , ";
+ response.setContentType("application/json");
+ try (PrintWriter writer = response.getWriter()) {
+ logger.error(logPrefix + "found error: " + accessDeniedException.getMessage());
+ writer.write("{\"msg\":\" Access Denied\"}");
+ }
+ }
+ }
+
+ // this is about where Spring SEC HTTPInterceptor would go however it was too flaky and inflexible for this use case
+ class SecureResouceMetadataSource implements FilterInvocationSecurityMetadataSource {
+
+ @Override
+ public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
+ String logPrefix = "SecureResouceMetadataSource.getAttributes , ";
+
+ final HttpServletRequest request = ((FilterInvocation) object).getRequest();
+ final String url = request.getRequestURI();
+ final String method = request.getMethod();
+
+ String[] roles = new String[] { String.format("%s|%s", url, method) };
+ logger.debug(logPrefix + "found roles: " + Arrays.toString(roles));
+ return SecurityConfig.createList(roles);
+ }
+
+ @Override
+ public Collection<ConfigAttribute> getAllConfigAttributes() {
+ String logPrefix = "SecureResouceMetadataSource.getAllConfigAttributes , ";
+ logger.debug(logPrefix + "returning ROLE_USER ...");
+ List<ConfigAttribute> attrs = SecurityConfig.createList("ROLE_USER");
+ return attrs;
+ }
+
+ /**
+ * true if the implementation can process the indicated class
+ */
+ @Override
+ public boolean supports(final Class<?> clazz) {
+ return true;
+ }
+
+ }
+
+ class StatelessSecurityContextRepository extends HttpSessionSecurityContextRepository {
+
+ @Override
+ public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
+ String logPrefix = "StatelessSecurityContextRepository.loadContext , ";
+ logger.debug(logPrefix + "inside loadContext() ... invoking createEmptyContext()");
+ return SecurityContextHolder.createEmptyContext();
+ }
+
+ @Override
+ public void saveContext(SecurityContext context,
+ HttpServletRequest request, HttpServletResponse response) {
+ String logPrefix = "StatelessSecurityContextRepository.saveContext , ";
+ logger.debug(logPrefix + "inside saveContext() ... no action taken");
+ }
+
+ @Override
+ public boolean containsContext(final HttpServletRequest request) {
+ String logPrefix = "StatelessSecurityContextRepository.containsContext , ";
+ logger.debug(logPrefix + "inside containsContext() ... returning false");
+ return false;
+ }
+
+ }
+
+ class GenericAccessDecisionManager implements AccessDecisionManager {
+
+ @Override
+ public void decide(final Authentication authentication, final Object object, final Collection<ConfigAttribute> configAttributes)
+ throws AccessDeniedException, InsufficientAuthenticationException {
+
+ /* TODO role based auth can go here
+ boolean allowAccess = false;
+
+ for (final GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
+
+ for (final ConfigAttribute attribute : configAttributes) {
+ allowAccess = attribute.getAttribute().equals(grantedAuthority.getAuthority());
+ if (allowAccess) {
+ break;// this loop
+ }
+ }
+
+ }
+
+ if (!allowAccess) {
+ logger.warn("Throwing access denied exception");
+ throw new AccessDeniedException("Access is denied");
+ }
+ */
+ }
+
+ @Override
+ public boolean supports(final ConfigAttribute attribute) {
+ return true;
+ }
+
+ @Override
+ public boolean supports(final Class<?> clazz) {
+ return true;
+ }
+ }
+
+ @Autowired
+ private JWTAuthenticationProvider jwtAuthenticationProvider;
+
+ @Autowired
+ private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
+
+ @Autowired
+ public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
+ auth.authenticationProvider(jwtAuthenticationProvider);
+ }
+
+ @Override
+ protected void configure(final HttpSecurity http) throws Exception {
+ String logPrefix = "StatelessSecurityContextRepository.configure(final HttpSecurity http) , ";
+ logger.debug(logPrefix + "inside Spring Boot filter config ...");
+ }
+
+ @Bean
+ WSLoginFilter wsLoginFilter() throws Exception {
+ final WSLoginFilter filter = new WSLoginFilter();
+ return filter;
+ }
+
+ @Bean
+ JWTAuthenticationFilter jwtAuthenticationFilter() throws Exception {
+ final JWTAuthenticationFilter filter = new JWTAuthenticationFilter();
+ return filter;
+ }
+
+ @Bean
+ HTTPPostOnlyRejectionFilter httpPostOnlyRejectionFilter() throws Exception {
+ final HTTPPostOnlyRejectionFilter filter = new HTTPPostOnlyRejectionFilter();
+ return filter;
+ }
+
+ @Bean
+ public ProviderManager authenticationManager() {
+ return new ProviderManager(Arrays.asList(jwtAuthenticationProvider));
+ }
+
+ public ExceptionTranslationFilter exceptionTranslationFilter() {
+ final ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(restAuthenticationEntryPoint);
+ exceptionTranslationFilter.setAccessDeniedHandler(new AuthorizationFailHandler());
+ return exceptionTranslationFilter;
+ }
+
+ @Bean
+ public SecureResouceMetadataSource secureResouceMetadataSource() {
+ return new SecureResouceMetadataSource();// gives allowed roles
+ }
+
+ @Bean
+ AffirmativeBased accessDecisionManager() {
+ List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<>();
+ voters.add(new RoleVoter());
+ AffirmativeBased decisionManager = new AffirmativeBased(voters);
+ decisionManager.setAllowIfAllAbstainDecisions(false);
+ return decisionManager;
+ }
+
+ @Bean
+ public GenericAccessDecisionManager genericAccessDecisionManager() {
+ return new GenericAccessDecisionManager();
+ }
+
+ public FilterSecurityInterceptor filterSecurityInterceptor() throws Exception {
+ final FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
+ filterSecurityInterceptor.setAuthenticationManager(authenticationManager());
+ filterSecurityInterceptor.setAccessDecisionManager(genericAccessDecisionManager());
+ filterSecurityInterceptor.setSecurityMetadataSource(secureResouceMetadataSource());
+ return filterSecurityInterceptor;
+ }
+
+ @Bean
+ public StatelessSecurityContextRepository statelessSecurityContextRepository() {
+ return new StatelessSecurityContextRepository();
+ }
+
+ @Bean
+ public Filter sessionManagementFilter() {
+ StatelessSecurityContextRepository repo = statelessSecurityContextRepository();
+ repo.setAllowSessionCreation(false);
+ SessionManagementFilter filter = new SessionManagementFilter(repo);
+ return filter;
+ }
+
+ @Bean
+ public HeaderWriterFilter headerWriterFilter() {
+ HeaderWriter headerWriter = new HeaderWriter() {
+ public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
+ response.setHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
+ response.setHeader("Expires", "0");
+ response.setHeader("Pragma", "no-cache");
+ response.setHeader("X-Frame-Options", "SAMEORIGIN");
+ response.setHeader("X-XSS-Protection", "1; mode=block");
+ response.setHeader("x-content-type-options", "nosniff");
+ }
+ };
+ List<HeaderWriter> headerWriterFilterList = new ArrayList<HeaderWriter>();
+ headerWriterFilterList.add(headerWriter);
+ HeaderWriterFilter headerFilter = new HeaderWriterFilter(headerWriterFilterList);
+ return headerFilter;
+ }
+
+ @Bean(name = "springSecurityFilterChain")
+ public FilterChainProxy springSecurityFilterChain() throws ServletException, Exception {
+ String logPrefix = "GenericAccessDecisionManager.springSecurityFilterChain , ";
+ logger.debug(logPrefix + "inside main filter config ...");
+
+ final List<SecurityFilterChain> listOfFilterChains = new ArrayList<SecurityFilterChain>();
+
+ // these two chains are a binary choice.
+ // A login url will match, otherwise invoke jwtAuthenticationFilter
+ listOfFilterChains.add(new DefaultSecurityFilterChain(new AnonRequestMatcher(), headerWriterFilter(), httpPostOnlyRejectionFilter(), requestAndResponseValidatorFilter(), wsLoginFilter(), sessionManagementFilter()));
+
+ listOfFilterChains.add(new DefaultSecurityFilterChain(new NegatedRequestMatcher(new AnonRequestMatcher()), headerWriterFilter(), httpPostOnlyRejectionFilter(), requestAndResponseValidatorFilter(), jwtAuthenticationFilter(), sessionManagementFilter(), exceptionTranslationFilter(), filterSecurityInterceptor()));
+
+ final FilterChainProxy filterChainProxy = new FilterChainProxy(listOfFilterChains);
+
+ return filterChainProxy;
+ }
+
+ /**
+ * Disable Spring boot automatic filter registration since we are using FilterChainProxy.
+ */
+ @Bean
+ FilterRegistrationBean disableWSLoginFilterAutoRegistration(final WSLoginFilter wsLoginFilter) {
+ String logPrefix = "GenericAccessDecisionManager.disableWSLoginFilterAutoRegistration , ";
+ logger.debug(logPrefix + "executing registration.setEnabled(false) on wsLoginFilter ...");
+ final FilterRegistrationBean registration = new FilterRegistrationBean(wsLoginFilter);
+ registration.setEnabled(false);
+ return registration;
+ }
+
+ /**
+ * Disable Spring boot automatic filter registration since we are using FilterChainProxy.
+ */
+ @Bean
+ FilterRegistrationBean disableJWTAuthenticationFilterAutoRegistration(final JWTAuthenticationFilter filter) {
+ String logPrefix = "GenericAccessDecisionManager.disableJWTAuthenticationFilterAutoRegistration , ";
+ logger.debug(logPrefix + "executing registration.setEnabled(false) on JWTAuthenticationFilter ...");
+ final FilterRegistrationBean registration = new FilterRegistrationBean(filter);
+ registration.setEnabled(false);
+ return registration;
+ }
+
+ /**
+ * Disable Spring boot automatic filter registration since we are using FilterChainProxy.
+ */
+ @Bean
+ FilterRegistrationBean disableHTTPPostOnlyRejectionFilterAutoRegistration(final HTTPPostOnlyRejectionFilter filter) {
+ String logPrefix = "GenericAccessDecisionManager.disableHTTPPostOnlyRejectionFilterAutoRegistration , ";
+ logger.debug(logPrefix + "executing registration.setEnabled(false) on HTTPPostOnlyRejectionFilter ...");
+ final FilterRegistrationBean registration = new FilterRegistrationBean(filter);
+ registration.setEnabled(false);
+ return registration;
+ }
+
+ /**
+ * Disable Spring boot automatic filter registration since we are using FilterChainProxy.
+ */
+ @Bean
+ FilterRegistrationBean disableRequestAndResponseValidatorFilterAutoRegistration(final RequestAndResponseValidatorFilter filter) {
+ String logPrefix = "GenericAccessDecisionManager.disableRequestAndResponseValidatorFilterAutoRegistration , ";
+ logger.debug(logPrefix + "executing registration.setEnabled(false) on RequestLoggingFilter ...");
+ final FilterRegistrationBean registration = new FilterRegistrationBean(filter);
+ registration.setEnabled(false);
+ return registration;
+ }
+
+ @Bean
+ public RequestAndResponseValidatorFilter requestAndResponseValidatorFilter() {
+ RequestAndResponseValidatorFilter filter = new RequestAndResponseValidatorFilter();
+ return filter;
+ }
+
+ @Bean()
+ FilterRegistrationBean FilterRegistrationBean() {
+ final FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
+ filterRegistrationBean.setFilter(new DelegatingFilterProxy("springSecurityFilterChain"));
+ filterRegistrationBean.setOrder(Ordered.LOWEST_PRECEDENCE);
+ filterRegistrationBean.setName("springSecurityFilterChain");
+ filterRegistrationBean.addUrlPatterns("/*");
+ return filterRegistrationBean;
+ }
+
+ @Bean
+ AuthenticationEntryPoint forbiddenEntryPoint() {
+ return new HttpStatusEntryPoint(FORBIDDEN);
+ }
+
+ // demo purposes only
+ @SuppressWarnings("deprecation")
+ @Bean
+ public static NoOpPasswordEncoder passwordEncoder() {
+ return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
+ }
+
+ }
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ setRegisterErrorPageFilter(false);
+ return application.sources(Axis2Application.class);
+ }
+
+ public static void main(String[] args) throws Exception {
+ String logPrefix = "Axis2Application.main , ";
+ if (!isRunning) {
+ SpringApplication ctx = new SpringApplication(Axis2Application.class);
+ ApplicationContext applicationContext = ctx.run(args);
+ String[] activeProfiles = applicationContext.getEnvironment().getActiveProfiles();
+ for (String profile : activeProfiles) {
+ logger.debug(logPrefix + "Spring Boot profile: " + profile);
+ }
+ }
+ isRunning = true;
+ }
+
+
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java
new file mode 100644
index 0000000..0d3acce
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/configuration/Axis2WebAppInitializer.java
@@ -0,0 +1,72 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.configuration;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.axis2.transport.http.AxisServlet;
+import org.springframework.boot.web.servlet.ServletContextInitializer;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+import org.springframework.core.annotation.Order;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRegistration;
+
+import java.util.Set;
+
+@Configuration
+@Order(4)
+public class Axis2WebAppInitializer implements ServletContextInitializer {
+
+ private static final Logger logger = LogManager.getLogger(Axis2WebAppInitializer.class);
+ private static final String SERVICES_MAPPING = "/services/*";
+
+ @Override
+ public void onStartup(ServletContext container) {
+ logger.warn("inside onStartup() ...");
+ // Create the 'root' Spring application context
+ AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
+
+ addAxis2Servlet(container, ctx);
+ logger.warn("onStartup() completed ...");
+ }
+
+ private void addAxis2Servlet(ServletContext container, AnnotationConfigWebApplicationContext ctx) {
+
+ ServletRegistration.Dynamic dispatcher = container.addServlet(
+ "AxisServlet", new AxisServlet());
+ dispatcher.setLoadOnStartup(1);
+ Set<String> mappingConflicts = dispatcher.addMapping(SERVICES_MAPPING);
+ if (!mappingConflicts.isEmpty()) {
+ for (String s : mappingConflicts) {
+ logger.error("Mapping conflict: " + s);
+ }
+ throw new IllegalStateException("'AxisServlet' could not be mapped to '" + SERVICES_MAPPING + "'");
+ }
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/hibernate/dao/SpringSecurityDAOImpl.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/hibernate/dao/SpringSecurityDAOImpl.java
new file mode 100755
index 0000000..37d9545
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/hibernate/dao/SpringSecurityDAOImpl.java
@@ -0,0 +1,115 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.hibernate.dao;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.dao.DataAccessException;
+
+import userguide.springboot.requestactivity.Axis2UserDetails;
+import userguide.springboot.security.webservices.WSSecUtils;
+import userguide.springboot.security.webservices.LoginDTO;
+
+@Service
+public class SpringSecurityDAOImpl implements UserDetailsService {
+
+ private static final Logger logger = LogManager.getLogger(SpringSecurityDAOImpl.class);
+
+ @Autowired
+ private WSSecUtils wssecutils;
+
+ /** Everyone needs this role. **/
+ public static final String ROLE_USER = "ROLE_USER";
+
+ /**
+ * Spring Security invokes this method to get the credentials from the DB.
+ */
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
+
+ String logPrefix = "SpringSecurityDAOImpl.loadUserByUsername() , ";
+ Axis2UserDetails userDetails = null;
+
+ logger.debug("user attempting Spring Security login: " + username);
+ if (username == null || username.equals("")) {
+ throw new BadCredentialsException("user login FAILED: username empty or null.");
+ }
+ LoginDTO persistedUser = null;
+ try {
+ persistedUser = wssecutils.findUserByEmail(username);
+ } catch (Exception ex) {
+ logger.error(logPrefix + "cannot create LoginDTO from email: " + username + " , " + ex.getMessage(), ex);
+ }
+ if (persistedUser == null) {
+ throw new BadCredentialsException("Can't find username: " + username);
+ }
+
+ Set<String> roles = new HashSet<String>();
+ // adding permissions - put Roles here
+ // Every user must have the ROLE_USER to navigate the application:
+ if (!roles.contains(ROLE_USER)) {
+ roles.add(ROLE_USER);
+ }
+ Iterator<String> it = roles.iterator();
+
+ Collection<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
+
+ int xx = 0;
+ while (it.hasNext()) {
+ String role = it.next();
+ GrantedAuthority authority = new SimpleGrantedAuthority(role);
+ authorities.add(authority);
+ if (logger.isDebugEnabled()) {
+ logger.debug("user: " + username + ", "
+ + "authorities : " + (xx - 1) + ", value:"
+ + authority.toString());
+ }
+ }
+
+ // Give these fields to Spring Security so it can compare with credentials passed in via the login page
+ userDetails = new Axis2UserDetails(persistedUser,
+ // username == email
+ persistedUser.getEmail().toLowerCase(),
+ persistedUser.getPassword(),
+ persistedUser.getEnabled(),
+ persistedUser.getAccountNonExpired(),
+ persistedUser.getCredentialsNonExpired(),
+ persistedUser.getAccountNonLocked(),
+ authorities);
+
+
+ return userDetails;
+
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/requestactivity/Axis2UserDetails.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/requestactivity/Axis2UserDetails.java
new file mode 100644
index 0000000..cc5db11
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/requestactivity/Axis2UserDetails.java
@@ -0,0 +1,64 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.requestactivity;
+
+import java.util.Collection;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+
+public class Axis2UserDetails extends User {
+
+ private static final long serialVersionUID = 2041888514077783198L;
+ /** User entity which is Stored by Spring's SecurityContext per every login. */
+ private Object userDomain;
+
+ /**
+ * @return Returns the userDomain.
+ */
+ public Object getUserDomain() {
+ return userDomain;
+ }
+
+ /**
+ * Override SPRING SECURITY Constructor to inform it about the User entity.
+ *
+ * @param userDomain Authenticated User entity
+ * @param username from DB
+ * @param password from DB
+ * @param enabled Indicates whether the user is enabled or disabled
+ * @param accountNonExpired Indicates whether the user's account has expired
+ * @param credentialsNonExpired Indicates whether the user's credentials
+ * (password) has expired.
+ * @param accountNonLocked Indicates whether the user is locked or unlocked.
+ * @param authorities the authorities granted to the user
+ * @throws IllegalArgumentException Invalid argument was found
+ */
+ public Axis2UserDetails(Object userDomain,
+ String username, String password, boolean enabled,
+ boolean accountNonExpired, boolean credentialsNonExpired,
+ boolean accountNonLocked,
+ Collection<? extends GrantedAuthority> authorities)
+ throws IllegalArgumentException {
+
+ super(username, password, enabled, accountNonExpired,
+ credentialsNonExpired, accountNonLocked, authorities);
+ this.userDomain = userDomain;
+ }
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/BadRequestMatcher.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/BadRequestMatcher.java
new file mode 100644
index 0000000..8adb2a1
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/BadRequestMatcher.java
@@ -0,0 +1,258 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.web.util.matcher.RequestMatcher;
+
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+public class BadRequestMatcher implements RequestMatcher {
+
+ /** commons logging declaration. **/
+ private static Log logger = LogFactory.getLog(BadRequestMatcher.class);
+
+ private Set<String> encodedUrlBlacklist = new HashSet<String>();
+
+ private Set<String> decodedUrlBlacklist = new HashSet<String>();
+
+ private static final String ENCODED_PERCENT = "%25";
+
+ private static final String PERCENT = "%";
+
+ private List<String> FORBIDDEN_ENCODED_PERIOD = Collections.unmodifiableList(Arrays.asList("%2e", "%2E"));
+
+ private List<String> FORBIDDEN_SEMICOLON = Collections.unmodifiableList(Arrays.asList(";", "%3b", "%3B"));
+
+ private List<String> FORBIDDEN_FORWARDSLASH = Collections.unmodifiableList(Arrays.asList("%2f", "%2F"));
+
+ private List<String> FORBIDDEN_BACKSLASH = Collections.unmodifiableList(Arrays.asList("\\", "%5c", "%5C"));
+
+ private int requestDebuggingActivated;
+
+ public BadRequestMatcher(int requestDebuggingActivated) {
+
+ this.requestDebuggingActivated = requestDebuggingActivated;
+ // this is a 'defense in depth' strategy as Cloudflare or another load balancer should reject this stuff
+ urlBlacklistsAddAll(FORBIDDEN_SEMICOLON);
+ urlBlacklistsAddAll(FORBIDDEN_FORWARDSLASH);
+ urlBlacklistsAddAll(FORBIDDEN_BACKSLASH);
+
+ this.encodedUrlBlacklist.add(ENCODED_PERCENT);
+ this.encodedUrlBlacklist.addAll(FORBIDDEN_ENCODED_PERIOD);
+ this.decodedUrlBlacklist.add(PERCENT);
+ }
+
+ private void urlBlacklistsAddAll(Collection<String> values) {
+ this.encodedUrlBlacklist.addAll(values);
+ this.decodedUrlBlacklist.addAll(values);
+ }
+
+ public boolean validate(HttpServletRequest request) {
+ return matches(request);
+ }
+ @Override
+ public boolean matches(HttpServletRequest request) {
+ String logPrefix = "BadRequestMatcher.matches , ";
+ boolean foundElements = false;
+ for (Enumeration en = request.getParameterNames(); en
+ .hasMoreElements();) {
+
+ foundElements = true;
+
+ Object obj = en.nextElement();
+ String value = request.getParameterValues((String) obj)[0];
+ if (!isNormalized(value)) {
+ logger.error(logPrefix +
+ "found illegal String: " +value+ " , returning false because the request has parameters that are not 'normalized i.e. paths contain dir traversal or illegal chars'");
+ return false;
+
+ }
+ if (!rejectedBlacklistedValues(value)) {
+ logger.error(logPrefix +
+ "found illegal String: " +value+ " , returning false because the request has rejected black list values");
+ return false;
+
+ }
+ if (requestDebuggingActivated == 1) {
+ logger.error(logPrefix +
+ "on requestDebuggingActivated=1 found String: " +value);
+
+ }
+ }
+ if (!foundElements) {
+ logger.warn(logPrefix + "on requestDebuggingActivated=1 , no HTTP elements found!");
+ }
+ rejectedBlacklistedUrls(request);
+ if (!isNormalized(request)) {
+ logger.error(logPrefix +
+ "inside BadRequestMatcher.matches, returning false because the request was not 'normalized i.e. paths contain dir traversal or illegal chars'");
+ return false;
+ }
+ String requestUri = request.getRequestURI();
+ if (!containsOnlyPrintableAsciiCharacters(requestUri)) {
+ logger.error(logPrefix +
+ "The requestURI was rejected because it can only contain printable ASCII characters.");
+ return false;
+
+ }
+ return true;
+ }
+
+ private boolean containsOnlyPrintableAsciiCharacters(String uri) {
+ int length = uri.length();
+ for (int i = 0; i < length; i++) {
+ char c = uri.charAt(i);
+ if (c < '\u0020' || c > '\u007e') {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean rejectedBlacklistedUrls(HttpServletRequest request) {
+ String logPrefix = "BadRequestMatcher.rejectedBlacklistedUrls , ";
+ for (String forbidden : this.encodedUrlBlacklist) {
+ if (encodedUrlContains(request, forbidden)) {
+ logger.error(logPrefix +
+ "returning false, The request was rejected because the URL contained a potentially malicious String \"" + forbidden + "\"");
+ return false;
+ }
+ }
+ for (String forbidden : this.decodedUrlBlacklist) {
+ if (decodedUrlContains(request, forbidden)) {
+ logger.error(logPrefix +
+ "The request was rejected because the URL contained a potentially malicious String \"" + forbidden + "\"");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean rejectedBlacklistedValues(String value) {
+ String logPrefix = "BadRequestMatcher.matches , ";
+ for (String forbidden : this.encodedUrlBlacklist) {
+ if (valueContains(value, forbidden)) {
+ logger.error(logPrefix + "found illegal String: " +value+ " , returning false because the request has parameters that are not 'normalized i.e. paths contain dir traversal or illegal chars'");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean valueContains(String value, String contains) {
+ return value != null && value.contains(contains);
+ }
+
+ private boolean encodedUrlContains(HttpServletRequest request, String value) {
+ if (valueContains(request.getContextPath(), value)) {
+ return true;
+ }
+ return valueContains(request.getRequestURI(), value);
+ }
+
+ private boolean decodedUrlContains(HttpServletRequest request, String value) {
+ if (valueContains(request.getServletPath(), value)) {
+ return true;
+ }
+ if (valueContains(request.getPathInfo(), value)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This should be done by Spring Security StrictHttpFirewall but isn't working as expected,
+ * turns out its not as detailed as we need.
+ * Instead of sub-classing it to add logging - there is none - and features, just do the important parts here
+ *
+ * Checks whether a path is normalized (doesn't contain path traversal
+ * sequences like "./", "/../" or "/.")
+ *
+ * @param path
+ * the path to test
+ * @return true if the path doesn't contain any path-traversal character
+ * sequences.
+ */
+ private boolean isNormalized(HttpServletRequest request) {
+ String logPrefix = "BadRequestMatcher.isNormalized , ";
+ if (!isNormalized(request.getRequestURI())) {
+ logger.error(logPrefix + "returning false on request.getRequestURI() : " + request.getRequestURI());
+ return false;
+ }
+ if (!isNormalized(request.getContextPath())) {
+ logger.error(logPrefix + "returning false on request.getContextPath() : " + request.getContextPath());
+ return false;
+ }
+ if (!isNormalized(request.getServletPath())) {
+ logger.error(logPrefix + "returning false on request.getServletPath() : " + request.getServletPath());
+ return false;
+ }
+ if (!isNormalized(request.getPathInfo())) {
+ logger.error(logPrefix + "returning false on request.getPathInfo() : " + request.getPathInfo());
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isNormalized(String path) {
+
+ String logPrefix = "BadRequestMatcher.isNormalized(String path) , ";
+
+ logger.warn(logPrefix + "evaluating path : " + path);
+
+ if (path == null) {
+ return true;
+ }
+
+ if (path.indexOf("//") > -1) {
+ return false;
+ }
+
+ for (int j = path.length(); j > 0;) {
+ int i = path.lastIndexOf('/', j - 1);
+ int gap = j - i;
+
+ if (gap == 2 && path.charAt(i + 1) == '.') {
+ // ".", "/./" or "/."
+ return false;
+ } else if (gap == 3 && path.charAt(i + 1) == '.' && path.charAt(i + 2) == '.') {
+ return false;
+ }
+
+ j = i;
+ }
+
+ return true;
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java
new file mode 100644
index 0000000..9b9dd58
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/HTTPPostOnlyRejectionFilter.java
@@ -0,0 +1,89 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.http.server.ServletServerHttpRequest;
+import org.springframework.web.filter.OncePerRequestFilter;
+import org.springframework.web.util.ContentCachingRequestWrapper;
+import org.springframework.web.util.ContentCachingResponseWrapper;
+import org.springframework.web.util.WebUtils;
+import org.springframework.security.web.RedirectStrategy;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.UUID;
+
+public class HTTPPostOnlyRejectionFilter extends OncePerRequestFilter {
+
+ private static Log logger = LogFactory.getLog(HTTPPostOnlyRejectionFilter.class);
+
+ private final RedirectStrategy redirectStrategy = new NoRedirectStrategy();
+
+ public HTTPPostOnlyRejectionFilter() {
+ super();
+ }
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+
+ String uuid = UUID.randomUUID().toString();
+ String logPrefix = "HTTPPostOnlyRejectionFilter.doFilterInternal , uuid: " + uuid + " , ";
+
+ logger.trace(logPrefix + "starting ... ");
+
+ if (!request.getMethod().equals("POST")) {
+
+ String ip = "unknown";
+ if (request.getHeader("X-Forwarded-For") != null) {
+ ip = request.getHeader("X-Forwarded-For");
+ }
+ logger.trace(logPrefix +
+ "this is not a POST request, ignoring with an HTTP 200 response, " +
+ " , on IP from X-Forwarded-For: " + request.getRequestURI() +
+ " , request.getRequestURI() : " + request.getRequestURI() +
+ " , request.getMethod() : " + request.getMethod());
+
+ response.setContentType("application/json;charset=UTF-8");
+ response.getWriter().print("HTTP requests that are not POST are ignored");
+ response.getWriter().flush();
+ this.redirectStrategy.sendRedirect((HttpServletRequest) request, (HttpServletResponse) response, "/");
+
+ } else {
+ filterChain.doFilter(request, response);
+ }
+ }
+
+ protected class NoRedirectStrategy implements RedirectStrategy {
+
+ @Override
+ public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
+ throws IOException {
+ // do nothing
+ }
+
+ }
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java
new file mode 100644
index 0000000..e46c9c7
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationFilter.java
@@ -0,0 +1,136 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+import java.io.IOException;
+import java.util.UUID;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
+import org.owasp.esapi.ESAPI;
+import org.owasp.esapi.Validator;
+
+public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
+
+ @Autowired
+ private WSSecUtils wssecutils;
+
+ public JWTAuthenticationFilter() {
+ super("/**");
+ }
+
+ @Override
+ @Autowired
+ public void setAuthenticationManager(AuthenticationManager authenticationManager) {
+ super.setAuthenticationManager(authenticationManager);
+ }
+
+ @Override
+ protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
+ return true;
+ }
+
+ @Override
+ public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
+ String logPrefix = "JWTAuthenticationFilter.attemptAuthentication() , ";
+
+ // if this fails it will throw a fatal error, don't catch it since it could be evil data
+ String authToken = getBearerToken(request);
+
+ JWTAuthenticationToken authRequest = new JWTAuthenticationToken(authToken);
+
+ return getAuthenticationManager().authenticate(authRequest);
+ }
+
+ public String getBearerToken(HttpServletRequest request) throws AuthenticationException {
+ String logPrefix = "JWTAuthenticationFilter.getBearerToken() , ";
+ String header = request.getHeader("Authorization");
+
+ if (header == null || !header.startsWith("Bearer ")) {
+ throw new JWTTokenMissingException("No JWT token found in request headers");
+ }
+ Validator validator = ESAPI.validator();
+ boolean headerstatus = validator.isValidInput("userInput", header, "HTTPHeaderValue", 1000 , false);
+ if (!headerstatus) {
+ logger.error(logPrefix + "returning with failure status on invalid header: " + header);
+ throw new JWTTokenMissingException("invalid header");
+ }
+
+ String authToken = header.substring(7);
+
+ return authToken;
+ }
+
+ @Override
+ protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
+
+ String logPrefix = "JWTAuthenticationFilter.successfulAuthentication() , ";
+
+ String authToken = getBearerToken(request);
+ JWTUserDTO parsedUser = null;
+ try{
+ parsedUser = wssecutils.getParsedUser(authToken);
+ } catch (Exception ex) {
+ logger.error(logPrefix + ex.getMessage(), ex );
+ }
+
+ if (parsedUser == null) {
+ throw new ServletException("JWT token is not valid, cannot find user");
+ }
+ String uuid = parsedUser.getUuid();
+ if (uuid == null) {
+ throw new ServletException("JWT token is not valid, cannot find uuid");
+ }
+ logger.warn(logPrefix + "found uuid from token: " + uuid);
+ String usernameFromToken = parsedUser.getUsername();
+ if (usernameFromToken == null) {
+ throw new ServletException("JWT token is not valid, cannot find username");
+ }
+ usernameFromToken = usernameFromToken.trim();
+
+ String currentUserIPAddress = null;
+
+ String newuuid = UUID.randomUUID().toString();
+
+ // As this authentication is in the HTTP header, after success we need to continue
+ // the request normally and return the response as if the resource was not secured at all
+
+ // set some vars that may be helpful to the webservices
+ request.setAttribute("email", usernameFromToken);
+ request.setAttribute("uuid", newuuid);
+ request.setAttribute("currentUserIPAddress", currentUserIPAddress);
+
+ SecurityContextHolder.getContext().setAuthentication(authResult);
+
+ chain.doFilter(request, response);
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationProvider.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationProvider.java
new file mode 100644
index 0000000..7137858
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationProvider.java
@@ -0,0 +1,108 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+import java.util.List;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Component;
+
+import userguide.springboot.requestactivity.Axis2UserDetails;
+
+@Component
+public class JWTAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
+
+ private static final Logger log = LogManager.getLogger(JWTAuthenticationProvider.class);
+
+ @Autowired
+ private WSSecUtils wssecutils;
+
+ @Override
+ public boolean supports(Class<?> authentication) {
+ return (JWTAuthenticationToken.class.isAssignableFrom(authentication));
+ }
+
+ @Override
+ protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
+ }
+
+ @Override
+ protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
+ String logPrefix = "JWTAuthenticationProvider.retrieveUser() , username: " +username+ " , ";
+ JWTAuthenticationToken jwtAuthenticationToken = (JWTAuthenticationToken) authentication;
+ String token = jwtAuthenticationToken.getToken();
+
+ try {
+ JWTUserDTO parsedUser = wssecutils.getParsedUser(token);
+
+ if (parsedUser == null) {
+ throw new JWTTokenMalformedException("JWT token is not valid, cannot find user");
+ }
+ logger.warn(logPrefix + "found parsedUser: " + parsedUser.toString());
+ String uuid = parsedUser.getUuid();
+ if (uuid == null) {
+ throw new JWTTokenMalformedException("JWT token is not valid, cannot find uuid");
+ }
+ if (parsedUser.getUsername() == null) {
+ throw new JWTTokenMalformedException("JWT token is not valid, cannot find email");
+ }
+ logger.warn(logPrefix + "found uuid from token: " + uuid);
+
+ LoginDTO persistedUser = null;
+ try {
+ persistedUser = wssecutils.findUserByEmail(parsedUser.getUsername());
+ } catch (Exception ex) {
+ logger.error(logPrefix + "cannot create LoginDTO from email: " + parsedUser.getUsername() + " , " + ex.getMessage(), ex);
+ throw new JWTTokenMalformedException("JWT token is not valid, cannot create LoginDTO from email: " + parsedUser.getUsername());
+ }
+ if (persistedUser == null) {
+ logger.error(logPrefix + "returning with failure status on failed creation of LoginDTO from email: " + parsedUser.getUsername());
+ throw new JWTTokenMalformedException("JWT token is not valid, LoginDTO is null from email: " + parsedUser.getUsername());
+ }
+ List<GrantedAuthority> authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList(parsedUser.getRole());
+
+ Boolean isNonLocked;
+
+ if (persistedUser.getAccountNonLocked()) {
+ isNonLocked = true;
+ } else {
+ isNonLocked = false;
+ }
+
+ Axis2UserDetails userDetails = new Axis2UserDetails(persistedUser, parsedUser.getUsername(), token, persistedUser.getEnabled(), persistedUser.getAccountNonExpired(), persistedUser.getCredentialsNonExpired(), isNonLocked, authorityList);
+
+ return userDetails;
+
+ } catch (Exception ex) {
+ logger.error(logPrefix + "failed: " + ex.getMessage(), ex);
+ throw new JWTTokenMalformedException("unexpected error parsing token");
+ }
+
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationSuccessHandler.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationSuccessHandler.java
new file mode 100644
index 0000000..ae0a6cd
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationSuccessHandler.java
@@ -0,0 +1,35 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+
+public class JWTAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
+
+ @Override
+ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
+ // We do not need to do anything extra on REST authentication success, because there is no page to redirect to
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationToken.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationToken.java
new file mode 100644
index 0000000..60f654f
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTAuthenticationToken.java
@@ -0,0 +1,48 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+
+public class JWTAuthenticationToken extends UsernamePasswordAuthenticationToken {
+
+ private static final long serialVersionUID = -5031102661066770894L;
+
+ private String token;
+
+ public JWTAuthenticationToken(String token) {
+ super(null, null);
+ this.token = token;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return null;
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return null;
+ }
+}
diff --git a/modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTTokenAuthenticationException.java
similarity index 61%
copy from modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java
copy to modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTTokenAuthenticationException.java
index 619c1ae..ea35763 100644
--- a/modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTTokenAuthenticationException.java
@@ -1,3 +1,4 @@
+
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -16,24 +17,16 @@
* specific language governing permissions and limitations
* under the License.
*/
+package userguide.springboot.security.webservices;
-package org.apache.axis2.json.gson;
+import org.springframework.security.core.AuthenticationException;
-import org.owasp.encoder.Encode;
+public class JWTTokenAuthenticationException extends AuthenticationException {
-import com.google.gson.JsonElement;
-import com.google.gson.JsonPrimitive;
-import com.google.gson.JsonSerializationContext;
-import com.google.gson.JsonSerializer;
-import java.lang.reflect.Type;
+ private static final long serialVersionUID = -659063016840102545L;
-public class JsonHtmlXssSerializer implements JsonSerializer<String> {
+ public JWTTokenAuthenticationException(String msg) {
+ super(msg);
+ }
- @Override
- public JsonElement serialize(String src, Type typeOfSrc,
- JsonSerializationContext context) {
-
- return new JsonPrimitive(Encode.forHtmlContent(src));
-
- }
}
diff --git a/modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTTokenMalformedException.java
similarity index 61%
copy from modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java
copy to modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTTokenMalformedException.java
index 619c1ae..df9a3c3 100644
--- a/modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTTokenMalformedException.java
@@ -1,3 +1,4 @@
+
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -16,24 +17,16 @@
* specific language governing permissions and limitations
* under the License.
*/
+package userguide.springboot.security.webservices;
-package org.apache.axis2.json.gson;
+import org.springframework.security.core.AuthenticationException;
-import org.owasp.encoder.Encode;
+public class JWTTokenMalformedException extends AuthenticationException {
+
+ private static final long serialVersionUID = 4207020475526562507L;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonPrimitive;
-import com.google.gson.JsonSerializationContext;
-import com.google.gson.JsonSerializer;
-import java.lang.reflect.Type;
+ public JWTTokenMalformedException(String msg) {
+ super(msg);
+ }
-public class JsonHtmlXssSerializer implements JsonSerializer<String> {
-
- @Override
- public JsonElement serialize(String src, Type typeOfSrc,
- JsonSerializationContext context) {
-
- return new JsonPrimitive(Encode.forHtmlContent(src));
-
- }
}
diff --git a/modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTTokenMissingException.java
similarity index 61%
copy from modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java
copy to modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTTokenMissingException.java
index 619c1ae..3acd5af 100644
--- a/modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTTokenMissingException.java
@@ -1,3 +1,4 @@
+
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -16,24 +17,16 @@
* specific language governing permissions and limitations
* under the License.
*/
+package userguide.springboot.security.webservices;
-package org.apache.axis2.json.gson;
+import org.springframework.security.core.AuthenticationException;
-import org.owasp.encoder.Encode;
+public class JWTTokenMissingException extends AuthenticationException {
-import com.google.gson.JsonElement;
-import com.google.gson.JsonPrimitive;
-import com.google.gson.JsonSerializationContext;
-import com.google.gson.JsonSerializer;
-import java.lang.reflect.Type;
+ private static final long serialVersionUID = -659063016840102545L;
-public class JsonHtmlXssSerializer implements JsonSerializer<String> {
-
- @Override
- public JsonElement serialize(String src, Type typeOfSrc,
- JsonSerializationContext context) {
-
- return new JsonPrimitive(Encode.forHtmlContent(src));
-
+ public JWTTokenMissingException(String msg) {
+ super(msg);
}
+
}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTUserDTO.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTUserDTO.java
new file mode 100644
index 0000000..dae5d35
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/JWTUserDTO.java
@@ -0,0 +1,55 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+public class JWTUserDTO {
+
+ private String uuid;
+
+ private String username;
+
+ private String role;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public void setUuid(String uuid) {
+
+ this.uuid = uuid;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/LoginDTO.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/LoginDTO.java
new file mode 100644
index 0000000..04614e8
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/LoginDTO.java
@@ -0,0 +1,105 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+public class LoginDTO {
+
+ private String email;
+
+ private String password;
+
+ private Boolean enabled;
+
+ private Boolean accountNonExpired;
+
+ private Boolean credentialsNonExpired;
+
+ private Boolean accountNonLocked;
+
+
+ public Boolean getAccountNonLocked() {
+ return accountNonLocked;
+ }
+
+ public void setAccountNonLocked(Boolean accountNonLocked) {
+ this.accountNonLocked = accountNonLocked;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public Boolean getEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(Boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Boolean getAccountNonExpired() {
+ return accountNonExpired;
+ }
+
+ public void setAccountNonExpired(Boolean accountNonExpired) {
+ this.accountNonExpired = accountNonExpired;
+ }
+
+ public Boolean getCredentialsNonExpired() {
+ return credentialsNonExpired;
+ }
+
+ public void setCredentialsNonExpired(Boolean credentialsNonExpired) {
+ this.credentialsNonExpired = credentialsNonExpired;
+ }
+
+ public LoginDTO(String email, String password, Boolean enabled, Boolean accountNonExpired, Boolean credentialsNonExpired, Boolean accountNonLocked) {
+ super();
+ this.email = email;
+ this.password = password;
+ this.enabled = enabled;
+ this.accountNonExpired = accountNonExpired;
+ this.credentialsNonExpired = credentialsNonExpired;
+ this.accountNonLocked = accountNonLocked;
+ }
+
+ @Override
+ public String toString() {
+ return "LoginDTO [email=" + email
+ + ", enabled=" + enabled + ", accountNonExpired="
+ + accountNonExpired + ", credentialsNonExpired="
+ + credentialsNonExpired + ", accountNonLocked="
+ + accountNonLocked + "]";
+ }
+
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/RequestAndResponseValidatorFilter.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/RequestAndResponseValidatorFilter.java
new file mode 100644
index 0000000..95a2e47
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/RequestAndResponseValidatorFilter.java
@@ -0,0 +1,200 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.http.server.ServletServerHttpRequest;
+import org.springframework.web.filter.OncePerRequestFilter;
+import org.springframework.web.util.ContentCachingRequestWrapper;
+import org.springframework.web.util.ContentCachingResponseWrapper;
+import org.springframework.web.util.WebUtils;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.UUID;
+
+@PropertySource("classpath:application.properties")
+public class RequestAndResponseValidatorFilter extends OncePerRequestFilter {
+
+ private static Log logger = LogFactory.getLog(RequestAndResponseValidatorFilter.class);
+
+ private static ThreadLocal<Long> requestBeginTime = new ThreadLocal<>();
+ private static final int DEFAULT_MAX_PAYLOAD_LENGTH = 16384;
+
+ private int maxPayloadLength = DEFAULT_MAX_PAYLOAD_LENGTH;
+
+ @Value("${requestDebuggingActivated}")
+ private int requestDebuggingActivated;
+
+ public RequestAndResponseValidatorFilter() {
+ super();
+ }
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+
+ String uuid = UUID.randomUUID().toString();
+ String logPrefix = "RequestAndResponseValidatorFilter.doFilterInternal , uuid: " + uuid + " , request.getRequestURI():" + request.getRequestURI() + " , ";
+
+ logger.debug(logPrefix + "starting ... ");
+
+ BadRequestMatcher bad = new BadRequestMatcher(requestDebuggingActivated);
+ if (!bad.validate(request)) {
+ throw new ServletException("request is invalid, it contains a potentially malicious String");
+ }
+
+ boolean isFirstRequest = !isAsyncDispatch(request);
+ HttpServletRequest requestToUse = request;
+
+ if (isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
+ requestToUse = new ContentCachingRequestWrapper(request, getMaxPayloadLength());
+ }
+
+ HttpServletResponse responseToUse = response;
+ if (!(response instanceof ContentCachingResponseWrapper)) {
+ responseToUse = new ContentCachingResponseWrapper(response);
+ }
+
+ requestBeginTime.set(System.currentTimeMillis());
+
+ String currentUserIPAddress = null;
+ if (requestToUse.getHeader("X-Forwarded-For") != null) {
+ currentUserIPAddress = requestToUse.getHeader("X-Forwarded-For");
+ } else {
+ logger.warn(logPrefix + "cannot find X-Forwarded-For header, this field is required for proper IP auditing");
+ logger.warn(logPrefix + "Because no X-Forwarded-For header was found, setting 'currentUserIPAddress = requestToUse.getRemoteAddr()' which is typically an internal address");
+ currentUserIPAddress = requestToUse.getRemoteAddr();
+ }
+
+ if (currentUserIPAddress == null || currentUserIPAddress.length() == 0 || "unknown".equalsIgnoreCase(currentUserIPAddress)) {
+ logger.warn(logPrefix + "cannot find valid currentUserIPAddress");
+ } else {
+ logger.warn(logPrefix + "proceeding on currentUserIPAddress: " + currentUserIPAddress);
+ // rate limiting and extra validation can go here
+ }
+
+ try {
+ filterChain.doFilter(requestToUse, responseToUse);
+ } finally {
+ logRequest(createRequestMessage(requestToUse,uuid));
+ logRequest(createResponseMessage(responseToUse,uuid));
+ }
+ }
+
+ protected String createRequestMessage(HttpServletRequest request, String uuid) throws ServletException {
+
+ StringBuilder msg = new StringBuilder();
+ msg.append("HTTP request with uuid: " + uuid + " , ");
+ msg.append(request.getMethod());
+ msg.append(" uri=").append(request.getRequestURI());
+
+ String queryString = request.getQueryString();
+ if (queryString != null) {
+ msg.append('?').append(queryString);
+ }
+
+ String user = request.getRemoteUser();
+ if (user != null) {
+ msg.append(";user=").append(user);
+ }
+
+
+ return msg.toString();
+ }
+
+ protected String createResponseMessage(HttpServletResponse resp, String uuid) throws ServletException{
+
+ StringBuilder msg = new StringBuilder();
+ msg.append("HTTP response with uuid: " + uuid + " , ");
+
+ ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(resp, ContentCachingResponseWrapper.class);
+ if (responseWrapper != null) {
+ byte[] buf = responseWrapper.getContentAsByteArray();
+ try {
+ responseWrapper.copyBodyToResponse();
+ } catch (IOException e) {
+ logger.error("Fail to write response body back", e);
+ }
+ if (buf.length > 0) {
+ String payload;
+ try {
+ payload = new String(buf, 0, buf.length, responseWrapper.getCharacterEncoding());
+ } catch (UnsupportedEncodingException ex) {
+ payload = "[unknown]";
+ }
+ msg.append(";response=").append(payload);
+ }
+ }
+
+ return msg.toString();
+ }
+
+ public static boolean validate(String msg) {
+ // Input validation is inferior to output sanitation as its impossible to think of
+ // everything. See JsonHtmlXssSerializer for html encoding of the output
+
+ if (msg != null && msg.toUpperCase().contains("DOCTYPE")) {
+ logger.error("DOCTYPE keyword is disallowed");
+ return false;
+ }
+
+ // reflected XSS
+ if (msg != null && msg.toUpperCase().indexOf("SCRIPT") != -1) {
+ logger.error("SCRIPT keyword is disallowed");
+ return false;
+ }
+ // reflected XSS without script tag, sneaky ... <img onerror=alert(1)/>
+ if (msg != null && msg.toUpperCase().indexOf("ALERT") != -1) {
+ logger.error("ALERT keyword is disallowed");
+ return false;
+ }
+
+ return true;
+
+ }
+
+ public int getMaxPayloadLength() {
+ return maxPayloadLength;
+ }
+
+ protected void logRequest(String message) {
+
+ String logPrefix = "RequestAndResponseValidatorFilter.logRequest() , ";
+ long begin = requestBeginTime.get();
+ long end = System.currentTimeMillis();
+
+ long duration = end - begin;
+ if (message != null && message.toString().toUpperCase().indexOf("CREDENTIALS") != -1) {
+ logger.info(logPrefix + " , not logging credentials ... request time:" + duration);
+ } else {
+ logger.info(logPrefix + message + ", request time:" + duration);
+ }
+ }
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/RestAuthenticationEntryPoint.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/RestAuthenticationEntryPoint.java
new file mode 100644
index 0000000..c7c3e68
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/RestAuthenticationEntryPoint.java
@@ -0,0 +1,39 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
+ @Override
+ public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
+ // This is invoked when user tries to access a secured REST resource without supplying any credentials
+ // We should just send a 401 Unauthorized response because there is no 'login page' to redirect to
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
+ }
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/WSLoginFilter.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/WSLoginFilter.java
new file mode 100644
index 0000000..c1df12e
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/WSLoginFilter.java
@@ -0,0 +1,93 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.filter.GenericFilterBean;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
+
+@PropertySource("classpath:application.properties")
+public class WSLoginFilter extends GenericFilterBean {
+
+ @Value("${requestDebuggingActivated}")
+ private int requestDebuggingActivated;
+
+ @Override
+ public void doFilter(
+ ServletRequest request,
+ ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+
+ final String logPrefix = "WSLoginFilter.doFilter() , requestDebuggingActivated: " + requestDebuggingActivated + " , ";
+
+ logger.debug(logPrefix + "starting ... ");
+
+ HttpServletRequest requestToUse = (HttpServletRequest) request;
+ HttpServletResponse responseToUse = (HttpServletResponse) response;
+
+ String currentUserIPAddress = null;
+ if (requestToUse.getHeader("X-Forwarded-For") != null) {
+ currentUserIPAddress = requestToUse.getHeader("X-Forwarded-For");
+ } else {
+ logger.warn(logPrefix + "cannot find X-Forwarded-For header, this field is required for proper IP auditing");
+ logger.warn(logPrefix + "Because no X-Forwarded-For header was found, setting 'currentUserIPAddress = requestToUse.getRemoteAddr()' which is typically an internal address");
+ currentUserIPAddress = requestToUse.getRemoteAddr();
+ }
+
+ if (currentUserIPAddress == null || currentUserIPAddress.length() == 0 || "unknown".equalsIgnoreCase(currentUserIPAddress)) {
+ logger.warn(logPrefix + "cannot find valid currentUserIPAddress");
+ } else {
+ logger.warn(logPrefix + "IP validation and rate limiting can go here, on currentUserIPAddress: " + currentUserIPAddress);
+ }
+
+ if (requestDebuggingActivated == 1) {
+ boolean foundElements = false;
+ for (Enumeration en = requestToUse.getParameterNames(); en
+ .hasMoreElements();) {
+
+ foundElements = true;
+
+ Object obj = en.nextElement();
+ String value = request.getParameterValues((String) obj)[0];
+ logger.warn(logPrefix + "on requestDebuggingActivated=1 found String: " +value);
+
+ }
+ if (!foundElements) {
+ logger.warn(logPrefix + "on requestDebuggingActivated=1 , no HTTP elements found!");
+ }
+ }
+
+ chain.doFilter(request, response);
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/WSSecUtils.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/WSSecUtils.java
new file mode 100644
index 0000000..2f5c98b
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/security/webservices/WSSecUtils.java
@@ -0,0 +1,83 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.security.webservices;
+
+import java.util.UUID;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+@Component
+public class WSSecUtils {
+
+ private static final Logger logger = LogManager.getLogger(WSSecUtils.class);
+
+ protected JWTUserDTO getParsedUser(String token) throws Exception {
+ String logPrefix = "WSSecUtils.getParsedUser() , ";
+
+ // JWT and JWE are specifications to generate and validate tokens
+ // securely, however they require a public / private key pair using
+ // elliptic curve cryptography and that is beyond the scope of this
+ // userguide.
+ // See below:
+ // https://datatracker.ietf.org/doc/html/rfc7516
+ // https://datatracker.ietf.org/doc/html/rfc7519
+
+ // token generated via RandomStringUtils.randomAlphanumeric(20);
+ // Do not use this for production code.
+ if (token == null || token.length() != 20) {
+ throw new Exception("Invalid Token");
+ }
+ try {
+ // All of this info is available in the JWT spec
+ // however that is beyond the scope of this userguide
+ JWTUserDTO user = new JWTUserDTO();
+ user.setUsername("java-dev@axis.apache.org");
+ user.setRole("ROLE_USER");
+ // JWT ID that could be from the "Claimset" i.e.
+ // jwt.getJWTClaimsSet().getJWTID());
+ user.setUuid(UUID.randomUUID().toString());
+
+ return user;
+
+ } catch (Exception ex) {
+ logger.error(logPrefix + "failed: " + ex.getMessage(), ex);
+ throw new JWTTokenMalformedException("unexpected error parsing token");
+ }
+
+ }
+
+ public final LoginDTO findUserByEmail(String email) {
+
+ String logPrefix = "WSSecUtils.findUserByEmail() , " ;
+
+ if (email != null && email.equals("java-dev@axis.apache.org")) {
+ LoginDTO persistedUser = new LoginDTO("java-dev@axis.apache.org", "userguide", true, true, true, true);
+ return persistedUser;
+ }
+
+ logger.error(logPrefix + "Unknown email: " + email);
+
+ return null;
+
+ }
+
+}
diff --git a/modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/TestwsRequest.java
similarity index 61%
copy from modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java
copy to modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/TestwsRequest.java
index 619c1ae..fbd1636 100644
--- a/modules/json/src/org/apache/axis2/json/gson/JsonHtmlXssSerializer.java
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/TestwsRequest.java
@@ -1,3 +1,4 @@
+
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -16,24 +17,28 @@
* specific language governing permissions and limitations
* under the License.
*/
+package userguide.springboot.webservices;
-package org.apache.axis2.json.gson;
+public class TestwsRequest {
+
+ String messagein;
+
+ public String getMessagein() {
+ return messagein;
+ }
-import org.owasp.encoder.Encode;
+ public void setMessagein(String messagein) {
+ this.messagein = messagein;
+ }
-import com.google.gson.JsonElement;
-import com.google.gson.JsonPrimitive;
-import com.google.gson.JsonSerializationContext;
-import com.google.gson.JsonSerializer;
-import java.lang.reflect.Type;
+ public TestwsRequest(String messagein) {
+ this.messagein = messagein;
+ }
-public class JsonHtmlXssSerializer implements JsonSerializer<String> {
-
- @Override
- public JsonElement serialize(String src, Type typeOfSrc,
- JsonSerializationContext context) {
-
- return new JsonPrimitive(Encode.forHtmlContent(src));
-
- }
+ @Override
+ public String toString() {
+ return "TestwsRequest [messagein="
+ + messagein + "]";
+ }
+
}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/TestwsResponse.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/TestwsResponse.java
new file mode 100644
index 0000000..dbd42d9
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/TestwsResponse.java
@@ -0,0 +1,56 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.webservices;
+
+public class TestwsResponse {
+
+ String messageout;
+ String status;
+
+ public String getMessageout() {
+ return messageout;
+ }
+
+ public void setMessageout(String messageout) {
+ this.messageout = messageout;
+ }
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public TestwsResponse() {
+ }
+
+ public TestwsResponse(String messageout, String status) {
+ this.messageout = messageout;
+ this.status = status;
+ }
+
+ @Override
+ public String toString() {
+ return "TestwsResponse [messageout="
+ + messageout + " , status=" + status + "]";
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/TestwsService.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/TestwsService.java
new file mode 100644
index 0000000..7fd14c5
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/TestwsService.java
@@ -0,0 +1,71 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.webservices;
+
+import java.util.UUID;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import org.owasp.esapi.ESAPI;
+import org.owasp.esapi.Validator;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class TestwsService {
+
+ private static final Logger logger = LogManager.getLogger(TestwsService.class);
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public TestwsResponse doTestws(TestwsRequest request) {
+
+ String uuid = UUID.randomUUID().toString();
+
+ String logPrefix = "TestwsService.doTestws() , uuid: " + uuid + " , ";
+
+ logger.warn(logPrefix + "starting on request: " + request.toString());
+ TestwsResponse response = new TestwsResponse();
+
+ try {
+ // All data is evil!
+ Validator validator = ESAPI.validator();
+ boolean messageinstatus = validator.isValidInput("userInput", request.getMessagein(), "SafeString", 100 , false);
+ if (!messageinstatus) {
+ logger.error(logPrefix + "returning with failure status on invalid messagein: " + request.getMessagein());
+ response.setStatus("FAILED");
+ return response;
+ }
+ response.setStatus("OK");
+ String evil = "<script xmlns=\"http://www.w3.org/1999/xhtml\">alert('Hello');</script> \">";
+ response.setMessageout(evil);
+
+ logger.warn(logPrefix + "returning response: " + response.toString());
+ return response;
+
+ } catch (Exception ex) {
+ logger.error(logPrefix + "failed: " + ex.getMessage(), ex);
+ response.setStatus("FAILED");
+ return response;
+ }
+
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginRequest.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginRequest.java
new file mode 100644
index 0000000..1e6d5bb
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginRequest.java
@@ -0,0 +1,55 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.webservices.secure;
+
+public class LoginRequest {
+
+ String email;
+
+ String credentials;
+
+ public String getEmail() {
+ return email != null ? email.trim() : null;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getCredentials() {
+ return credentials;
+ }
+
+ public void setCredentials(String credentials) {
+ this.credentials = credentials;
+ }
+
+
+ public LoginRequest(String email, String credentials) {
+ this.email = email;
+ this.credentials = credentials;
+ }
+
+ @Override
+ public String toString() {
+ // implement toString() for debugging in trace mode of axis2
+ return "LoginRequest [email=" + email + ", credentials=not_shown ]";
+ }
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginResponse.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginResponse.java
new file mode 100644
index 0000000..c140b5d
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginResponse.java
@@ -0,0 +1,63 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.webservices.secure;
+
+public class LoginResponse {
+
+ String status;
+
+ String token;
+
+ String uuid;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ public LoginResponse(String status, String token) {
+ this.status = status;
+ this.token = token;
+ }
+
+ public LoginResponse() {
+
+ }
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginService.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginService.java
new file mode 100644
index 0000000..7bddf44
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginService.java
@@ -0,0 +1,238 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package userguide.springboot.webservices.secure;
+
+import java.util.UUID;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+
+import org.apache.commons.lang3.RandomStringUtils;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+
+import userguide.springboot.security.webservices.WSSecUtils;
+import userguide.springboot.security.webservices.LoginDTO;
+import userguide.springboot.security.webservices.RequestAndResponseValidatorFilter;
+import userguide.springboot.hibernate.dao.SpringSecurityDAOImpl;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.axis2.context.MessageContext;
+import org.apache.axis2.transport.http.HTTPConstants;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.owasp.esapi.ESAPI;
+import org.owasp.esapi.Validator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class LoginService {
+
+ private static final Logger logger = LogManager.getLogger(LoginService.class);
+
+ @Autowired
+ SpringSecurityDAOImpl springSecurityDAOImpl;
+
+ @Autowired
+ NoOpPasswordEncoder passwordEncoder;
+
+ @Autowired
+ private WSSecUtils wssecutils;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public LoginResponse doLogin(LoginRequest request) {
+
+ Long startTime = System.currentTimeMillis();
+
+ String uuid = UUID.randomUUID().toString();
+
+ String logPrefix = "LoginService.doLogin() , "
+ + " , uuid: " + uuid + " , request: " + request.toString() + " , ";
+
+ logger.warn(logPrefix + "starting ... ");
+ LoginResponse response = new LoginResponse();
+
+ try {
+ if (request == null) {
+ logger.error(logPrefix + "returning with failure status on null LoginRequest");
+ response.setStatus("FAILED");
+ return response;
+ }
+ if (request.getEmail() == null) {
+ logger.error(logPrefix + "returning with failure status on null email");
+ response.setStatus("FAILED");
+ return response;
+ }
+ request.email = request.email.trim();
+
+ MessageContext ctx = MessageContext.getCurrentMessageContext();
+ HttpServletRequest httpServletRequest = (HttpServletRequest) ctx.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
+ if (httpServletRequest == null) {
+ logger.error(logPrefix + "returning with failure status on null httpServletRequest");
+ response.setStatus("FAILED");
+ return response;
+ }
+ String currentUserIPAddress = null;
+
+ if (httpServletRequest.getHeader("X-Forwarded-For") != null) {
+ currentUserIPAddress = httpServletRequest.getHeader("X-Forwarded-For");
+ } else {
+ logger.warn(logPrefix + "cannot find X-Forwarded-For header, this field is required for proper IP auditing");
+ currentUserIPAddress = httpServletRequest.getRemoteAddr();
+ logger.warn(logPrefix + "found currentUserIPAddress from httpServletRequest.getRemoteAddr() :" + currentUserIPAddress);
+ }
+ // All data is evil!
+ Validator validator = ESAPI.validator();
+
+ String email = request.getEmail().trim();
+ boolean emailstatus = validator.isValidInput("userInput", email, "Email", 100 , false);
+ if (!emailstatus) {
+ logger.error(logPrefix + "returning with failure status on invalid email (in quotes): '" + email + "'");
+ response.setStatus("FAILED");
+ return response;
+ }
+
+ String creds = "";
+ // handle unicode escaped chars that were sent that way for '@' etc
+ if (request.getCredentials().contains("u00")) {
+ String uu = request.getCredentials();
+ String uut = uu.replaceAll("u00", "\\\\u00");
+ creds = StringEscapeUtils.unescapeJava(uut);
+ } else {
+ creds = request.getCredentials();
+ if (logger.isTraceEnabled()) {
+ logger.trace(logPrefix + "found creds: " +creds);
+ }
+ }
+ // passwords require special char's ... just do some minimal validation
+ boolean credentialsstatus = RequestAndResponseValidatorFilter.validate(creds);
+ if (!credentialsstatus || creds.length() > 100) {
+ logger.error(logPrefix + "returning with failure status, credentials failed validation, credentialsstatus: " + credentialsstatus + " , length: " + creds.length());
+ response.setStatus("FAILED");
+
+ return response;
+ }
+
+ LoginDTO loginDTO = null;
+ try {
+ loginDTO = wssecutils.findUserByEmail(email);
+ } catch (Exception ex) {
+ logger.error(logPrefix + "cannot create LoginDTO from email: " + email + " , " + ex.getMessage(), ex);
+ response.setStatus("FAILED");
+ return response;
+ }
+
+ if (loginDTO == null) {
+ logger.error(logPrefix + "returning with failure status on failed creation of LoginDTO from email: " + email);
+ response.setStatus("FAILED");
+ return response;
+ }
+
+ logger.warn(logPrefix + "found loginDTO: " + loginDTO.toString());
+
+ response.setUuid(uuid);
+ UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(email, creds);
+
+ logger.warn(logPrefix
+ + "calling authenticate(authRequest) with username: " + email);
+
+ boolean hasFailedLogin = false;
+ String failedStr = "";
+ try {
+ // will throw an Exception if it fails
+ DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
+ daoAuthenticationProvider.setUserDetailsService(springSecurityDAOImpl);
+ daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
+ Authentication authResult = daoAuthenticationProvider.authenticate(authRequest);
+ logger.warn(logPrefix + "authenticate(authRequest) completed successfully with username: " + email);
+ } catch (Exception ex) {
+ if (ex.getMessage() == null) {
+ failedStr = "Authentication Exception failed state is undefined";
+ } else {
+ failedStr = ex.getMessage();
+ }
+ logger.error(logPrefix + "failed: " + failedStr, ex);
+ hasFailedLogin = true;
+ }
+
+ if (hasFailedLogin) {
+ logger.error(logPrefix + "returning with failure status on failed login");
+ response.setStatus("LOGIN FAILED");
+ return response;
+ }
+
+
+ if (!generateTokenForReturn(httpServletRequest, request, response, currentUserIPAddress, email, uuid)) {
+ logger.warn(logPrefix + "generateTokenForReturn() failed, goodbye");
+ response.setStatus("TOKEN GENERION FAILED");
+ }
+
+ return response;
+
+ } catch (Exception ex) {
+ logger.error(logPrefix + "failed: " + ex.getMessage(), ex);
+ response.setStatus("FAILED");
+ return response;
+ }
+
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private boolean generateTokenForReturn(HttpServletRequest httpServletRequest, LoginRequest request, LoginResponse response, String currentUserIPAddress, String email, String uuid) {
+
+ String logPrefix = "LoginService.generateTokenForReturn() , "
+ + " , uuid: " + uuid + " , ";
+
+ try {
+ String token = null;
+
+ // JWT and JWE are specifications to generate and validate tokens
+ // securely, however they require a public / private key pair using
+ // elliptic curve cryptography and that is beyond the scope of this
+ // userguide.
+ // See below:
+ // https://datatracker.ietf.org/doc/html/rfc7516
+ // https://datatracker.ietf.org/doc/html/rfc7519
+
+ // this is an example only for demo purposes - do not use this for
+ // production code
+ token = RandomStringUtils.randomAlphanumeric(20);
+
+ response.setStatus("OK");
+ response.setToken(token);
+
+ return true;
+
+ } catch (Exception ex) {
+ logger.error(logPrefix + "failed: " + ex.getMessage(), ex);
+ response.setStatus("FAILED");
+ return false;
+ }
+
+ }
+
+
+}
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/ESAPI.properties b/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/ESAPI.properties
new file mode 100644
index 0000000..710a84e
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/ESAPI.properties
@@ -0,0 +1,461 @@
+#
+# OWASP Enterprise Security API (ESAPI) Properties file -- PRODUCTION Version
+#
+# This file is part of the Open Web Application Security Project (OWASP)
+# Enterprise Security API (ESAPI) project. For details, please see
+# http://www.owasp.org/index.php/ESAPI.
+#
+# Copyright (c) 2008,2009 - The OWASP Foundation
+#
+# DISCUSS: This may cause a major backwards compatibility issue, etc. but
+# from a name space perspective, we probably should have prefaced
+# all the property names with ESAPI or at least OWASP. Otherwise
+# there could be problems is someone loads this properties file into
+# the System properties. We could also put this file into the
+# esapi.jar file (perhaps as a ResourceBundle) and then allow an external
+# ESAPI properties be defined that would overwrite these defaults.
+# That keeps the application's properties relatively simple as usually
+# they will only want to override a few properties. If looks like we
+# already support multiple override levels of this in the
+# DefaultSecurityConfiguration class, but I'm suggesting placing the
+# defaults in the esapi.jar itself. That way, if the jar is signed,
+# we could detect if those properties had been tampered with. (The
+# code to check the jar signatures is pretty simple... maybe 70-90 LOC,
+# but off course there is an execution penalty (similar to the way
+# that the separate sunjce.jar used to be when a class from it was
+# first loaded). Thoughts?
+###############################################################################
+#
+# WARNING: Operating system protection should be used to lock down the .esapi
+# resources directory and all the files inside and all the directories all the
+# way up to the root directory of the file system. Note that if you are using
+# file-based implementations, that some files may need to be read-write as they
+# get updated dynamically.
+#
+# Before using, be sure to update the MasterKey and MasterSalt as described below.
+# N.B.: If you had stored data that you have previously encrypted with ESAPI 1.4,
+# you *must* FIRST decrypt it using ESAPI 1.4 and then (if so desired)
+# re-encrypt it with ESAPI 2.0. If you fail to do this, you will NOT be
+# able to decrypt your data with ESAPI 2.0.
+#
+# YOU HAVE BEEN WARNED!!! More details are in the ESAPI 2.0 Release Notes.
+#
+#===========================================================================
+# ESAPI Configuration
+#
+# If true, then print all the ESAPI properties set here when they are loaded.
+# If false, they are not printed. Useful to reduce output when running JUnit tests.
+# If you need to troubleshoot a properties related problem, turning this on may help.
+# This is 'false' in the src/test/resources/.esapi version. It is 'true' by
+# default for reasons of backward compatibility with earlier ESAPI versions.
+ESAPI.printProperties=true
+
+# ESAPI is designed to be easily extensible. You can use the reference implementation
+# or implement your own providers to take advantage of your enterprise's security
+# infrastructure. The functions in ESAPI are referenced using the ESAPI locator, like:
+#
+# String ciphertext =
+# ESAPI.encryptor().encrypt("Secret message"); // Deprecated in 2.0
+# CipherText cipherText =
+# ESAPI.encryptor().encrypt(new PlainText("Secret message")); // Preferred
+#
+# Below you can specify the classname for the provider that you wish to use in your
+# application. The only requirement is that it implement the appropriate ESAPI interface.
+# This allows you to switch security implementations in the future without rewriting the
+# entire application.
+#
+# ExperimentalAccessController requires ESAPI-AccessControlPolicy.xml in .esapi directory
+ESAPI.AccessControl=org.owasp.esapi.reference.DefaultAccessController
+# FileBasedAuthenticator requires users.txt file in .esapi directory
+ESAPI.Authenticator=org.owasp.esapi.reference.FileBasedAuthenticator
+ESAPI.Encoder=org.owasp.esapi.reference.DefaultEncoder
+ESAPI.Encryptor=org.owasp.esapi.reference.crypto.JavaEncryptor
+
+ESAPI.Executor=org.owasp.esapi.reference.DefaultExecutor
+ESAPI.HTTPUtilities=org.owasp.esapi.reference.DefaultHTTPUtilities
+ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector
+ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory
+
+ESAPI.Randomizer=org.owasp.esapi.reference.DefaultRandomizer
+ESAPI.Validator=org.owasp.esapi.reference.DefaultValidator
+
+#===========================================================================
+# ESAPI Authenticator
+#
+Authenticator.AllowedLoginAttempts=3
+Authenticator.MaxOldPasswordHashes=13
+Authenticator.UsernameParameterName=username
+Authenticator.PasswordParameterName=password
+# RememberTokenDuration (in days)
+Authenticator.RememberTokenDuration=14
+# Session Timeouts (in minutes)
+Authenticator.IdleTimeoutDuration=20
+Authenticator.AbsoluteTimeoutDuration=120
+
+#===========================================================================
+# ESAPI Encoder
+#
+# ESAPI canonicalizes input before validation to prevent bypassing filters with encoded attacks.
+# Failure to canonicalize input is a very common mistake when implementing validation schemes.
+# Canonicalization is automatic when using the ESAPI Validator, but you can also use the
+# following code to canonicalize data.
+#
+# ESAPI.Encoder().canonicalize( "%22hello world"" );
+#
+# Multiple encoding is when a single encoding format is applied multiple times. Allowing
+# multiple encoding is strongly discouraged.
+Encoder.AllowMultipleEncoding=false
+
+# Mixed encoding is when multiple different encoding formats are applied, or when
+# multiple formats are nested. Allowing multiple encoding is strongly discouraged.
+Encoder.AllowMixedEncoding=false
+
+# The default list of codecs to apply when canonicalizing untrusted data. The list should include the codecs
+# for all downstream interpreters or decoders. For example, if the data is likely to end up in a URL, HTML, or
+# inside JavaScript, then the list of codecs below is appropriate. The order of the list is not terribly important.
+Encoder.DefaultCodecList=HTMLEntityCodec,PercentCodec,JavaScriptCodec
+
+
+#===========================================================================
+# ESAPI Encryption
+#
+# The ESAPI Encryptor provides basic cryptographic functions with a simplified API.
+# To get started, generate a new key using java -classpath esapi.jar org.owasp.esapi.reference.crypto.JavaEncryptor
+# There is not currently any support for key rotation, so be careful when changing your key and salt as it
+# will invalidate all signed, encrypted, and hashed data.
+#
+# WARNING: Not all combinations of algorithms and key lengths are supported.
+# If you choose to use a key length greater than 128, you MUST download the
+# unlimited strength policy files and install in the lib directory of your JRE/JDK.
+# See http://java.sun.com/javase/downloads/index.jsp for more information.
+#
+# Backward compatibility with ESAPI Java 1.4 is supported by the two deprecated API
+# methods, Encryptor.encrypt(String) and Encryptor.decrypt(String). However, whenever
+# possible, these methods should be avoided as they use ECB cipher mode, which in almost
+# all circumstances a poor choice because of it's weakness. CBC cipher mode is the default
+# for the new Encryptor encrypt / decrypt methods for ESAPI Java 2.0. In general, you
+# should only use this compatibility setting if you have persistent data encrypted with
+# version 1.4 and even then, you should ONLY set this compatibility mode UNTIL
+# you have decrypted all of your old encrypted data and then re-encrypted it with
+# ESAPI 2.0 using CBC mode. If you have some reason to mix the deprecated 1.4 mode
+# with the new 2.0 methods, make sure that you use the same cipher algorithm for both
+# (256-bit AES was the default for 1.4; 128-bit is the default for 2.0; see below for
+# more details.) Otherwise, you will have to use the new 2.0 encrypt / decrypt methods
+# where you can specify a SecretKey. (Note that if you are using the 256-bit AES,
+# that requires downloading the special jurisdiction policy files mentioned above.)
+#
+# ***** IMPORTANT: Do NOT forget to replace these with your own values! *****
+# To calculate these values, you can run:
+# java -classpath esapi.jar org.owasp.esapi.reference.crypto.JavaEncryptor
+#
+#Encryptor.MasterKey=
+#Encryptor.MasterSalt=
+
+# Provides the default JCE provider that ESAPI will "prefer" for its symmetric
+# encryption and hashing. (That is it will look to this provider first, but it
+# will defer to other providers if the requested algorithm is not implemented
+# by this provider.) If left unset, ESAPI will just use your Java VM's current
+# preferred JCE provider, which is generally set in the file
+# "$JAVA_HOME/jre/lib/security/java.security".
+#
+# The main intent of this is to allow ESAPI symmetric encryption to be
+# used with a FIPS 140-2 compliant crypto-module. For details, see the section
+# "Using ESAPI Symmetric Encryption with FIPS 140-2 Cryptographic Modules" in
+# the ESAPI 2.0 Symmetric Encryption User Guide, at:
+# http://owasp-esapi-java.googlecode.com/svn/trunk/documentation/esapi4java-core-2.0-symmetric-crypto-user-guide.html
+# However, this property also allows you to easily use an alternate JCE provider
+# such as "Bouncy Castle" without having to make changes to "java.security".
+# See Javadoc for SecurityProviderLoader for further details. If you wish to use
+# a provider that is not known to SecurityProviderLoader, you may specify the
+# fully-qualified class name of the JCE provider class that implements
+# java.security.Provider. If the name contains a '.', this is interpreted as
+# a fully-qualified class name that implements java.security.Provider.
+#
+# NOTE: Setting this property has the side-effect of changing it in your application
+# as well, so if you are using JCE in your application directly rather than
+# through ESAPI (you wouldn't do that, would you? ;-), it will change the
+# preferred JCE provider there as well.
+#
+# Default: Keeps the JCE provider set to whatever JVM sets it to.
+Encryptor.PreferredJCEProvider=
+
+# AES is the most widely used and strongest encryption algorithm. This
+# should agree with your Encryptor.CipherTransformation property.
+# By default, ESAPI Java 1.4 uses "PBEWithMD5AndDES" and which is
+# very weak. It is essentially a password-based encryption key, hashed
+# with MD5 around 1K times and then encrypted with the weak DES algorithm
+# (56-bits) using ECB mode and an unspecified padding (it is
+# JCE provider specific, but most likely "NoPadding"). However, 2.0 uses
+# "AES/CBC/PKCSPadding". If you want to change these, change them here.
+# Warning: This property does not control the default reference implementation for
+# ESAPI 2.0 using JavaEncryptor. Also, this property will be dropped
+# in the future.
+# @deprecated
+Encryptor.EncryptionAlgorithm=AES
+# For ESAPI Java 2.0 - New encrypt / decrypt methods use this.
+Encryptor.CipherTransformation=AES/CBC/PKCS5Padding
+
+# Applies to ESAPI 2.0 and later only!
+# Comma-separated list of cipher modes that provide *BOTH*
+# confidentiality *AND* message authenticity. (NIST refers to such cipher
+# modes as "combined modes" so that's what we shall call them.) If any of these
+# cipher modes are used then no MAC is calculated and stored
+# in the CipherText upon encryption. Likewise, if one of these
+# cipher modes is used with decryption, no attempt will be made
+# to validate the MAC contained in the CipherText object regardless
+# of whether it contains one or not. Since the expectation is that
+# these cipher modes support support message authenticity already,
+# injecting a MAC in the CipherText object would be at best redundant.
+#
+# Note that as of JDK 1.5, the SunJCE provider does not support *any*
+# of these cipher modes. Of these listed, only GCM and CCM are currently
+# NIST approved. YMMV for other JCE providers. E.g., Bouncy Castle supports
+# GCM and CCM with "NoPadding" mode, but not with "PKCS5Padding" or other
+# padding modes.
+Encryptor.cipher_modes.combined_modes=GCM,CCM,IAPM,EAX,OCB,CWC
+
+# Applies to ESAPI 2.0 and later only!
+# Additional cipher modes allowed for ESAPI 2.0 encryption. These
+# cipher modes are in _addition_ to those specified by the property
+# 'Encryptor.cipher_modes.combined_modes'.
+# Note: We will add support for streaming modes like CFB & OFB once
+# we add support for 'specified' to the property 'Encryptor.ChooseIVMethod'
+# (probably in ESAPI 2.1).
+# DISCUSS: Better name?
+Encryptor.cipher_modes.additional_allowed=CBC
+
+# 128-bit is almost always sufficient and appears to be more resistant to
+# related key attacks than is 256-bit AES. Use '_' to use default key size
+# for cipher algorithms (where it makes sense because the algorithm supports
+# a variable key size). Key length must agree to what's provided as the
+# cipher transformation, otherwise this will be ignored after logging a
+# warning.
+#
+# NOTE: This is what applies BOTH ESAPI 1.4 and 2.0. See warning above about mixing!
+Encryptor.EncryptionKeyLength=128
+
+# Because 2.0 uses CBC mode by default, it requires an initialization vector (IV).
+# (All cipher modes except ECB require an IV.) There are two choices: we can either
+# use a fixed IV known to both parties or allow ESAPI to choose a random IV. While
+# the IV does not need to be hidden from adversaries, it is important that the
+# adversary not be allowed to choose it. Also, random IVs are generally much more
+# secure than fixed IVs. (In fact, it is essential that feed-back cipher modes
+# such as CFB and OFB use a different IV for each encryption with a given key so
+# in such cases, random IVs are much preferred. By default, ESAPI 2.0 uses random
+# IVs. If you wish to use 'fixed' IVs, set 'Encryptor.ChooseIVMethod=fixed' and
+# uncomment the Encryptor.fixedIV.
+#
+# Valid values: random|fixed|specified 'specified' not yet implemented; planned for 2.1
+Encryptor.ChooseIVMethod=random
+# If you choose to use a fixed IV, then you must place a fixed IV here that
+# is known to all others who are sharing your secret key. The format should
+# be a hex string that is the same length as the cipher block size for the
+# cipher algorithm that you are using. The following is an *example* for AES
+# from an AES test vector for AES-128/CBC as described in:
+# NIST Special Publication 800-38A (2001 Edition)
+# "Recommendation for Block Cipher Modes of Operation".
+# (Note that the block size for AES is 16 bytes == 128 bits.)
+#
+Encryptor.fixedIV=0x000102030405060708090a0b0c0d0e0f
+
+# Whether or not CipherText should use a message authentication code (MAC) with it.
+# This prevents an adversary from altering the IV as well as allowing a more
+# fool-proof way of determining the decryption failed because of an incorrect
+# key being supplied. This refers to the "separate" MAC calculated and stored
+# in CipherText, not part of any MAC that is calculated as a result of a
+# "combined mode" cipher mode.
+#
+# If you are using ESAPI with a FIPS 140-2 cryptographic module, you *must* also
+# set this property to false.
+Encryptor.CipherText.useMAC=true
+
+# Whether or not the PlainText object may be overwritten and then marked
+# eligible for garbage collection. If not set, this is still treated as 'true'.
+Encryptor.PlainText.overwrite=true
+
+# Do not use DES except in a legacy situations. 56-bit is way too small key size.
+#Encryptor.EncryptionKeyLength=56
+#Encryptor.EncryptionAlgorithm=DES
+
+# TripleDES is considered strong enough for most purposes.
+# Note: There is also a 112-bit version of DESede. Using the 168-bit version
+# requires downloading the special jurisdiction policy from Sun.
+#Encryptor.EncryptionKeyLength=168
+#Encryptor.EncryptionAlgorithm=DESede
+
+Encryptor.HashAlgorithm=SHA-512
+Encryptor.HashIterations=1024
+Encryptor.DigitalSignatureAlgorithm=SHA1withDSA
+Encryptor.DigitalSignatureKeyLength=1024
+Encryptor.RandomAlgorithm=SHA1PRNG
+Encryptor.CharacterEncoding=UTF-8
+
+# This is the Pseudo Random Function (PRF) that ESAPI's Key Derivation Function
+# (KDF) normally uses. Note this is *only* the PRF used for ESAPI's KDF and
+# *not* what is used for ESAPI's MAC. (Currently, HmacSHA1 is always used for
+# the MAC, mostly to keep the overall size at a minimum.)
+#
+# Currently supported choices for JDK 1.5 and 1.6 are:
+# HmacSHA1 (160 bits), HmacSHA256 (256 bits), HmacSHA384 (384 bits), and
+# HmacSHA512 (512 bits).
+# Note that HmacMD5 is *not* supported for the PRF used by the KDF even though
+# the JDKs support it. See the ESAPI 2.0 Symmetric Encryption User Guide
+# further details.
+Encryptor.KDF.PRF=HmacSHA256
+#===========================================================================
+# ESAPI HttpUtilties
+#
+# The HttpUtilities provide basic protections to HTTP requests and responses. Primarily these methods
+# protect against malicious data from attackers, such as unprintable characters, escaped characters,
+# and other simple attacks. The HttpUtilities also provides utility methods for dealing with cookies,
+# headers, and CSRF tokens.
+#
+# Default file upload location (remember to escape backslashes with \\)
+# HttpUtilities.UploadDir=C:\\ESAPI\\testUpload
+# HttpUtilities.UploadTempDir=C:\\temp
+# Force flags on cookies, if you use HttpUtilities to set cookies
+HttpUtilities.ForceHttpOnlySession=false
+HttpUtilities.ForceSecureSession=false
+HttpUtilities.ForceHttpOnlyCookies=true
+HttpUtilities.ForceSecureCookies=true
+# Maximum size of HTTP headers
+HttpUtilities.MaxHeaderSize=4096
+# File upload configuration
+HttpUtilities.ApprovedUploadExtensions=.zip,.pdf,.doc,.docx,.ppt,.pptx,.tar,.gz,.tgz,.rar,.war,.jar,.ear,.xls,.rtf,.properties,.java,.class,.txt,.xml,.jsp,.jsf,.exe,.dll
+HttpUtilities.MaxUploadFileBytes=500000000
+# Using UTF-8 throughout your stack is highly recommended. That includes your database driver,
+# container, and any other technologies you may be using. Failure to do this may expose you
+# to Unicode transcoding injection attacks. Use of UTF-8 does not hinder internationalization.
+HttpUtilities.ResponseContentType=text/html; charset=UTF-8
+# This is the name of the cookie used to represent the HTTP session
+# Typically this will be the default "JSESSIONID"
+HttpUtilities.HttpSessionIdName=JSESSIONID
+
+
+
+#===========================================================================
+# ESAPI Executor
+# CHECKME - This should be made OS independent. Don't use unsafe defaults.
+# # Examples only -- do NOT blindly copy!
+# For Windows:
+# Executor.WorkingDirectory=C:\\Windows\\Temp
+# Executor.ApprovedExecutables=C:\\Windows\\System32\\cmd.exe,C:\\Windows\\System32\\runas.exe
+# For *nux, MacOS:
+# Executor.WorkingDirectory=/tmp
+# Executor.ApprovedExecutables=/bin/bash
+Executor.WorkingDirectory=
+Executor.ApprovedExecutables=
+
+
+#===========================================================================
+# ESAPI Logging
+# Set the application name if these logs are combined with other applications
+Logger.ApplicationName=DPT
+# If you use an HTML log viewer that does not properly HTML escape log data, you can set LogEncodingRequired to true
+Logger.LogEncodingRequired=false
+# Determines whether ESAPI should log the application name. This might be clutter in some single-server/single-app environments.
+Logger.LogApplicationName=true
+# Determines whether ESAPI should log the server IP and port. This might be clutter in some single-server environments.
+Logger.LogServerIP=true
+# Determines whether ESAPI should log the user info.
+Logger.UserInfo=true
+# Determines whether ESAPI should log the session id and client IP.
+Logger.ClientInfo=true
+
+
+#===========================================================================
+# ESAPI Intrusion Detection
+#
+# Each event has a base to which .count, .interval, and .action are added
+# The IntrusionException will fire if we receive "count" events within "interval" seconds
+# The IntrusionDetector is configurable to take the following actions: log, logout, and disable
+# (multiple actions separated by commas are allowed e.g. event.test.actions=log,disable
+#
+# Custom Events
+# Names must start with "event." as the base
+# Use IntrusionDetector.addEvent( "test" ) in your code to trigger "event.test" here
+# You can also disable intrusion detection completely by changing
+# the following parameter to true
+#
+IntrusionDetector.Disable=false
+#
+IntrusionDetector.event.test.count=2
+IntrusionDetector.event.test.interval=10
+IntrusionDetector.event.test.actions=disable,log
+
+# Exception Events
+# All EnterpriseSecurityExceptions are registered automatically
+# Call IntrusionDetector.getInstance().addException(e) for Exceptions that do not extend EnterpriseSecurityException
+# Use the fully qualified classname of the exception as the base
+
+# any intrusion is an attack
+IntrusionDetector.org.owasp.esapi.errors.IntrusionException.count=1
+IntrusionDetector.org.owasp.esapi.errors.IntrusionException.interval=1
+IntrusionDetector.org.owasp.esapi.errors.IntrusionException.actions=log,disable,logout
+
+# for test purposes
+# CHECKME: Shouldn't there be something in the property name itself that designates
+# that these are for testing???
+IntrusionDetector.org.owasp.esapi.errors.IntegrityException.count=10
+IntrusionDetector.org.owasp.esapi.errors.IntegrityException.interval=5
+IntrusionDetector.org.owasp.esapi.errors.IntegrityException.actions=log,disable,logout
+
+# rapid validation errors indicate scans or attacks in progress
+# org.owasp.esapi.errors.ValidationException.count=10
+# org.owasp.esapi.errors.ValidationException.interval=10
+# org.owasp.esapi.errors.ValidationException.actions=log,logout
+
+# sessions jumping between hosts indicates session hijacking
+IntrusionDetector.org.owasp.esapi.errors.AuthenticationHostException.count=2
+IntrusionDetector.org.owasp.esapi.errors.AuthenticationHostException.interval=10
+IntrusionDetector.org.owasp.esapi.errors.AuthenticationHostException.actions=log,logout
+
+
+#===========================================================================
+# ESAPI Validation
+#
+# The ESAPI Validator works on regular expressions with defined names. You can define names
+# either here, or you may define application specific patterns in a separate file defined below.
+# This allows enterprises to specify both organizational standards as well as application specific
+# validation rules.
+#
+Validator.ConfigurationFile=validation.properties
+
+# Validators used by ESAPI
+Validator.AccountName=^[a-zA-Z0-9]{3,20}$
+Validator.SystemCommand=^[a-zA-Z\\-\\/]{1,64}$
+Validator.RoleName=^[a-z]{1,20}$
+
+#the word TEST below should be changed to your application
+#name - only relative URL's are supported
+Validator.Redirect=^\\/test.*$
+
+# Global HTTP Validation Rules
+# Values with Base64 encoded data (e.g. encrypted state) will need at least [a-zA-Z0-9\/+=]
+Validator.HTTPScheme=^(http|https)$
+Validator.HTTPServerName=^[a-zA-Z0-9_.\\-]*$
+Validator.HTTPParameterName=^[a-zA-Z0-9_]{1,32}$
+Validator.HTTPParameterValue=^[a-zA-Z0-9.\\-\\/+=@_,:\\\\ ]*$
+Validator.HTTPParameterTransactionValue=^[a-zA-Z0-9.\\-\\/+=@_<>:\\"\\-, ]*$
+Validator.HTTPCookieName=^[a-zA-Z0-9\\-_]{1,32}$
+Validator.HTTPCookieValue=^[a-zA-Z0-9\\-\\/+=_ ]*$
+Validator.HTTPHeaderName=^[a-zA-Z0-9\\-_]{1,32}$
+Validator.HTTPHeaderValue=^[a-zA-Z0-9()\\-=\\*\\.\\?;,+\\/:&_ ]*$
+Validator.HTTPContextPath=^\\/?[a-zA-Z0-9.\\-\\/_]*$
+Validator.HTTPServletPath=^[a-zA-Z0-9.\\-\\/_]*$
+Validator.HTTPPath=^[a-zA-Z0-9.\\-_]*$
+Validator.HTTPQueryString=^[a-zA-Z0-9()\\-=\\*\\.\\?;,+\\/:&_ %]*$
+Validator.HTTPURI=^[a-zA-Z0-9()\\-=\\*\\.\\?;,+\\/:&_ ]*$
+Validator.HTTPURL=^.*$
+Validator.HTTPJSESSIONID=^[A-Z0-9]{10,30}$
+Validator.SafeString=^[.\\p{Alnum}\\p{Space}]{0,1024}$
+Validator.Email=^[A-Za-z0-9._%'\\-+]+@[A-Za-z0-9.-]+\\.[a-zA-Z]{2,4}$
+Validator.IPAddress=^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
+
+# Validation of file related input
+Validator.FileName=^[a-zA-Z0-9!@#$%^&{}\\[\\]()_+\\-=,.~'` ]{1,255}$
+Validator.DirectoryName=^[a-zA-Z0-9:/\\\\!@#$%^&{}\\[\\]()_+\\-=,.~'` ]{1,255}$
+
+# Validation of dates. Controls whether or not 'lenient' dates are accepted.
+# See DataFormat.setLenient(boolean flag) for further details.
+Validator.AcceptLenientDates=false
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/application.properties b/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/application.properties
new file mode 100644
index 0000000..b59217d
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+requestDebuggingActivated=1
+spring.main.allow-bean-definition-overriding=true
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/esapi-java-logging.properties b/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/esapi-java-logging.properties
new file mode 100644
index 0000000..c5f619b
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/esapi-java-logging.properties
@@ -0,0 +1,6 @@
+handlers= java.util.logging.ConsoleHandler
+.level= INFO
+java.util.logging.ConsoleHandler.level = INFO
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+java.util.logging.SimpleFormatter.format=[%1$tF %1$tT] [%3$-7s] %5$s %n
+#https://www.logicbig.com/tutorials/core-java-tutorial/logging/customizing-default-format.html
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/log4j2.xml b/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..fe37cbd
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/resources/log4j2.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="warn" name="MyApp" packages="">
+ <Appenders>
+ <Console name="Console" target="SYSTEM_OUT">
+ <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
+ </Console>
+ <RollingFile name="RollingFile" fileName="axis2-json-api.log"
+ filePattern="axis2-json-api-%d{MM-dd-yyyy}-%i.log">
+ <PatternLayout>
+ <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
+ </PatternLayout>
+ <Policies>
+ <TimeBasedTriggeringPolicy />
+ <SizeBasedTriggeringPolicy size="20 MB"/>
+ </Policies>
+ <DefaultRolloverStrategy max="20"/>
+ </RollingFile>
+ </Appenders>
+ <Loggers>
+ <Logger name="userguide.springboot" level="debug" additivity="false" >
+ <AppenderRef ref="RollingFile"/>
+ <AppenderRef ref="Console"/>
+ </Logger>
+ <Logger name="org.apache" level="warn" additivity="false" >
+ <AppenderRef ref="RollingFile"/>
+ <AppenderRef ref="Console"/>
+ </Logger>
+ <Logger name="org.apache.axis2" level="warn" additivity="false" >
+ <AppenderRef ref="RollingFile"/>
+ <AppenderRef ref="Console"/>
+ </Logger>
+ <Logger name="org.springframework" level="warn" additivity="false" >
+ <AppenderRef ref="RollingFile"/>
+ <AppenderRef ref="Console"/>
+ </Logger>
+ <Root level="debug">
+ <AppenderRef ref="RollingFile"/>
+ </Root>
+ </Loggers>
+</Configuration>
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/modules/samples/userguide/src/userguide/springbootdemo/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
new file mode 100644
index 0000000..6840eea
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -0,0 +1,13 @@
+<jboss-deployment-structure>
+ <deployment>
+ <exclude-subsystems>
+ <subsystem name="jaxrs" />
+ </exclude-subsystems>
+ <exclusions>
+ <module name="org.apache.log4j" /> <module name="org.apache.commons.logging" />
+ </exclusions>
+ <dependencies>
+ <module name="jdk.unsupported" slot="main" export="true" />
+ </dependencies>
+ </deployment>
+</jboss-deployment-structure>
diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/webapp/WEB-INF/jboss-web.xml b/modules/samples/userguide/src/userguide/springbootdemo/src/main/webapp/WEB-INF/jboss-web.xml
new file mode 100755
index 0000000..4259d75
--- /dev/null
+++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/webapp/WEB-INF/jboss-web.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!DOCTYPE jboss-web PUBLIC
+ "-//JBoss//DTD Web Application 5.0//EN"
+ "http://www.jboss.org/j2ee/dtd/jboss-web_5_0.dtd">
+<!-- force JBoss home page to the one and only war file that has this file defined on each server.
+ There can only be one root context per server.
+-->
+<jboss-web>
+ <!--deleteThisCommentForRootContext <context-root>/</context-root> deleteThisCommentForRootContext-->
+</jboss-web>
diff --git a/modules/webapp/src/main/webapp/WEB-INF/include/footer.inc b/modules/webapp/src/main/webapp/WEB-INF/include/footer.inc
index da9e51d..de42cb3 100644
--- a/modules/webapp/src/main/webapp/WEB-INF/include/footer.inc
+++ b/modules/webapp/src/main/webapp/WEB-INF/include/footer.inc
@@ -31,7 +31,7 @@
</tr>
<tr>
<td align="center">
- Copyright © 1999-2006, The Apache Software Foundation<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
+ Copyright © 1999-2021, The Apache Software Foundation<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
</td>
</tr>
</table>
diff --git a/modules/webapp/src/main/webapp/axis2-web/Error/GenError.html b/modules/webapp/src/main/webapp/axis2-web/Error/GenError.html
index 748fbb2..de5355d 100644
--- a/modules/webapp/src/main/webapp/axis2-web/Error/GenError.html
+++ b/modules/webapp/src/main/webapp/axis2-web/Error/GenError.html
@@ -41,4 +41,4 @@
</tr>
</table>
</body>
-</html>
\ No newline at end of file
+</html>
diff --git a/modules/webapp/src/main/webapp/axis2-web/Error/error404.jsp b/modules/webapp/src/main/webapp/axis2-web/Error/error404.jsp
index b57fc76..c64576b 100644
--- a/modules/webapp/src/main/webapp/axis2-web/Error/error404.jsp
+++ b/modules/webapp/src/main/webapp/axis2-web/Error/error404.jsp
@@ -51,7 +51,7 @@
<table summary="embedded footer table">
<tr><td><hr size="1" noshade="noshade"></td></tr>
<tr>
- <td align="center">Copyright © 1999-2006, The Apache Software Foundation<br>Licensed under the <a
+ <td align="center">Copyright © 1999-2021, The Apache Software Foundation<br>Licensed under the <a
href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</td>
</tr>
</table>
diff --git a/modules/webapp/src/main/webapp/axis2-web/Error/error500.jsp b/modules/webapp/src/main/webapp/axis2-web/Error/error500.jsp
index 696c95f..886f55d 100644
--- a/modules/webapp/src/main/webapp/axis2-web/Error/error500.jsp
+++ b/modules/webapp/src/main/webapp/axis2-web/Error/error500.jsp
@@ -52,7 +52,7 @@
<table summary="embedded footer table">
<tr><td><hr></td></tr>
<tr>
- <td style="align: center">Copyright © 1999-2006, The Apache Software Foundation<br>Licensed under the <a
+ <td style="align: center">Copyright © 1999-2021, The Apache Software Foundation<br>Licensed under the <a
href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</td>
</tr>
</table>
diff --git a/src/site/xdoc/docs/userguide.xml b/src/site/xdoc/docs/userguide.xml
index 551d92b..c9a130c 100644
--- a/src/site/xdoc/docs/userguide.xml
+++ b/src/site/xdoc/docs/userguide.xml
@@ -35,8 +35,10 @@
use Axis2 to create and deploy Web services as well as how to use
WSDL to generate both clients and services.</p>
For experienced users of Apache Axis2, we recommend the <a href=
-"adv-userguide.html">Advanced User's Guide.</a> <a name="intro" id=
-"intro"></a>
+"adv-userguide.html">Advanced User's Guide.</a>
+For users of JSON and Spring Boot, see the sample application in the <a href=
+"json-springboot-userguide.html">JSON and Spring Boot User's Guide.</a>
+<a name="intro" id= "intro"></a>
<h1>Introducing Axis2</h1>
<p>This section introduces Axis2 and its structure, including an
explanation of various directories/files included in the latest