I am getting this error as i have mentioned in title. I am making a sample application which is on angularJs, spring and hibernate. my application is working with spring, hibernate and jsp page but when I am not able to do it with angularJs. Here is the html page
<div ng-controller="empController">
<form>
<label>FirstName</label>
<input type="text" name="Firstname" ng-model="emp.firstName"/>
<br/>
<label>LastName</label>
<input type="text" name="lastName" ng-model="emp.lastName"/>
<br/>
<label>Email</label>
<input type="text" name="email" ng-model="emp.email"/>
<br/>
<label>Phone</label>
<input type="text" name="phone" ng-model="emp.phone"/>
<br/>
<input type="hidden" ng-model="emp.id" />
<input type="button" value="Save" ng-click="saveEmp()" />
</form>
below is the code of angularJs controller
function empController($scope,$http,$location) {
$scope.saveEmp = function(emp) {
$http.post('add', $scope.emp).success(function() {
//location.href = "index.html";
});
$scope.emp = {};
};
}
Below is the code of springController
#RequestMapping(value = "/", method = RequestMethod.GET)
public String listEmployees(ModelMap map)
{
map.addAttribute("emp", new TestEmployee());
System.out.println("calling listEmployees");
return "editEmployeeNew";
}
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addEmployee(#ModelAttribute(value="emp") TestEmployee emp, BindingResult result)
{
employeeManager.addEmployee(emp);
return null;
}
Below is my web.xml file
<servlet>
<servlet-name>employee</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>employee</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/employee-servlet.xml</param-value>
</context-param>
Below is my employee-servlet.xml (snippet)
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".html" />
</bean>
I have searched this problem on net but nothing helped me as i am using angularJs. Kindly help me. I am new to these technologies so kindly help me with code if I am doing something in wrong way.
Related
Plop,
Spring version: 4.0.2.RELEASE
Spring Security Version: 4.0.2.RELEASE
DB PostgreSQL Version: 9.4-1202-jdbc42
I'm trying to acces to my home page with a secure connection using spring-security.
When I try to connect with login/password I've got this error:
WARNING: No mapping found for HTTP request with URI
[/web-client-smarteo/j_spring_security_check] in DispatcherServlet
with name 'servlet-dispatcher'
When I submit with log/pass it's get me to:
http://localhost:8080/web-client-smarteo/j_spring_security_check?username=alfacamp&password=alfacam&submit=&%24%7B_csrf.parameterName%7D=%24%7B_csrf.token%7D
And show
HTTP 404 The requested ressource is unvailable
Details of my sample:
UPDATE
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/dispatcher-servlet.xml
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<!-- Spring Security Filter -->
<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>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>servlet-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>servlet-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
dispatcher-servlet.xml
<mvc:annotation-driven />
<context:component-scan base-package="com.smarteo.laugustoni.*" />
[...]
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/vues/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
spring-security.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/welcome**" access="hasRole('CUSTOMER')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/connection"
default-target-url="/welcome"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/connection?error"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/connection?logout" />
<!-- enable csrf protection -->
<csrf/>
</http>
<!-- Select users and user_roles from database -->
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query=
"select usr_name,usr_password from smarteo_user where usr_name=?"
authorities-by-username-query=
"select usr_name, usr_role from smarteo_user where usr_name =? " />
</authentication-provider>
</authentication-manager>
ConnectionController.java
package com.smarteo.laugustoni.controller;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.smarteo.laugustoni.services.User.IServiceUser;
#Controller
public class ConnectionController {
#RequestMapping(value={"/", "/welcome**"}, method = RequestMethod.GET)
public String defaultPage(ModelMap pModel)
{
return "connection";
}
#RequestMapping(value="/connexion", method = RequestMethod.GET)
public ModelAndView connection(
#RequestParam(value="error", required = false) String error,
#RequestParam(value = "logout", required = false)String logout)
{
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("connection");
return model;
}
Thanks for helping.
EDIT 1
connection.jsp
<%#page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%#taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%#page session="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
<form name="loginForm" action="/j_spring_security_check">
<!-- TextBox Section -->
<div class="input-group visible">
<spring:message code="connection.label.account"/>
<input name="username" path="username" placeholder="Nom du compte" type="text" class="form-control" aria-describedby="basic-addon1"/>
<div class="alert alert-danger" role="alert"><form:errors path="username" cssclass="error"/></div>
</div><br />
<div class="input-group visible">
<spring:message code="connection.label.password"/>
<input name="password" path="password" placeholder="Mot de passe" type="password" class="form-control" aria-describedby="basic-addon1"/><br />
<div class="alert alert-danger" role="alert"><form:errors path="password" cssclass="error"/></div>
</div><br />
<!-- TextBoxSection -->
<!-- Button Section -->
<button name="submit" type="submit" class="btn btn-default visible">
<spring:message code="connection.button.label.connect"/>
</button><br />
<!-- Button Section -->
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
EDIT 2:
I'm now using:
<form name="loginForm" action="<c:url value='/login' />" method="POST" >
I had also change my spring-security.xml:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/welcome**" access="hasRole('CUSTOMER')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-page="/login"
default-target-url="/welcome**"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/login?logout" />
<!-- enable csrf protection -->
<csrf/>
</http>
And my ConnectionController.java
#RequestMapping(value = "/welcome**", method = RequestMethod.GET)
public String defaultPage()
{
return "home";
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(
#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout)
{
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("connection");
return model;
}
#RequestMapping(value = "/403", method = RequestMethod.GET)
public ModelAndView accesssDenied() {
ModelAndView model = new ModelAndView();
//check if user is login
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
UserDetails userDetail = (UserDetails) auth.getPrincipal();
model.addObject("username", userDetail.getUsername());
}
model.setViewName("403");
return model;
}
I'm now getting State HTTP 405 - Request method 'POST' not supported when I'm trying to login
My problem was due to spring security version.
Indeed for 4.x you have to put the csrf in your form action.
My sources modified with the solution:
connection.jsp
<form name="loginForm" action="<c:url value='/login?${_csrf.parameterName}=${_csrf.token} }' />" method="POST" >
<!-- TextBox Section -->
<div class="input-group visible">
<spring:message code="connection.label.account"/>
<input name="username" path="username" placeholder="Nom du compte" type="text" class="form-control" aria-describedby="basic-addon1"/>
<!--<div class="alert alert-danger" role="alert"><form:errors path="username" cssclass="error"/></div>-->
</div><br />
<div class="input-group visible">
<spring:message code="connection.label.password"/>
<input name="password" path="password" placeholder="Mot de passe" type="password" class="form-control" aria-describedby="basic-addon1"/><br />
<!--<div class="alert alert-danger" role="alert"><form:errors path="password" cssclass="error"/></div>-->
</div><br />
<!-- TextBoxSection -->
<!-- Button Section -->
<input name="submit" type="submit" class="btn btn-default visible" value=<spring:message code="connection.button.label.connect"/> />
<br />
<!-- Button Section -->
</form>
spring-security.xml:
<http auto-config="true" >
<intercept-url pattern="/welcome**" access="hasRole('CUSTOMER')" />
<form-login login-page="/login"
default-target-url="/welcome"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/403" />
<!-- enable csrf protection -->
<csrf disabled="true"/>
</http>
I have a web service, and for that I want to authenticate users.
I'm trying to have a form based authentication with org.apache.shiro.realm.ldap.JndiLdapRealm as my realm.
But when I enter the credentials nothing happens but redirecting to login page again. And there's nothing get printed on the log.
My Question is how can I debug the shiro to figure out what is happening?
Edit:
Here is my shiro ini file
[main]
authc.loginUrl = /login.jsp
authc.successUrl = /index.jsp
ldapRealm = org.apache.shiro.realm.ldap.JndiLdapRealm
ldapRealm.userDnTemplate = sAMAccountName={0},DC=aaa,DC=bbb
ldapRealm.contextFactory.url = ldap://aaa.bbb.ccc:3268
ldapRealm.contextFactory.systemUsername = admin
ldapRealm.contextFactory.systemPassword= password
securityManager.realms = $ldapRealm
[urls]
/login.jsp = authc
/logout = logout
/** = authc
Edit 2: my login jsp
<form name="loginform" method="post">
plain
<label for="username">Username:</label>
<input type="text" id="username" name="username" />
<br/>
<label for="password">Password:</label>
<input type="password" id="password" name="password" />
<br/>
<label for="rememberMe">Remember me:</label>
<input type="checkbox" id="rememberMe" name="rememberMe" value="true" />
<br/>
<input type="submit" value="Login" />
</form>
my web.xml
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
I have the following JSF Page:
<h:form>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<b:navBar brand="TEST" brandHref="#" inverse="true">
<p:lightBox styleClass="menucolored">
<p:commandLink id="logout"
type="button"
action="/j_spring_security_logout"
value="Log Out" ajax="false"
styleClass="menucolored"/>
</p:lightBox>
</b:navBar>
</h:form>
Spring Security xml:
<http use-expressions="true" auto-config="true">
<form-login login-page="/pages/Login.xhtml"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/loginPage?error=1"
default-target-url="/pages/Home.xhtml"
always-use-default-target="true"
username-parameter="j_username"
password-parameter="j_password"/>
<!-- On logout success load the login page -->
<logout logout-success-url="/pages/Login.xhtml" />
<!-- enable csrf protection -->
<csrf />
</http>
Web.xml
<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>
I have tried replacing the command link with
<h:outputLink value="${request.contextPath}/j_spring_security_logout">logout</h:outputLink>
or
<h:outputLink value="${pageContext.request.contextPath}/j_spring_security_logout">logout</h:outputLink>
Still no luck. When I click the button nothing happens.
If CSRF enabled, you must logout with a POST method. You need to wrap it in a standard HTML form instead:
<form action="${request.contextPath}/j_spring_security_logout" method="post">
<input type="submit" value="Log out" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
For using a link instead of a button, you'll need to write some javascript in order to make the link submit the form. See this post.
I fixed it:
public String doLogout() throws ServletException, IOException {
System.out.println("In doLogout()");
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
.getRequestDispatcher("/logout");
dispatcher.forward((ServletRequest) context.getRequest(),
(ServletResponse) context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
System.out.println("End doLogout()");
return null;
}
I had to use /logout instead of /j_spring_security_logout
You can use this javascript solution for Spring Security 4 + CSRF + JSF:
Logout
<form action="logout" id="logout" method="post">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
I’m developing Spring MVC, on Apache 7.xx application and have setup everything without any errors.
I have a my application map my dispatcher servlet to HomeController , which serves the view “home/View” which is also working.
I want to implement UserAccount & Registeration use case before wiring & itegrating with spring security.
However my registration form (Register.jsp) on form submit ( or action="UserRegisteration/RegisterForm" method="POST">) gives 404 error rather than serving a view via (for testing I have UserRegisterationController serve Register.jsp again)
Register.jsp (form snippet)
<form action="/UserRegisteration/RegisterForm" method="POST">
<table width="283" border="1">
<tr>
<td width="123"><label for="firstname">First Name</label></td>
<td width="144"><input type="text" name="firstname" id="firstname"></td>
</tr>
<tr>
<td><label for="lastname">Last Name</label></td>
<td><input type="text" name="lastname" id="lastname"></td>
</tr>
<tr>
<td><label for="email">Email</label></td>
<td><input type="text" name="email" id="email"></td>
</tr>
<tr>
<td><label for="phonecontact1">Phone Contact 1</label></td>
<td><input type="text" name="phonecontact1" id="phonecontact1"></td>
</tr>
<tr>
<td><label for="phonecontact2">Phone Contact 2</label></td>
<td><input type="text" name="phonecontact2" id="phonecontact2"></td>
</tr>
<tr>
<td><label for="address1">Address 1</label></td>
<td><input type="text" name="address1" id="address1"></td>
</tr>
<tr>
<td><label for="address2">Address 2</label></td>
<td><input type="text" name="address2" id="address2"></td>
</tr>
<tr>
<td><label for="industry ">Industry </label></td>
<td><input type="text" name="industry " id="industry "></td>
</tr>
<tr>
<td><label for="password">Enter Desired Password</label></td>
<td><input type="text" name="password" id="password"></td>
</tr>
<tr>
<td><input type="reset" name="clear " id="clear " value="Clear Fields"></td>
<td><input type="submit" name="register" id="register" value="Register"></td>
</tr>
</table>
</form>
I have the following method createUserAccountRegisteration()mapped to
#RequestMapping(value="/RegisterForm", method=RequestMethod.POST) see below:
(UserRegisterationController.java)
#Controller
#RequestMapping("/UserRegisteration")
public class UserRegisterationController {
#Autowired
private RegisterationService registerationService;
#Autowired
private UserAccountService userAccountService;
#Autowired
private PasswordService passwordService;
public UserRegisterationController() {
}
public UserRegisterationController(RegisterationService registerationService, UserAccountService userAccountService, PasswordService password) {
this.registerationService = registerationService;
this.userAccountService = userAccountService;
this.passwordService = password;
}
//if checked on register link , forward to registeration page
#RequestMapping(value="/RegisterForm", method=RequestMethod.GET)
public String serveRegisterationView()
{
return "UserAccount/Register";
}
#RequestMapping(value="/RegisterForm", method=RequestMethod.POST)
public String createUserAccountRegisteration()
{
//if submited registeration
//check for previous registeration
//if registered prompt , forward to sign in
//else create registeration , and user account , and password , forward to main user page
return "UserAccount/Register";
}
}
web.xml
<web-app metadata-complete="true" 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>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/hibernate-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>cmgr</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cmgr</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>
spring-servlet relevat snippet (in my case cmgr-servlet)
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/views/" p:suffix=".jsp" p:viewClass="org.springframework.web.servlet.view.JstlView" />
applicationContext.xml (relevant snippet)
<!-- Activates various annotations to be detected in bean classes -->
<context:annotation-config />
<!-- Scans the classpath for annotated components that will be auto-registered as Spring beans. For example #Controller and #Service. Make sure to set the correct base-package-->
<context:component-scan base-package="com.cmgr.*" />
<!-- Configures the annotation-driven Spring MVC Controller programming model. Note that, with Spring 3.0, this tag works in Servlet MVC only! -->
<mvc:annotation-driven/>
<!-- mapping of static resources-->
<mvc:resources mapping="/resources/**" location="/resources/" />
</beans>
Result of Register.jsp form sumbmit:
Browser URL: (http://localhost:8084/UserRegisteration/RegisterForm)
HTTP Status 404 - /UserRegisteration/RegisterForm
type Status report
message /UserRegisteration/RegisterForm
description The requested resource (/UserRegisteration/RegisterForm) is not available.
Apache Tomcat/7.0.22
What i noticed is the browser url is missing my applications context (/cmgr) the correct url should be "http://localhost:8084/cmgr/UserRegisteration/RegisterForm"
Result of Register.jsp form sumbmit:
Browser URL: (http://localhost:8084/UserRegisteration/RegisterForm)
What i noticed is the browser url is missing my applications context (/cmgr) the correct url >should be "http://localhost:8084/cmgr/UserRegisteration/RegisterForm"
This is right, the context root "/cmgr" is missing. Show us your view, presumably the form action is the problem.
You could use the Spring url tag, like this:
<spring:url value="/UserRegisteration/RegisterForm" var="targetURL"/>
<form action="${targetURL}" [...] >
</form>`
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