HTTP Status [404] ? [Not Found] for /login in spring security - spring

I'm having a problem with the customized login form in spring security. I'm new with the spring mvc. As of now I'm having a 404 Not found when clicking the submit button in my login form.
CODE BELOW:
headerindex.jsp
<form class="navbar-form navbar-right" method="post" action="<c:url value="/login" />" id="form_login">
<div class="form-group">
<input type="text" class="form-control" name="username"
placeholder="Username">
</div>
<div class="form-group">
<input type="text" class="form-control" name="password"
placeholder="Password">
</div>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<button type="submit" class="btn btn-default">Sign In</button>
</form>
security-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select username, password, enabled from user where binary username = ?" />
</security:authentication-provider>
</security:authentication-manager>
<security:http use-expressions="true">
<security:intercept-url pattern="/" access="permitAll" />
<security:intercept-url pattern="/index" access="permitAll" />
<security:intercept-url pattern="/login" access="permitAll" />
<security:intercept-url pattern="/**" access="denyAll" />
<security:form-login authentication-success-forward-url="/home"
login-page="/" password-parameter="password"
username-parameter="username"
authentication-failure-forward-url="/login?error=true" />
<security:logout logout-success-url="/loggedout" />
<security:access-denied-handler error-page="/denied" />
</security:http>
<security:global-method-security secured-annotations="enabled"></security:global-method-security>
</beans>
UsersDao.java
#Component("usersDao")
public class UsersDao {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private SessionFactory sessionFactory;
public Session session() {
return sessionFactory.getCurrentSession();
}
#Transactional
public void create(User user) {
System.out.println(user);
user.setPassword(passwordEncoder.encode(user.getPassword()));
session().save(user);
}
public boolean exists(String username) {
return getUser(username) != null;
}
#SuppressWarnings("unchecked")
public List<User> getAllUsers() {
return session().createQuery("from user").list();
}
public User getUser(String username) {
Criteria criteria = session().createCriteria(User.class);
criteria.add(Restrictions.idEq(username));
return (User)criteria.uniqueResult();
}

#Component("usersDao")
public class UsersDao {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private SessionFactory sessionFactory;
public Session session() {
return sessionFactory.getCurrentSession();
}
#Transactional
public void create(User user) {
System.out.println(user);
//user.setPassword(passwordEncoder.encode(user.getPassword()));
session().save(user);
}
public boolean exists(String username) {
return getUser(username) != null;
}
#SuppressWarnings("unchecked")
public List<User> getAllUsers() {
return session().createQuery("from user").list();
}

I solved my problem. After checking my DAO codes I found that I was using the PasswordEncoder and I didn't set it in the bean of the security-context.xml. I just commented out the PasswordEncoder and I can now login. :)
UsersDao.java
#Component("usersDao")
public class UsersDao {
//#Autowired
//private PasswordEncoder passwordEncoder;
#Autowired
private SessionFactory sessionFactory;
public Session session() {
return sessionFactory.getCurrentSession();
}
#Transactional
public void create(User user) {
System.out.println(user);
//user.setPassword(passwordEncoder.encode(user.getPassword()));
session().save(user);
}
public boolean exists(String username) {
return getUser(username) != null;
}
#SuppressWarnings("unchecked")
public List<User> getAllUsers() {
return session().createQuery("from user").list();
}
public User getUser(String username) {
Criteria criteria = session().createCriteria(User.class);
criteria.add(Restrictions.idEq(username));
return (User)criteria.uniqueResult();
}

Related

Problem with spring security and custom login

My problem is quite similar to this one (How can I do Spring Security authentication from within a JSF form), but I've tried that solution and the problem still occurs.
index.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://java.sun.com/jsf/html">
<h:head>
<title>Info</title>
</h:head>
<h:body>
<h:form prependId="false">
<p>Usuario <h:inputText id="j_username" value="#{control.idUsuario}"/></p>
<p>Password <h:inputSecret id="j_password" value="#{control.password}"/></p>
<h:commandButton value="Entrar" action="#{control.login}" />
</h:form>
</h:body>
</html>
Control.java
#ManagedBean
#SessionScoped
public class Control implements Serializable {
private static final long serialVersionUID = 1L;
private String idUsuario;
private String password;
private UsuarioDAO usuarios;
private Usuario usuario;
public Control() {}
public String login() {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext extenalContext = facesContext.getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest)extenalContext.getRequest()).getRequestDispatcher("/j_spring_security_check");
try {
dispatcher.forward((ServletRequest)
extenalContext.getRequest(), (ServletResponse)extenalContext.getResponse());
} catch (ServletException | IOException e) {
e.printStackTrace();
}
facesContext.responseComplete();
return null;
}
public String getIdUsuario() {return idUsuario;}
public void setIdUsuario(String idUsuario) {this.idUsuario = idUsuario;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
public Usuario getUsuario() {return usuario;}
public void setUsuario(Usuario usuario) {this.usuario = usuario;}
public UsuarioDAO getUsuarios() {return usuarios;}
public void setUsuarios(UsuarioDAO usuarios) {this.usuarios = usuarios;}
}
applicationContext-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-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<http>
<intercept-url pattern="/faces/ok.xhtml" access="ROLE_ADMIN"/>
<intercept-url pattern="/faces/ko.xhtml" access="ROLE_USER"/>
<form-login
login-page="/faces/index.xhtml"
default-target-url="/login_success"
authentication-failure-url="/faces/failLogin.xhtml"
username-parameter="j_username"
password-parameter="j_password" />
<port-mappings>
<port-mapping http="8080" https="8443" /> <!-- Tomcat -->
</port-mappings>
</http>
<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
<beans:property name="url" value="jdbc:mysql://localhost:3306/BUsuariosSecurity" />
<beans:property name="username" value="root" />
<beans:property name="password" value="" />
</beans:bean>
<authentication-manager>
<authentication-provider>
<password-encoder hash="bcrypt" />
<jdbc-user-service data-source-ref="dataSource"
authorities-by-username-query="SELECT IdUsuario, Rol FROM TUsuarios WHERE IdUsuario = ?"
users-by-username-query="SELECT IdUsuario, PwUsuario, Habilitado FROM TUsuarios WHERE IdUsuario = ?" />
</authentication-provider>
</authentication-manager>
</beans:beans>
When I try to login with a valid user, it sends me to failLogin.xhtml
My DataBase: https://gyazo.com/3997921c1c9bc2787a25c9b0ff904f4b
What's my mistake?
Any help please?
The problem was that the passwords in the DB were not well encrypted, I tried to encrypt them with another website and I went all.

How to combine token Authenication and CRSF?

I am developing a web application with consist of the following
Rest Web service (Spring 4) | JWT token authentication
Web pages (login.xhtml, index.xhtml) (JSF, primeface) | crsf
The problem I am facing now is weird.
If my spring security is enabled, any access to rest web services need to be authenticated before the access is granted. I am using JWT token authentication for my login. However my web pages will fail after I login. i.e my login is successful but any action after this, results in an invalid crsf token or null request error.
If my spring security is disabled, my rest services does not need to be authenticated to access the web services but my web pages works perfectly fine.
How do I integrate both solutions together?
All my web pages already included the following:
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
ApplicationContext-Security.xml:
<http pattern="/auth/login" security="none" />
<http pattern="/login.xhtml" security="none" />
<http pattern="/index.xhtml" security="none" />
<http pattern="/javax.faces.resource/**" security="none" />
<http pattern="/RES_NOT_FOUND" security="none" />
<http pattern="/img/**" security="none" />
<sec:http auto-config="false" create-session="stateless" entry-point-ref="customEntryPoint" use-expressions="true">
<intercept-url pattern="/admin/**" access="hasRole('ADMIN') or hasRole('HQ')" />
<intercept-url pattern="/audit/**" access="hasRole('ADMIN')" />
<intercept-url pattern="/request/**" access="hasRole('ADMIN') or hasRole('HQ')" />
<intercept-url pattern="/reporting/**" access="hasRole('ADMIN') or hasRole('HQ')" />
<sec:custom-filter ref="customAuthenticationFilter"
before="PRE_AUTH_FILTER" />
<!-- <sec:csrf disabled="true" /> -->
</sec:http>
As you can see i included the <http pattern="/index.xhtml" security="none" /> so that i can allow what feature that is in my index.xhtml to work. But now i can access the index.xhtml directly.
Can someone advise on how to fix this?
===== EDITED. MORE INFO =====
To add on, this is my login page and controller.
login.xhtml:
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>BTS Upload</title>
<h:outputStylesheet library="css" name="bootstrap.min.css" />
<h:outputScript library="js" name="jquery-1.11.1.min.js" />
<h:outputScript library="js" name="bootstrap.min.js" />
</h:head>
<!-- Css here -->
<h:body>
<font color="red"> <h:outputLabel
value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
</font>
<div class="container">
<div class="row">
<div class="col-sm-6 col-md-4 col-md-offset-4">
<h1 class="text-center login-title">Sign in</h1>
<div class="account-wall">
<h:graphicImage class="profile-img" library="images"
name="photo.png" />
<h:form class="form-signin">
<h:outputLabel value="Enter UserName:" />
<h:inputText id="username" value="#{loginAction.username}"
required="true" requiredMessage="Please enter your username"
autofocus="true" class="form-control"></h:inputText>
<h:message for="username" id="msg"
errorStyle="color:red; display:block" />
<br />
<h:outputLabel value="Enter Password:" />
<h:inputSecret id="password" value="#{loginAction.pwd}"
required="true" requiredMessage="Please enter your password"
class="form-control"></h:inputSecret>
<h:message for="password" id="msg1"
errorStyle="color:red; display:block" />
<br />
<br />
<h:commandButton class="btn btn-lg btn-primary btn-block"
action="#{loginAction.login}"
value="Login"></h:commandButton>
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</h:form>
</div>
</div>
</div>
</div>
</h:body>
</html>
Controller:
#ManagedBean(name="loginAction")
#SessionScoped
public class LoginAction extends BaseAction implements Serializable
{
private static final long serialVersionUID = 1094801825228386363L;
private String pwd;
private String msg;
private String username;
#ManagedProperty("#{accessControlService}")
private AccessControlService accessControlService;
public String getPwd()
{
return pwd;
}
public void setPwd(String pwd)
{
this.pwd = pwd;
}
public String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public String getUsername()
{
return username;
}
public void setUsername(String user)
{
this.username = user;
}
//validate login and redirect to the specified website.
public String login()
{
System.out.println();
System.out.println("Call Log in");
if (username.equals("") || pwd.equals(""))
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Username and Password", "Please enter correct username and Password"));
return "login";
}
boolean valid = false;
String token = "";
try
{
token = accessControlService.isAuthorizedUser(username, pwd, PropertiesUtil.LoginType.WEB_BTS.ordinal(), this.getRequest());
}
catch (Exception e)
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Error", e.getLocalizedMessage()));
}
if(token.contains(PropertiesUtil.TOKEN_HEADER))
{
valid = true;
}
if (valid)
{
HttpSession session = this.getSession();
session.setAttribute("username", username);
session.setAttribute("token", token);
return "admin";
}
else
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Username and Password", "Please enter correct username and Password"));
return "login";
}
}
// logout event, invalidate session
public String logout()
{
System.out.println("**********************************************************");
try
{
accessControlService.logout(getUsername(), PropertiesUtil.LoginType.WEB_BTS.ordinal(), getRequest());
HttpSession session = this.getSession();
session.invalidate();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return "login";
}
public AccessControlService getAccessControlService()
{
return accessControlService;
}
public void setAccessControlService(AccessControlService accessControlService)
{
this.accessControlService = accessControlService;
}
}
Firstly you must be sure that you have spring security 4 compatible *-security.xml and *-servlet.xml look at this
From part of security.xml that you posted I can see that you don't have form-login tag. It should be something like this
<security:form-login default-target-url="/index"
login-page="/login"
username-parameter="j_username"
password-parameter="j_password"
login-processing-url="/j_spring_security_check"
authentication-failure-url="/login?login_error=1"/>
Your login jsp needs to have action j_spring_security_check to trigger filter chain:
<form action="<c:url value="/j_spring_security_check"/>" method="POST"> ...
You don't need csrf hidden input because spring automatically injects it into request header and parameters (if you don't disable it) as of spring 4

