Extend OrbeonProxyPortlet with custom provider for security headers

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Extend OrbeonProxyPortlet with custom provider for security headers

ajw625
I need to modify the OrbeonProxyPortlet and write my own code to provide the security headers (user, role, group) to Orbeon. Currently Orbeon supports sending the Liferay headers with a true/false parameter. I would like to extend the portlet to support a custom "Security Provider".

I would create an interface for the provider that would define one method. Since my Scala skills are limited, I would prefer to write the provider in Java so I would define the interface as something like:

public interface OrbeonProxyPortletSecurityProvider {
    List<List<String>> getSecurityHeaders(javax.portlet.PortletRequest request);
}

The method would return the headers as a list of name, value pairs. The fully qualified name of the implementing class would be configured as an init parameter in portlet.xml. A jar containing a custom implementation of the provider interface could then be dropped into the WEB-INF/lib directory of the portlet. The provider interface would have to be built into a separate jar so that it could be used to compile the custom provider. The "userHeaders" function in OrbeonProxyPortlet would be replaced with a call to the provider class implementing the interface. The proxy portlet could then convert the Java lists into the required Scala lists of tuples.

Ideally, I would like this to be a new Orbeon feature rather than a custom branch. The send-liferay-user init param could still be supported for backwards compatibility, but deprecated and overridden by the new init param.

Is this this something you would be interested in? Do you have any comments or suggestions? As of now, I have only done a simple proof of concept. Of course, it would be ideal if a provider could be written in Scala too. I expect that is doable. I know I can use Class.forName(...).newInstance() to instantiate a Java class by name, but I'm not so sure about Scala.

Of course, all this is up for debate since I haven't implemented it yet.

This is what I did for my POC. It's a bit of a hack, but it works. I used a map, but that's probably not best since it doesn't allow multiple values for each header name.

Custom Provider:

public class CustomUserHeaders {

    public Map<String, String> getCustomHeaders(HttpServletRequest request) {

        Map<String, String> result = new HashMap<String, String>();

        result.put("Custom-User-Id", "user_1");
        result.put("Custom-User-Group-Id", "group_1");
        result.put("Custom-User-Roles", "role_1, role_2");

        return result;
    }

Added to ProxyPortletEdit.scala:


    case object CustomHeadersImpl    extends Pref { val tpe = InputControl;                      val nameLabel = NameLabel("custom-headers-implementation-class",   "Custom Headers Implementation Class") }

Added to OrbeonProxyPortlet.scala:

import javax.servlet.http.HttpServletRequest
import scala.collection.JavaConversions._
...
    private def newRequestDetails(
...
        val customHeadersImpl = getPreference(request, CustomHeadersImpl)

        def customHeaders = {
            var customHeaderList = List[(String, String)]()
            if (!Option(customHeadersImpl).getOrElse("").isEmpty) {
                val servletRequest = findServletRequest(request)
                for (
                    javaPair ← Class.forName(customHeadersImpl).newInstance().asInstanceOf[ {
                        def getCustomHeaders(request: HttpServletRequest): java.util.Map[java.lang.String, java.lang.String]
                    }].getCustomHeaders(servletRequest.get)
                ) {
                    customHeaderList = (javaPair._1, javaPair._2) :: customHeaderList
                }
            }
            customHeaderList
        }

        def headersToSet =
            APISupport.headersToForward(clientHeaders, settings.forwardHeaders).toList ++ languageHeader.toList ++ userHeaders ++ customHeaders
Reply | Threaded
Open this post in threaded view
|

Re: Extend OrbeonProxyPortlet with custom provider for security headers

Erik Bruchez
Administrator
Thanks for all the work.

This said, I am wondering if another approach wouldn't be better. In 4.9, we moved some authentication-related code from the full portlet and the servlet to filters instead:

    https://github.com/orbeon/orbeon-forms/blob/master/src/main/scala/org/orbeon/oxf/servlet/FormRunnerAuthFilter.scala
    https://github.com/orbeon/orbeon-forms/blob/master/src/main/scala/org/orbeon/oxf/portlet/liferay/FormRunnerAuthFilter.scala

The benefit is that this completely separates the creation of the security headers from the internals, and things are more modular.

If we did the same thing in the proxy portlet, namely move out the code creating the headers to a filter, you could simply plug your own filter to create new headers. The proxy portlet would then just forward these headers if selected.

Would this make sense?

-Erik
Reply | Threaded
Open this post in threaded view
|

Re: Extend OrbeonProxyPortlet with custom provider for security headers

ajw625
Hi Erik. That would be ideal. We were already planning to add our own filter to the proxy portlet to work with the provider I described. This solution would eliminate the need for that extra provider piece. Will you plan to implement that? I would be interested in trying it out as soon as it is available.

On Mon, Jun 15, 2015 at 10:58 AM, Erik Bruchez [via Orbeon Forms community mailing list] <[hidden email]> wrote:
Thanks for all the work.

This said, I am wondering if another approach wouldn't be better. In 4.9, we moved some authentication-related code from the full portlet and the servlet to filters instead:

    https://github.com/orbeon/orbeon-forms/blob/master/src/main/scala/org/orbeon/oxf/servlet/FormRunnerAuthFilter.scala
    https://github.com/orbeon/orbeon-forms/blob/master/src/main/scala/org/orbeon/oxf/portlet/liferay/FormRunnerAuthFilter.scala

The benefit is that this completely separates the creation of the security headers from the internals, and things are more modular.

If we did the same thing in the proxy portlet, namely move out the code creating the headers to a filter, you could simply plug your own filter to create new headers. The proxy portlet would then just forward these headers if selected.

Would this make sense?

-Erik


If you reply to this email, your message will be added to the discussion below:
http://discuss.orbeon.com/Extend-OrbeonProxyPortlet-with-custom-provider-for-security-headers-tp4660074p4660089.html
To unsubscribe from Extend OrbeonProxyPortlet with custom provider for security headers, click here.
NAML

Reply | Threaded
Open this post in threaded view
|

Re: Extend OrbeonProxyPortlet with custom provider for security headers

Erik Bruchez
Administrator
I *hope* it's an easy thing and we can fit this in 4.10:

    https://github.com/orbeon/orbeon-forms/issues/2277

-Erik
Reply | Threaded
Open this post in threaded view
|

Re: Extend OrbeonProxyPortlet with custom provider for security headers

ajw625
Sounds good. Thanks, Erik.

On Sat, Jun 20, 2015 at 10:07 PM, Erik Bruchez [via Orbeon Forms community mailing list] <[hidden email]> wrote:
I *hope* it's an easy thing and we can fit this in 4.10:

    https://github.com/orbeon/orbeon-forms/issues/2277

-Erik


If you reply to this email, your message will be added to the discussion below:
http://discuss.orbeon.com/Extend-OrbeonProxyPortlet-with-custom-provider-for-security-headers-tp4660074p4660111.html
To unsubscribe from Extend OrbeonProxyPortlet with custom provider for security headers, click here.
NAML

Reply | Threaded
Open this post in threaded view
|

Re: Extend OrbeonProxyPortlet with custom provider for security headers

Erik Bruchez
Administrator
Orbeon Forms 4.10 will include support for this, see:

    Proxy portlet: support forwarding portlet "request properties" #2286
    https://github.com/orbeon/orbeon-forms/issues/2286

    Doc of forward-properties
    https://github.com/orbeon/orbeon-forms/wiki/Form-Runner-~-Portal-~-Liferay-Proxy-Portlet-Guide#configuring-header-and-url-parameter-forwarding

-Erik