Forums

Home » Liferay Portal » English » 3. Development

Combination View Flat View Tree View
Threads [ Previous | Next ]
toggle
Bruno Vernay
How to put HTTP headers in USER_INFO
February 4, 2011 2:15 AM
Answer

Bruno Vernay

Rank: Junior Member

Posts: 36

Join Date: April 6, 2010

Recent Posts

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
RE: How to put HTTP headers in USER_INFO
February 7, 2011 1:45 AM
Answer

Bruno Vernay

Rank: Junior Member

Posts: 36

Join Date: April 6, 2010

Recent Posts

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 ...
hung ngo
RE: How to put HTTP headers in USER_INFO
February 7, 2011 2:19 AM
Answer

hung ngo

Rank: New Member

Posts: 15

Join Date: July 5, 2008

Recent Posts

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
RE: How to put HTTP headers in USER_INFO
February 7, 2011 8:23 AM
Answer

Bruno Vernay

Rank: Junior Member

Posts: 36

Join Date: April 6, 2010

Recent Posts

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:
 1package com.sample.hook;
 2import com.liferay.portal.kernel.events.Action;
 3import javax.servlet.http.HttpServletRequest;
 4import javax.servlet.http.HttpServletResponse;
 5public class LoginAction extends Action {
 6    public void run(   HttpServletRequest req,
 7                       HttpServletResponse res)  {
 8        System.out.println("## My custom login action");
 9    }
10}

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
hung ngo
RE: How to put HTTP headers in USER_INFO
February 7, 2011 5:57 PM
Answer

hung ngo

Rank: New Member

Posts: 15

Join Date: July 5, 2008

Recent Posts

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

 1
 2<filter>
 3    <filter-name>Session Id Filter</filter-name>
 4        <filter-class>com.liferay.portal.servlet.filters.sessionid.SessionIdFilter</filter-class>
 5    </filter>
 6    <filter>
 7        <filter-name>SSO CAS Filter</filter-name>
 8        <filter-class>com.liferay.portal.servlet.filters.sso.cas.CASFilter</filter-class>
 9    </filter>
10    <filter>
11        <filter-name>SSO Ntlm Filter</filter-name>
12        <filter-class>[b]com.liferay.portal.servlet.filters.sso.ntlm.NtlmFilter[/b]</filter-class>
13    </filter>
14    <filter>
15        <filter-name>SSO Ntlm Post Filter</filter-name>
16        <filter-class>com.liferay.portal.servlet.filters.sso.ntlm.NtlmPostFilter</filter-class>
17    </filter>
Bruno Vernay
RE: How to put HTTP headers in USER_INFO
February 10, 2011 5:32 AM
Answer

Bruno Vernay

Rank: Junior Member

Posts: 36

Join Date: April 6, 2010

Recent Posts

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:
1PortletSession portletSession = request.getPortletSession();
2String attribute = (String) portletSession.getAttribute("SAMLAssertion", PortletSession.APPLICATION_SCOPE);

and also
1HttpServletRequest httpRequest = PortalUtil.getHttpServletRequest(request); 
2HttpSession httpSession = httpRequest.getSession(true);
3String 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
RE: How to put HTTP headers in USER_INFO
February 10, 2011 6:00 AM
Answer

Bruno Vernay

Rank: Junior Member

Posts: 36

Join Date: April 6, 2010

Recent Posts

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:

 1public class LoginAction extends Action {
 2
 3    public void run(HttpServletRequest req, HttpServletResponse res) {
 4
 5        final String assertionCountHeader = req.getHeader("Shib-Assertion-Count");
 6        try {
 7            assertionCount = Integer.parseInt(assertionCountHeader);
 8        } catch (NumberFormatException nfe) {}
 9
10        final String firstAssertionHeader = req.getHeader("Shib-Assertion-01");
11
12        URL samlAssertionURL = null;
13        samlAssertionURL = new URL(firstAssertionHeader);
14        String content = "";
15        try {
16            BufferedReader in = new BufferedReader(new InputStreamReader(samlAssertionURL.openStream()));
17            String str;
18            StringBuilder sb = new StringBuilder();
19            while ((str = in.readLine()) != null)  sb.append(str);
20            content = sb.toString();
21        } catch (IOException ex) { }
22               
23        HttpSession session = req.getSession();
24        session.setAttribute("USER_SAMLAssertion", content);       
25       
26        // TODO: Using the session is fine for a start, but there are use case when the deleguate SAML session
27        // could last longuer than the user session. It is likely that it should go to database
28       
29    }


So in a standard portlet I can get the SAML assertion
 1    @Override
 2    public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
 3       
 4        PortletSession portletSession = request.getPortletSession();
 5        String attribute = (String) portletSession.getAttribute("USER_SAMLAssertion", PortletSession.APPLICATION_SCOPE);
 6       
 7        /*
 8        Map userInfoMap = (Map) request.getAttribute(PortletRequest.USER_INFO);
 9        String samlAssertion = (String) userInfoMap.get("samlAssertion");
10        */
11       
12        PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher("/jsp/view.jsp");
13        dispatcher.include(request, response);
14    }


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
Attachments: LoginAction.java (3.8k)