Hibernate Validator 5.1.1 is not working in Web application - spring

I am using Spring 4.0 and latest Spring Security in my Web application. I want to use the Hibernate validation 5.1.1 Final. But It's not working. The same code works in my JUNIT but not in the web application.
The code which works:
#Test
public void testUserAuthenticationRequestValidation(){
try{
UserAuthenticationRequest req=new UserAuthenticationRequest().addUserName("bla").addPasswd("passw");
Validator validation=Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<UserAuthenticationRequest>> constraintViolations= validation.validate(req);
Assert.assertTrue("There are some errors", constraintViolations.size()>0);
System.out.println(constraintViolations);
}catch(Exception ex){
ex.printStackTrace();
Assert.fail();
}
But if I try to use the same code in my web application, it doesn't work, In the below code, I am expecting contraintViolation set not to be empty because I intentionally left both the username & password empty but I always find it empty.
#Override
public UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
LOGGER.debug("About to check authentication for username: {}", username);
final UserAuthenticationRequest userData = new UserAuthenticationRequest()
.addUserName(username).addPasswd(
authentication.getCredentials().toString());
Validator validation = Validation.buildDefaultValidatorFactory()
.getValidator();
Set<ConstraintViolation<UserAuthenticationRequest>> constraintViolations = validation
.validate(userData);
LOGGER.info("Constraints Violations: {}", constraintViolations);
LOGGER.info("Obejct: username: {} password: {}",
userData.getUsername(), userData.getPasswd());
UserDetailVO userDetailVO = new UserDetailVO(
userInfoService.authenticate(userData));
return userDetailVO;
}
So far I have also tried in vain initializing the validation bean as shown below and injecting in my Class as well as shown below:
#Configuration
#ComponentScan({ "com.sell.mystuff.web.security",
"com.sell.mystuff.web.service" })
#ImportResource({ "classpath*:spring/common-context.xml" })
public class CommonAppContext {
#Bean(name = "javaxValidator")
public Validator getValidator() {
return Validation.buildDefaultValidatorFactory().getValidator();
}
}
I have even tried to explicitly initialized in the validation bean as shown above but nothing seems to be working.
Below is my partial POM.xml file related to validation api:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.1.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>5.1.1.Final</version>
</dependency>

Do you have the validator bean configured?
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
This will bootstrap Bean Validation 1.0 or 1.1, depending on which version of Hibernate Validator you have on the classpath. See also http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html
Even if you plan to manually call the validation, you should do it by retrieving the configured factory bean, since this will guarantee proper caching of the factory.

I got this working by adding a later version of javax.el
e.g.
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
BTW I didn't need to define a LocalValidatorFactoryBean in my spring mvc config.

Related

Spring Boot Admin UI login redirects either back to login page either to a "variables.css" file

Recently I have integrated Spring Boot Admin in my application. Everything fine, until I've stared adding security (nothing complicated, just Basic Auth). When I try to login in Spring Boot Admin UI, it redirects me back to the login page with "Login required to access the resource (Error: 401).", or to "variables.css". I am using Spring Boot 3.0.0 with Spring Boot Admin version 3.0.0-M6.
I have to mention that everything works alright if I disable spring security.
Security Config class looks like this:
#Configuration(proxyBeanMethods = false)
#EnableWebSecurity
#AllArgsConstructor
public class AdminSecurityConfig {
private final AdminServerProperties adminServerProperties;
private final SecurityProperties securityProperties;
private final AuthenticationConfiguration authenticationConfiguration;
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(this.adminServerProperties.path("/"));
http
.authorizeHttpRequests(
(authorizeRequests) ->
authorizeRequests.requestMatchers(this.adminServerProperties.path("/assets/**")).permitAll()
.requestMatchers(this.adminServerProperties.path("/*.css")).permitAll()
.requestMatchers(this.adminServerProperties.path("/actuator/info")).permitAll()
.requestMatchers(this.adminServerProperties.path("/actuator/health")).permitAll()
.requestMatchers(this.adminServerProperties.path("/login")).permitAll()
.anyRequest().authenticated()
).formLogin(
(formLogin) -> formLogin.loginPage(this.adminServerProperties.path("/login")).successHandler(successHandler).and()
).logout((logout) -> logout.logoutUrl(this.adminServerProperties.path("/logout")))
.httpBasic(Customizer.withDefaults())
.csrf(
(csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers(
new AntPathRequestMatcher(this.adminServerProperties.path("/instances"),
HttpMethod.POST.name()),
new AntPathRequestMatcher(this.adminServerProperties.path("/instances/*"),
HttpMethod.DELETE.name()),
new AntPathRequestMatcher(this.adminServerProperties.path("/actuator/**"))
));
return http.build();
}
#Bean
public AuthenticationManager authenticationManager() throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
#Bean
public UserDetailsService userDetailsService() {
UserDetails user =
User.withUsername(securityProperties.getUser().getName())
.password("{noop}" + securityProperties.getUser().getPassword())
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
also, I have added this in the application.yaml file
spring:
security:
user:
name: ****
password: ****
roles:
- USER
boot:
admin:
monitor:
status-interval: 30000
status-lifetime: 30000
ui:
title: "Invoice Matching Admin"
remember-me-enabled: false
Main class looks like this:
#EnableAdminServer
#SpringBootApplication
public class InvoiceAdminServiceApplication {
public static void main(String[] args) {
SpringApplication.run(InvoiceAdminServiceApplication.class, args);
}
}
pom.xml contains this dependencies
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
In case that somebody will encounter the same problem, I managed to find the solution.
In the filterChain method you should add this:
.dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll()
Here is a documentation (https://codecentric.github.io/spring-boot-admin/3.0.0-M7/security.html#securing-spring-boot-admin) for Spring Admin security.

log4j2 java classes do not load application.properties entries with spring boot

I am using log4j2(log4j-core and log4j-api) with Spring boot 2.2.0.RELEASE. I want to masking sensitive data inmy json payload in the logs. I have written a custom LogMaskingConverter which extends LogEventPatternConverter.
#Plugin(name = "LogMaskingConverter", category = "Converter")
#ConverterKeys({ "spi", "trscId" })
#Configuration
public class LogMaskingConverter extends LogEventPatternConverter {
#Value("${maskingFields}")
private String maskingFields;
protected LogMaskingConverter(String name, String style) {
super(name, style);
}
public static LogMaskingConverter newInstance(String[] options) {
return new LogMaskingConverter("spi", Thread.currentThread().getName());
}
#Override
public void format(LogEvent event, StringBuilder outputMessage) {
........
}
private String mask(String message) {
....
}
The problem is that the maskingFields does not get loaded from the application properties file.I read that log4j2 gets loaded before spring boot. Hence I have renamed my xml to log4j2-spring.xml so that spring boot is the first to intialise and load all the properties before it gets read via LogMaskingConverter.
Also below are my pom.xml dependencies related to log4j2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
To summarise below code does not fetch any values:
#Value("${maskingFields}")
private String maskingFields;

How to send mail using Spring Batch

I want to send mail after processor. These is my step configuration:
public Step remindByMail() {
return stepBuilderFactory
.get("remindByMail")
.<Customer, SimpleMailMessage> chunk(1)
.reader(getCustomerList())
.processor(new MailProcessor())
.writer(new SendMail())
.build();
}
public class MailProcessor implements ItemProcessor<Customer, SimpleMailMessage> {
private String from = "aaa#oku.com";
#Override
public SimpleMailMessage process(Customer customer) throws Exception {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo("duyetpt#oku.com");
message.setSubject("Welcome " + customer.getUsername());
message.setText(customer.getInfo());
return message;
}
}
public class SendMail implements ItemWriter<SimpleMailMessage> {
#Override
public void write(List<? extends SimpleMailMessage> messages) throws Exception {
messages.stream().forEach((message)->mailSender.send(message));
}
}
And I have set these properties in application.properties file,
spring.mail.default-encoding=UTF-8
spring.mail.protocol=smtp
spring.mail.host=195.179.79.52
spring.mail.port=25
spring.mail.username=admin
spring.mail.password=admin
spring.mail.properties.mail.smtp.auth=true
My pom.xml:
<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-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-task</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>19.3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
However, I got the error:
org.springframework.mail.MailAuthenticationException: Authentication failed; nested exception is javax.mail.AuthenticationFailedException: No authentication mechanisms supported by both server and client
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:440)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:323)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:312)
.....
Caused by: javax.mail.AuthenticationFailedException: No authentication mechanisms supported by both server and client
at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:880)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:780)
.....
What should I do to send mail using Spring Batch?
Its my guess by your error message - No authentication mechanisms supported by both server and client that below properties needs to be removed from your configuration.
spring.mail.username=admin
spring.mail.password=admin
spring.mail.properties.mail.smtp.auth=true
In Spring Boot + Batch , I send emails using my organization's server without these properties as user name & passwords are not needed because program has to reside in organization network & that is the only security.
Its altogether a different story if one is trying to use - gmail , yahoo etc.

Decode Spring Boot 2.1 OAuth2 encoded JWT on Resource Server

Trying to upgrade existing resource services from Spring Boot 1.x to 2.x. Spring Security 4.5 is running on the authentication server and encodes JWT tokens like this:
#Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(privateKey);
converter.setVerifierKey(publicKey);
return converter;
}
A resource server upgraded to Spring Boot 2.1.3.RELEASE throws this error:
OAuth2AuthenticationProcessingFilter:165 :
Authentication request failed: error="invalid_token",
error_description="Invalid access token:****..."
The log reveals that the OAuth2AuthenticationProcessingFilter is using the MappingJackson2HttpMessageConverter to extract the JWT token. Spring Security auto-configuration should provide the JwtAccessTokenConverter bean instead of the MappingJackson2HttpMessageConverter bean since there is a key-value in my properties file:
security:
oauth2:
resource:
jwt:
key-value: |
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
Here is the Spring Security ResourceServerTokenServiceConfiguration class that should detect it. The property matches "security.oauth2.resource.jwt.key-value".
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage
.forCondition("OAuth JWT Condition");
Environment environment = context.getEnvironment();
String keyValue = environment
.getProperty("security.oauth2.resource.jwt.key-value");
String keyUri = environment
.getProperty("security.oauth2.resource.jwt.key-uri");
if (StringUtils.hasText(keyValue) || StringUtils.hasText(keyUri)) {
return ConditionOutcome
.match(message.foundExactly("provided public key"));
}
return ConditionOutcome
.noMatch(message.didNotFind("provided public key").atAll());
}
These are the resource server security dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
This is the resource server configuration. It is essentially the same as it was with Spring Boot 1.5.x.
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "my-service";
#Override
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
}
What am I missing?
The problem was an issue with the properties. I had moved "security.oauth2" to "spring.security.oauth2." When I turned on logging for org.springframework.boot.autoconfigure.security.oauth2 and saw this:
did not match due to OAuth Client ID did not find security.oauth2.client.client-id property
So, I decided to try moving the oauth2 properties back out from under "spring." and it was able to extract the JWT token.

Missing dependencies for HttpServletRequest with Jersey

I have a Standalone Jersey server running at the beginning of my JunitTest. I'm testing if my JaxRS controller works, as well as my custom HttpClient. Please note that I've always been able to use this JaxRsResourceController embedded in glassfish.
Here is the JaxRsController (light version)
#Path("root")
public class JaxRsResourceController implements
ResourceController<HttpServletRequest> {
#Context
private UriInfo context;
#Context
HttpServletRequest request;
#Context
HttpServletResponse response;
#GET
public String hello(){
System.out.println("Uri is "+this.context.getBaseUri().toString());
return "Hello "+peoples;
}
}
I have no problem with the client, but when I start the server, I have :
GRAVE: The following errors and warnings have been detected with resource and/or provider classes:
SEVERE: Missing dependency for field: javax.servlet.http.HttpServletRequest com.robustaweb.library.rest.controller.implementation.JaxRsResourceController.request
SEVERE: Missing dependency for field: javax.servlet.http.HttpServletResponse com.robustaweb.library.rest.controller.implementation.JaxRsResourceController.response
at com.sun.jersey.api.container.httpserver.HttpServerFactory.create(HttpServerFactory.java:172)
at com.robustaweb.library.rest.server.JerseyServer.startServer(JerseyServer.java:44)
Basically it says that at the #Context injection time, there is no dependency on the HttpServletRequest.
However if I remove the #Context annotations on request and response, but keep it for UriInfo context, it's ok, and I can read the Uri.
I changed a few times the Maven pom wich is now to force the libs in:
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
Any idea ?
servlet dependencies were separated to another module, try adding
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.14</version>
</dependency>
to your pom.
It was not easy, but I found out. The thing is that in my JUnit test, I was creating the server like this :
HttpServer server = HttpServerFactory.create(url);
But that way, you create a lightweight container that does not have servlet containers, and so is the failure reason. So in order to have it all, I used the jersey-test-framework that allow to use the Grizzly web container (or even Embedded glassfish).
Here is the maven :
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<!-- Unit test are using jersey server directly -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey.test.framework</groupId>
<artifactId>jersey-test-framework</artifactId>
<version>1.0.3</version>
<scope>test</scope>
</dependency>
</dependencies>
Here is the JerseyServerTest : note that it extends JerseyTest
public class JerseyServerTest extends JerseyTest {
protected String baseUri = "http://localhost:" + TestConstants.JERSEY_HTTP_PORT + "/";
public JerseyServerTest() throws Exception {
super("com.robustaweb.library.rest.controller");
/*
It's possible to NOT call the super() but to manually do :
1) ApplicationDescriptor appDescriptor = new ApplicationDescriptor()
.setRootResourcePackageName(resourcePackageName) // resource packages
.setContextPath(contextPath) //context of app
.setServletPath(servletPath); // context of spi servlet
2)setupTestEnvironment(appDescriptor);
*/
}
#Test
public void testHelloWorldRequest() {
SunRestClient client = new SunRestClient(baseUri + "root");
String result = client.GET("", null);
System.out.println(result);
}
#Test
public void testDeleteRequest() {
SunRestClient client = new SunRestClient(baseUri + "root");
String result = client.DELETE("john", null);
System.out.println(result);
}
}
And finally the Resource file, that contains #GET and #DELETE
#Path("root")
public class JaxRsController extends JaxRsResourceController{
List<String> peoples = new ArrayList<String>();
#GET
public String hello(){
System.out.println("Uri is "+getUri());
return "Hello "+peoples;
}
#DELETE
#Path("{name}")
public String deletePeople(#PathParam("name") String name){
System.out.println("deleting "+name);
this.peoples.remove(name);
return String.valueOf(peoples.size());
}
}
And now it works !
I had some help in this article, and there is a small chapter on the documentation. Beeing able to attach the source code of the Jersey framework really helped, so thantks to IntelliJ also.

Resources