Spring security unable to prevent forward to the previous page/j_spring_security_check after successful login?

I would like to prevent spring security from forwarding to the default "j_spring_security_check" after successful login,instead after successful login I would like to forward to custom welcome page "/auth/welcome.jsp" , attempted 2 approaches:
Diagram of my desired flow:
Approach # 1 (used xml configuration)
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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 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>Toyota Relocation App</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- load spring security -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml,/WEB-INF/security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>
security.xml:
<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-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<!-- spring security should ignore "/" & "/resources/**" paths -->
<http pattern="/" security="none" auto-config="true"
use-expressions="true" />
<http pattern="/resources/**" security="none" auto-config="true"
use-expressions="true" />
<!-- spring security configuration -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/auth**" access="hasRole('ROLE_USER')" />
<form-login login-page="/login" authentication-failure-url="/login?error"
username-parameter="emailInputField" password-parameter="pinInputField"
default-target-url="/auth/welcome" always-use-default-target="true" />
<logout logout-success-url="/login?logout" />
</http>
<!-- user accounts -->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="naim#test.com" password="12345" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
login.jsp: (relevant snippet)
<div class="mycontent">
<div id="logo_div">
<img src="resources/images/01_toyota_logo_small.png">
</div>
<div class="login_form_wrapper">
<c:if test="${not empty error}">
<div class="error">${error}</div>
</c:if>
<c:if test="${not empty msg}">
<div class="msg">${msg}</div>
</c:if>
<!-- content-->
<form name='loginForm' action="<c:url value='j_spring_security_check' />" method='POST'>
<!-- <FORM name='loginForm' action="auth" method="post">-->
<ul class="mylistview" data-role="listview">
<li>
<div><img id="email_input_icon" src="resources/images/01_login_email_icon_small.png"></div><div id="email_input" ><input name="emailInputField"" id="email_input_field" type="email" data-role="none" /></div></li>
<li>
<div><img id="pin_input_icon"src="resources/images/01_login_password_icon_small.png"></div><div id="pin_input" ><input name="pinInputField" id="pin_input_field" type="password" data-role="none" /></div></li>
<li>
<div id="login_button">
<button id="login" class="button" type="submit">LOGIN</button>
</div>
</li>
</ul>
</FORM>
</div>
HomeController:
package com.xyz.thedallasapp_poc;
//removed imports
#Controller
public class HomeControler {
public HomeControler() {
super();
// TODO Auto-generated constructor stub
}
/* serves the login landing/home page view*/
#RequestMapping("/")
public String printWelcome(ModelMap model) {
return "login";
}
/*process login request from login view */
#RequestMapping (value="/login**", method = RequestMethod.GET)
public ModelAndView processLogin(
#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout) {
ModelAndView model = new ModelAndView();
model.addObject("previousView", "/login");
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
/* forward /auth/welcome request to /auth/welcome.jsp*/
#RequestMapping(value = "/auth/welcome")
public ModelAndView authWelcome() {
ModelAndView model = new ModelAndView();
//if reffer is /login than view is auth/welcome
//else view is reffer
model.setViewName("/auth/welcome");
return model;
}
}//end controller
Result:
Successful authentication & failure happen correctly, however I'm forwarded "j_spring_security_check" view which after careful inspection is actually the previous view/page with a new URL , instead of /auth/welcome.jsp view.
The logs have no error.
Approach # 2 (used xml configuration & implemented AuthenticationSuccessHandler )
I implemented AuthenticationSuccessHandler in order to redirect to "auth/welcome.jsp after successful login.
The web.xml, HomeController.java are not changed compared to approach #1.
spring.xml:
<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-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<!-- spring security should ignore "/" & "/resources/**" paths -->
<http pattern="/" security="none" auto-config="true"
use-expressions="true" />
<http pattern="/resources/**" security="none" auto-config="true"
use-expressions="true" />
<!-- spring security configuration -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/auth**" access="hasRole('ROLE_USER')" />
<form-login login-page="/login" authentication-failure-url="/login?error"
username-parameter="emailInputField" password-parameter="pinInputField"
default-target-url="/auth/welcome" always-use-default-target="true"
authentication-success-handler-ref="myAuthSuccessHandler"/>
<logout logout-success-url="/login?logout" />
</http>
<!-- user accounts -->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="naim#test.com" password="12345" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<!-- custom bean used to override spring security page redirection after successful authentication -->
<beans:bean id="myAuthSuccessHandler"
class="com.hitachi.thedallasapp_poc.security.MyAuthSuccessHandler" />
</beans:beans>
**MyAuthSuccessHandler: **
package com.hitachi.thedallasapp_poc.security;
//removed imports
public class MyAuthSuccessHandler implements AuthenticationSuccessHandler {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
System.out.println("Class onAuthenticationSuccess request: "+request.getRequestURL());
System.out.println("Class onAuthenticationSuccess response status: "+response.getStatus());
handle(request, response, authentication);
clearAuthenticationAttributes(request);
}
protected void handle(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException {
String targetUrl = determineTargetUrl(authentication,request);
if (response.isCommitted()) {
return;
}
System.out.println("Class onAuthenticationSuccess ,request.getContextPath(): " + request.getContextPath());
System.out.println("Class onAuthenticationSuccess ,targetUrl: " + targetUrl);
redirectStrategy.sendRedirect(request, response, targetUrl);
}
/** check the Role of the user that was granted access, based on the role redirect to success page */
protected String determineTargetUrl(Authentication authentication, HttpServletRequest request) {
boolean isUser = false;
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
String redirectURL = null;
for (GrantedAuthority grantedAuthority : authorities) {
if (grantedAuthority.getAuthority().equals("ROLE_USER")) {
System.out.println("Class MyAuthSuccessHandler, grantedAuthority.getAuthority():" +grantedAuthority.getAuthority());
isUser = true;
break;
}
}//end for
//if user is USER_ROLE redirect to "/auth/welcome"
if (isUser) {
System.out.println("Class MyAuthSuccessHandler, request.getRequestURL():" +request.getRequestURL().toString());
redirectURL = "/auth/welcome";
}
//else redirect to default
else
{
redirectURL = request.getRequestURL().toString();
}
return redirectURL;
}
protected void clearAuthenticationAttributes(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
return;
}
session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
protected RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
}//end class MyAuthSuccessHandler
Result:
After successful login the user is still redirected to previous page but again with path "j_spring_security_check", rather than desired "auth/welcome.jsp"
Logs show no error.
My System.println results:
Class MyAuthSuccessHandler, grantedAuthority.getAuthority():ROLE_USER
Class MyAuthSuccessHandler, request.getRequestURL():http://theda
llasapp_poc/j_spring_security_check
Class onAuthenticationSuccess ,request.getContextPath(): /thedallasapp_poc
Class onAuthenticationSuccess ,targetUrl: /auth/welcome
Thanks any help would be appreciated.

SpringSecurity + JSF custom authentication

I trying find solution but noone work. i've some spring security configs and frontend written in JSF. I found some configs in intenter but together they dont wanna work
<http>
<intercept-url pattern="/index*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/javax.faces.resource/**"
access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="ROLE_USER" />
<intercept-url pattern="/admin/*" access="ROLE_SUPERVISOR" />
<form-login login-page="/index.html" default-target-url="/home.html"
always-use-default-target="true" authentication-failure-url="/index.xhtml?login_error=1" />
<logout logout-url="/logout.html" />
</http>
and:
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_USER, ROLE_SUPERVISOR" />
<user name="anonim" password="anonim" authorities="" />
<user name="user" password="user" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
I'd like to make some custom class that will be like custom logger i found solution that will be similar these:
public class LoginBeenController {
private static final Logger LOGGER = Logger.getLogger(LoginBeenController.class);
private String login;
private String password;
#Autowired
private AuthenticationManager authenticationManager;
public LoginBeenController() {
}
public String getLogin() {
return login;
}
public String getPassword() {
return password;
}
public void setLogin(String login) {
this.login = login;
}
public void setPassword(String password) {
this.password = password;
}
public String login(){
Authentication authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(
this.login, this.password));
if (authentication.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(
authentication);
}
return new String();
}
}
Here is prime form:
<h:form>
<h:panelGrid columns="2" cellpadding="5">
<h:outputLabel for="username" name='j_username' value="Username:" />
<p:inputText id="username" value="#{loginBeenController.login}" required="true" label="username" />
<h:outputLabel for="password" value="Password:" />
<h:inputSecret id="password" value='#{loginBeenController.password}' required="true" label="password" />
<f:facet name="footer">
<p:commandButton ajax='false' id="loginButton" value="Login" action="#{loginBeenController.login()}" />
</f:facet>
</h:panelGrid>
</h:form>
Ok I found solution i had to add only:
#Autowired
#Qualifier("authenticationManager")
AuthenticationManager authenticationManager;
You should be forwarding to Spring Security authentication URL instead of using the AuthenticationManager. Try this:
public String doLogin() throws ServletException, IOException {
FacesContext context = FacesContext.getCurrentInstance();
String springCheckUrl = this.buildSpringSecurityCheckUrl();
HttpServletRequest request = (HttpServletRequest) context
.getExternalContext().getRequest();
RequestDispatcher dispatcher = request
.getRequestDispatcher(springCheckUrl);
dispatcher.forward((ServletRequest) request,
(ServletResponse) context.getExternalContext.getResponse());
context.responseComplete();
return null;
}
private String buildSpringSecurityCheckUrl() {
StringBuilder springCheckUrl = new StringBuilder(
"/j_spring_security_check").append("?").append("j_username")
.append("=").append(this.userName.trim()).append("&")
.append("j_password").append("=")
.append(this.userPassword.trim());
return springCheckUrl.toString();
}
}

