Spring Security with Openid and Database Integration - spring

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.

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.

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

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();
}

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.

Spring Security openid-login attribute-exchange only call once at first time

I have trouble in spring security 3.1.
I'm going to use spring security openid-login with gmail, and I want to get user information using attribute-exchange. but if I use it, it is always called when user log-in my website.
How can i call only once at user sign-in my website?
I managed sign-in at openIdAuthFailureHandler, and I want to get user information in this bean...please help me!
(I found security:remember-me, but it doesn't work..)
security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:global-method-security
secured-annotations="enabled" proxy-target-class="true" />
<security:http auto-config="true" access-denied-page="/denied/accessDenied">
<security:intercept-url pattern="/admin/**"
access="ROLE_ADMIN" />
<security:intercept-url pattern="/reservation/**"
access="ROLE_USER, ROLE_ADMIN" />
<security:intercept-url pattern="/board/**"
access="ROLE_ADMIN, ROLE_USER" />
<security:openid-login login-page="/"
login-processing-url="/j_spring_openid_security_check.do"
authentication-success-handler-ref="customAuthenticationHandler"
authentication-failure-handler-ref="openIdAuthFailureHandler">
<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:attribute-exchange>
</security:openid-login>
<security:logout logout-url="/j_spring_openid_security_logout.do"
logout-success-url="/" invalidate-session="true" />
<!-- <security:http-basic /> -->
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<!-- <security:user-service properties="/WEB-INF/resources/users.xml"
/> -->
<security:password-encoder ref="passwordEncoder" />
<security:jdbc-user-service id="userDetailsService"
data-source-ref="dataSource"
users-by-username-query="SELECT id as id, passwd as passwd, 1 as enabled FROM user WHERE id=?"
authorities-by-username-query="SELECT id as id, power as authority FROM user WHERE id=?" />
<!-- <security:password-encoder hash="sha-256"></security:password-encoder> -->
</security:authentication-provider>
</security:authentication-manager>
<bean id="customTokenRepository" class="com.jinyoung.reservation.openid.CustomTokenRepository" />
<bean id="openIdAuthFailureHandler" class="com.jinyoung.reservation.openid.OpenIDAuthenticationFailureHandler"/>
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />
</beans>
OpenIDAuthenticationFailureHandler
public class OpenIDAuthenticationFailureHandler extends
SimpleUrlAuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
if (exception instanceof UsernameNotFoundException && exception.getAuthentication() instanceof OpenIDAuthenticationToken && ((OpenIDAuthenticationToken) exception.getAuthentication()).getStatus().equals(OpenIDAuthenticationStatus.SUCCESS)) {
DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
request.getSession(true).setAttribute("USER_OPENID_CREDENTIAL", ((UsernameNotFoundException)exception).getExtraInformation());
OpenIDAuthenticationToken openIdAuth = (OpenIDAuthenticationToken)exception.getAuthentication();
request.getSession(true).setAttribute("USER_OPENID_CREDENTIAL_EXTRA", openIdAuth);
for(OpenIDAttribute attr : openIdAuth.getAttributes()) {
System.out.printf("AX Attribute: %s, Type: %s, Count: %d\n", attr.getName(), attr.getType(), attr.getCount());
for(String value : attr.getValues()) {
System.out.printf(" Value: %s\n", value);
}
}
redirectStrategy.sendRedirect(request, response, "/login/registrationOpenid");
// redirect to create account page
/*redirectStrategy.sendRedirect(request, response,
"/?fail=true");*/
} else {
super.onAuthenticationFailure(request, response, exception);
}
}
}
Ran in to a similar problem which I solved by having two different form targets (j_spring_openid_security_check_signup and j_spring_openid_security_check) for the signup/login page. One used when signing up and one when logging in. In spring-security.xml we use two different configs, one that asks for attributes and one that don't:
<!-- Configure attribute-exchange for signup -->
<!-- will only match /j_spring_openid_security_check_signup -->
<security:http auto-config="true" use-expressions="true" path-type="ant" pattern="/j_spring_openid_security_check_signup">
<security:openid-login
login-processing-url="/j_spring_openid_security_check_signup"
user-service-ref="userDetailsService"
authentication-failure-handler-ref="authenticationFailureHandler"
authentication-success-handler-ref="authenticationSuccessHandler">
<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:attribute-exchange>
</security:openid-login>
</security:http>
<!-- Skip attribute-exchange at log-in -->
<!-- match everything else -->
<security:http auto-config="true" use-expressions="true" path-type="ant">
<security:openid-login
login-processing-url="/j_spring_openid_security_check"
user-service-ref="userDetailsService"
authentication-failure-handler-ref="authenticationFailureHandler"
authentication-success-handler-ref="authenticationSuccessHandler"
/>
</security:http>
Then in the authenticationSuccessHandler you will have access to attributes while signing in but not at log-in.
-------------------------------I solved!!!------------------------------------------
I modified spring-security-openid-3.1.1.RELEASE.jar, and I call attribute-change only once at user access my site first time. if one who want to know, give me e-mail kjy30532#gmail.com !

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();
}
}

Resources