Announcement Announcement Module
Collapse
No announcement yet.
Can't get IceFaces login form to work Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    I've just looked in Spring 3 sources and I've seen that UsernamePasswordAuthenticationFilter has a postOnly property. If you set this to false in the configuration file it should also work (with the original login method):

    Code:
        /**
         * Defines whether only HTTP POST requests will be allowed by this filter.
         * If set to true, and an authentication request is received which is not a POST request, an exception will
         * be raised immediately and authentication will not be attempted. The <tt>unsuccessfulAuthentication()</tt> method
         * will be called as if handling a failed authentication.
         * <p>
         * Defaults to <tt>true</tt> but may be overridden by subclasses.
         */
        public void setPostOnly(boolean postOnly) {
            this.postOnly = postOnly;
        }
    You can define custom filters in this way:
    Code:
    	<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
    		<filter-chain-map path-type="ant">
    			<filter-chain pattern="/**" filters="filter1,...,filterM,authenticationFilter",filterN,...,filterZ />
    		</filter-chain-map>
    	<bean>
    	<bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    		<property name="authenticationManager" ref="authenticationManager" />
    		<property name="postOnly" value="false" />
    	</bean>
    And this in your web.xml:
    Code:
    	<!--Spring Security -->
    	<filter>
    		<filter-name>filterChainProxy</filter-name>
    		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    	</filter>
    
    	<filter-mapping>
    		<filter-name>filterChainProxy</filter-name>
    		<url-pattern>/*</url-pattern>
    		<dispatcher>REQUEST</dispatcher>
    		<dispatcher>FORWARD</dispatcher>
    		<dispatcher>INCLUDE</dispatcher>
    		<dispatcher>ERROR</dispatcher>
    	</filter-mapping>
    	<!--Spring Security -->
    Or you can use the <custom-filter/> in <http/> as below:
    Code:
    	<security:http entry-point-ref="loginUrlAuthenticationEntryPoint">
    		<security:intercept-url pattern="/secured/**" access="ROLE_USER" />
    		<security:session-management>
    			<security:concurrency-control max-sessions="1" />
    		</security:session-management>
    		<security:custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter" />
    	</security:http>
    	<security:authentication-manager alias="authenticationManager">
    		<security:authentication-provider>
    			<security:user-service>
    				<security:user name="bob" password="bobspassword" authorities="ROLE_USER" />
    			</security:user-service>
    		</security:authentication-provider>
    	</security:authentication-manager>
    
    	<bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    		<property name="authenticationManager" ref="authenticationManager" />
    		<property name="postOnly" value="false" />
    		<property name="authenticationSuccessHandler" ref="successHandler" />
    	</bean>
    
    	<bean id="successHandler"
    		class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    		<property name="defaultTargetUrl" value="/test.iface" />
    		<property name="alwaysUseDefaultTargetUrl" value="true" />
    	</bean>
    
    	<bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    		<property name="loginFormUrl" value="/login.iface" />
    	</bean>
    
    	<bean id="loginBean" class="test.LoginController" scope="session">
    		<property name="authenticationManager" ref="authenticationManager" />
    	</bean>
    without changing anything in web.xml.

    Dumi.
    Last edited by Dumi; Apr 15th, 2010, 09:35 AM.

    Comment


    • #17
      Absolutely Great!!! Your Solution (not using j_spring_security_check) worked for me out of the box!!!

      Thank you very much! I owe you!

      Your second solution would make all the Tutorial from IceFaces working again with Spring Security 3. However I think Spring has restricted the default behaviour of the authenticationManager not accepting the GET method for a reason. Passwords don't belong into the URL and it has been always a dirty workaround for JSF. Therefore I prefere your first solution as best practice!

      neurox

      Comment


      • #18
        I'm glad I could help! If you improve the login method code in any way please also post it.

        Thanks & best regards,
        Dumi.

        Comment


        • #19
          I think it's pretty perfect apart from the hardcoded redirection. I think we should read the original target from Spring Security.

          However this is a minor issue and I haven't had the time yet to come up with a solution.

          Kind regards
          neurox

          Comment


          • #20
            Originally posted by Dumi View Post
            I've managed to make it work, but I'm not using j_spring_security_check anymore. Here is the updated code in my login bean:

            Code:
            public AuthenticationManager getAuthenticationManager() {
            	return authenticationManager;
            }
            
            public void setAuthenticationManager(AuthenticationManager authenticationManager) {
            	this.authenticationManager = authenticationManager;
            }
            
            public void login(ActionEvent e) throws IOException {
            	try {
            		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            		UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(username, password);
            		authToken.setDetails(authentication.getDetails());
            
            		FacesContext context = FacesContext.getCurrentInstance();
            		ExternalContext ec = context.getExternalContext();
            		((HttpServletRequest) ec.getRequest()).getSession().setAttribute(
            				UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY, authToken.getName());
            
            		Authentication newAuth = authenticationManager.authenticate(authToken);
            		SecurityContextHolder.getContext().setAuthentication(newAuth);
            	} catch (UsernameNotFoundException unfe) {
            		FacesContext.getCurrentInstance().addMessage(null,
            				new FacesMessage(FacesMessage.SEVERITY_ERROR, unfe.getMessage(), unfe.getMessage()));
            	}
            
            	ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
            	String encodedURL = ec.encodeResourceURL(ec.getRequestContextPath() + "/test.xhtml");
            
            	((HttpServletResponse) ec.getResponse()).sendRedirect(encodedURL);
            }
            I'm not using navigation rules and the login method is used from actionListener.

            Also, to make this work I had to remove the LoginController bean from faces-config and define it using spring:

            Code:
            <security:authentication-manager alias="authenticationManager">
            	<security:authentication-provider>
            		<security:user-service>
            			<security:user name="bob" password="bobspassword" authorities="ROLE_USER" />
            		</security:user-service>
            	</security:authentication-provider>
            </security:authentication-manager>
            <bean id="loginBean" class="test.LoginController" scope="session">
            	<property name="authenticationManager" ref="authenticationManager" />
            </bean>
            I've added the required alias to the authentication manager.

            For "remember me" to work you will need to call the rememberMeServices.loginSuccess(...).

            Best regards,
            Dumi.
            Hey! I'm new to those things and I'm getting the same problems discussed in this topic. Your solutions seems to work perfectly, but I can't understand some things:

            What's the name of this class?.. doing the "login()" method? LoginController?
            If it is LoginController and you removed from faces-config, how is your page calling the method with actionListener? I mean, if your remove the bean from faces-config, the page can't find the method, right?..

            Thanks..

            Comment


            • #21
              The bean is still defined, but in applicationContext.xml.

              Comment


              • #22
                Sorry for the bump but I can't get any of these methods to work. I simply just want to turn postOnly off and I can't seem to do it. I run in to so many errors I'd hate to even post them here.

                I'm also using Icefaces and I just bumped from spring 2.0.3 to 3. I may end up having to back down but I really want to be on the latest version.

                I'm defining the bean in applicationContext.xml but my page is saying it can't find it.

                Thanks.

                Comment


                • #23
                  If you really want to allow methods other than post (I discourage it) try setting UsernamePasswordAuthenticationFilter's postOnly attribute to false. If you are not familiar with changing from the namespace configuration to standard bean configuration you can checkout this blog post.

                  HTH,

                  Comment


                  • #24
                    Hi. Well I have got the login to work without POST. I know this is kind of bad but isn't there a way to encrypt urls with faces context?
                    Last edited by drewh; Aug 11th, 2010, 08:09 AM.

                    Comment


                    • #25
                      Quick Adjustment

                      Thanks Dumi for posting that great bit of code... you saved me a lot of time. I made a quick adjustment so that after login the page could be redirected to either the original request, or to a default target url. The default target url and login page needed to be specified in the bean definition. I know this thread is a little old, but maybe this will be useful to someone, anyway.

                      This was for an app using Spring Security 3.0.5, Spring 3.0.3, and jsf 2.0

                      Code:
                      public void loginAction(ActionEvent e) throws IOException {
                      	
                      		FacesContext context = FacesContext.getCurrentInstance();
                      		ExternalContext ec = context.getExternalContext();
                      		try {
                      			HttpServletRequest request = (HttpServletRequest) ec.getRequest();
                      				
                      			Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); //filter.attemptAuthentication(request, response); // SecurityContextHolder.getContext().getAuthentication();
                      			UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(j_username, j_password);
                      			authToken.setDetails(authentication.getDetails());
                      			
                      			request.getSession().setAttribute(
                      					UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY, authToken.getName());
                      			
                      			try {
                      				
                      				Authentication newAuth = authenticationManager.authenticate(authToken);
                      				SecurityContextHolder.getContext().setAuthentication(newAuth);
                      				String savedUrl = "";
                      				if (request != null && request.getSession() != null) {
                      					SavedRequest req = ((SavedRequest)request.getSession().getAttribute(WebAttributes.SAVED_REQUEST));
                      					if (req != null) {
                      						savedUrl = req.getRedirectUrl();
                      						savedUrl = ec.getRequestContextPath() + 
                      								savedUrl.substring(savedUrl.lastIndexOf("/", savedUrl.length()));
                      					}
                      				}
                      				String goUrl = ec.getRequestContextPath() + "/" + defaultTargetUrl; 
                      				if (!savedUrl.equals("") && !savedUrl.equals(ec.getRequestContextPath() + "/" +loginUrl)) {
                      					goUrl = savedUrl;
                      				} 
                      				String encodedURL = ec.encodeResourceURL(goUrl);
                      				ec.redirect(encodedURL);
                      			} catch (AuthenticationException ae) {
                      				FacesContext.getCurrentInstance().addMessage(null,
                      						new FacesMessage(FacesMessage.SEVERITY_ERROR, "Invalid Password", "Invalid Password"));
                      			}
                      			
                      		} catch (UsernameNotFoundException unfe) {
                      			FacesContext.getCurrentInstance().addMessage(null,
                      					new FacesMessage(FacesMessage.SEVERITY_ERROR, unfe.getMessage(), unfe.getMessage()));
                      		}	
                      		
                      	}

                      Comment


                      • #26
                        Thanks everybody for posting this helpful code. It seems to be an option/solution for a similar problem I'm struggling with right now.

                        I do have a question to gkontos, what are loginUrl and defaultTargetUrl?
                        Is it the defaultTargetUrl variable of the AbstractAuthenticationTargetUrlRequestHandler class?

                        Thanks

                        Comment


                        • #27
                          It would have been much cooler if I took the values from an instance of a spring security class such as AbstractAuthenticationTargetUrlRequestHandler ... but I didn't. I ended up making those values part of the bean definition for my login handler.

                          Comment


                          • #28
                            Your code really helped me to solve my problem! I set parameters in the pages I want to be redirected after authentication. I didn't use the spring-security-redirect parameter. That would have been cooler too. Anyway I managed to get everything work fine: role based default target Urls, restricted page access and redirect after authentication for some special pages.

                            Comment

                            Working...
                            X