Can you please also post your login page and login bean?
Dumi.
Can you please also post your login page and login bean?
Dumi.
In the meantime I got a least a bit further. I had some misconfiguration in my Maven POM which is solved now. However I still have problems with Spring Security getting the message:
My login-Method looks like this:Code:Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: Authentication m ethod not supported: GET
My Login-Form is like this:Code:public void login(ActionEvent e) throws java.io.IOException { FacesContext context = FacesContext.getCurrentInstance(); ExternalContext ec = context.getExternalContext(); String encodedURL = ec.encodeResourceURL(ec.getRequestContextPath() + "/j_spring_security_check?j_username=" + loginName.toLowerCase() + "&j_password=" + password + "&_spring_security_remember_me=" + "true"); ec.redirect(encodedURL); FacesContext.getCurrentInstance().responseComplete(); }
It seems as Version 3 of Spring Security is not accepting GETs anymore (which I can understand). However I am wondering how to POST the credentials to the Spring Security Filter.Code:<body> <h2>Login</h2> <ice:form> <ice:panelGrid columns="3"> <ice:outputText value="Benutzername: " /> <ice:inputText id="j_username" value="#{LoginController.loginName}" redisplay="true" /> <br /> <ice:outputText value="Passwort: " /> <ice:inputSecret id="j_password" value="#{LoginController.password}" /> <br /> <ice:commandButton actionListener="#{LoginController.login}" value="Login"/> </ice:panelGrid> <ice:messages style="color: red;"/> </ice:form> </body>
Yes, this is where I also got today using your configuration files. This "Authentication method not supported: GET" is caused by the latest version of Spring Security. In my projects I'm using Spring 2.5.6.SEC01 and Spring Security 2.0.4.
What I was trying right now was to change the version of Spring/Spring Security in your pom to the ones that work for me, but I'm getting some other errors.
I'll play more with it tomorrow. In the end I will also need to use Spring 3, so we must find a solution
Dumi.
Just as an Update: What I have changed since yesterday is my POM. This was essential to have the right set of JARs:
Code:<properties> <spring.version>3.0.2.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>org.springframework.orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>org.springframework.asm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>org.springframework.web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>org.springframework.security.web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>org.springframework.security.core</artifactId> <version>${spring-security.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>org.springframework.security.config</artifactId> <version>${spring-security.version}</version> <scope>compile</scope> </dependency> </dependencies>
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:
I'm not using navigation rules and the login method is used from actionListener.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); }
Also, to make this work I had to remove the LoginController bean from faces-config and define it using spring:
I've added the required alias to the authentication manager.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>
For "remember me" to work you will need to call the rememberMeServices.loginSuccess(...).
Best regards,
Dumi.
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):
You can define custom filters in this way: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; }
And this in your web.xml: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>
Or you can use the <custom-filter/> in <http/> as below: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 -->
without changing anything in web.xml.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>
Dumi.
Last edited by Dumi; Apr 15th, 2010 at 08:35 AM.
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
I'm glad I could help! If you improve the login method code in any way please also post it.
Thanks & best regards,
Dumi.
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
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..