This is an automated email from the ASF dual-hosted git repository. robertlazarski pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git
The following commit(s) were added to refs/heads/master by this push: new 28c9cbe AXIS2-6006, json-springboot-userguide completed first pass 28c9cbe is described below commit 28c9cbe82fc9fb1070527bd716d5c12ae67013ef Author: Robert Lazarski <robertlazar...@gmail.com> AuthorDate: Tue Jul 27 14:46:24 2021 -0400 AXIS2-6006, json-springboot-userguide completed first pass --- .../userguide/src/userguide/springbootdemo/pom.xml | 8 +- .../services.xml | 6 +- .../test_service_resources/services.xml | 2 +- .../userguide/springboot/Axis2Application.java | 16 +- ...oginTokenizerRequest.java => LoginRequest.java} | 6 +- ...inTokenizerResponse.java => LoginResponse.java} | 6 +- ...oginTokenizerService.java => LoginService.java} | 16 +- src/site/xdoc/docs/json-springboot-userguide.html | 179 +++++++++++++++++---- 8 files changed, 180 insertions(+), 59 deletions(-) diff --git a/modules/samples/userguide/src/userguide/springbootdemo/pom.xml b/modules/samples/userguide/src/userguide/springbootdemo/pom.xml index 85b9037..731fdec 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo/pom.xml +++ b/modules/samples/userguide/src/userguide/springbootdemo/pom.xml @@ -340,8 +340,8 @@ <!-- 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/LoginTokenizer.aar"> - <metainf file="resources-axis2/login_tokenizer_resources/services.xml"/> + <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"/> @@ -352,8 +352,8 @@ </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/LoginTokenizer.aar"> - <metainf file="resources-axis2/login_tokenizer_resources/services.xml"/> + <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"/> diff --git a/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/login_tokenizer_resources/services.xml b/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/login_resources/services.xml similarity index 89% rename from modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/login_tokenizer_resources/services.xml rename to modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/login_resources/services.xml index 952ac49..64812c7 100755 --- a/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/login_tokenizer_resources/services.xml +++ b/modules/samples/userguide/src/userguide/springbootdemo/resources-axis2/login_resources/services.xml @@ -16,12 +16,12 @@ ~ specific language governing permissions and limitations ~ under the License. --> -<service name="loginTokenizerService"> +<service name="loginService"> <description> - Alpha Theory Login Tokenizer Resources + Login Resources </description> <parameter name="ServiceObjectSupplier">org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier</parameter> - <parameter name="SpringBeanName">loginTokenizerService</parameter> + <parameter name="SpringBeanName">loginService</parameter> <operation name="doLogin"> <messageReceivers> <messageReceiver mep="http://www.w3.org/ns/wsdl/in-out" 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 index 055789d..6a202ff 100755 --- 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 @@ -18,7 +18,7 @@ --> <service name="testws"> <description> - Alpha Theory testws Resources + testws Resources </description> <parameter name="ServiceObjectSupplier">org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier</parameter> <parameter name="SpringBeanName">testwsService</parameter> 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 index 38b19d9..7aefd00 100644 --- 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 @@ -122,7 +122,7 @@ public class Axis2Application extends SpringBootServletInitializer { public boolean matches(HttpServletRequest request) { String logPrefix = "AnonRequestMatcher.matches , "; boolean result = request.getRequestURI().contains( - "/services/loginTokenizerService"); + "/services/loginService"); logger.debug(logPrefix + "inside AnonRequestMatcher.matches, will return result: " + result + " , on request.getRequestURI() : " @@ -165,7 +165,7 @@ public class Axis2Application extends SpringBootServletInitializer { @Override public Collection<ConfigAttribute> getAllConfigAttributes() { - String logPrefix = "SecurityConfigurationTokenWebServices.getAllConfigAttributes , "; + String logPrefix = "SecureResouceMetadataSource.getAllConfigAttributes , "; logger.debug(logPrefix + "returning ROLE_USER ..."); List<ConfigAttribute> attrs = SecurityConfig.createList("ROLE_USER"); return attrs; @@ -257,7 +257,7 @@ public class Axis2Application extends SpringBootServletInitializer { @Override protected void configure(final HttpSecurity http) throws Exception { - String logPrefix = "SecurityConfigurationTokenWebServices.configure(final HttpSecurity http) , "; + String logPrefix = "StatelessSecurityContextRepository.configure(final HttpSecurity http) , "; logger.debug(logPrefix + "inside Spring Boot filter config ..."); } @@ -350,7 +350,7 @@ public class Axis2Application extends SpringBootServletInitializer { @Bean(name = "springSecurityFilterChain") public FilterChainProxy springSecurityFilterChain() throws ServletException, Exception { - String logPrefix = "SecurityConfigurationTokenWebServices.springSecurityFilterChain , "; + String logPrefix = "GenericAccessDecisionManager.springSecurityFilterChain , "; logger.debug(logPrefix + "inside main filter config ..."); final List<SecurityFilterChain> listOfFilterChains = new ArrayList<SecurityFilterChain>(); @@ -371,7 +371,7 @@ public class Axis2Application extends SpringBootServletInitializer { */ @Bean FilterRegistrationBean disableWSLoginFilterAutoRegistration(final WSLoginFilter wsLoginFilter) { - String logPrefix = "SecurityConfigurationLogin.disableWSLoginFilterAutoRegistration , "; + String logPrefix = "GenericAccessDecisionManager.disableWSLoginFilterAutoRegistration , "; logger.debug(logPrefix + "executing registration.setEnabled(false) on wsLoginFilter ..."); final FilterRegistrationBean registration = new FilterRegistrationBean(wsLoginFilter); registration.setEnabled(false); @@ -383,7 +383,7 @@ public class Axis2Application extends SpringBootServletInitializer { */ @Bean FilterRegistrationBean disableJWTAuthenticationFilterAutoRegistration(final JWTAuthenticationFilter filter) { - String logPrefix = "SecurityConfigurationTokenWebServices.disableJWTAuthenticationFilterAutoRegistration , "; + String logPrefix = "GenericAccessDecisionManager.disableJWTAuthenticationFilterAutoRegistration , "; logger.debug(logPrefix + "executing registration.setEnabled(false) on JWTAuthenticationFilter ..."); final FilterRegistrationBean registration = new FilterRegistrationBean(filter); registration.setEnabled(false); @@ -395,7 +395,7 @@ public class Axis2Application extends SpringBootServletInitializer { */ @Bean FilterRegistrationBean disableHTTPPostOnlyRejectionFilterAutoRegistration(final HTTPPostOnlyRejectionFilter filter) { - String logPrefix = "SecurityConfigurationTokenWebServices.disableHTTPPostOnlyRejectionFilterAutoRegistration , "; + String logPrefix = "GenericAccessDecisionManager.disableHTTPPostOnlyRejectionFilterAutoRegistration , "; logger.debug(logPrefix + "executing registration.setEnabled(false) on HTTPPostOnlyRejectionFilter ..."); final FilterRegistrationBean registration = new FilterRegistrationBean(filter); registration.setEnabled(false); @@ -407,7 +407,7 @@ public class Axis2Application extends SpringBootServletInitializer { */ @Bean FilterRegistrationBean disableRequestAndResponseValidatorFilterAutoRegistration(final RequestAndResponseValidatorFilter filter) { - String logPrefix = "SecurityConfigurationTokenWebServices.disableRequestAndResponseValidatorFilterAutoRegistration , "; + String logPrefix = "GenericAccessDecisionManager.disableRequestAndResponseValidatorFilterAutoRegistration , "; logger.debug(logPrefix + "executing registration.setEnabled(false) on RequestLoggingFilter ..."); final FilterRegistrationBean registration = new FilterRegistrationBean(filter); registration.setEnabled(false); diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginTokenizerRequest.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginRequest.java similarity index 88% rename from modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginTokenizerRequest.java rename to modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginRequest.java index deb0097..1e6d5bb 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginTokenizerRequest.java +++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginRequest.java @@ -19,7 +19,7 @@ */ package userguide.springboot.webservices.secure; -public class LoginTokenizerRequest { +public class LoginRequest { String email; @@ -42,7 +42,7 @@ public class LoginTokenizerRequest { } - public LoginTokenizerRequest(String email, String credentials) { + public LoginRequest(String email, String credentials) { this.email = email; this.credentials = credentials; } @@ -50,6 +50,6 @@ public class LoginTokenizerRequest { @Override public String toString() { // implement toString() for debugging in trace mode of axis2 - return "LoginTokenizerRequest [email=" + email + ", credentials=not_shown ]"; + return "LoginRequest [email=" + email + ", credentials=not_shown ]"; } } diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginTokenizerResponse.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginResponse.java similarity index 90% rename from modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginTokenizerResponse.java rename to modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginResponse.java index 936a0df..c140b5d 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginTokenizerResponse.java +++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginResponse.java @@ -19,7 +19,7 @@ */ package userguide.springboot.webservices.secure; -public class LoginTokenizerResponse { +public class LoginResponse { String status; @@ -51,12 +51,12 @@ public class LoginTokenizerResponse { this.token = token; } - public LoginTokenizerResponse(String status, String token) { + public LoginResponse(String status, String token) { this.status = status; this.token = token; } - public LoginTokenizerResponse() { + public LoginResponse() { } diff --git a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginTokenizerService.java b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginService.java similarity index 94% rename from modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginTokenizerService.java rename to modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginService.java index 33a87b1..7bddf44 100644 --- a/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginTokenizerService.java +++ b/modules/samples/userguide/src/userguide/springbootdemo/src/main/java/userguide/springboot/webservices/secure/LoginService.java @@ -49,9 +49,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class LoginTokenizerService { +public class LoginService { - private static final Logger logger = LogManager.getLogger(LoginTokenizerService.class); + private static final Logger logger = LogManager.getLogger(LoginService.class); @Autowired SpringSecurityDAOImpl springSecurityDAOImpl; @@ -63,21 +63,21 @@ public class LoginTokenizerService { private WSSecUtils wssecutils; @SuppressWarnings({ "unchecked", "rawtypes" }) - public LoginTokenizerResponse doLogin(LoginTokenizerRequest request) { + public LoginResponse doLogin(LoginRequest request) { Long startTime = System.currentTimeMillis(); String uuid = UUID.randomUUID().toString(); - String logPrefix = "LoginTokenizerService.doLogin() , " + String logPrefix = "LoginService.doLogin() , " + " , uuid: " + uuid + " , request: " + request.toString() + " , "; logger.warn(logPrefix + "starting ... "); - LoginTokenizerResponse response = new LoginTokenizerResponse(); + LoginResponse response = new LoginResponse(); try { if (request == null) { - logger.error(logPrefix + "returning with failure status on null LoginTokenizerRequest"); + logger.error(logPrefix + "returning with failure status on null LoginRequest"); response.setStatus("FAILED"); return response; } @@ -201,9 +201,9 @@ public class LoginTokenizerService { } @SuppressWarnings({ "unchecked", "rawtypes" }) - private boolean generateTokenForReturn(HttpServletRequest httpServletRequest, LoginTokenizerRequest request, LoginTokenizerResponse response, String currentUserIPAddress, String email, String uuid) { + private boolean generateTokenForReturn(HttpServletRequest httpServletRequest, LoginRequest request, LoginResponse response, String currentUserIPAddress, String email, String uuid) { - String logPrefix = "LoginTokenizerService.generateTokenForReturn() , " + String logPrefix = "LoginService.generateTokenForReturn() , " + " , uuid: " + uuid + " , "; try { diff --git a/src/site/xdoc/docs/json-springboot-userguide.html b/src/site/xdoc/docs/json-springboot-userguide.html index 76c5917..527aa2b 100644 --- a/src/site/xdoc/docs/json-springboot-userguide.html +++ b/src/site/xdoc/docs/json-springboot-userguide.html @@ -22,19 +22,19 @@ <html> <head> <meta http-equiv="content-type" content=""/> - <title>Axis2 Advanced User's Guide</title> + <title>Apache Axis2 JSON and REST with Spring Boot User's Guide</title> </head> <body dir="ltr" lang="en-US"> <a name="_Toc96697849" id="_Toc96697849"></a> -<h1 align="center">Apache Axis2 JSON with Spring Boot User's Guide</h1> +<h1 align="center">Apache Axis2 JSON and REST with Spring Boot User's Guide</h1> -<p>This guide will help you get started with Axis2 and JSON, using Spring Boot! -It gives a detailed description on how to write Web services and also -Web service clients via JSON and Curl, how to write a custom login, -and how to use them in a token based Web service that also helps prevent cross site -scripting (XSS). +<p>This guide will help you get started with Axis2 and JSON via REST, using +Spring Security with Spring Boot! It gives a detailed description on how to write +JSON based REST Web services and also Web service clients via JSON and Curl, how to +write a custom login, and how to use them in a token based Web service that also helps +prevent cross site scripting (XSS). </p> <a name="Introduction"></a> @@ -62,43 +62,164 @@ prefix the subject of the mail with [Axis2].</p> <h2>Getting Started</h2> -<p>The first two sections of the user guide explain how to write and deploy a -new Web Service using Axis2, and how to write a Web Service client using -Axis2. The next section - <a href="#config"> Configuring Axis2</a> - provides -an introduction to important configuration options in Axis2. +<p>This user guide explains how to write and deploy a +new JSON and REST based Web Service using Axis2, and how to write a Web Service client +using JSON with Curl. +</p> -<p>In this (first) section, we will learn how to write and deploy Web -JSON based services using Axis2. All the samples mentioned in this guide are located in +<p>All the sample code mentioned in this guide is located in the <b>"samples/userguide/src/springbootdemo"</b> directory of <a href="../download.cgi">Axis2 standard binary distribution</a>.</p> - +<p> +This quide supplies a pom.xml for building an exploded WAR with Spring Boot - +however this WAR does not have an embedded web server such as Tomcat. +</p> +<p> +The testing was carried out on Wildfly, by installing the WAR in its app server. +</p> <p>Please deploy the result of the maven build via 'mvn clean install', axis2-json-api.war, into your servlet container and ensure that it installs without any errors.</p> -<a name="ws_codegen"></a><a name="Web_Services_Using_Axis2"></a> <h2>Creating a New Web Service</h2> <p> -Areas out of scope for this guide are the JWT and JWE, since they require -elliptic curve cryptography. - +Areas out of scope for this guide are JWT and JWE for token generation and validation, +since they require elliptic curve cryptography. A sample token that is not meant for +production is generated in this demo - with the intent that the following standards +should be used in its place. This demo merely shows a place to implement these +standards. +</p> +<p> https://datatracker.ietf.org/doc/html/rfc7519 https://datatracker.ietf.org/doc/html/rfc7516 - -DB operations are also out of scope. Very limited credential validation is done. +</p> +<p> +Tip: com.nimbusds is recommended as an open-source Java implementation of these +standards, for both token generation and validation. +</p> +<p> +DB operations are also out of scope. There is a minimal DAO layer for authentication. +Very limited credential validation is done. +</p> +<p> The NoOpPasswordEncoder Spring class included in this guide is meant for demos -and testing only. - -This guide provides two JSON based web services, LoginTokenizerService and TestwsService. - +and testing only. Do not use this code as is in production. +</p> +<p> +This guide provides two JSON based web services, LoginService and TestwsService. +</p> +<p> The login, if successful, will return a simple token not meant for anything beyond demos. - -Axis2 JSON support is via POJO Objects. LoginTokenizerRequest and LoginTokenizerResponse are coded in the LoginTokenizerService as the names would indicate. - +The intent of this guide is to show a place that the JWT and JWE standards can be +implemented. +</p> +<p> +Axis2 JSON support is via POJO Objects. LoginRequest and LoginResponse are coded in the LoginService as the names would indicate. +</p> +<p> Also provided is a test service, TestwsService. It includes two POJO Objects as would be expected, TestwsRequest and TestwsResponse. This service attempts to return a String with some Javascript, that is HTML encoded by Axis2 and thereby -eliminating the possibility of Javascript running the response. -</ol> +eliminating the possibility of a Javascript engine executing the response i.e. a +reflected XSS attack. +</p> +<p> +Concerning Spring Security and Spring Boot, the Axis2Application class that +extends SpringBootServletInitializer as typically done utilizes +List<SecurityFilterChain> as a binary choice; A login url will match, otherwise invoke +JWTAuthenticationFilter. All URL's to other services besides the login, will proceed +after JWTAuthenticationFilter verifies the token. +</p> +<p> +The JWTAuthenticationFilter class expects a token from the web services JSON client in +the form of "Authorization: Bearer mytoken". +</p> +<p> +The Axis2WebAppInitializer class supplied in this guide, is the config class +that registers AxisServlet with spring boot. +</p> +<p> +Axis2 web services are installed via a WEB-INF/services directory that contains +files with an .aar extention for each service. These aar files are similar to +jar files, and contain a services.xml that defines the web service behavior. +The pom.xml supplied in this guide generates these files. +</p> +<p> +Tip: don't expose methods in your web services that are not meant to be exposed, +such as getters and setters. Axis2 determines the avaliable methods by reflection. +For JSON, the message name at the start of the JSON received by the Axis2 server +defines the Axis2 operation to invoke. It is recommended that only one method per +class be exposed as a starting point. The place to add method exclusion is the +services.xml file: +</p> +<p> + <excludeOperations> + <operation>setMyVar</operation> + </excludeOperations> +</p> +<p> +The axis2.xml file can define Moshi or GSON as the JSON engine. GSON was the original +however development has largely ceased. Moshi is very similar and is widely considered +to be the superior implementation in terms of performance. GSON will likely continue to +be supported in Axis2 because it is helpful to have two JSON implementations to compare +with for debugging. +</p> +<p> +JSON based web services in the binary distribution of axis2.xml are not enabled by +default. See the supplied axis2.xml of this guide, and note the places were it has +"moshi". Just replace "moshi" with "gson" as a global search and replace to switch to +GSON. +</p> +<p> +Axis2 web services that are JSON based must be invoked from a client that sets an +HTTP header as "Content-Type: application/json". In order for axis2 to properly +handle JSON requests, this header behavior needs to be defined in the file +WEB-INF/conf/axis2.xml. +</p> +<p> + <messageFormatter contentType="application/json" + class="org.apache.axis2.json.moshi.JsonFormatter"/> +</p> +<p> +Other required classes for JSON in the axis2.xml file include JsonRpcMessageReceiver, +JsonInOnlyRPCMessageReceiver, JsonBuilder, and JSONMessageHandler. +</p> +<p> +Invoking the client for a login that returns a token can be done as follows: +</p> +<p> +curl -v -H "Content-Type: application/json" -X POST --data @/home/myuser/login.dat http://localhost:8080/axis2-json-api/services/loginService +</p> +<p> +Where the contents of /home/myuser/login.dat are: +</p> +<p> +{"doLogin":[{"arg0":{"email":java-...@axis.apache.org,"credentials":userguide}}]} +</p> +<p> +Response: +</p> +<p> +{"response":{"status":"OK","token":"95104Rn2I2oEATfuI90N","uuid":"99b92d7a-2799-4b20-b029-9fbd6108798a"}} +</p> +<p> +Invoking the client for a Test Service that validates a sample token can be done as +follows: +</p> +<p> +curl -v -H "Authorization: Bearer I2SpAHWrU5gYbGNwNNKg" -H "Content-Type: application/json" -X POST --data @/root/test.dat http://localhost:8080/axis2-json-api/services/testws' +</p> +<p> +Where the contents of /home/myuser/test.dat are: +</p> +<p> +{"doTestws":[{"arg0":{"messagein":hello}}]} +</p> +<p> +Response, HTML encoded to prevent XSS: +</p> +<p> +{"response":{"messageout":"<script xmlns=\"http://www.w3.org/1999/xhtml\">alert('Hello');</script> \">","status":"OK"}} +</p> </body> </html>