Page 1 of 2 12 LastLast
Results 1 to 10 of 14

Thread: Spring Security + WebFlow + JSF 2.0 Problem

  1. #1
    Join Date
    Sep 2012
    Posts
    6

    Default Spring Security + WebFlow + JSF 2.0 Problem

    Hi, I am making a project based on the spring web flow sample (about the books in the hotel) but I have a problem in the security part. The project has JSF2.0, Primefaces, Spring security and Spring webflow.
    I use Spring security with a ldap provider and it's working, but I would like to do another step, I want to check the login and password with my database too.

    this is my login.xhtml:
    Code:
    <form name="f" action="${request.contextPath}/j_spring_security_check" method="post">
    		<fieldset>
    			<legend>Login Information</legend>
    				<p>
    					User:
    					<br />
    					<c:if test="${not empty param.login_error}">
    						<c:set var="username" value="${sessionScope.SPRING_SECURITY_LAST_USERNAME}"/>
    					</c:if>
    					<input type="text" name="j_username" value="#{loginBean.username}"/>
    				</p>
    				<p>
    					Password:
    					<br />
    					<input type="password" name="j_password" />				
    				</p>
    				<p>
    					<input type="checkbox" name="_spring_security_remember_me"/> 
    					Don't ask for my password for two weeks:
    				</p>
    				<p>
    					<input name="submit" type="submit" value="Login" />
    				</p>
    		</fieldset>
    	</form>
    and this is my security-config.xml:

    Code:
    <?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/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.0.xsd">
    
    
    <security:http access-denied-page="/spring/main/accessDenied" auto-config="true"> 
    	<security:intercept-url access="ROLE_ADMIN" pattern="/flows/admin/**"/> 
    	<security:intercept-url access="ROLE_USER" pattern="/flows/admin/**"/> 
    	<security:intercept-url access="IS_AUTHENTICATED_ANONYMOUSLY" pattern="/*"/> 
    	<security:form-login 
    		authentication-failure-url="/spring/login?login_error=1" 
    		default-target-url="/spring/admin" 
    		login-processing-url="/j_spring_security_check" 
    		login-page="/spring/login"/> 
    	<security:logout logout-success-url="/spring/logoutSuccess" logout-url="/spring/logout"/> 
    </security:http> 
    
    <security:authentication-manager> 
    	<security:ldap-authentication-provider user-search-filter="(uid={0})" user-search-base="ou=users,ou=Internal,o=company"/> 
    </security:authentication-manager> 
    <security:ldap-server manager-password="PWD" manager-dn="uid=Uname,ou=Users,ou=Internal,o=ericsson" url="ldap://mycompany.com"/>
    		
    </beans>
    This code is working with the ldap provider, webflow... etc, but now I want to add the customUserContextMapper.
    I have these functions :

    mapUserFromContext (the class extends LdapUserDetailsMapper):

    Code:
    @Override
    	public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<GrantedAuthority> authority) {
    		
    		Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
    		UserDetails originalUser = super.mapUserFromContext(ctx, username,
    				authority);
    
    		System.out.println("loginService " + loginService);
    		boatUser = loginService.getUser(username);
    		Set<Role> hs = new HashSet<Role>();				
    		
    		LoginBean loginBean = (LoginBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("loginBean");
    		loginBean.setBoatUser(boatUser);
    
    		if (boatUser != null) {
    			hs = boatUser.getRoles();
    		}
    
    		for (Role role : hs) {
    			authorities.add(new GrantedAuthorityImpl(role.getRole_name()));
    		}
    
    		User newUser = new User(originalUser.getUsername(), "na",
    				originalUser.isEnabled(), originalUser.isAccountNonExpired(),
    				originalUser.isCredentialsNonExpired(),
    				originalUser.isAccountNonLocked(), authorities);
    
    		return newUser;
    	}
    The loginBean is the following:

    Code:
    @Component
    @Scope("session")
    @ManagedBean(name = "loginBean")
    public class LoginBean {
    
    	private String username = "";
    	private String password = "";
    	private boolean rememberMe = false;
    	private boolean loggedIn = false;
    	private User boatUser;
    
    	public String doLogin() throws IOException, ServletException {
    
    		System.out.println("DoLogin Method");
    		ExternalContext context = FacesContext.getCurrentInstance()
    				.getExternalContext();
    
    		RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
    	            .getRequestDispatcher("/j_spring_security_check");
    
    
    		dispatcher.forward((ServletRequest) context.getRequest(),
    				(ServletResponse) context.getResponse());
    
    		FacesContext.getCurrentInstance().responseComplete();
    
    		// It's OK to return null here because Faces is just going to exit.
    		return "succcess";
    	}
    and I changed the login.xhtml with

    Code:
    <h:form id="loginForm"  prependId="false">
    
    ...
    
    <h:commandButton type="submit"	id="login" action="#{loginBean.doLogin}" value="Login" />
    
    ...
    
    </h:form>
    and I changed security-config.xml:

    Code:
    ...
    	<bean class="com.ericsson.boat.login.service.CustomUserDetailsMapper" id="customUserContextMapper"/> 
    
    	<security:authentication-manager>
    		<security:ldap-authentication-provider 
    			user-search-base="ou=users,ou=Internal,o=company" 
    			user-search-filter="(uid={0})" 
    			user-context-mapper-ref="customUserContextMapper" />
    	</security:authentication-manager>
    
    ...
    But it doesn't work, when I push the submit button, I have the following error:

    Code:
    com.sun.faces.context.FacesFileNotFoundException
    	at com.sun.faces.facelets.impl.DefaultFaceletFactory.resolveURL(DefaultFaceletFactory.java:232)
    	at com.sun.faces.facelets.impl.DefaultFaceletFactory.resolveURL(DefaultFaceletFactory.java:273)
    	at com.sun.faces.facelets.impl.DefaultFaceletFactory.getFacelet(DefaultFaceletFactory.java:201)
    	at com.sun.faces.application.view.FaceletViewHandlingStrategy.buildView(FaceletViewHandlingStrategy.java:764)
    	at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:100)
    	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    	at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
    	...
    	at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    	at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    	at java.lang.Thread.run(Thread.java:722)
    And the web page goes to:

    http://localhost:8080/BOAT/spring/WEB-INF/login.xhtml

    The system never executes doLogin. In another version I got to execute the mapUserFromContext, but FacesContext was null because the system doesn't execute doLogin...
    Do I need something else? Is possible to do what I am trying??

  2. #2
    Join Date
    Aug 2012
    Posts
    15

    Default

    hi,

    perhaps return "succcess"; (3 c's ?) ? :-) you can return null there !

    We ourselves at work had trouble with JSF (also PrimeFaces) and Spring (our views are outside WEB-INF folder, otherwise request went dangling ! (was in previous version of prime faces v2.2.1)

    We have our loginbean request scope. Have you tried that ?

    Grtz,

    Sikke

  3. #3
    Join Date
    Sep 2012
    Posts
    6

    Default

    Hi, finally I found the solution here:

    http://stackoverflow.com/questions/1...authentication

    In this little comment

    "You can use html <form> tag and post it to j_spring_security_check and use the default-target-url attribute to point to the secured.xhtml. If you would like to use JSF <h:form> tag then look at this answer stackoverflow.com/questions/11742283/… – Ravi Aug 17 at 3:25"

    So I changed my login.xhtml to this using the <form> tag:

    Code:
       	<form name="f" action="${request.contextPath}/j_spring_security_check" method="post">   
    		<fieldset>
    			<legend>Login Information</legend>
    				<p>
    					User:
    					<br />
    					<c:if test="${not empty param.login_error}">
    						<c:set var="username" value="${sessionScope.SPRING_SECURITY_LAST_USERNAME}"/>
    					</c:if>
    					<input type="text" name="j_username" value="${loginBean.username}" />
    				</p>
    				<p>
    					Password:
    					<br />
    					<input type="password" name="j_password" value="${loginBean.password}"/>				
    				</p>
    				<p>
    					<input type="checkbox" name="_spring_security_remember_me" value="${loginBean.rememberMe}"/> 
    					Don't ask for my password for two weeks:
    				</p>
    				<p>
    				   <input name="submit" type="submit" value="Login" onclick="${loginBean.doLogin()}"/> 			    		
    				</p>
    		</fieldset>
    	</form>
    and deleted this line in then LoginBean class:

    Code:
    dispatcher.forward((ServletRequest) context.getRequest(),
    				(ServletResponse) context.getResponse());
    And now it's working... but anyway, I get null in FacesContext.getExternalContext in the mapUserFromContext function and I dont know why... I had to comment this line too:

    Code:
    LoginBean loginBean = (LoginBean) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("loginBean");
    		loginBean.setBoatUser(boatUser);
    Maybe is logical that but I don't know why... anyone knows about this?

    Thank you!
    Regards

    Carlos

  4. #4
    Join Date
    Aug 2012
    Posts
    15

    Default

    Hi,

    Normally the facescontext and externalcontext can't be null... if your application has been deployed successfully there should be a facescontext and servletcontext around... so for me thats really weird ... Never seen this behaviour before... I try to look tomorrow at our login page and bean and security config to see what could be different...

    The loginbean I know is request scope just for logging in into application... We also use spring for managing beans and scopes... We even had to create a viewscope implementation of scope interface of spring in order to make view scope happening... but I can't believe that that would be the cause...

    Have you also tried the ui:debug to see what variables that are created ?

    Cheers

  5. #5
    Join Date
    Sep 2012
    Posts
    6

    Default

    Hi,

    I don't see nothing strange with ui:debug...
    In fact, I don't see any error... only the null pointer when I try to access to the FacesContext.getCurrentInstance.getExternalContext .

    Regards

  6. #6
    Join Date
    Aug 2012
    Posts
    15

    Default

    Hi,

    I'll post our bean and xhtml and security settings:

    loginbean:

    Code:
    package be.laco.estatemanagement.web.bean;
    
    import java.io.IOException;
    
    import javax.faces.context.ExternalContext;
    import javax.faces.context.FacesContext;
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    import org.apache.commons.lang3.builder.ToStringBuilder;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    
    import be.laco.framework.core.bean.AbstractBean;
    import be.laco.framework.core.jsf.JsfUtil;
    
    @Scope("request")
    @Component("loginBean")
    public class LoginBean extends AbstractBean {
    
    	private static final long serialVersionUID = 735513459965038312L;
    	
    	private static final Logger LOGGER = LoggerFactory.getLogger(LoginBean.class);
    
    	private static final String SPRING_SECURITY_URL = "/j_spring_security_check";
    
    	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;
    	}
    
    	/**
    	 * Constructor
    	 */
    	public LoginBean() {
    		super();
    	}
    
    	/**
    	 * Login into application.
    	 * 
    	 * @return String view
    	 * @throws ServletException
    	 * @throws IOException
    	 */
    	public String login() throws ServletException, IOException {
    		
    		LOGGER.debug("Logging in into application ...");
    
    		FacesContext facesContext = JsfUtil.getFacesContext();
    		ExternalContext externalContext = JsfUtil.getFacesExternalContext();
    
    		final RequestDispatcher dispatcher = ((ServletRequest) externalContext.getRequest()).getRequestDispatcher(SPRING_SECURITY_URL);
    		dispatcher.forward((ServletRequest) externalContext.getRequest(), (ServletResponse) externalContext.getResponse());
    		
    		facesContext.responseComplete();
    		
    		return navigationResolver.returnCurrentView();
    	}
    	
    	/**
    	 * Resets field 'username' and 'password'.
    	 * 
    	 * @return String view
    	 */
    	public String reset() {
    			
    		LOGGER.debug("Reset login ...");
    		
    		username = null;
    		password = null;
    
    		return navigationResolver.returnCurrentView();
    	}
    	
    	/**
    	 * {@inheritDoc}}
    	 */
    	@Override
    	public String toString() {
    		return new ToStringBuilder(this).append("LoginBean").toString();
    	}
    }
    login page:

    HTML Code:
    <?xml version="1.0" encoding="UTF-8" ?>
    
    <!DOCTYPE HTML>
    
    <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:p="http://primefaces.org/ui">
    	 
    	<h:head>
    		<title>EstateManagement - Login Page</title>
    		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    		<link rel="stylesheet" id="login-css" href="#{request.contextPath}/resources/styles/login.css" type="text/css" media="all"/>
    		
    		<script>
    			function focus() {
    				document.loginForm.j_username.focus();
    			}
    		</script>
    	</h:head>
    	
    	<h:body onload="focus();">	
    		<div id="login">
    	 		<h:form id="loginForm" prependId="false">
    	 			<p:growl id="msgs" showDetail="false" redisplay="false" life="2000"/>
    				<br/>
    				<br/>
    				<h1><a href="http://www.laco.be"/></h1>
    				<p>
    					<h:outputLabel id="lblUsername" value="#{messages['lbl.username']} :"/>
    					<p:inputText id="j_username" value="#{loginBean.username}" styleClass="input" name="j_username" size="20" minlength="6" maxlength="20" tabindex="1">
    						<f:validator validatorId="loginValidator" for="j_username"/>
    					</p:inputText>
    				</p>
    				<p>
    					<h:outputLabel id="lblPassword" value="#{messages['lbl.password']} :"/>
    					<p:password id="j_password" value="#{loginBean.password}" styleClass="input" name="j_password" size="20" minlength="6" maxlength="20" tabindex="2" feedback="false">
    						<f:validator validatorId="loginValidator" for="j_password"/>
    					</p:password>
    				</p>
    				<br/>
    				<div class="submit">
    					<p:commandButton id="btnLogin" ajax="false" type="submit" value="#{messages['btn.login']}" action="#{loginBean.login}" tabindex="3" update="msgs,loginForm"/>
    					<p:spacer width="5px"/>
    					<p:commandButton id="btnReset" ajax="false" type="reset" value="#{messages['btn.reset']}" action="#{loginBean.reset}" tabindex="4" update="msgs,loginForm"/>
    				</div>
    			</h:form>
    			<br/><br/>
    		</div>	
    	</h:body>
    </html>
    spring security context:
    HTML Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:context="http://www.springframework.org/schema/context"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xmlns:s="http://www.springframework.org/schema/security"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="
      	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 
      	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
          
        <context:component-scan base-package="be.laco.estatemanagement.security"/>
              
    	<s:global-method-security secured-annotations="enabled"/>
    	
    	<bean id="securityManager" class="be.laco.estatemanagement.security.manager.SecurityManagerImpl" scope="session">
        	<aop:scoped-proxy proxy-target-class="false"/>
        </bean>
    	
    	<s:http pattern="/faces/javax.faces.resource/**" security="none"/>
    	
    	<s:http auto-config="false" use-expressions="true">
    		<s:intercept-url pattern="/estatemanagement/login" access="permitAll"/>
    		<s:intercept-url pattern="/estatemanagement/logout" access="isAuthenticated()"/>
    		<s:intercept-url pattern="/estatemanagement/main" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>
    		<s:intercept-url pattern="/estatemanagement/list/estate/**" access="hasRole('ROLE_ESTATE')"/>
    		<s:intercept-url pattern="/estatemanagement/detail/estate/**" access="hasRole('ROLE_ESTATE')"/>
    		<s:intercept-url pattern="/estatemanagement/detail/unit/**" access="hasRole('ROLE_ESTATE')"/>
    		
    		<s:intercept-url pattern="/faces/views/protected/estate/**" access="hasAnyRole('ROLE_ADMIN','ROLE_ESTATE')" method="POST"/>
    		<s:intercept-url pattern="/faces/views/protected/unit/**" access="hasAnyRole('ROLE_ADMIN','ROLE_ESTATE')" method="POST"/>
    		<s:intercept-url pattern="/faces/views/protected/service/**" access="hasAnyRole('ROLE_ADMIN','ROLE_SERVICE')" method="POST"/>
    		<s:intercept-url pattern="/faces/views/protected/**" access="isAuthenticated()" method="POST"/>
    		
    		<s:form-login login-page="/estatemanagement/login" default-target-url="/estatemanagement/main" authentication-failure-url="/estatemanagement/login"
    			login-processing-url="/j_spring_security_check" always-use-default-target="true" username-parameter="j_username" password-parameter="j_password"/>
    		<s:logout logout-success-url="/estatemanagement/logout" logout-url="/j_spring_security_logout" invalidate-session="true" />
    	</s:http>
    	
    	<s:authentication-manager alias="authenticationManager">
    		<s:authentication-provider>
    			<s:user-service id="userDetailsService" properties="classpath:security.properties"/>
    		</s:authentication-provider>
    	</s:authentication-manager>
    </beans>
    Now I don't know but I see @Component and @ManagedBean on same bean, is that desired ? It's normally either spring or JSF that manages the beans, not both ... (I think)

    GRtz,

    Kristof


    PS: what version of Spring, JSF, and prime faces are you using ? Also which application server ?

    We are using Spring v3.1, JSF v2.1 (servlet 3.0), Tomcat 7, Prime Faces 3.4

  7. #7
    Join Date
    Sep 2012
    Posts
    6

    Default

    I tried to delete @Component but it's not working...
    I am using Spring v3.1.1, Spring Security 3.0.5, Spring Webflow 2.3.1, JSF v2.1 servlet 2.5, Glassfish 3.1, Primefaces 3.1.1
    I don't know if it was a good idea to include spring webflow because I have a lot of problems with this and JSF...

    Regards.

  8. #8

    Default

    you want to keep @Component and @Scope

  9. #9
    Join Date
    Aug 2012
    Posts
    15

    Default

    Quote Originally Posted by sCarlosSM View Post
    I tried to delete @Component but it's not working...
    I am using Spring v3.1.1, Spring Security 3.0.5, Spring Webflow 2.3.1, JSF v2.1 servlet 2.5, Glassfish 3.1, Primefaces 3.1.1
    I don't know if it was a good idea to include spring webflow because I have a lot of problems with this and JSF...

    Regards.
    We tried Webflow first too but we kicked it due to many problems... Spring on the other hand has some nice classes to support JSF. In my opinion, Spring Webflow is overkill... but I am sure it has its purpose ...

    It could be something with servlet versions ? We first were on servlet 2.5 and had to switch to 3.0 because of errors and configuration problems.. also Tomcat requires it. But I saw on Glassfish site that its backwards compatible with older versions.. so guess that's not the problem.. but you can try it. Btw, soon if I am not wrong, JSF 2.2 will work best with servlet 3.0.. don't know if its required

    What you also could try is to have Spring and Security to have same versions.. (perhaps it's stupid but those work mostly the best together)
    Last edited by Kristof303; Sep 13th, 2012 at 03:10 AM.

  10. #10
    Join Date
    Aug 2012
    Posts
    15

    Default

    Quote Originally Posted by NicoTexas View Post
    you want to keep @Component and @Scope
    You can let Spring manage you beans instead of JSF... and use JSF and PrimeFaces purely for its components and navigation.

    So perhaps remove the @ManagedBean and leave the @Scope and @Component for what it is

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •