Tags:
create new tag
view all tags

Feature Proposals » Single sign-on support for %INCLUDE{...}%

Summary

Current State: Developer: Reason: Date: Concerns By: Bug Tracking: Proposed For:
AcceptedProposal MahiroAndo AcceptedByReleaseMeeting 2012-10-11     KampalaRelease

Edit Form

TopicSummary:
CurrentState:
CommittedDeveloper:
ReasonForDecision:
DateOfCommitment:   Format: YYYY-MM-DD
ConcernRaisedBy:
BugTracking:
OutstandingIssues:
RelatedTopics:
InterestedParties:
ProposedFor:
TWikiContributors:
 

Motivation

On the intranet, users enjoy single sign-on for almost all the sites including locally installed TWiki. In order to use an intranet URL for %INCLUDE{...}%, the single sign-on token needs to be forwarded to the included URL.

Description and Documentation

Assuming the single sign-on session token is passed over the cookie, we can achieve the goal by forwarding the cookie value from the browser to the included URL when %INCLUDE{...}% is invoked.

ALERT! Note: the proposal has been revised, and the below configurations will be implemented in a separate plugin rather than the TWiki core code. See the comment.

Since it can be a security breach to forward arbitrary cookies, a proposed method is to provide a configuration variable $TWiki::cfg{SingleSignOnDomain}, where cookies are forwarded only when the domain suffix of the included URL matches the configured value.

Since there are plugins that retrieve contents at URLs, it is ideal for plugins to utilize the same configuration value, so that intranet resources are readily available through the common mechanism. A proposed interface to plugins is the following API methods:

  • TWiki::Func::getSingleSignOnDomain() -> $TWiki::cfg{SingleSignOnDomain}
  • TWiki::Func::checkSingleSignOnDomain($url) -> $boolean
  • TWiki::Func::makeSingleSignOnCookieJar([$existingCookieJar]) -> HTTP::Cookies
For simple cases, TWiki::Func::getExternalResource($url) should conform to the mechanism so that plugins do not need to care about the single sign-on.

Examples

$cfg{SingleSignOnDomain} = 'example.com'; # example.com and its subdomains
$cfg{SingleSignOnDomain} = '.example.com'; # example.com's subdomains only

%INCLUDE{"http://intranet.example.com/cgi-bin/print_twiki_table.cgi"}%

Impact

Implementation

-- Contributors: MahiroAndo - 2012-10-01

Discussion

Accepted by release meeting at JerusalemReleaseMeeting2012x10x12

-- PeterThoeny - 2012-10-13

Depending on the intranet environment, there can be other situations such as forwarding some HTTP headers other than cookies.

In order to provide a "hook" mechanism to deal with generic situations, the proposed interface is modified as follows:

  • TWiki::Net exposes $cfg{HTTPRequestHandler} config, which is a class name to hook LWP::UserAgent and HTTP::Request, which is disabled by default.
    • The handler object is create as $class->new($session) and the hook method expects $handle->($ua, $request).
  • All the cookie forwarding is handled by a separate plugin (SingleSignOnPlugin), which sets the appropriate $cfg{HTTPRequestHandler}. In the future, it is also possible to support other types of credential forwarding (Authorization header or any others).
  • TWiki::Net::getExternalResource() and TWiki::Func::getExternalResource() are automatically configured with any hooks and configurations.
  • TWiki::Func provides a standardized method getLWPRequest to retrieve LWP::UserAgent and HTTP::Request objects, which have been properly set up with any configurations including $cfg{HTTPRequestHandler}.
    • Plugins and any other extentions should use either TWiki::Func::getExternalResource() or TWIki::Func::getLWPRequest() rather than directly using LWP::UserAgent->new() and HTTP::Request->new.

      my $response = TWiki::Func::getExternalResource($url);
      # or
      my ($ua, $request) = TWiki::Func::getLWPRequest(GET => $url);
      my $response = $ua->request($request);
      

-- MahiroAndo - 2012-10-16

When we designed TWiki::Func::getExternalResource() we purposely were hiding the complexity of LWP to get an external resource. Is there any way to avoid adding TWIki::Func::getLWPRequest(), I feel it raises the complexity too much, and may confuse plugin authors on which API to use. May be I miss something, getExternalResource() already uses LWP in case available, so why do we need getLWPRequest()?

Also, plugin authors are encouraged to keep plugins compatible with older TWiki releases. Offering two API calls for the same makes this task more complicated.

I just glanced over the latest JiraPlugin code:

    if ($TWiki::Plugins::VERSION >= 1.5) {
        ($ua, $req) = TWiki::Func::getLWPRequest(GET => $url);
    } else {
        $ua = LWP::UserAgent->new();
        $req = HTTP::Request->new(GET => $url);
    }
    $ua->timeout($timeout);
    my $res = $ua->request($req);

Compare that to a more simple:

    $res = TWiki::Func::getExternalResource( $url );

I don't recommend to use your own LWP code for TWiki older than upcoming 5.2, you will bypass all TWiki internal handling such as proxy settings.

I recommend to enhance the getExternalResource() if needed (such as adding new params or timeout etc), and remove getLWPRequest() unless there is a good argument to keep it. KISS.

-- PeterThoeny - 2012-10-17

