JSF 2.2 Tomcat 8, Bean Validation - validation

I'm new to JSF development and do already have some troubles with the bean validation I can't get to worK:
As a Servlet container, I am using Tomcat 8.0.22 together with JSF 2.2 (Mojarra 2.2).
The problem is that the validation annotations in the code aren't being triggered.
For example, I've got a class customer with an attribute name, which is supposed to be filled by an <h:inputText>.
The input is passed problemless to the entity, but the annotated validations aren't triggered.
Neither #NotNull nor #Size or anything else is triggered, so I guess it's a problem with Tomcat rather than JSF.
I've got the following Jars:
bval-core-0.5.jar
bval-jsr303-0.5.jar
validation-api-1.0.0.GA.jar
in the WEB-INF/lib Folder of my WebApp and in the lib folder of Tomcat. Of course they're in the apps classpath as well.
I already tried it with the hibernate validator as well but can't get it running either.
I don't know what I'm not getting here and am thankful for any help!
Thanks in advance!
Benedikt
Here the code:
User.java:
package com.example;
import java.io.Serializable;
import java.util.Date;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
#Size(min = 1, message = "Please enter username")
private String username;
#NotNull(message = "Please enter password")
private String password;
#NotNull(message = "Please enter email")
private String email;
private Date birthdate;
...
}
Register.java:
package com.example;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
#ManagedBean
#ViewScoped
public class Register implements Serializable {
private static final long serialVersionUID = 1L;
private User user;
#PostConstruct
public void init() {
user = new User();
}
public void submit() {
FacesMessage message = new FacesMessage("Registration succesful for: "
+ user.getUsername() + ", Username is null: " + (user.getUsername() == null));
FacesContext.getCurrentInstance().addMessage(null, message);
}
public User getUser() {
return user;
}
}
register.xhtml:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>Insert title here</title>
</h:head>
<h:body>
<h:form id="Form">
<h:panelGrid columns="3">
<h:outputLabel for="username">Username</h:outputLabel>
<h:inputText id="username" value="#{register.user.username}">
<f:ajax event="blur" render="usernameMessage" />
</h:inputText>
<h:message id="usernameMessage" for="username" />
<h:outputLabel for="password">Password</h:outputLabel>
<h:inputSecret id="password" value="#{register.user.password}" redisplay="true">
<f:ajax event="blur" render="passwordMessage" />
</h:inputSecret>
<h:message id="passwordMessage" for="password" />
<h:outputLabel for="email">Email</h:outputLabel>
<h:inputText id="email" value="#{register.user.email}">
<f:ajax event="blur" render="emailMessage" />
</h:inputText>
<h:message id="emailMessage" for="email" />
<h:outputLabel for="birthdate">Birthdate (yyyy-MM-dd)</h:outputLabel>
<h:inputText id="birthdate" value="#{register.user.birthdate}">
<f:convertDateTime pattern="yyyy-MM-dd" />
<f:ajax event="blur" render="birthdateMessage" />
</h:inputText>
<h:message id="birthdateMessage" for="birthdate" />
<h:panelGroup />
<h:commandButton value="Register" action="#{register.submit}">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:messages globalOnly="true" layout="table" />
</h:panelGrid>
</h:form>
</h:body>
</html>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>JSFFaceletsTutorial</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<context-param>
<description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>resources.application</param-value>
</context-param>
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
</web-app>

What I have done to solve this problem is that I downloaded the Hibernate api for validation from hibernate-validator.
It comes with the required dependencies in the folder lib/required. I copied the hibernate validator jars and the required jars into the lib folder of Apache Tomcat 8.
You should not put those jars in the WEB-INF/lib of your application. I tried to put them there to see what would happen, but I had errors while deploying the app.
You might say that dropping libraries in the lib folder of Tomcat is not a good practice, but if you deploy your application that uses bean validation in Glassfish you won't have to do all this work because they come built in the JEEServer. This means that it is ok to have these libraries in your Apache Tomcat server.

Related