Spring Security with Openid and Database Integration

I am very new to Spring and Spring Security, and hoping someone can help me to solve the following problem.
What I want to achieve is to extract user's username and email address after this user is successfully authenticated by OpenID provider(gmail), then check with the database in order to load the usermodel for this user.
In my spring-security.xml, i have
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<security:authentication-manager alias="openIDAuthenticationManager" />
<bean id="authenticationSuccessHandler" class="org.school.openid.service.YouEatAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/krams/main/common" />
<property name="attributes2UserDetails" ref="openIDAttributes2UserDetails" />
</bean>
<security:http >
<security:anonymous enabled="false" />
<security:logout />
<security:openid-login user-service-ref="userDetailsServiceOpenIDImpl" authentication-success-handler-ref="authenticationSuccessHandler"
login-page="/krams/auth/login" authentication-failure-url="/krams/auth/login?error=true">
<security:attribute-exchange>
<security:openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true" />
<security:openid-attribute name="firstName" type="http://axschema.org/namePerson/first" required="true" />
<security:openid-attribute name="lastName" type="http://axschema.org/namePerson/last" required="true" />
</security:attribute-exchange>
</security:openid-login>
</security:http>
<bean id="openIDAttributes2UserDetails" class="org.school.openid.service.OpenIDAttributes2UserDetailsImpl" />
<bean id="userDetailsServiceOpenIDImpl" class="org.school.openid.service.UserDetailsServiceOpenIDImpl" />
</beans>
my problem is at UserDetailsServiceOpenIDImpl.java is
public class UserDetailsServiceOpenIDImpl implements UserDetailsService {
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
System.out.println(username);
//extract username and email address, HOW?
}
}
The print statement prints out something like
https://www.google.com/accounts/o8/id?id=AItOawlq2C3EdFAuqp-ski_xkgB8jsEKbe-mZE
My questions are
(1) How could I extract the username and the email address from the returned url (also, I am not even sure if the username and email address returned correctly)?
(2) By running the debug on Eclipse, the YouEatAuthenticationSuccessHandler seems not called when the url (https://www.google.com/accounts/o8/id?id=AItOawlq2C3EdFAuqp-ski_xkgB8jsEKbe-mZE) returned.
Thanks.
Edit:
thanks for the link http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html#ns-openid.
It says that "The attribute values are returned as part of the authentication process and can be accessed afterwards using the following code:..."
I have added
OpenIDAuthenticationToken token = (OpenIDAuthenticationToken)SecurityContextHolder.getContext().getAuthentication();
List attributes = token.getAttributes();
into loadUserByUsername method. But the "token" object is null.
Edit 2
By following page https://fisheye.springsource.org/browse/spring-security/samples/openid/src/main/webapp/WEB-INF/applicationContext-security.xml?hb=true, i am able to extra the name and email address for the user.
My spring-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:authentication-manager alias="openIDAuthenticationManager" />
<security:http pattern="/krams/auth/login" security="none"/>
<security:http auto-config="true" access-denied-page="/krams/auth/denied">
<security:intercept-url pattern="/krams/main/*" access="ROLE_USER" />
<security:anonymous enabled="false" />
<security:logout
invalidate-session="true"
logout-success-url="/krams/auth/login"
logout-url="/krams/auth/logout"/>
<security:openid-login
user-service-ref="registeringUserService"
login-page="/krams/auth/login"
authentication-failure-url="/krams/auth/login?error=true"
default-target-url="/krams/main/common">
<security:attribute-exchange identifier-match="https://www.google.com/.*">
<security:openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true" />
<security:openid-attribute name="firstName" type="http://axschema.org/namePerson/first" required="true" />
<security:openid-attribute name="lastName" type="http://axschema.org/namePerson/last" required="true" />
</security:attribute-exchange>
<security:attribute-exchange identifier-match=".*yahoo.com.*">
<security:openid-attribute name="email" type="http://axschema.org/contact/email" required="true"/>
<security:openid-attribute name="fullname" type="http://axschema.org/namePerson" required="true" />
</security:attribute-exchange>
</security:openid-login>
<!-- if remember is needed
<security:remember-me token-repository-ref="tokenRepo"/>
-->
</security:http>
<bean id="tokenRepo" class="org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl" />
<!--
A custom UserDetailsService which will allow any user to authenticate and "register" their IDs in an internal map
for use if they return to the site. This is the most common usage pattern for sites which use OpenID.
-->
<bean id="registeringUserService" class="org.school.openid.service.CustomUserDetailsService" />
</beans>
My CustomUserDetailsService.java
public class CustomUserDetailsService implements AuthenticationUserDetailsService {
/*
private final Map registeredUsers = new HashMap();
*/
private static final List DEFAULT_AUTHORITIES = AuthorityUtils.createAuthorityList("ROLE_USER");
protected static Logger logger = Logger.getLogger("service");
/**
* Implementation of {#code AuthenticationUserDetailsService} which allows full access to the submitted
* {#code Authentication} object. Used by the OpenIDAuthenticationProvider.
*/
public UserDetails loadUserDetails(OpenIDAuthenticationToken token) {
String id = token.getIdentityUrl();
String email = null;
String firstName = null;
String lastName = null;
String fullName = null;
List attributes = token.getAttributes();
for (OpenIDAttribute attribute : attributes) {
if (attribute.getName().equals("email")) {
email = attribute.getValues().get(0);
}
if (attribute.getName().equals("firstName")) {
firstName = attribute.getValues().get(0);
}
if (attribute.getName().equals("lastName")) {
lastName = attribute.getValues().get(0);
}
if (attribute.getName().equals("fullname")) {
fullName = attribute.getValues().get(0);
}
}
if (fullName == null) {
StringBuilder fullNameBldr = new StringBuilder();
if (firstName != null) {
fullNameBldr.append(firstName);
}
if (lastName != null) {
fullNameBldr.append(" ").append(lastName);
}
fullName = fullNameBldr.toString();
}
CustomUserDetails user = new CustomUserDetails(id,fullName,email, DEFAULT_AUTHORITIES);
logger.debug("Set username " + fullName + " email " + email);
return user;
}
}
My CustomUserDetails.java
public class CustomUserDetails extends User {
private static final long serialVersionUID = 1L;
private String email;
private String name;
public CustomUserDetails(String id,String name, String email,Collection authorities) {
super(name, "unused", true,true,true,true,authorities);
this.email = email;
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
And
...
<repository>
<id>org.springframework.maven.milestone</id>
<name>Spring Maven Milestone Repository</name>
<url>http://maven.springframework.org/milestone</url>
</repository>
...
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.1.0.RC1</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.1.0.RC1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.1.0.RC1</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>3.1.0.RC1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>3.1.0.RC1</version>
<type>pom</type>
<scope>compile</scope>
</dependency>
Hope can save you some time.
As I see that question text itself contains the answer. I am just pulling it out and posting it as the answer for the sake of clarity to other developers with the same problem. It took me a while to figure out that question has the answer!
To access user email & name, you need to add below configuration in the security xml file.
<security:attribute-exchange identifier-match="https://www.google.com/.*">
<security:openid-attribute name="email" type="http://schema.openid.net/contact/email" required="true" />
<security:openid-attribute name="firstName" type="http://axschema.org/namePerson/first" required="true" />
<security:openid-attribute name="lastName" type="http://axschema.org/namePerson/last" required="true" />
</security:attribute-exchange>
<security:attribute-exchange identifier-match=".*yahoo.com.*">
<security:openid-attribute name="email" type="http://axschema.org/contact/email" required="true"/>
<security:openid-attribute name="fullname" type="http://axschema.org/namePerson" required="true" />
</security:attribute-exchange>
Thereafter, it will be accessible in the AuthenticationUserDetailsService class, as shown below.
public UserDetails loadUserDetails(OpenIDAuthenticationToken token) {
String id = token.getIdentityUrl();
:
:
List attributes = token.getAttributes();
for (OpenIDAttribute attribute : attributes) {
if (attribute.getName().equals("email")) {
email = attribute.getValues().get(0);
}
if (attribute.getName().equals("firstName")) {
firstName = attribute.getValues().get(0);
}
if (attribute.getName().equals("lastName")) {
lastName = attribute.getValues().get(0);
}
if (attribute.getName().equals("fullname")) {
fullName = attribute.getValues().get(0);
}
}
:
:
// form and return user object
}
Considering that we use more of Java-based configuration/beans now, translating these XML configuration to Java-based configuration shouldn't be a problem.
Hope it helps.

Resources