Func API enhancements warrant their own feature proposals.

-- PeterThoeny - 2012-10-17

It makes much sense that we should keep all the historical enhancement (proxy settings etc.) applicable in as many contexts as possible. In fact, that is what I intend while adding a new interface to retrieve LWP, while now I see it is not a good idea to add a new API function.

Although I agree that LWP could confuse plugin authors, we have also seen plugin authors easily tend to use LWP::UserAgent->new(). HeadlinesPlugin is an example. IncludeXMLPlugin and JiraPlugin also have used LWP::UserAgent historically in our firm (for the purpose of using POST method, adding headers, setting timeout, etc.).

We also have internal code that is not exposed to public where LWP is required. A particular example is to utilize LWP's response handler hooks so as to provide near real-time feedback of progress to the user while running a time-consuming HTTP request.

If there are a number of places where LWP is used independently, all the customization at the TWiki level will be ignored, including proxy settings, or for our case, forwardable single sign-on token.

On the other hand, I really much appreciate your insight of the concern with adding an extra API to TWiki::Func. It sounds a good idea to enhance getExternalResource() instead. How about adding a way to getExternalResource() so as to pass arbitrary parameters to LWP::UserAgent ? Perhaps something like getExternalResource($url, @headers [,\%lwpParams]) ? But taking the last argument based on the count of @headers might be a bit unusual and risky.

Any suggestions?

-- MahiroAndo - 2012-10-17

By the way, I have also been pointed out that "SingleSignOnPlugin" would sound misleading and should not be named as a plugin. A new suggested name for the extension is "CredCookieFwdContrib".

I think it was quite hasty of me committing everything too soon when there were changes in the original proposal. I will ensure to wait for feedback first in the future.

-- MahiroAndo - 2012-10-17

No problem, we have a collaborative process. Things can be redefined and changed before a release. Keep in mind that APIs have a long life, much longer than the underlying software, so it is worth putting some brain cycles towards solid API enhancements. smile

As for getExternalResource(), yes I think it is good to add additional parameters. Instead of a @headers parameter that has no defined end (@ parameter = list of parameters) it is better to pass along an array reference. For LWP options a hash reference might be good. We already have parameters that are hash references, such as in TWikiFuncDotPm.

On name of plugin, yes, I was confused myself. First I thought that this is a plugin that does SSO similar to SsoLoginContrib. So you could rename it (not too late) to something like SsoForwardCookiePlugin. However, it depends how you plan to enhance the plugin. If in the future you envision full SSO for TWiki itself it makes sense to keep the name as it is.

-- PeterThoeny - 2012-10-17

Thanks for your message as always.

I'm happy to enhance getExternalResource(), and I'll add a proposal page for that. One concern I still have is that the current getExternalResource() already takes the no-defined-end @headers parameter (as in the code, although it does not seem to be documented in TWikiFuncDotPm. I can support both of the ways if it's appropriate.

SsoForwardCookiePlugin as the name looks good, with the same prefix as SsoLoginContrib. Or perhaps should it also be a Contrib? It is to add implementation of $cfg{HTTPRequestHandler} (introduced in TWikirev:23653) via Config.spec, but it will not use any of the API callbacks like commonTagsHandler, registerTagHandler, etc. I'm wondering which would be better (Plugin or Contrib).

-- MahiroAndo - 2012-10-18

On Contrib vs Plugin: By convention, plugins should only use documented API - with this they are expected to be stable across releases. Contribs interact more closely with core and may break on upgrades, e.g. need to be kept in sync with core code. The SsoLoginContrib is a contrib because the Func API is not sufficient for login.

-- PeterThoeny - 2012-10-18

Thanks for the clarification. Then SsoForwardCookie should be a Contrib, because it needs to hook internal behavior of TWiki::Net, which is outside the scope of the API from TWiki::Plugins and TWiki::Func.

I will name it SsoForwardCookieContrib. Please let me know if it should be otherwise.

-- MahiroAndo - 2012-10-22

Some of TWiki::Net is exposed in TWiki::Func. What else do you need? May be enhance TWiki::Func?

-- PeterThoeny - 2012-10-22

It needs to be able to insert cookies into LWP for all the HTTP requests to any external resources, regardless of whether it is invoked from %INCLUDE{...}% or through getExternalResource called by plugins.

How about providing a new function TWiki::Func::registerExternalHTTPHandler( \&callback )? As the function name implies, it should only be called from initPlugin.

If it is fine, SsoForwardCookiePlugin will fit in the concept of plugins smile

-- MahiroAndo - 2012-10-23

thumbs up

-- PeterThoeny - 2012-10-23

Thank you. Added a proposal here: RegisterExternalHTTPHandler

-- MahiroAndo - 2012-10-24

Edit | Attach | Watch | Print version | History: r19 < r18 < r17 < r16 < r15 | Backlinks | Raw View | Raw edit | More topic actions
Topic revision: r19 - 2013-10-11 - PeterThoeny
 
  • Learn about TWiki  
  • Download TWiki
This site is powered by the TWiki collaboration platform Powered by Perl Hosted by OICcam.com Ideas, requests, problems regarding TWiki? Send feedback. Ask community in the support forum.
Copyright © 1999-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.