Forums de discussion

How to put HTTP headers in USER_INFO

Bruno Vernay, modifié il y a 13 années.

How to put HTTP headers in USER_INFO

Junior Member Publications: 36 Date d'inscription: 06/04/10 Publications récentes
Hello,

I would like my portlet to have access to some HTTP headers (and REMOTE_USER and "Environment variables" set by the Server). I would like my portlet to stay standard, without any Liferay's specific code.

After a short try, it looks like I cannot access HTTP headers from the portlet.

I guess it should be possible to develop some kind of filter or hook or login hook at the portal level, that could put some HTTP headers in the USER_INFO structure. I would like to do a simplified version of https://source.jasig.org/sandbox/uportal-shibboleth-delegation-integration but for Liferay. Also maybe make the link with http://www.liferay.com/community/forums/-/message_boards/message/4774550.

Any pointer would be appreciated.
Bruno Vernay, modifié il y a 13 années.

RE: How to put HTTP headers in USER_INFO

Junior Member Publications: 36 Date d'inscription: 06/04/10 Publications récentes
I guess that I will have to write a Hook: http://www.liferay.com/documentation/liferay-portal/6.0/development/-/ai/hooks

I will see how it goes ...
thumbnail
hung ngo, modifié il y a 13 années.

RE: How to put HTTP headers in USER_INFO

New Member Publications: 15 Date d'inscription: 05/07/08 Publications récentes
Hi Bruno,

Not sure if this helps. You can access the original request by calling

PortalUtil.getOriginalServletRequest

Are you trying to single sign on?
Maybe you would need to create a set of users in Liferay first for the mapping (e.g. through some web services).

Then you can use a hook to implement a custom login filter/ service pre-action that can map the user to this Liferay user id.

Probably, using a combination of cookies and web services will help?

You can also write your own filter at a higher level following examples of NtlmFilter, OpenSSOFilter.
Bruno Vernay, modifié il y a 13 années.

RE: How to put HTTP headers in USER_INFO

Junior Member Publications: 36 Date d'inscription: 06/04/10 Publications récentes
Hi hung,

PortalUtil.getOriginalServletRequest would do the job for a Portlet tied to Liferay implementation. But I would like to keep the portlet standard.

I just tested the tutorial about Hook (the link is in the first post) and I have access to the original HTTP request:
package com.sample.hook;
import com.liferay.portal.kernel.events.Action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginAction extends Action {
    public void run(   HttpServletRequest req, 
                       HttpServletResponse res)  {
        System.out.println("## My custom login action");
    }
}

Now I can see that there are many hooks available http://www.liferay.com/community/wiki/-/wiki/Main/Hook+DTD+-+6.0
auth.pipeline.post
auth.pipeline.pre
auth.token.impl
auto.login.hooks
login.events.post
login.events.pre
logout.events.post
logout.events.pre
...

I am not sure witch one is the best to use. But I will start with login.events.post, I should be able to read the SAML assertion and put it in the USER_INFO structure.
I have yet to find how to add fields to USER_INFO ...
Then the Portlet will be able to access this data in a portable way.

There may be code coming on the subject, but I cannot just wait.

I found some interesting code here \liferay-src\portal\portal-impl\src\com\liferay\portal\security\auth
But they are not hooks, I didn't find NtlmFilter not OpenSSOFilter
thumbnail
hung ngo, modifié il y a 13 années.

RE: How to put HTTP headers in USER_INFO

New Member Publications: 15 Date d'inscription: 05/07/08 Publications récentes
From the link you provide, there is a patch in this issue:

http://issues.liferay.com/browse/LPS-8427

http://issues.liferay.com/secure/attachment/27744/LPS-8427-build-70637.patch


From what I see, they write a filter on top to intercept the requests.
They also write a hook to extend the auto login process.
As you can see, the filter is defined in web.xml of Liferay ROOT.war where NtlmFilter and OpenSSOFilter is defined:

web.xml


<filter>
	<filter-name>Session Id Filter</filter-name>
		<filter-class>com.liferay.portal.servlet.filters.sessionid.SessionIdFilter</filter-class>
	</filter>
	<filter>
		<filter-name>SSO CAS Filter</filter-name>
		<filter-class>com.liferay.portal.servlet.filters.sso.cas.CASFilter</filter-class>
	</filter>
	<filter>
		<filter-name>SSO Ntlm Filter</filter-name>
		<filter-class>[b]com.liferay.portal.servlet.filters.sso.ntlm.NtlmFilter[/b]</filter-class>
	</filter>
	<filter>
		<filter-name>SSO Ntlm Post Filter</filter-name>
		<filter-class>com.liferay.portal.servlet.filters.sso.ntlm.NtlmPostFilter</filter-class>
	</filter>