NPE in #ManagedBean - javax.servlet.ServletException: An error occurred performing resource injection

I have Spring project, now I want to add few JSF (Primefaces) xhtml pages, but I get null pointer exception in my #ManagedBean on #PostConstruct method when i try get data from existing services?
Do You know how to properly import AuctionViewService to my #ManagedBean? I think that's the problem but I dont know how to fix it :)
Below java classes there's my stacktrace with null pointer (also i mark line with NPE in SalesBean.java)
This is my xhtml page:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css"></link>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/main.css"></link>
<script src="${pageContext.request.contextPath}/js/jquery-3.4.1.min.js" type=""></script>
<script src="${pageContext.request.contextPath}/js/bootstrap.min.js" type=""></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/common/main.js"></script>
<title>Sales</title>
</h:head>
<h:body>
<div id="wrapper">
<div id="navigationMenuPlaceholder"></div>
<!-- Page Content -->
<div id="page-content-wrapper">
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<p:panelGrid columns="2">
<h:outputText value="#{SalesBean.firstName}"/>
<h:outputText value="#{SalesBean.lastName}" />
</p:panelGrid>
<p:dataTable var="property" value="#{SalesBean.userProperty}">
<p:column headerText="PropertyId">
<h:outputText value="#{property.propertyId}" />
</p:column>
<p:column headerText="UserId">
<h:outputText value="#{property.userId}" />
</p:column>
<p:column headerText="Street">
<h:outputText value="#{property.street}" />
</p:column>
<p:column headerText="House no">
<h:outputText value="#{property.homeNumber}" />
</p:column>
<p:column headerText="Local no">
<h:outputText value="#{property.localNumber}" />
</p:column>
<p:column headerText="Post code">
<h:outputText value="#{property.postCode}" />
</p:column>
<p:column headerText="City">
<h:outputText value="#{property.city}" />
</p:column>
<p:column headerText="Price">
<h:outputText value="#{property.price}" />
</p:column>
<p:column headerText="Size">
<h:outputText value="#{property.size}" />
</p:column>
</p:dataTable>
</div>
</div>
</div>
</div>
<div id="footerPlaceholder">
</div>
<!-- /#page-content-wrapper -->
</div>
</h:body>
</html>
SalesBean:
package application.beans;
import application.model.views.AuctionView;
import application.service.AuctionViewService;
import lombok.Getter;
import lombok.Setter;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import java.util.ArrayList;
import java.util.List;
#Setter
#Getter
#ViewScoped
#ManagedBean(name="SalesBean")
public class SalesBean {
#ManagedProperty("#{auctionViewService}")
private AuctionViewService auctionViewService;
//private String userName = SecurityContextHolder.getContext().getAuthentication().getName();
private String userName = "seller#seller.com";
private String firstName = "first";
private String lastName = "last";
private List<AuctionView> userProperty = new ArrayList<>();
#PostConstruct
public void init() { userProperty = auctionViewService.findByEmail(userName); //NULL POINTER EXCEPTION in this line
}
}
AuctionViewServiceImpl:
package application.service;
import application.dao.*;
import application.model.views.AuctionView;
import org.apache.log4j.Logger;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.util.List;
#Service("auctionViewService")
public class AuctionViewServiceImpl implements AuctionViewService {
final static Logger LOGGER = Logger.getLogger(AuctionViewServiceImpl.class.getName());
private final AuctionViewDAO auctionViewDAO;
public AuctionViewServiceImpl(AuctionViewDAO auctionViewDAO) {
this.auctionViewDAO = auctionViewDAO;
}
#Override
public List<AuctionView> findAll() {
return auctionViewDAO.findAll();
}
#Override
public ResponseEntity<Object> findByType(String propertyType) {
return new ResponseEntity<>(auctionViewDAO.findByType(propertyType), HttpStatus.OK);
}
#Override
public List<AuctionView> findByEmail(String email) {
return auctionViewDAO.findByEmail(email);
}
}
faces-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd"
version="2.1">
<application>
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
</application>
</faces-config>
web.xml
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>khn</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
stacktrace: https://pastebin.com/iaBHUupQ
If needed i can attach more files and whole project structure, but problem is in importing AuctionViewService to SalesBean, or maybe in mixing JSF and Spring annotations
Ok, I changed #ManagedBean annotation to #Component, link AuctionViewService with #Autowire, and it works for me :) but how can I explain this situation?
package application.beans;
import application.model.views.AuctionView;
import application.service.AuctionViewService;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
#Setter
#Getter
#ViewScoped
#Component
//#ManagedBean(name="SalesBean")
public class SalesBean implements Serializable {
#Autowired
private AuctionViewService auctionViewService;
//private String userName = SecurityContextHolder.getContext().getAuthentication().getName();
private String userName = "seller#seller.com";
private String firstName = "first";
private String lastName = "last";
private List<AuctionView> userProperty = new ArrayList<>();
#PostConstruct
public void init() { userProperty = auctionViewService.findByEmail(userName);
}
}

JSF xhtml page not found

I've been trying to follow various articles on setting up my first JSF application and can't get my first xhtml page to be found. I keep getting the error "This application has no explicit mapping for /error, so you are seeing this as a fallback" in the browser.
In the browser, I type http://localhost:8080/modelSimulation.xhtml to get this error, and in the console, I see:
... :GET "/modelSimulation.xhtml", parameters={}
... :No mapping for GET /modelSimulation.xhtml
My spring boot application has added the various things required to setup JSF with spring boot, but clearly I'm missing something to be able to view my modelSimulation.xhtml page. What am I missing? Thanks!
I also tried http://localhost:8080 but get corresponding no mapping error too.
src/main/webapp/WEB-INF/modelSimulation.xhtml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui">
<ui:composition template="layout.xhtml">
<ui:define name="content">
<h:form id="mainForm">
<p:panel header="Details">
<h:panelGrid columns="1">
<p:outputLabel for="symbol" value="Symbol: " />
<p:inputText id="symbol" value="#{tradingModelSimulationController.symbol}" />
<p:outputLabel for="ranking" value="ranking: " />
<p:inputNumber id="ranking" value="#{tradingModelSimulationController.ranking}" />
<h:commandButton value="apply" action="#{tradingModelSimulationController.apply}" />
</h:panelGrid>
</p:panel>
</h:form>
</ui:define>
</ui:composition>
</html>
src/main/webapp/WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="3.1">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
</web-app>
I added the 2 required beans to the SpringBootApplication class:
#Bean
public ServletRegistrationBean servletRegistrationBean() {
FacesServlet servlet = new FacesServlet();
return new ServletRegistrationBean(servlet, "*.jsf");
}
#Bean
public FilterRegistrationBean rewriteFilter() {
FilterRegistrationBean rwFilter = new FilterRegistrationBean(new RewriteFilter());
rwFilter.setDispatcherTypes(EnumSet.of(DispatcherType.FORWARD, DispatcherType.REQUEST,
DispatcherType.ASYNC, DispatcherType.ERROR));
rwFilter.addUrlPatterns("/*");
return rwFilter;
}
Here's the backing bean (I don't understand the #Join...)
#Scope(value = "session")
#Component(value = "tradingModelSimulationController")
#ELBeanName(value = "tradingModelSimulationController")
#Join(path = "/modelSimulation", to = "/modelSimulation.jsf")
public class TradingModelSimulationController {
ModelSimulation modelSimulation = new ModelSimulation();
String symbol;
int ranking;
public void apply() {
System.out.println("Applied: " + modelSimulation.toString());
RequestContext.getCurrentInstance()
.execute("handleMsg('applied!');");
}
public ModelSimulation getModelSimulation() {
return modelSimulation;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public int getRanking() {
return ranking;
}
public void setRanking(int ranking) {
this.ranking = ranking;
}
}

Beans not 'managed' using SpringBoot

I use JSF with Spring Boot.
My problem is, that if I use the #javax.faces.bean.ManagedBean annotation I receive
javax.el.PropertyNotFoundException: Target Unreachable, identifier
[numberTest] resolved to null
I resolved the issue with put also the #Component annotation on the managed bean.
The other way was to put the Java classes in the WEB-INF.
My question is: both above-mentioned way seems to be bad and I think that they will cause trouble. What would be the solution to this problem?
I Googled a lot and tried every solution found.
(An additional fact, is that with #javax.annotation.ManagedBean the core JSP functions work (I didn't receive the error) but for example EL doesn't.)
Here is the code, in which with I receive the PropertyNotFoundException:
Configuration.java
import javax.faces.webapp.FacesServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#SpringBootApplication
#EnableAutoConfiguration
#EnableTransactionManagement
#EnableWebMvc
#Configuration
#EnableJpaRepositories(basePackageClasses = {})
#ComponentScan(basePackageClasses = { CLASSES_ARE_HERE })
public class Configuration {
public static void main(String[] args) {
SpringApplication.run(Configuration.class, args);
}
#Bean
public ServletRegistrationBean servletRegistrationBean() {
FacesServlet servlet = new FacesServlet();
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(servlet, "*.xhtml");
return servletRegistrationBean;
}
}
The managed bean:
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
#ManagedBean
#ApplicationScoped
public class NumberTest {
private int theNumber=0;
public NumberTest() {
}
public void addOne() {
theNumber++;
}
public void addN(int n) {
theNumber+=n;
}
public int getTheNumber() {
return theNumber;
}
public void setTheNumber(int theNumber) {
this.theNumber = theNumber;
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="3.1">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<!-- Time in seconds that facelets should be checked for changes since last
request. A value of -1 disables refresh checking. -->
<context-param>
<param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
<param-value>1</param-value>
</context-param>
<!-- Set the project stage to "Development", "UnitTest", "SystemTest", or
"Production". -->
<!-- An optional parameter that makes troubleshooting errors much easier. -->
<!-- You should remove this context parameter before deploying to production! -->
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
</web-app>
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
version="2.2">
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
</faces-config>
The .xhtml
<!DOCTYPE html>
<f:view xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui" encoding="UTF-8">
<html>
<h:head>
</h:head>
<h:body>
<h1>Szám</h1>
<h3>#{numberTest.theNumber}</h3>
<h:form>
<br></br>
<h:commandButton action="#{numberTest.addOne()}" value="Add one"></h:commandButton>
</h:form>
<h:form>
<br></br>
<h:inputText binding="#{input1}" />
<h:commandButton value="Add N" action="#{numberTest.addN(input1.value)}" />
</h:form>
</h:body>
</html>
</f:view>

Send HTTP 400 error when <f:viewParam required> has failed on #NotNull property

I'm creating a JSF 2.2 page that requires a GET parameter to display data but I'm having difficult to enforce that parameter.
I also tried to use Omnifaces's viewParam without success, I don't know what to try anymore.
I also found a similar issue on this link and I tried all suggestions...
When I open:
http://url-to/required-test.xhtml?test=foo
It works correctly, Param is: foo is displayed.
But when I open:
http://url-to/required-test.xhtml?test=
http://url-to/required-test.xhtml
Param is: null! is displayed instead of a validation error message. And null! is only displayed because I added a special outputText only for this test, on the real application it would cause a NullPointerException somewhere.
How do I make the required attribute on <f:viewParam /> or <o:viewParam /> work?
My test code:
required-test.xhtml
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:o="http://omnifaces.org/ui">
<f:metadata>
<f:viewParam name="test" value="#{requiredTestBean.value}" required="true" />
</f:metadata>
<h:head>
<title>Required Test</title>
</h:head>
<h:body>
Param is:
<h:outputText value="#{requiredTestBean.value}" rendered="#{requiredTestBean.value != null}" />
<h:outputText value="null!" rendered="#{requiredTestBean.value == null}" />
</h:body>
</html>
RequiredTestBean.java
package test;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.validation.constraints.NotNull;
#ManagedBean
#RequestScoped
public class RequiredTestBean
{
#NotNull
private String value;
#NotNull
public String getValue()
{
return value;
}
public void setValue(#NotNull String value)
{
this.value = value;
}
}
Context params on web.xml
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>javax.faces.CLIENT_WINDOW_MODE</param-name>
<param-value>url</param-value>
</context-param>
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
<param-value>true</param-value>
</context-param>
It's incredible how I search for a solution for hours and I find it 20 minutes after asking this question...
I just replaced the view param tag with:
<o:viewParam name="test" value="#{requiredTestBean.value}" required="true">
<o:viewParamValidationFailed sendError="400" />
</o:viewParam>
And it worked perfectly.
Reference: https://stackoverflow.com/a/29841384/804976

Spring custom JSF login page, always "Bad credentials"

I'm trying to get a JSF login page to work with Spring security. I've looked around for numerous examples but none works. Every time I try to log in using the JSF page I get a "Bad credentials" warning in my server log.
Spring-Security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<http auto-config="true">
<intercept-url pattern="/Login.xhtml*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**/*.css*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**/*.js*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN" />
<form-login login-page="/Login.xhtml" default-target-url="/Secure.xhtml"
authentication-failure-url="/Login.xhtml" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" authorities="ROLE_ADMIN" password="admin"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.example" />
<context:annotation-config />
<tx:annotation-driven />
<import resource="classpath:spring/security/Spring-Security.xml" />
</beans>
Login.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head></h:head>
<body>
<h:form>
<h:outputLabel value="username" for="j_username"
style="float:left" />
<h:inputText id="j_username" style="float:left" />
<h:outputLabel value="password" for="j_password"
style="float:left; clear:both" />
<h:inputSecret id="j_password" style="float:left" />
<h:commandButton value="login"
actionListener="#{loginBean.login}" style="float:left;clear:both" />
</h:form>
<h:messages style="float:left;clear:both" />
</body>
</html>
LoginBean
#Named
#Scope("request")
public class LoginBean
{
public void login() throws ServletException, IOException
{
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.dispatch("/j_spring_security_check");
facesContext.responseComplete();
}
}
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<filter>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>
When I use a non-JSF page as Login.xhtml it works flawlessly.
Page that does work:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head></h:head>
<body>
<form action="j_spring_security_check" method="post">
<table>
<tr>
<td>User:</td>
<td><input type="text" name="j_username" /></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="j_password" /></td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit"
value="submit" /></td>
</tr>
</table>
</form>
</body>
</html>
Any help is appreciated.
This is an old problem. By default the FilterSecurityInterceptor will only execute once-per-request and doesn't do security re-checking unless there is change in the url but with JSP/JSF forwards the page is rendered as a response to the current request and the url in the browser contains the address of the previous page.
Before Spring Security 3.0 this was bypassed doing a GET request something like this:
String encodedURL = externalcontext.encodeResourceURL(externalcontext.getRequestContextPath() + "/j_spring_security_check?j_username=" + username + "&j_password=" + password);
externalcontext.redirect(encodedURL);
But from Spring Security 3.0, by default it supports POST only.
So one way, probably the easiest to use is a simple HTML form. Otherwise you need to manually authenticate the request by getting the AuthenticationManager.
I guess the whole story originated from this post on Spring forums.
And the best working example can be found on the ICEFaces wiki
Here is the relevant LoginController class from the tutorial.zip
/**
* This class handles all login attempts except html forms that directly
* post to the /j_spring_security_check method.
*
* #author Ben Simpson
*/
#ManagedBean(name = "loginController")
#RequestScoped
public class LoginController implements Serializable {
private static final long serialVersionUID = 1L;
/**
* This action logs the user in and returns to the secure area.
*
* #return String path to secure area
*/
public String loginUsingSpringAuthenticationManager() {
//get backing bean for simple redirect form
LoginFormBackingBean loginFormBean =
(LoginFormBackingBean) FacesUtils.getBackingBean("loginFormBean");
//authentication manager located in Spring config: /WEB-INF/authenticationContext-security.xml
AuthenticationManager authenticationManager =
(AuthenticationManager) getSpringBean("authenticationManager");
//simple token holder
Authentication authenticationRequestToken = createAuthenticationToken(loginFormBean);
//authentication action
try {
Authentication authenticationResponseToken =
authenticationManager.authenticate(authenticationRequestToken);
SecurityContextHolder.getContext().setAuthentication(authenticationResponseToken);
//ok, test if authenticated, if yes reroute
if (authenticationResponseToken.isAuthenticated()) {
//lookup authentication success url, or find redirect parameter from login bean
return "/secure/examples";
}
} catch (BadCredentialsException badCredentialsException) {
FacesMessage facesMessage =
new FacesMessage("Login Failed: please check your username/password and try again.");
FacesContext.getCurrentInstance().addMessage(null,facesMessage);
} catch (LockedException lockedException) {
FacesMessage facesMessage =
new FacesMessage("Account Locked: please contact your administrator.");
FacesContext.getCurrentInstance().addMessage(null,facesMessage);
} catch (DisabledException disabledException) {
FacesMessage facesMessage =
new FacesMessage("Account Disabled: please contact your administrator.");
FacesContext.getCurrentInstance().addMessage(null,facesMessage);
}
return null;
}
private Authentication createAuthenticationToken(LoginFormBackingBean loginFormBean) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(
loginFormBean.getUserName(),
loginFormBean.getPassword()
);
return usernamePasswordAuthenticationToken;
}
private Object getSpringBean(String name){
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(
(ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext());
return ctx.getBean(name);
}
}
OPTION 3 : I haven't personally tried but even this should work:
By setting once-per-request attribute to false in your http element in applicationContext thus forcing security rechecking. But I don't recommend it.
<http auto-config="true" use-expressions="true" once-per-request="false">
The answer to the question left me a little wanting.
So to get this working with a minimal amount of code in the controller (I wanted to avoid manually authenticating), I used a combination of a JSF (primefaces) form and a simple form.
I ended up with a view like this:
<h:form id="login-form" prependId="false">
<p:focus for="userName" />
<p:fieldset id="login-fs" legend="User Authentication">
<h:panelGrid id="login-grid" columns="3">
<p:outputLabel for="userName" value="User Name" />
<p:inputText id="userName" value="#{loginView.userName}" required="true" />
<p:message for="userName" />
<p:outputLabel for="password" value="Password" />
<p:inputText type="password" id="password" value="#{loginView.password}" required="true" />
<p:message for="password" />
</h:panelGrid>
<br />
<p:commandButton value="Submit" icon="ui-icon-check" process="#form" update="login-grid" actionListener="#{loginView.login}" />
</p:fieldset>
</h:form>
<form id="hidden-form" action="#{request.contextPath}/j_spring_security_check" method="post">
<h:inputHidden id="j_username" />
<h:inputHidden id="j_password" />
</form>
<script type="text/javascript">
function mysubmit() {
$('#j_username').val($('#userName').val());
$('#j_password').val($('#password').val());
$('#hidden-form').submit();
}
</script>
And the backing bean could do the typical jsf lifecycle, after which it would send javascript back to transfer values from the successfully validated JSF form to the hidden one and submit the hidden form:
#ManagedBean
public class LoginView {
private String userName;
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void login() {
RequestContext.getCurrentInstance().execute("mysubmit()");
}
}
You could do anything else you want on the server-side before the submit actually happens, if you need to.
Someone correct me if i'm wrong, but I think you are specifying your backing bean incorrectly.
The correct JSF way to specify your backing bean scope is like this:
#ManagedBean
#RequestScoped
public class LoginBean
{
public void login() throws ServletException, IOException
{
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.dispatch("/j_spring_security_check");
facesContext.responseComplete();
}
}
Change your h:commandButton to use an action method instead of an actionListener:
<h:commandButton value="login"
action="#{loginBean.login}" style="float:left;clear:both" />
See also: Differences between action and actionListener

Resources