Skip to content

Commit 3b1747b

Browse files
Merge pull request #135 from dixyushi/httpRestClient
devon4j_http_rest_client
2 parents 1b60441 + 705ffd1 commit 3b1747b

17 files changed

Lines changed: 544 additions & 0 deletions
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package com.example.application.httprestserver.general.service.impl.config;
2+
3+
import javax.inject.Inject;
4+
import javax.servlet.Filter;
5+
6+
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
7+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
8+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
9+
import org.springframework.security.core.userdetails.UserDetailsService;
10+
import org.springframework.security.crypto.password.PasswordEncoder;
11+
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
12+
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
13+
import org.springframework.security.web.authentication.logout.LogoutFilter;
14+
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
15+
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
16+
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
17+
18+
import com.devonfw.module.security.common.api.config.WebSecurityConfigurer;
19+
import com.devonfw.module.security.common.impl.rest.AuthenticationSuccessHandlerSendingOkHttpStatusCode;
20+
import com.devonfw.module.security.common.impl.rest.JsonUsernamePasswordAuthenticationFilter;
21+
import com.devonfw.module.security.common.impl.rest.LogoutSuccessHandlerReturningOkHttpStatusCode;
22+
23+
/**
24+
* This type serves as a base class for extensions of the {@code WebSecurityConfigurerAdapter} and provides a default
25+
* configuration. <br/>
26+
* Security configuration is based on {@link WebSecurityConfigurerAdapter}. This configuration is by purpose designed
27+
* most simple for two channels of authentication: simple login form and rest-url.
28+
*/
29+
public abstract class BaseWebSecurityConfig extends WebSecurityConfigurerAdapter {
30+
31+
@Inject
32+
private UserDetailsService userDetailsService;
33+
34+
@Inject
35+
private PasswordEncoder passwordEncoder;
36+
37+
@Inject
38+
private WebSecurityConfigurer webSecurityConfigurer;
39+
40+
/**
41+
* Configure spring security to enable a simple webform-login + a simple rest login.
42+
*/
43+
@Override
44+
public void configure(HttpSecurity http) throws Exception {
45+
46+
String[] unsecuredResources = new String[] { "/login", "/security/**", "/services/rest/login",
47+
"/services/rest/logout" };
48+
49+
// disable CSRF protection by default, use csrf starter to override.
50+
http = http.csrf().disable();
51+
// load starters as pluggins.
52+
http = this.webSecurityConfigurer.configure(http);
53+
54+
http.httpBasic().and()
55+
//
56+
.userDetailsService(this.userDetailsService)
57+
// define all urls that are not to be secured
58+
.authorizeRequests().antMatchers(unsecuredResources).permitAll().anyRequest().authenticated().and()
59+
// configure parameters for simple form login (and logout)
60+
.formLogin().successHandler(new SimpleUrlAuthenticationSuccessHandler()).defaultSuccessUrl("/")
61+
.failureUrl("/login.html?error").loginProcessingUrl("/j_spring_security_login").usernameParameter("username")
62+
.passwordParameter("password").and()
63+
// logout via POST is possible
64+
.logout().logoutSuccessUrl("/login.html").and()
65+
// register login and logout filter that handles rest logins
66+
.addFilterAfter(getSimpleRestAuthenticationFilter(), BasicAuthenticationFilter.class)
67+
.addFilterAfter(getSimpleRestLogoutFilter(), LogoutFilter.class);
68+
}
69+
70+
/**
71+
* Create a simple filter that allows logout on a REST Url /services/rest/logout and returns a simple HTTP status 200
72+
* ok.
73+
*
74+
* @return the filter.
75+
*/
76+
protected Filter getSimpleRestLogoutFilter() {
77+
78+
LogoutFilter logoutFilter = new LogoutFilter(new LogoutSuccessHandlerReturningOkHttpStatusCode(),
79+
new SecurityContextLogoutHandler());
80+
81+
// configure logout for rest logouts
82+
logoutFilter.setLogoutRequestMatcher(new AntPathRequestMatcher("/services/rest/logout"));
83+
84+
return logoutFilter;
85+
}
86+
87+
/**
88+
* Create a simple authentication filter for REST logins that reads user-credentials from a json-parameter and returns
89+
* status 200 instead of redirect after login.
90+
*
91+
* @return the {@link JsonUsernamePasswordAuthenticationFilter}.
92+
* @throws Exception if something goes wrong.
93+
*/
94+
protected JsonUsernamePasswordAuthenticationFilter getSimpleRestAuthenticationFilter() throws Exception {
95+
96+
JsonUsernamePasswordAuthenticationFilter jsonFilter = new JsonUsernamePasswordAuthenticationFilter(
97+
new AntPathRequestMatcher("/services/rest/login"));
98+
jsonFilter.setPasswordParameter("j_password");
99+
jsonFilter.setUsernameParameter("j_username");
100+
jsonFilter.setAuthenticationManager(authenticationManager());
101+
// set failurehandler that uses no redirect in case of login failure; just HTTP-status: 401
102+
jsonFilter.setAuthenticationManager(authenticationManagerBean());
103+
jsonFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
104+
// set successhandler that uses no redirect in case of login success; just HTTP-status: 200
105+
jsonFilter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandlerSendingOkHttpStatusCode());
106+
return jsonFilter;
107+
}
108+
109+
@SuppressWarnings("javadoc")
110+
@Inject
111+
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
112+
113+
auth.inMemoryAuthentication().withUser("admin").password(this.passwordEncoder.encode("admin")).roles("Admin");
114+
}
115+
116+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.sample.application.httprestclient.general.service.api.rest;
2+
3+
import javax.ws.rs.Consumes;
4+
import javax.ws.rs.GET;
5+
import javax.ws.rs.Path;
6+
import javax.ws.rs.Produces;
7+
import javax.ws.rs.core.MediaType;
8+
9+
@Path("/devon4jrestclient")
10+
@Consumes(MediaType.APPLICATION_JSON)
11+
@Produces(MediaType.APPLICATION_JSON)
12+
public interface Devon4jRestClient {
13+
14+
@GET
15+
@Path("/response")
16+
public String showResponse();
17+
18+
@GET
19+
@Path("/clientService")
20+
public String returnServiceDetail();
21+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.sample.application.httprestclient.general.service.impl.rest;
2+
3+
import javax.inject.Inject;
4+
import javax.inject.Named;
5+
import com.sample.application.httprestclient.general.service.api.rest.Devon4jRestClient;
6+
import com.sample.application.httprestclient.general.service.api.rest.VisitormanagementRestService;
7+
import com.devonfw.module.service.common.api.client.ServiceClientFactory;
8+
9+
@Named("Devon4jRestClient")
10+
public class Devon4jRestClientImpl implements Devon4jRestClient {
11+
12+
@Inject
13+
private ServiceClientFactory serviceClientFactory;
14+
15+
@Override
16+
public String showResponse() {
17+
18+
String result = callSynchronous();
19+
System.out.println(result);
20+
return result;
21+
}
22+
23+
private String callSynchronous() {
24+
25+
VisitormanagementRestService visitormanagementRestService = this.serviceClientFactory
26+
.create(VisitormanagementRestService.class);
27+
// call of service over the wire, synchronously blocking until result is received or error occurred
28+
String resultFromAPICall = visitormanagementRestService.returnResponseToClient();
29+
return resultFromAPICall;
30+
}
31+
32+
@Override
33+
public String returnServiceDetail() {
34+
35+
String result = "This is devon4j rest service client";
36+
return result;
37+
}
38+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
For implementing REST services we use the JAX-RS standard. As an implementation we recommend CXF. For JSON bindings we use Jackson while XML binding works out-of-the-box with JAXB. To implement a service you write an interface with JAX-RS annotations for the API and a regular implementation class annotated with @Named to make it a spring-bean.
2+
3+
The REST service implementation is a regular CDI bean that can use dependency injection. The separation of the API as a Java interface allows to use it for service client calls.
4+
5+
**Why** **Should** **you** **prefer** **devon4j** **client** **over** **other** **clients?**
6+
7+
devon4j supports flexible configuration, adding headers for authentication, mapping of errors from server, logging success/errors with duration for performance analysis, support for synchronous and asynchronous invocations. Easy invocation of service inside a micro-service.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.sample.application.httprestclient.general.service.api.rest;
2+
3+
import javax.ws.rs.Consumes;
4+
import javax.ws.rs.GET;
5+
import javax.ws.rs.Path;
6+
import javax.ws.rs.Produces;
7+
import javax.ws.rs.core.MediaType;
8+
9+
10+
@Path("/visitormanagement")
11+
@Consumes(MediaType.APPLICATION_JSON)
12+
@Produces(MediaType.APPLICATION_JSON)
13+
public interface VisitormanagementRestService {
14+
15+
@GET
16+
@Path("/clientrequest")
17+
public String returnResponseToClient();
18+
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.example.application.httprestserver.visitormanagement.service.api.rest;
2+
3+
import javax.ws.rs.Consumes;
4+
import javax.ws.rs.GET;
5+
import javax.ws.rs.Path;
6+
import javax.ws.rs.Produces;
7+
import javax.ws.rs.core.MediaType;
8+
9+
10+
@Path("/visitormanagement")
11+
@Consumes(MediaType.APPLICATION_JSON)
12+
@Produces(MediaType.APPLICATION_JSON)
13+
public interface VisitormanagementRestService {
14+
15+
@GET
16+
@Path("/clientrequest")
17+
public String returnResponseToClient();
18+
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.example.application.httprestserver.visitormanagement.service.impl.rest;
2+
3+
import javax.inject.Inject;
4+
import javax.inject.Named;
5+
6+
import com.example.application.httprestserver.visitormanagement.service.api.rest.VisitormanagementRestService;
7+
8+
@Named("VisitormanagementRestService")
9+
public class VisitormanagementRestServiceImpl implements VisitormanagementRestService {
10+
11+
@Override
12+
public String returnResponseToClient() {
13+
String args = "welcome to rest api";
14+
return args;
15+
}
16+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# This is the configuration file shipped with the application that contains reasonable defaults.
2+
# Environment specific configurations are configured in config/application.properties.
3+
# If you are running in a servlet container you may add this to lib/config/application.properties in case you do not
4+
# want to touch the WAR file.
5+
6+
server.port=8081
7+
spring.application.name=httprestclient
8+
server.servlet.context-path=/httprestclient
9+
10+
security.expose.error.details=false
11+
12+
spring.jpa.hibernate.ddl-auto=validate
13+
14+
# Datasource for accessing the database
15+
# https://github.com/spring-projects/spring-boot/blob/d3c34ee3d1bfd3db4a98678c524e145ef9bca51c/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java
16+
spring.jpa.database=h2
17+
# spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
18+
# spring.datasource.driver-class-name=org.h2.Driver
19+
spring.datasource.username=sa
20+
21+
# Hibernate NamingStrategy has been deprecated and then removed in favor of two step naming strategy ImplicitNamingStrategy and PhysicalNamingStrategy
22+
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
23+
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
24+
25+
# https://github.com/devonfw/devon4j/issues/65
26+
# https://vladmihalcea.com/the-open-session-in-view-anti-pattern/
27+
spring.jpa.open-in-view=false
28+
29+
# to prevent that Spring Boot launches batch jobs on startup
30+
# might otherwise lead to errors if job parameters are needed (or lead to unwanted modifications and longer startup times)
31+
# see http://stackoverflow.com/questions/22318907/how-to-stop-spring-batch-scheduled-jobs-from-running-at-first-time-when-executin
32+
spring.batch.job.enabled=false
33+
34+
# Flyway for Database Setup and Migrations
35+
spring.flyway.locations=classpath:db/migration
36+
37+
# rest client setup
38+
service.client.default.url=http://localhost:8081/httprestserver/services/rest
39+
service.client.app.httprestserver.url=http://localhost:8081/httprestserver/services/rest
40+
service.client.default.timeout.connection=120
41+
service.client.default.timeout.response=3600
42+
service.client.app.httprestserver.auth=basic
43+
service.client.app.httprestserver.user.login=admin
44+
service.client.app.httprestserver.user.password=admin
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# This is the spring boot configuration file for development. It will not be included into the application.
2+
# In order to set specific configurations in a regular installed environment create an according file
3+
# config/application.properties in the server. If you are deploying the application to a servlet container as untouched
4+
# WAR file you can locate this config folder in ${symbol_dollar}{CATALINA_BASE}/lib. If you want to deploy multiple applications to
5+
# the same container (not recommended by default) you need to ensure the WARs are extracted in webapps folder and locate
6+
# the config folder inside the WEB-INF/classes folder of the webapplication.
7+
8+
server.port=8081
9+
server.servlet.context-path=/httprestclient
10+
11+
# Datasource for accessing the database
12+
# See https://github.com/devonfw/devon4j/blob/develop/documentation/guide-configuration.asciidoc#security-configuration
13+
#jasypt.encryptor.password=none
14+
#spring.datasource.password=ENC(7CnHiadYc0Wh2FnWADNjJg==)
15+
spring.datasource.password=
16+
spring.datasource.url=jdbc:h2:./.httprestclient;
17+
18+
# print SQL to console for debugging (e.g. detect N+1 issues)
19+
spring.jpa.show-sql=true
20+
spring.jpa.properties.hibernate.format_sql=true
21+
22+
# Enable JSON pretty printing
23+
spring.jackson.serialization.INDENT_OUTPUT=true
24+
25+
# Flyway for Database Setup and Migrations
26+
spring.flyway.enabled=true
27+
spring.flyway.clean-on-validation-error=true
28+
29+
# rest client setup
30+
service.client.default.url=http://localhost:8081/httprestserver/services/rest
31+
service.client.app.httprestserver.url=http://localhost:8081/httprestserver/services/rest
32+
service.client.default.timeout.connection=120
33+
service.client.default.timeout.response=3600
34+
service.client.app.httprestserver.auth=basic
35+
service.client.app.httprestserver.user.login=admin
36+
service.client.app.httprestserver.user.password=admin
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## Service Discovery
2+
* service.client.default.url :- It is used to set the default url of server and it is added for service discovery.
3+
* service.client.app.httprestserver.url :- This property provide base url of REST in your application. It follows format such as "service.client.app.«application».url". Here, «application» refers to the technical name of the application providing the service.
4+
5+
## Timeouts
6+
* service.client.default.timeout.connection:- It is used to set the default timeout for particular connection.
7+
* service.client.default.timeout.response:- It is used to set the default timeout for particular response.
8+
9+
## Headers
10+
* service.client.app.httprestserver.auth:- It is used for customization of Service Header. Here it is used for basic authentication.
11+
12+
## Authentication
13+
* service.client.app.httprestserver.user.login:- It is used to set username of server for authentication
14+
* service.client.app.httprestserver.user.password:- It is used to set password.

0 commit comments

Comments
 (0)