JSF/Acegi authentication with a backing bean
Thanx to this blog post i managed to integrate Acegi 1.0.1 with JSF. Some minor modifications were necessary, because in this version of Acegi some things have changed.
The basic idea of this approach is to use a JSF backing bean that is responsible for authentication (that processes the “login” request from the user). This allows you not only to send the user to a success/error page, but you are also able to send him to a custom page if some condition is met.
The backing bean looks like the following:
package com.freiheit;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.context.HttpSessionContextIntegrationFilter;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;
public final class AuthenticationController {
private static final Log LOG = LogFactory.getLog( AuthenticationController.class );
private String _username;
private String _password;
// injected properties
private AuthenticationManager _authenticationManager;
public String getPassword() {
return _password;
}
public void setPassword( String password ) {
_password = password;
}
public String getUsername() {
return _username;
}
public void setUsername( String userName ) {
_username = userName;
}
@SuppressWarnings("unchecked")
public String authenticate() {
String outcome = "failure";
try {
final String userName = getUsername();
final String password = getPassword();
final UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(
userName, password );
final HttpServletRequest request = getRequest();
authReq.setDetails( new WebAuthenticationDetails( request ) );
final HttpSession session = request.getSession();
session.setAttribute(
AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY,
userName );
/* perform authentication
*/
final Authentication auth = getAuthenticationManager().authenticate( authReq );
/* initialize the security context.
*/
final SecurityContext secCtx = SecurityContextHolder.getContext();
secCtx.setAuthentication( auth );
session.setAttribute( HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY, secCtx );
outcome = "success";
} catch ( Exception e ) {
outcome = "failure";
FacesContext.getCurrentInstance().addMessage( null, new FacesMessage( e.getMessage() ) );
}
return outcome;
}
public void logout( ActionEvent e ) {
final HttpServletRequest request = getRequest();
request.getSession( false ).removeAttribute( HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY );
/* simulate the SecurityContextLogoutHandler
*/
SecurityContextHolder.clearContext();
request.getSession( false ).invalidate();
}
private HttpServletRequest getRequest() {
return (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
}
public AuthenticationManager getAuthenticationManager() {
return _authenticationManager;
}
@Required
public void setAuthenticationManager(
AuthenticationManager authenticationManager ) {
_authenticationManager = authenticationManager;
}
}
The spring configuration (applicationContext.xml) has the following entries (note that this is spring-2, this introduces new scopes like e.g. “session”):
<bean id="acegiFilterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,securityRequestFilter,exceptionTranslationFilter,filterSecurityInterceptor
</value>
</property>
<!--
/**=httpSessionContextIntegrationFilter,requestWrapper,filterSecurityInterceptor
-->
</bean>
<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
<property name="context">
<value>org.acegisecurity.context.SecurityContextImpl</value>
</property>
</bean>
<bean id="securityRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter" />
<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl">
<value>/login.jsf</value>
</property>
<property name="forceHttps"><value>false</value></property>
</bean>
</property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage">
<value>/accessDenied.jsf</value>
</property>
</bean>
</property>
</bean>
<bean id="filterSecurityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager">
<!--
The AffirmativeBased voter allows access if at least one voter votes
to grant access. Use the UnanimousBased voter if you only want to
grant access if no voter votes to deny access. -->
<bean class="org.acegisecurity.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<bean class="org.acegisecurity.vote.RoleVoter">
<!-- Reset the role prefix to "", default is ROLE_ -->
<property name="rolePrefix">
<value></value>
</property>
</bean>
<!--
The authenticated voter grant access if e.g.
IS_AUTHENTICATED_FULLY is an attribute -->
<bean class="org.acegisecurity.vote.AuthenticatedVoter" />
</list>
</property>
</bean>
</property>
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/pages/**=IS_AUTHENTICATED_FULLY
/pages/company/**=/permissions/permission1
/pages/**=/permissions/permission01
</value>
</property>
</bean>
<bean id="authenticationManager"
class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider" />
</list>
</property>
</bean>
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService">
<bean class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
mgrotzke=test123,/permissions/permission1,/permissions/permission01
skaiser=test123,/permissions/permission01
</value>
</property>
</bean>
</property>
</bean>
<bean id="authenticationController" class="com.freiheit.AuthenticationController" scope="session">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
</bean>
The authenticationController bean is the backing bean (see above) that is called from the (jsp/facelets) page. It can be defined in the spring applicationContext.xml because the faces-config contains an entry for springs DelegatingVariableResolver:
<application>
<variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
</application>
The web.xml has the following filter entry for acegi:
<filter>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetBean</param-name>
<param-value>acegiFilterChainProxy</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
The faces-config.xml contains the following navigation-rules for login and logout:
<navigation-rule>
<from-view-id>/login.xhtml</from-view-id>
<navigation-case>
<from-action>#{authenticationController.authenticate}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/pages/index.xhtml</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-action>#{authenticationController.authenticate}</from-action>
<from-outcome>failure</from-outcome>
<to-view-id>/login.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-action>logout</from-action>
<to-view-id>/login.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
The login page using facelets essentially has the following content:
<form jsfc="h:form" id="loginForm">
<span jsfc="h:messages"/><br/>
Username: <input jsfc="h:inputText" id="inputUsername" value="#{authenticationController.username}" /><br/>
Password: <input jsfc="h:inputSecret" value="#{authenticationController.password}" /><br/>
<input jsfc="h:commandButton" action="#{authenticationController.authenticate}"
value="Login" />
</form>
The logout button should be defined in an overall template, and would look like the following:
<a href="#" jsfc="h:commandLink" action="logout"
actionListener="#{authenticationController.logout}">#{msgs.logout}</a>
Can’t you just post the WHOLE example ? The little fragments just won’t help much :( Maybe you can post the JSP page, etc. That will save us a lot of time, otherwise we spend quite sometime trying to understand the solution…
Thanks in advance…
Comment by Anonymous — August 23, 2006 @ 7:40 pm
Hello, i just added the relevant parts of the faces-config.xml and the login page, additionally an example for a logout-button.
Notice that the logout method changed from an action method (String logout()) to an actionlistener (void logout(ActionEvent e)).
I hope this helps,
cheers,
Martin
Comment by Martin Grotzke — August 23, 2006 @ 10:13 pm
The bean
filterSecurityInterceptorrequires the additional decisionVoterorg.acegisecurity.vote.AuthenticatedVoterso that s.th. like/pages/**=IS_AUTHENTICATED_FULLYcan be specified in the objectDefinitionSource. Example is updated accordingly.Comment by martin.grotzke — September 14, 2006 @ 6:03 pm
Hi Martin,
wanna thank you for your email support. I got it running.
Suggestion:
I had some problems with the labels that are used. As I mixed your code with another example for acegi method access security, e.g. the faces servlet label didn’t match. Would be nice to get complete examples of faces-config.xml, applicationContext.xml and web.xml. A full deployable example would be even better ;-).
Regards Rainer
Comment by Rainer Eschen — September 20, 2006 @ 11:50 am
Hey Rainer,
thank you for your feedback!
I tried to extract the relevant parts, so that one is not distracted by less important things. Although, if there’s a dependency on the Faces Servlet name then it should be mentioned. I’ll update the example soon.
Cheers,
Martin
Comment by martin.grotzke — September 20, 2006 @ 12:29 pm
Interesting information concerning forwards was just posted in the myfaces mailinglist:
http://www.mail-archive.com/users@myfaces.apache.org/msg28125.html
I’ll check if this has to be applied to this example.
Comment by martin.grotzke — September 21, 2006 @ 2:39 pm
As posted by Dmitry V. Zemnitskiy at http://magrokosmos.blogspot.com/2006/07/jsfacegi-authentication-with-backing.html i have missed to set the scope of the
authenticationControllerbean in this example toscope="session". This is fixed now !Comment by martin.grotzke — September 22, 2006 @ 3:52 pm
I’m not sure about that scope=”session”, don’t recall such an attribute for Spring’s app context.
Anyway, I’m actually wondering how you’ve displayed the error messages on the login page. Adding a simple sufficed? I can’t seem to get the error message to appear though…
Comment by David Lim — September 26, 2006 @ 9:42 am
Hi David,
new scopes are one of the new features of spring2, e.g. scopes
requestandsession, see spring documentation.The error messages are displayed with a
<span jsfc="h:messages"/>tag in the login.xhtml. Probably i should add this also to the example.Thanx for this hint,
cheers,
Martin
Comment by martin.grotzke — September 26, 2006 @ 9:56 am
Hi,
Love your example, it got me going. I have one problem, however. The requests seem to “lag” by one; I login, but the next operation causes a new login and that second login then sticks. The same with logout. Any suggestions?
Comment by Nik — November 8, 2006 @ 9:16 am
Ehem, ignore my post, I did some changes and messed up my logout-navigation which resulted in something off-by-one with the filters…
Comment by Nik — November 8, 2006 @ 9:51 am
I tried to run the application. But my jsf file could not resolve the values which are coming from spring session scope bean. It is giving me error “Scope ’session’ is not active; nested exception is java.lang.IllegalStateException: thread-bound request: use RequestContextFilter”.
Could you plz send me complete working code.
Comment by Umesh Sinha — November 13, 2006 @ 3:52 pm
Did you configure the spring RequestContextFilter correctly? I only showed web.xml entries that are relevant for acegi, asuming that all other stuff is set up already.
What I have for spring in the web.xml:
(Asuming that your faces servlet is named “Faces Servlet”).
I’m off for holiday for the next two weeks, so don’t get it wrong if I’m not responding… ;)
Cheers,
Martin
Comment by martin.grotzke — November 13, 2006 @ 5:36 pm
[…] JSF/Acegi authentication with a backing bean […]
Pingback by Howto Secure JSF via Spring/Acegi at rain.webs Blog: Springsteam — November 14, 2006 @ 6:53 pm
Hi Martin,
I’m changing to session scope at the moment. During the deployment I got an exception, because the authenticationController is a final class. You may skip the final. This works with OC4J 10.
Regards Rainer
Comment by Rainer Eschen — November 15, 2006 @ 10:27 am
Hi all,
if you think about using your beans in a mixed Spring/JSF environment, asking when to use what (Spring bean vs. JSF managed bean), here are some hints:
http://blog.rainer.eschen.name/2006/11/16/the-observer-pattern-in-mixed-dependency-injection-contexts-spring-jsf/
Regards Rainer
Comment by Rainer Eschen — November 17, 2006 @ 10:29 am
I used your example to integrate acegi with jsf but I have a problem where my secured pages are being exposed when I don’t log in. Any help would be appreciated
Comment by SpringLover — November 24, 2006 @ 7:03 am
Check the property
objectDefinitionSourceof the bean with idfilterSecurityInterceptorin theapplicationContext.xml, it must have the entry with s.th. like/pages/**=IS_AUTHENTICATED_FULLY. Additionally you must have theAuthenticatedVoterin the list ofdecisionVoters.Do you have it like it is shown in this example?
Cheers,
Martin
Comment by martin.grotzke — November 27, 2006 @ 5:41 pm
yes, I was finally able to get this working by doing some digging into javadocs and finding that it needs an additional property
false
This did the trick.
thanks for your valuable example
Comment by SpringLover — November 28, 2006 @ 12:14 am
Martin,
I am running into a strange issue. Let me layout the scenario
I have two secured pages
/pages/page1.jsf
/page/page2.jsf
User A has access to view page1.jsf but not page2.jsf
when user A clicks on page1.jsf he is directed to the login screen. Everything is good.
Then when user A clicks on page2.jsf he does not get directed to the login screen but the browser just goes into an infinite loop.
If this explanation is not clear please let me know
Please let me know if you can be of assistance
thanks
Comment by SpringLover — November 29, 2006 @ 3:12 pm
Hi SpringLover :)
what is the location of the login screen?
Can you post the
objectDefinitionSourceproperty?Cheers,
Martin
Comment by martin.grotzke — November 29, 2006 @ 4:35 pm
/pages/project/addproject.jsp=ROLE_PW_APP_ADMIN,ROLE_PW_SUPERVISOR,ROLE_PW_INSPECTOR,ROLE_APPLICANT_ADMIN,ROLE_APPLICANT_USER,ROLE_DESIGN_ADMIN,ROLE_DESIGN_USER
/pages/project/enforcement/enforcements.jsp=ROLE_PW_APP_ADMIN,ROLE_PW_SUPERVISOR,ROLE_PW_INSPECTOR
/pages/project/correspondence/correspondence.jsp=ROLE_PW_APP_ADMIN,ROLE_PW_SUPERVISOR,ROLE_PW_INSPECTOR,ROLE_PW_REVIEWER
/pages/admin/admin.jsp=ROLE_PW_APP_ADMIN,ROLE_APPLICANT_ADMIN,ROLE_ENGINEERING_ADMIN,ROLE_DESIGN_ADMIN,ROLE_GRADING_ADMIN
/pages/admin/environment/**=ROLE_PW_APP_ADMIN
/pages/admin/project/**=ROLE_APP_ADMIN
/pages/admin/security/firms.jsp=ROLE_APP_ADMIN
Comment by SpringLover — November 30, 2006 @ 6:57 am
Okay, then where’s the login screen? Is it e.g. at /pages/login.jsf?
I just tried to reproduce this behavior in our application but was not able to get this behavior.
Can you debug the problem (server side debugging), step through (having sources of myfaces, acegi & co is very helpful) and determine the reason of this behavior?
Or you could search/ask for help directly at acegi.
Cheers,
Martin
Comment by martin.grotzke — November 30, 2006 @ 10:28 am
the login page is /pages/login/login.jsp
could you please send me your setup to look at it
Comment by SpringLover — December 1, 2006 @ 4:42 pm
Martin,
Thanks for your help. It was my AccessDecisionHandler that was not configured correctly. It is working now
Comment by SpringLover — December 2, 2006 @ 12:54 pm
Great to hear that it’s working now :)
Have fun, cheers,
Martin
Comment by martin.grotzke — December 3, 2006 @ 8:07 pm
Here’s how to add remember services to the example above for anyone who’s interested. I will also add support for redirect to target url in a following post.
[BLOG] refers to code fragments in this entry.
[NEW] is added support for remember me services.
[NEW] private RememberMeServices rememberMeServices; // injected
[BLOG] ..
[BLOG] session.setAttribute( HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY, secCtx );
[NEW] rememberMeServices.loginSuccess(request, response, authResult);
[BLOG] outcome = “success”;
[BLOG] catch ( Exception e ) {
[NEW] SecurityContextHolder.getContext().setAuthentication(null);
[NEW] rememberMeServices.loginFail(request, response);
[BLOG outcome = “failure”;
spring.xml
———-
…
…
Hung Tang
Comment by Hung Tang — December 5, 2006 @ 9:27 pm
Support for redirection to target path after successful login:
Comment by Hung Tang — December 5, 2006 @ 9:30 pm
spring.xml got cut off from first entry, hopefully this goes through.
faces-config.xml got cut off for second entry. trying again…
/insert login page here
defaultUrl
/insert redirect page here
[/code]
Comment by Hung Tang — December 5, 2006 @ 9:36 pm
Sorry, I am amateur at using quicktags. Hopefully the author can clean up my mess…and put all this extra info together. Hope others can benefit from it.
Comment by Hung Tang — December 5, 2006 @ 9:40 pm
Hello Hung,
just saw your comments, they seem to be very interesting…
Having just a short look, I don’t get the meaning of the “/insert login page here” etc. stuff, but when I have more time I’ll think about it ;)
Thanx && cheers,
Martin
Comment by martin.grotzke — December 6, 2006 @ 1:42 am
Martin,
I am trying to insert a piece of fragment from faces-config.xml but the blog software is “snipping” them off. Let me try again.
Comment by Hung Tang — December 6, 2006 @ 6:39 pm
Hello Hung,
I just added a
tag before the
tag, then it worked.
Cheers,
Martin
Comment by martin.grotzke — December 7, 2006 @ 10:12 am
Hung, can you please upload a complete example of this redirect? I can’t seem to get it working and desperately need this functionality.
Comment by Mick Knutson — March 5, 2007 @ 11:54 pm
Email me at [mail(at)hungtang.com] and I’ll see what I can do.
Comment by Hung Tang — March 7, 2007 @ 10:56 pm
I’ve gotten this to work successfully except for JSF it processes on the request uri instead of the view ID.
So if you go from a login page to a page in admin directory your admin home page won’t get authenticated because the first request doesn’t have /admin/ in it. However if you go to another page in the directory the next path will have the path in it. I will attempt to look at the view id instead of the uri to apply security in the filter.
I’ve done this in the past so shouldn’t be too extremeley hard.
Shawn
Comment by Shawn Garner — March 11, 2007 @ 7:27 pm
Hi,
I tried your code and have made all the neccessary changes but couldn’t get it running. The problem is whenver I submit the login form I am being directed to the Error.jsp that I have designed. Can you help me please. Thanks!
Comment by carp — March 12, 2007 @ 10:38 am
Hi Carp,
are you speaking of the RememberMeServices of Hung? Then he would have to help you.
Do you have any logging output that you could post? Are you sure that authentication was successful?
Cheers,
Martin
Comment by martin.grotzke — March 12, 2007 @ 10:50 am
Hi Martin,
Thanks a lot for your reply.
No, its not the rememberMe services. The problem is with:
Authentication auth = getAuthenticationManager().authenticate(authReq);
The authenticationManager is not getting populated.
If you don’t mind I would like to send my piece(Acegi and JSF part) of code to you. Please let me know your mail-id.
Thanks & Regards,
Carp.
Comment by carp — March 12, 2007 @ 12:35 pm
Hey Carp,
what do you mean with “is not getting populated”?
Feel free to send your code, I just sent you my email address.
Cheers,
Martin
Comment by martin.grotzke — March 12, 2007 @ 1:03 pm
Hey Martin,
I didn’t get ur mail-id.
Please send it to: qt_23@sifymail.com
Thanks & Regards,
Carp.
Comment by Carp — March 12, 2007 @ 1:33 pm
Hi Martin,
I didn’t get your email address. Anyways here is my piece of code.
I am using the same AuthenticationController.java as presented on this blog.
This is what I have as my Login Page:
Comment by carp — March 12, 2007 @ 2:18 pm
I can’t see anything wrong in your code snipplets. And your autenticationController returns “success” as outcome?
Can you also post the objectDefinitionSource property of the filterSecurityInterceptor in your applicationContext.xml?
Cheers,
Martin
Comment by martin.grotzke — March 13, 2007 @ 12:04 am
Hi Martin,
I have got it working now. Thanks for your support.
The problem was that I had not added the following property to my bean in faces-config.xml:
authenticationManager
#{authenticationManager}
What a relief!
;)Cheers,
Carp
Comment by carp — March 13, 2007 @ 10:46 am
Good that it’s working now :)
Cheers,
Martin
Comment by martin.grotzke — March 13, 2007 @ 11:01 am
Hi Martin,
When I run Menu.jsp page directly without Authenticating the ExceptionTranslationFilter should spawn the Login page for me as defined in the AuthenticationEntryPoint but its not happening. I am getting an error: org.apache.jasper.JasperException: Cannot find FacesContext
My objectDefinitionSource is:
Comment by carp — March 14, 2007 @ 8:46 am
Hi Carp,
does this also happen when you request some page at /admin/… ?
We moved all secured pages to /pages/ and added /pages/**=IS_AUTHENTICATED_FULLY to the
objectDefinitionSource to make sure that these pages are accessed by authenticated
users only (you need the AuthenticatedVoter for this).
Can you try to put the menu.jsp to s.th. like /pages/menu.jsp or some other subfolder and test if the error then also occurrs?
Or can you try the IS_AUTHENTICATED_FULLY configuration and see if this changes s.th.?
Otherwise I’d debug and step through the acegi code to see what happens…
Cheers,
Martin
Comment by martin.grotzke — March 14, 2007 @ 11:06 am
Hi,
Thanks very much for posting this. I am trying to use it with MyFaces and am getting the following exception:
Exception starting filter Acegi Filter Chain Proxy
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
at org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:86)
at org.acegisecurity.util.FilterToBeanProxy.getContext(FilterToBeanProxy.java:177)
at org.acegisecurity.util.FilterToBeanProxy.doInit(FilterToBeanProxy.java:119)
at org.acegisecurity.util.FilterToBeanProxy.init(FilterToBeanProxy.java:189)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:221)
would anybody be able to give me some pointers please?
Thanks in advance.
Regards,
-Eric
Comment by Eric — March 15, 2007 @ 7:34 am
Hi Martin,
toI have resolved the issue by changing the
<constructor-arg value="/faces/Login.jsp"/>.There is a new problem that has come up i.e. when I changed the location of my Menu.jsp from /WebContent/Menu.jsp to /WebContent/common/Menu.jsp, I am unable to access the page: The requested resource (/common/Menu.jsp) is not available. Here is my objectDefinitionSource:
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/secured/admin/**=ROLE_ADMINISTRATOR
/common/users/**=ROLE_REQUESTER,ROLE_ADMINISTRATOR
/**=ROLE_ANONYMOUS,ROLE_ADMINISTRATOR,ROLE_REQUESTER
Comment by carp — March 15, 2007 @ 8:25 am
Hi Eric,
do you have the ConfigLoaderListener configured in your web.xml like the following?
Cheers,
Martin
Comment by martin.grotzke — March 15, 2007 @ 10:48 am
Hi Carp,
in your previous post you did not have a
<constructor-arg value="/Login.jsp"/>, so I do not really know what you changed…Do you have somewhere in your directory structure the path “/faces”?
Concerning the “not available” issue of
/common/Menu.jspI’d suggest that you first make sure that this works without any authentication/authorization stuff.Can you turn on logging of related libs (e.g. acegi) and have a look at the logs, perhaps there’s some helpful output.
Cheers,
Martin
Comment by martin.grotzke — March 15, 2007 @ 10:59 am
Hi Martin,
Since I am using MyFaces (as well as hibernate and spring), I have the following ContextListener:
org.apache.myfaces.webapp.StartupServletContextListener
And I don’t seem to be allowed to have 2 ContextListener registered. Thanks again for your help on this.
-Eric
Comment by Eric — March 15, 2007 @ 10:32 pm
Hi Eric,
why do you think that you’re not allowed to register more than 1 listener in your servlet container?
What happens when you add the spring ContextLoaderListener?
Cheers,
Martin
Comment by martin.grotzke — March 15, 2007 @ 10:59 pm
Hi Martin,
If I add the following to my web.xml file:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.apache.myfaces.webapp.StartupServletContextListener
</listener-class>
</listener>
I get the following exception:
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present -
check whether you have multiple ContextLoader* definitions in your web.xml!
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:167)
at org.springframework.web.context.ContextLoaderServlet.init(ContextLoaderServlet.java:83)
at javax.servlet.GenericServlet.init(GenericServlet.java:212)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1139)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:966)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:3956)
Thank you,
-Eric
Comment by Eric — March 16, 2007 @ 3:14 am
Hi Martin,
I am sorry to pollute your awesome blog with this. I actually feel ashamed :-(. I removed the following from my web.xml and everything works.
Thanks again for your help on this.
-Eric
<servlet>
<servlet-name>SpringContextServlet</servlet-name>
<servlet-class>
org.springframework.web.context.ContextLoaderServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Comment by Eric — March 16, 2007 @ 3:27 am
No prob, Eric :)
Comment by martin.grotzke — March 16, 2007 @ 12:03 pm
Hi Martin,
In your AuthenticationController you have two outcomes based on which u direct the user to either a login or failure page.
I have different roles such as ADMINISTRATOR,PC MEMBER,REQUESTER,etc.
What I wanted was that when an ADMINISTRATOR logs in he shhould be directed to an admin page but when a REQUESTER logs in he should get a different page and so on.
I know one way that I can do this is by directing the user(irrespective of his role) to a common page and then use the tags but I dont want to add an extra page.
Can you please help me with the issue.
Thanks for all ur help in the past.
Regards,
Carp.
Comment by carp — March 27, 2007 @ 7:49 am
Hi Carp,
the Authentication object that is returned from
getAuthenticationManager().authenticatecontains the list of permissions / roles (GrantedAuthorities). So you should be able to determine the role that the user has and return the appropriate outcome according to this.Cheers,
Martin
Comment by martin.grotzke — March 27, 2007 @ 9:38 am
Hi Martin,
I had tried extracting the role by: auth.getAuthorities()
The output that I get for the above is: org.acegisecurity.GrantedAuthority;@1988886
So how do I make the comparison and return the appropriate outcome.
Also, I am trying to implement method security but facing some problems.
Can u please tell me what changes do I need to make in applicationContext.
Thanks.
Regards,
Carp.
Comment by carp — March 28, 2007 @ 9:31 am
getAuthoritiesreturns an array, so you probably want to iterate over all authorities and see what’s the most appropriate (”highest”) one… You are doing this in theAuthenticationController, right?Cheers,
Martin
Comment by martin.grotzke — March 28, 2007 @ 9:46 am
Hi Martin,
I have got that working now.
Please can you tell me how to secure method invocations.
I have gone thru the reference guide and implemented
the MethodSecuirtyInterceptor but that’s not enough. Please let me know what changes are required.
Thanks a lot.
Regards,
Carp.
Comment by carp — March 28, 2007 @ 12:15 pm
I haven’t used security restrictions on methods until now, so I cannot tell you anything about that, sorry!
Cheers,
Martin
Comment by martin.grotzke — March 28, 2007 @ 1:34 pm
Hi Martin,
Anways, u have been very kind for sparing ur time.
Thanks a lot.
Cheers :)
Carp.
Comment by carp — March 28, 2007 @ 4:09 pm
the example is almost perfect.
there is one context listener missing though:
web.xml
org.springframework.web.context.request.RequestContextListener
Comment by Jakob — April 4, 2007 @ 1:19 pm
Thanx, a lot people helped to improve it :)
In my web.xml I do not have the RequestContextListener but the RequestContextFilter.
In the API docs I just read that both seem to be alternatives…
Cheers,
Martin
Comment by martin.grotzke — April 4, 2007 @ 2:14 pm
Hi Martin,
Thanks for your very informative blog. It looks like its gonna work v well for me if I can just fix a few issues. The first seems to be that the backing bean doesn’t get its authenticationManager value injected (its null when executing ‘authenticate’). My quite new to JSF et al so this is probably a config/version issue. Target is Tomcat 5.5 (via Eclipse).
Any help appreciated.
Regards
Andy
Here’s my applicationContext.xml
Here’s my faces-config.xml
And my web.xml
Comment by Andy — April 26, 2007 @ 1:03 pm
I tried to run the application. But my jsf file could not resolve the values which are coming from spring session scope bean. It is giving me error “Scope ’session’ is not active; nested exception is java.lang.IllegalStateException: thread-bound request: use RequestContextFilter”.
I had the same problem like usesr “Umesh Sinha”
My solution is to add the RequestContextListener
org.springframework.web.context.request.RequestContextListener
Hope this helps
Comment by NewToAcegi — August 16, 2007 @ 3:21 pm
Hi Martin! Thanks for the blog! Is a very important information. Well, in my application, when i insert the ACEGI filters in my web.xml, the application not start up throwing the folowing erro:
SEVERE: Error filterStart
What would be?
Here’s may web.xml:
contextConfigLocation
classpath:/applicationContext.xml
org.springframework.web.context.ContextLoaderListener
org.springframework.web.context.request.RequestContextListener
Faces Servlet
javax.faces.webapp.FacesServlet
1
Faces Servlet
/faces/*
30
faces/Login.jsp
com.sun.faces.verifyObjects
false
com.sun.faces.validateXml
true
javax.faces.STATE_SAVING_METHOD
client
Acegi Filter Chain Proxy
org.acegisecurity.util.FilterToBeanProxy
targetBean
acegiFilterChainProxy
Acegi Filter Chain Proxy
Faces Servlet
FORWARD
REQUEST
Comment by Paulo Melo — October 2, 2007 @ 7:38 pm
Hi,
it’s good to see that it’s still useful :)
If there’s no more information in catalina.out, can you check other log files (like localhost*.log)?
These should contain more details about the error then.
Cheers,
Martin
Comment by martin.grotzke — October 2, 2007 @ 8:17 pm
Hi Martin, thank you for response. Already running but the ACEGI filters do not filter.(!) Like this: http://forum.springframework.org/showthread.php?p=144734#post144734
Do you know what is this?
Again, thanx!
A Paz!
Comment by Paulo — October 4, 2007 @ 9:26 pm
Nope, I’m sorry, I haven’t experienced such behavior.
Hopefully you’ll find the reason for this,
cheers,
Martin
Comment by martin.grotzke — October 5, 2007 @ 9:38 am
I tried with the rememberMe code provided above, but I am not getting it.
Where to send the check box value??
Where should I write the code related to it.
Please suggest me to implement it.
Thank you in advance
Comment by Sridevi — October 7, 2007 @ 1:17 pm
I haven’t included the rememberMe functionality, so I can’t tell you how to name the checkbox.
But you might have a look at the RememberMeServices and check which request parameter is tested therein.
Cheers,
Martin
Comment by martin.grotzke — October 7, 2007 @ 5:51 pm
Hi,
I had followed this blog to integrate jsf with acegi.
But i could not make refer the AuthenticationManager from my backing bean .Though i had configured my applicationContext.xml, it was not picking the authentication information.Pls help me
regards,
Lakshmi.
Comment by mlakshmi — January 3, 2008 @ 2:20 pm
Hi Lakshmi,
what do you mean with ?
Can you clarify your problem a little bit more, please? What exactly does not work?
Cheers,
Martin
Comment by martin.grotzke — January 4, 2008 @ 6:31 pm
Hi,
I try your code and get error by:
/*
* perform authentication
*/
final Authentication auth = getAuthenticationManager().authenticate(authReq);
I have to cast it to:
final Authentication auth = ((AuthenticationManager) getAuthenticationManager()).authenticate(authReq);
Comment by Thomas Roland — January 30, 2008 @ 1:18 pm
Hi,
Hwere can I find the deployable example?
Comment by Thomas Roland — February 10, 2008 @ 9:55 am
Hi Martin,
Now I can get your example run. But I have a question/problem:
The “objectDefinitionSource” by me looks as follow:
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/pages/admin/**=ROLE_ADMIN,ROLE_SUPERVISOR
/pages/supervisor/**=ROLE_SUPERVISOR
/pages/user/**=ROLE_USER
/pages/**=IS_AUTHENTICATED_FULLY
After I loggined as a role of Admin and when I access the page “http://localhost:8585/TestMyAcegiFacelets/pages/admin/admin.faces”, I got access denied error.
Could you explain a little bit about using and configuring the “objectDefinitionSource”
Regards
Thomas
Comment by thomas — February 12, 2008 @ 10:14 am
Hi Thomas,
concerning the objectDefinitionSource I suspect that acegi docs explain this in a better way than I could ;)
Regarding your issue: do have configured your voters correctly (AffirmativeBased)?
Cheers,
Martin
Comment by martin.grotzke — February 12, 2008 @ 10:33 am
Hi Martin,
Nice to get your answer finally. :-)
Yuo are right. I check my code again and correct it to using “AffirmativeBased”. It is better. :-)
But another question:
After I logined, the page “welcome.xhtml” is shown. In this page there are some links as follow:
This means, if I logged as User and when I click the link to “toAdmin”, I should get access denied. The “toAdmin” links to “Admin.xhtml” as follow:
But it’s not the case. I click the “toAdmin” and it links to “Admin.xhtml”. Only when I click the “toSupervisor” in “Admin.xhtml”, I get the access denied.
Besides, when I access the page “http://localhost:8585/TestMyAcegiFacelets/pages/admin/admin.faces” the first time, I get no access denied. By the second time I get access denied.
It seems it’s a step later. I’ve heard this is the problem of using JSF because JSF has, by design, a “navigation engine” that relies on forwards instead of redirect. The displayed URL in the browser rarely corresponds to the actual displayed page. (in fact, the URL address is the previous navigation).
Don’t have such a problem? How can one solve such a problem?
Regards
Thomas
Comment by thomas — February 12, 2008 @ 12:02 pm
I wonder why my program code can not be shown?
Here again:
welcome.xhtml
**************
…
…
Admin.xhtml
***********
…
…
Comment by thomas — February 12, 2008 @ 12:05 pm
I wonder I can’t upload jsf code?
Comment by thomas — February 12, 2008 @ 12:07 pm
Try
followed by a
tag around your code.
Comment by martin.grotzke — February 12, 2008 @ 2:11 pm
Thomas,
you might try to add a
element to your acegi filter mapping, so that this is applied to any forward targets matching the specified servlet or URL pattern.
Cheers,
Martin
Comment by martin.grotzke — February 12, 2008 @ 2:42 pm
My filter-mapping looks as follow. Isn’t correct?
Comment by thomas — February 12, 2008 @ 4:12 pm
Here again my codes:
welcome.xhtml:
Admni.xhtml
Comment by thomas — February 12, 2008 @ 4:15 pm
Ok. What about setting a
in the faces-config for these navigation cases?
Comment by martin.grotzke — February 12, 2008 @ 5:30 pm
This helps.
Now I see what’s the reason why you use this in your faces-config.
Many thanks!
Comment by thomas — February 13, 2008 @ 9:37 am
You’re welcome :)
Comment by martin.grotzke — February 13, 2008 @ 10:21 am
Hi,
I am implementing Acegi in my JSF application. Both authentication and authorization is working fine with my application. But If i register a new user in my application then i have to stop and restart the server inorder to authenticate that new user. Else it shows “user not found” message . Acegi retrieves all the authentication information from database while loading the application itself. It was not holding the newly registered user’s details. i searched in the net and tried to instantiate the Acegi’s application context from its xml files explicitly when a new user is activated. But it was not working. How can we add a new user to Authentication object??
Comment by lakshmi — March 11, 2008 @ 11:30 am
Hi Laskhmi,
have you implemented acegi authentication as described here?
So that I understand your problem: your authentication provider does not provide authentication information correctly?
Why does it do this? What are the differences compared to the “standard” acegi configuration?
Cheers,
Martin
Comment by martin.grotzke — March 11, 2008 @ 12:33 pm
[…] JSF/Acegi authentication with a backing bean […]
Pingback by Howto Secure JSF via Spring/Acegi | rainwebs.net — January 16, 2012 @ 11:39 pm