Bruno Vernay, modifié il y a 13 années.

RE: How to put HTTP headers in USER_INFO

Junior Member Publications: 36 Date d'inscription: 06/04/10 Publications récentes
Indeed, I found the patch.
It is really impressive work. The whole SAML SP is coded. It replaces Shibboleth SP, didn't even use OpenSAML library.

But, I think I will wait for this patch to be moved in a Plugin or Hook (I voted for the issue). I don't feel like hacking right into the trunk ...

Besides, I have been able to make some progress: I can read the HTTP headers to find the SAML Assertion from my post login hook. It is a bit messy, but simple.

Now, I "just" have to put it in USER_INFO for the portlets to consume.
I guess I will start a new thread.

I think that I will have to do it in 2 steps:
- put the information in the HttpSession, since in the hook I have no access to the PortletRequest.
- Looks like USER_INFO comes from LinkedHashMap<String, String> UserInfoFactory.getUserInfo for which I may be able do a hook also. So I can read from the session and add the fields to UserInfo (hopefully)

It is how they do it in uPortal and here: http://wikis.sun.com/display/websynergy/Post+Login+Hook But I can get it to work !?

Looks like I cannot use the HTTP session to transmit my variable from the login.events.post (I also tryied login.events.pre) to the portlet ! I wonder if a new HTTP Session is created after the login.events.post ??

I tried this code in my portlet to retrieve the variables:
PortletSession portletSession = request.getPortletSession();
String attribute = (String) portletSession.getAttribute("SAMLAssertion", PortletSession.APPLICATION_SCOPE);

and also
HttpServletRequest httpRequest = PortalUtil.getHttpServletRequest(request);  
HttpSession httpSession = httpRequest.getSession(true);
String attribute = (String) httpSession.getAttribute("SAMLAssertion");

Without success ...

I wonder if the session is recreated after the post login hook ? See com/liferay/portlet/login/util/LoginUtil ?
Bruno Vernay, modifié il y a 13 années.

RE: How to put HTTP headers in USER_INFO

Junior Member Publications: 36 Date d'inscription: 06/04/10 Publications récentes
OK, I got it working ! The solution is in the Sun / Oracle wiki !

The point is to prefix the name with "USER_...". otherwise it is lost somewhere in the session (not sure exactly why nor when).

In the login.events.post hook, I get the SAML assertion and put it in the HTTP session:

public class LoginAction extends Action {

    public void run(HttpServletRequest req, HttpServletResponse res) {

        final String assertionCountHeader = req.getHeader("Shib-Assertion-Count");
        try {
            assertionCount = Integer.parseInt(assertionCountHeader);
        } catch (NumberFormatException nfe) {}

        final String firstAssertionHeader = req.getHeader("Shib-Assertion-01");

        URL samlAssertionURL = null;
        samlAssertionURL = new URL(firstAssertionHeader);
        String content = "";
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(samlAssertionURL.openStream()));
            String str;
            StringBuilder sb = new StringBuilder();
            while ((str = in.readLine()) != null)  sb.append(str); 
            content = sb.toString();
        } catch (IOException ex) { }
                
        HttpSession session = req.getSession();
        session.setAttribute("USER_SAMLAssertion", content);        
        
        // TODO: Using the session is fine for a start, but there are use case when the deleguate SAML session 
        // could last longuer than the user session. It is likely that it should go to database
        
    }


So in a standard portlet I can get the SAML assertion
    @Override
    public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
        
        PortletSession portletSession = request.getPortletSession();
        String attribute = (String) portletSession.getAttribute("USER_SAMLAssertion", PortletSession.APPLICATION_SCOPE);
        
        /*
        Map userInfoMap = (Map) request.getAttribute(PortletRequest.USER_INFO);
        String samlAssertion = (String) userInfoMap.get("samlAssertion");
        */
        
        PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher("/jsp/view.jsp");
        dispatcher.include(request, response);
    }


Here is the doc about the famous Session: Portal Properties 6.0.5 : Session

# Note that this property is used to specify the sharing of session
# attributes from the portal to the portlet. This is not used to specify
# session sharing between portlet WARs or from the portlet to the portal.
#
session.shared.attributes=org.apache.struts.action.LOCALE,COMPANY_,USER_,LIFERAY_SHARED_


Now I am back to the next step for SAML delegation: http://www.liferay.com/community/forums/-/message_boards/message/111342

Pièces jointes: