-
1. Re: PortalIdentity.getPrincipal() returns null
wesleyhales Oct 5, 2009 4:15 PM (in response to rlhr)Are you trying to share/inject this Identity object across multiple portlets?
-
2. Re: PortalIdentity.getPrincipal() returns null
rlhr Oct 5, 2009 4:18 PM (in response to rlhr)No, I don't.
I just want to add some specific roles for the portlet the user just clicked on. -
3. Re: PortalIdentity.getPrincipal() returns null
rlhr Oct 5, 2009 4:26 PM (in response to rlhr)Each portlet needs to have its own Identity containing a list of roles for that particular user and portlet.
Now having an identity object per portlet session comes out of the box.
My problem is that at the time I try to add the roles, FacesContext.getCurrentInstance() is null and PortalIdentity.isPortletPhase() returns false. So I can't access the principal and find out about the user name using Identity. -
4. Re: PortalIdentity.getPrincipal() returns null
rlhr Oct 6, 2009 8:42 AM (in response to rlhr)Also I notice that PortalIdentity overrides hasRole but not addRole.
So existing code from a standalone application may still add roles using the Identity object, but these roles are "lost" because when we try to read them back, the method hasRole will not find them when the application is a portlet.
I believe it would be nice to override addRole to either:
- Properly add roles to portal (as a complement of hasRole)
- or throw an UnsupportedOperationException so that existing code will fail, making it easy to know what's going on.
Richard -
5. Re: PortalIdentity.getPrincipal() returns null
rlhr Oct 6, 2009 2:25 PM (in response to rlhr)I looked at the Portlet Bridge code and found out what the problem is.
PortalIdenty extends the Seam Identity class and overrides the getPrincipal() methods as below:public Principal getPrincipal() { if (isPortletPhase()) { Principal bridgePrincipal = FacesContext.getCurrentInstance() .getExternalContext().getUserPrincipal(); return bridgePrincipal; } else { return super.getPrincipal(); } }
Thus the PortalIdentity.getPrincipal relies on FacesContext.getCurrentInstance() to be defined (where Identity does not).
Now if I have a Session scope component defined as in my first post, when a user click on the portlet tab in the portal, the AjaxPortletBridge.doFacesRequest(RenderRequest request, RenderResponse response) is called. This method calls AjaxPortletBridge.initRequest(PortletRequest request, PortletResponse response, PortletPhase actionPhase)
In this step, Seam will instantiate all the session scope component before the bridge propagate the FacesContext to the portlet environment.
Therefore, the Seam portlet application has no access to the Principal object even though the user is already logged in.
I believe this is a bug since the portlet should have a way to access the principal object at this time.
I can think of 2 way to fix this.
- The PortalIdentity doesn't depend on FacesContext to retrieve the Principal.
- The portlet bridge ensures the Faces environment is setup properly (ie FacesContext.getCurrentInstance() is not null) before Seam instantiates the session scope components.
Let me know what you think?
Richard -
6. Re: PortalIdentity.getPrincipal() returns null
alexsmirnov Oct 13, 2009 12:10 PM (in response to rlhr)I'll check PortalIdentity class to proper integration between Seam and portal sequrity, but I don't see a way to manage user roles from portlet because Portlet API does not allows that; only declarative authentication is supported.
-
7. Re: PortalIdentity.getPrincipal() returns null
rlhr Oct 13, 2009 1:53 PM (in response to rlhr)Yes regarding the roles, this is clearly not part of the spec.
Now regarding FacesContext.getCurrentInstance() being null, I believe this is due to the fact that the Session scoped component are
instanciated before the FacesContext is setup.
In org.jboss.portletbridge.AjaxPortletBridge, the doFacesRequest() methods calls
initRequest(request, response, Bridge.PortletPhase.ActionPhase) where the Session component will be instanciated.
Only after this, the code deals with the FacesContext.
Maybe windowState.restoreRequest(facesContext, true) needs to be called earlier? (I'm not quite sure this is what need to be fixed as I haven't looked deeper in the code yet). -
8. Re: PortalIdentity.getPrincipal() returns null
alexsmirnov Oct 15, 2009 1:46 PM (in response to rlhr)I've moved PortalIdentity to core bridge project, so I instantiated by default if Seam framework is presented. In the code snippet that you mentioned, isPortletPhase() checks for FacesContex too, so that should not cause an error.
I do not see any case there Seam can call Identity component without FacesContext except Seam Filter that is supposed to check user credentials for all, even non-faces requests. Do you have Seam Filter in your web.xml with /* mapping ?
For protlets, it would be even better to remove all JSF stuff, even Faces Servlet from there to block direct access to JSF pages. -
9. Re: PortalIdentity.getPrincipal() returns null
rlhr Oct 15, 2009 2:50 PM (in response to rlhr)I'm not sure what you mean by:
it would be even better to remove all JSF stuff, even Faces Servlet
I have the following 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_2_5.xsd" version="2.5"> <display-name>uarp</display-name> <session-config> <session-timeout>15</session-timeout> </session-config> <!-- JSF --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.seam</url-pattern> </servlet-mapping> <!-- Seam --> <listener> <listener-class>org.jboss.seam.servlet.SeamListener</listener-class> </listener> <servlet> <servlet-name>Seam Resource Servlet</servlet-name> <servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Seam Resource Servlet</servlet-name> <url-pattern>/seam/resource/*</url-pattern> </servlet-mapping> <filter> <filter-name>Seam Filter</filter-name> <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class> </filter> <filter-mapping> <filter-name>Seam Filter</filter-name> <servlet-name>Faces Servlet</servlet-name> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping> <filter> <display-name>Ajax4jsf Filter</display-name> <filter-name>ajax4jsf</filter-name> <filter-class>org.ajax4jsf.Filter</filter-class> <init-param> <param-name>createTempFiles</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>ajax4jsf</filter-name> <servlet-name>Faces Servlet</servlet-name> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping> <!-- Parameters --> <!-- Facelets --> <context-param> <param-name>facelets.DEVELOPMENT</param-name> <param-value>false</param-value> </context-param> <context-param> <param-name>facelets.SKIP_COMMENTS</param-name> <param-value>false</param-value> </context-param> <!-- JSF --> <context-param> <param-name>javax.faces.DEFAULT_SUFFIX</param-name> <param-value>.xhtml</param-value> </context-param> <context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>server</param-value> </context-param> <context-param> <param-name>javax.portlet.faces.renderPolicy</param-name> <param-value>ALWAYS_DELEGATE</param-value> </context-param> <!-- RichFaces --> <context-param> <param-name>org.richfaces.SKIN</param-name> <param-value>blueSky</param-value> </context-param> <context-param> <param-name>org.richfaces.CONTROL_SKINNING</param-name> <param-value>enable</param-value> </context-param> <context-param> <param-name>org.richfaces.LoadStyleStrategy</param-name> <param-value>DEFAULT</param-value> </context-param> <context-param> <param-name>org.richfaces.LoadScriptStrategy</param-name> <param-value>NONE</param-value> </context-param> <context-param> <param-name>org.ajax4jsf.RESOURCE_URI_PREFIX</param-name> <param-value>rfRes</param-value> </context-param> <context-param> <param-name>org.ajax4jsf.COMPRESS_SCRIPT</param-name> <param-value>false</param-value> </context-param> <context-param> <param-name>org.ajax4jsf.VIEW_HANDLERS</param-name> <param-value>org.jboss.portletbridge.application.FaceletPortletViewHandler</param-value> </context-param> <!-- PortletBridge --> <context-param> <param-name>org.jboss.portletbridge.ExceptionHandler</param-name> <param-value>org.jboss.portletbridge.SeamExceptionHandlerImpl</param-value> </context-param> <!-- The documentation says it is not needed, but it is! --> <context-param> <param-name>javax.faces.LIFECYCLE_ID</param-name> <param-value>SEAM_PORTLET</param-value> </context-param> </web-app>
When a component is scoped session and has the @Startup annotation, Seam will instantiate such a component only when the user click on the portal tab for the given portlet. If this component tries to access PortalIdentity, FacesContext should be defined since it is a faces resquest, but it is not (therefore the problem). -
10. Re: PortalIdentity.getPrincipal() returns null
rlhr Oct 15, 2009 2:51 PM (in response to rlhr)I got 1.0.0.SNAPSHOT but it doesn't seem your changes made it in yet. Is that correct?
-
11. Re: PortalIdentity.getPrincipal() returns null
wesleyhales Oct 16, 2009 9:40 AM (in response to rlhr)Only available in 2.0 right now...
http://snapshots.jboss.org/maven2/org/jboss/portletbridge/portletbridge-api/2.0.0-SNAPSHOT/portletbridge-api-2.0.0-20091015.204005-4.jar
http://snapshots.jboss.org/maven2/org/jboss/portletbridge/portletbridge-api/2.0.0-SNAPSHOT/portletbridge-impl-2.0.0-20091015.204005-4.jar -
12. Re: PortalIdentity.getPrincipal() returns null
wesleyhales Oct 16, 2009 9:42 AM (in response to rlhr) -
13. Re: PortalIdentity.getPrincipal() returns null
rlhr Oct 20, 2009 10:42 AM (in response to rlhr)This build didn't fix my problem and after reading again the previous posts, I believe we have a little misunderstanding :)
I have a Session scoped bean annotated @Startup (see first post)
The flow is the following:
- A user logs into the portal. Then MyApp portlet tab appears on the portal page.
- The user clicks on the portlet tab (at this point all the seam session scoped bean are instantiated when the AjaxPortletBridge.doFacesRequest(RenderRequest request, RenderResponse response) is called.
More precisely the following code is ran when the user clicks on the portlet tab:public void doFacesRequest(RenderRequest request, RenderResponse response) throws BridgeException { ... // Amongs other things, create the Seam Session Scoped beans PortletBridgeContext bridgeContext = initRequest(request, wrappedResponse, Bridge.PortletPhase.RENDER_PHASE); ... // Instantiate the facesContext FacesContext facesContext = createFacesContext(request, wrappedResponse); ... }
AndPortletBridgeContext initRequest(PortletRequest request, PortletResponse response, PortletPhase currentPhase) throws BridgeException { ... // Create the Seam Session Scoped beans PortletSession portletSession = request.getPortletSession(); ... }
We can see that when the session scoped components are created, FacesContext hasn't been created yet.
Thus in my Session Scope bean @Create method, PortalIdentity.getPrincipal() returns null because PortalIdentity.isPortletPhase() return false.
So I can't rely on PortalIdentity to get the principal in the @Create method of the Session Scope bean with the current implementation of the portlet bridge.
At the time the bean is instantiated, the user is logged in already, so I believe the principal should be available at the portlet level through PortalIdentity.
The problem is that the PortalIdentity relies on FacesContext to retrieve the principal.
Either PortalIdentity should not get the Principal from the FacesContext or if it should then the PortelBridge should make sure the FacesContext is created before instantiating the Session scoped components.
In another end, in the @Create method of my bean, I can also use another way to retrieve the principal. How would I get access to it without using PortalIdentity.getPrincipal()? -
14. Re: PortalIdentity.getPrincipal() returns null
wesleyhales Oct 20, 2009 10:26 PM (in response to rlhr)can you use something like:
@Observer(PortalIdentity.EVENT_LOGIN_SUCCESSFUL) public void addLoginSuccessfulMessage() { //do your role magic here }
If not, why are you trying to get the principal in the @Create method - I mean at that specific point in processing? I understand the UC, and there are a few different ways to do this.
Also, you should compare your web.xml to this reference (http://anonsvn.jboss.org/repos/portletbridge/trunk/examples/seam/booking/seamBookingPortlet/src/main/webapp/WEB-INF/web.xml) Seam automatically does the setup for your Ajax4JSf filters, so you don't need that config.