Need documentation on Gbrowse session handling

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

Need documentation on Gbrowse session handling

Michael Dondrup
Dear Gbrowse list,

I have, with a little desperation, started to search look for documentation on the Gbrowse2 Session module. In particular, I am
interested in how to *correctly* initialize and build up a Gbrowse session which is fully authorized for a user. Let's assume the
task is to: write a cgi script (in addition to the gbrowse cgi) to initialize a gbrowse session with an authenticated user, such that in
the next invocation of gbrowse, the user is authenticated and logged in.

I found by reading through the source code and reverse
engineering a sequence of commands that will *almost* get me there. I am seemingly missing one step only:
- the example code below works in case I already have a Gbrowse session
- the example doesn't work when there is no session at all, because subsequent calls to gbrowse make a new session which then is not authenticated.

So, what is the correct way to initialize a Gbrowse2 Session programmatically? Am I missing something.

I'd really appreciate your help, because now I am definitely stuck.



Michael Dondrup
Postdoctoral fellow
Sea Lice Research Centre/Department of Informatics
University of Bergen
Thormøhlensgate 55, N-5008 Bergen,
Norway


#!/usr/bin/env perl

use strict;
use warnings;
use Net::SAML;
use CGI::Fast qw(:standard);

use Bio::Graphics::Browser2;
use Bio::Graphics::Browser2::Render::HTML;

while (my $q = CGI::Fast->new) {
my $username ="valid user";
# it's not really important where this comes from,
# the user information is coming from an authentication module using Net::SAML
my $fullname = "Fully Valid";
my $mail = "[hidden email]";

 if ($username) {

        my $p = "https://url";
        my $myurl = "https://url/gbrowse/lsalmonis/";
        my $htmlhead = <<HTML
<script src="$p/gbrowse2/js/login.js" type="text/javascript"></script>
<script src="$p/gbrowse2/js/controller.js" type="text/javascript"></script>
HTML
;
       ## STEP 1:
        ## get the session and initialize it
       
        my $session = $render->session;
        $session->lock();
        $session->username($username);
        $session->flush;

        ## STEP 2:
        ## authorization handling:
        my $userdb = $render->userdb;
        my $id = $userdb->check_or_add_named_session($session->id,$username);
        $userdb->set_fullname_from_username($username=>$fullname,$mail) if defined $fullname;
        warn "username ".$session->username. " stored in session ".$session->id();
        # now authenticate
        my ($sid, $nonce) = $render->authorize_user($username,$id, 1,undef);
        my $is_authorized = $render->user_authorized_for_source($username);

        ## STEP 3:
        ## prepare for JavaScript invocation
        ## seems like the final step is to invoke login_load_account to make the UI aware of the login

        # convert the login data to json
        my $result = to_json { userOK  => 1,
                sessionid => $id,
                username  => $username,
                message   => 'login ok',
              };
       
        ## STEP 5:
        ## print an intermediate web page to invoke javascript
        print header(-type=>"text/html");
      print start_html(-head=>$htmlhead);
      print b("user $username". (($is_authorized)?" is ": "is not ") . "authorized!");
        print script({-type=>'text/javascript'},
<<SCRIPT      
var p = $result;
login_load_account("$myurl",p);
SCRIPT
);
        $session->unlock();
        print end_html();
 }








------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and
their applications. This 200-page book is written by three acclaimed
leaders in the field. The early access version is available now.
Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
_______________________________________________
Gmod-gbrowse mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse
Reply | Threaded
Open this post in threaded view
|

Re: Need documentation on Gbrowse session handling

Ryan Doherty
Hi Micheal,

I'm not on the GBrowse team, but have been trying to do a similar thing,
with success.  Let me tell you what I've done and maybe you can take the
pieces of it you need.

We have a system which establishes a session separate from gbrowse; when
a user logged into that system, I wanted to "automatically" log the user
into his corresponding gbrowse account (i.e. log in to both systems
simultaneously).  Also, if the user exists in our main system, but does
NOT exist in gbrowse (yet), we wanted to be able to create a new account
for him on the fly.  It is working; however I'm still working on some
details regarding configuration and postgres support on the backend.

Here's how it works:

1. Our system's login process (java on tomcat) sets a custom cookie on
the client for our main system, which contains the userid and a
checksum, and then redirects to a stand-alone HTML page, passing along a
URL that the user will eventually be redirected to.
2. The HTML page loads javascript that submits the information in the
cookie (via AJAX) as the username and "password" to gbrowse.
3. A custom gbrowse authentication plugin connects to a web service,
asking if the username and checksum are valid and retrieving the user's
email and display name if so.
4. If the creds are valid, the plugin looks to see if the user exists in
gbrowse (i.e. has a gbrowse account), and creates one if not,
establishing a session for the new user.
5. The 'authority' value (which confirms the login was successful), is
returned to the client, where a second AJAX call uses it to request the
user's session ID.
6. The gbrowse session ID and auth ID are returned to the client, where
more javascript sets them as normal gbrowse session cookies.
7. The user is redirected to the URL originally passed to the standalone
HTML page.

At the end of this process, both our system's normal login cookie, and
the needed gbrowse cookies are set on the client, so the user can visit
a gbrowse page and is already logged in.  We never display the
Login/Account/Logout links in gbrowse itself (hidden with CSS).  
Instead, we have a logout link for our whole system which expires not
only our normal cookie, but the gbrowse cookies as well.  Obviously,
this requires our regular system and gbrowse to share a domain, and
there are a few other details I'm glossing over.

The thing that might help you out the most is the authentication plugin,
which lives (for now) here:

https://www.cbil.upenn.edu/svn/apidb/ApiCommonShared/branches/gbrowse_login/Model/lib/gbrowse/plugins/WdkSessionAuthenticator.pm

If you're interested in the javascript that creates the session, let me
know and I'll point it to you.  I had to make some modifications to
functions in controller.js and login.js.  As I said, I'm not an expert
and don't know everything about how gbrowse maintains its sessions, but
I'll answer any questions you have the best I can.

Ryan


On 5/7/13 7:31 AM, Michael Dondrup wrote:

> Dear Gbrowse list,
>
> I have, with a little desperation, started to search look for documentation on the Gbrowse2 Session module. In particular, I am
> interested in how to *correctly* initialize and build up a Gbrowse session which is fully authorized for a user. Let's assume the
> task is to: write a cgi script (in addition to the gbrowse cgi) to initialize a gbrowse session with an authenticated user, such that in
> the next invocation of gbrowse, the user is authenticated and logged in.
>
> I found by reading through the source code and reverse
> engineering a sequence of commands that will *almost* get me there. I am seemingly missing one step only:
> - the example code below works in case I already have a Gbrowse session
> - the example doesn't work when there is no session at all, because subsequent calls to gbrowse make a new session which then is not authenticated.
>
> So, what is the correct way to initialize a Gbrowse2 Session programmatically? Am I missing something.
>
> I'd really appreciate your help, because now I am definitely stuck.
>
>
>
> Michael Dondrup
> Postdoctoral fellow
> Sea Lice Research Centre/Department of Informatics
> University of Bergen
> Thormøhlensgate 55, N-5008 Bergen,
> Norway
>
>
> #!/usr/bin/env perl
>
> use strict;
> use warnings;
> use Net::SAML;
> use CGI::Fast qw(:standard);
>
> use Bio::Graphics::Browser2;
> use Bio::Graphics::Browser2::Render::HTML;
>
> while (my $q = CGI::Fast->new) {
> my $username ="valid user";
> # it's not really important where this comes from,
> # the user information is coming from an authentication module using Net::SAML
> my $fullname = "Fully Valid";
> my $mail = "[hidden email]";
>
>   if ($username) {
>
> my $p = "https://url";
> my $myurl = "https://url/gbrowse/lsalmonis/";
> my $htmlhead = <<HTML
> <script src="$p/gbrowse2/js/login.js" type="text/javascript"></script>
> <script src="$p/gbrowse2/js/controller.js" type="text/javascript"></script>
> HTML
> ;
>         ## STEP 1:
>          ## get the session and initialize it
>        
>          my $session = $render->session;
>          $session->lock();
>          $session->username($username);
>          $session->flush;
>
> ## STEP 2:
>          ## authorization handling:
> my $userdb = $render->userdb;
>          my $id = $userdb->check_or_add_named_session($session->id,$username);
>          $userdb->set_fullname_from_username($username=>$fullname,$mail) if defined $fullname;
>          warn "username ".$session->username. " stored in session ".$session->id();
>          # now authenticate
>          my ($sid, $nonce) = $render->authorize_user($username,$id, 1,undef);
>          my $is_authorized = $render->user_authorized_for_source($username);
>
>          ## STEP 3:
>          ## prepare for JavaScript invocation
>          ## seems like the final step is to invoke login_load_account to make the UI aware of the login
>
> # convert the login data to json
>          my $result = to_json { userOK  => 1,
>                  sessionid => $id,
>                  username  => $username,
>                  message   => 'login ok',
>                };
>
> ## STEP 5:
>          ## print an intermediate web page to invoke javascript
> print header(-type=>"text/html");
>         print start_html(-head=>$htmlhead);
>         print b("user $username". (($is_authorized)?" is ": "is not ") . "authorized!");
>          print script({-type=>'text/javascript'},
> <<SCRIPT
> var p = $result;
> login_load_account("$myurl",p);
> SCRIPT
> );
> $session->unlock();
> print end_html();
>   }
>
>
>
>
>
>
>
>
> ------------------------------------------------------------------------------
> Learn Graph Databases - Download FREE O'Reilly Book
> "Graph Databases" is the definitive new guide to graph databases and
> their applications. This 200-page book is written by three acclaimed
> leaders in the field. The early access version is available now.
> Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
> _______________________________________________
> Gmod-gbrowse mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse


------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and
their applications. This 200-page book is written by three acclaimed
leaders in the field. The early access version is available now.
Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
_______________________________________________
Gmod-gbrowse mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse
Reply | Threaded
Open this post in threaded view
|

Re: Need documentation on Gbrowse session handling

Michael Dondrup-3
=pod

Dear Ryan,

thank you so much for the source code. I have implemented a solution based on the code
found in your authentication module, and it worked! In the end, it turned out that I was
failing to set the session cookie, something that one has to do yourself if one attempts authentication
outside of the ordinary GBrowse control flow. I must admit that this was kinda stupid mistake.

For the sake of adding to the developer documentation - I found that GBrowse could really need some
improvement of the internal code documentation, there is hardly anything - I wish to provide a
little more detail about my setting and code.

I am implementing SAML based authentication for our local GBrowse installation. This setting is very similar to
described by Ryan. The authentication is provided by a SAML Identity provider (IdP) for single sign-on,
in this case simpleSAMLphp.
When a restricted resource is encountered, the authentication plugin redirects to the IdP, which maintains its
own session with the client. After a successful login at the IdP, the IdP sends an encrypted message with the
credentials to GBrowse, this can be done via different mechanisms, but in this case the message is sent via
HTTP POST. The receiver (Net::SAML in this case) decrypts the message and returns the user credentials.

In some settings (mod_fcgid) I had experienced problems with sudden crashes (e.g. sig_pipe) of the
receiving process. For reasons I have to further investigate, crashes occur if
I just let the gbrowse cgi script receive the post message and dispatch it to the
authentication plugin.

In order not to mess with the original gbrowse cgi, I implemented another
cgi script as a receiver of the post data. Using my own script to initialize the session and authenticate
the users also means that I am totally responsible for setting the session up correctly. One of the things
that need to be done in this case is to generate the session cookie, this is not necessary if one is implementing
the authentication through the plugin because gbrowse will handle setting the cookie.

As a result, the complete sequence of commands to initialize a session with an external perl script
and load the interface with the user logged in, (given _parse_saml() is a function returning  some credentials)
is given below for completeness.  

=cut

#!/usr/bin/env perl
use strict;
use warnings;
use Bio::Graphics::Browser2;
Bio::Graphics::Browser2::UserDB;
use CGI::Fast qw(:standard);
use CGI::Cookie;
use JSON;
my $DEBUG = 1;

my $myurl = "http://localhost/fgb2/gbrowse/yeast"; # or whatever to load

while (my $q = CGI::Fast->new) {
 my ($userid, $displayName, $email) = (_parse_saml());
 if ($userid) {
      my $globals = Bio::Graphics::Browser2->open_globals;
      my $userdb = Bio::Graphics::Browser2::UserDB->new($globals);
      ## get the session
      my $session = $globals->session;
      my $sessionid = $session->id;
      ## set the username for the session
      $session->username($userid);
      $session->flush();
      ## check if the user exists already
      my $confirmedUserId = $userdb->userid_from_username($userid);
      if ( $confirmedUserId eq "") {
         print STDERR "User $userid does not yet exist; will create.\n" if $DEBUG;
         print STDERR "Flushed session.  Will now create user using session.\n" if $DEBUG;
         my ($status,undef,$message) = $userdb->do_add_user($userid,$email,$displayName,'dummy-password',$sessionid);
         print STDERR "Results from do_add_user: Status: $status\n" if $DEBUG;
         print STDERR "Results from do_add_user: Message: $message\n" if $DEBUG;
         $userdb->set_confirmed_from_username($userid);
         print STDERR "User set as confirmed.\n" if $DEBUG;
         ## set the full name, but only once
         $userdb->set_fullname_from_username($userid, $displayName, $email) if $displayName;
      } else {
        print STDERR "Found existing user with ID: $confirmedUserId so skipping creation.\n" if $DEBUG;
      }

      ## now generate the html page that will initialize the session
      ## start with the session cookie:
      my $cookie = CGI::Cookie->new(-name => 'gbrowse_sess',
      -path => '/fgb2/',
      -expires => '+1M',
      -value => $sessionid);

      ## some JSON data is required for calling the java script:
       my $result = to_json { userOK  => 1,
                  sessionid => $sessionid,
                  username  => $username,
                  message   => 'login ok',
                 };
      ## import required javascript functions
      my $htmlhead = <<HTML
<script src="gbrowse2/js/login.js" type="text/javascript"></script>
<script src="/gbrowse2/js/controller.js" type="text/javascript"></script>
HTML
;

   print header(-type=>"text/html", -cookie=>$cookie);
   print start_html(-head=>$htmlhead);
   print script({-type=>'text/javascript'},
<<SCRIPT      
var p = $result;
login_load_account("$myurl", p);
SCRIPT
);
   print end_html();
} else {
  die "I should never receive invalid userid from external IdP";
}

sub _parse_saml {
 ## return some dummy data, this part is a bit simplyfied:
return ('joe', 'joe user', '[hidden email]');
}

__END__

This script should generate a page setting the session cookie, and the javascript that loads the
gbrowse session. Hope this is useful in the future.

Best
Michael

On May 8, 2013, at 6:01 PM, Ryan Doherty wrote:

> Hi Micheal,
>
> I'm not on the GBrowse team, but have been trying to do a similar thing,
> with success.  Let me tell you what I've done and maybe you can take the
> pieces of it you need.
>
> We have a system which establishes a session separate from gbrowse; when
> a user logged into that system, I wanted to "automatically" log the user
> into his corresponding gbrowse account (i.e. log in to both systems
> simultaneously).  Also, if the user exists in our main system, but does
> NOT exist in gbrowse (yet), we wanted to be able to create a new account
> for him on the fly.  It is working; however I'm still working on some
> details regarding configuration and postgres support on the backend.
>
> Here's how it works:
>
> 1. Our system's login process (java on tomcat) sets a custom cookie on
> the client for our main system, which contains the userid and a
> checksum, and then redirects to a stand-alone HTML page, passing along a
> URL that the user will eventually be redirected to.
> 2. The HTML page loads javascript that submits the information in the
> cookie (via AJAX) as the username and "password" to gbrowse.
> 3. A custom gbrowse authentication plugin connects to a web service,
> asking if the username and checksum are valid and retrieving the user's
> email and display name if so.
> 4. If the creds are valid, the plugin looks to see if the user exists in
> gbrowse (i.e. has a gbrowse account), and creates one if not,
> establishing a session for the new user.
> 5. The 'authority' value (which confirms the login was successful), is
> returned to the client, where a second AJAX call uses it to request the
> user's session ID.
> 6. The gbrowse session ID and auth ID are returned to the client, where
> more javascript sets them as normal gbrowse session cookies.
> 7. The user is redirected to the URL originally passed to the standalone
> HTML page.
>
> At the end of this process, both our system's normal login cookie, and
> the needed gbrowse cookies are set on the client, so the user can visit
> a gbrowse page and is already logged in.  We never display the
> Login/Account/Logout links in gbrowse itself (hidden with CSS).  
> Instead, we have a logout link for our whole system which expires not
> only our normal cookie, but the gbrowse cookies as well.  Obviously,
> this requires our regular system and gbrowse to share a domain, and
> there are a few other details I'm glossing over.
>
> The thing that might help you out the most is the authentication plugin,
> which lives (for now) here:
>
> https://www.cbil.upenn.edu/svn/apidb/ApiCommonShared/branches/gbrowse_login/Model/lib/gbrowse/plugins/WdkSessionAuthenticator.pm
>
> If you're interested in the javascript that creates the session, let me
> know and I'll point it to you.  I had to make some modifications to
> functions in controller.js and login.js.  As I said, I'm not an expert
> and don't know everything about how gbrowse maintains its sessions, but
> I'll answer any questions you have the best I can.
>
> Ryan
>
>
> On 5/7/13 7:31 AM, Michael Dondrup wrote:
>> Dear Gbrowse list,
>>
>> I have, with a little desperation, started to search look for documentation on the Gbrowse2 Session module. In particular, I am
>> interested in how to *correctly* initialize and build up a Gbrowse session which is fully authorized for a user. Let's assume the
>> task is to: write a cgi script (in addition to the gbrowse cgi) to initialize a gbrowse session with an authenticated user, such that in
>> the next invocation of gbrowse, the user is authenticated and logged in.
>>
>> I found by reading through the source code and reverse
>> engineering a sequence of commands that will *almost* get me there. I am seemingly missing one step only:
>> - the example code below works in case I already have a Gbrowse session
>> - the example doesn't work when there is no session at all, because subsequent calls to gbrowse make a new session which then is not authenticated.
>>
>> So, what is the correct way to initialize a Gbrowse2 Session programmatically? Am I missing something.
>>
>> I'd really appreciate your help, because now I am definitely stuck.
>>
>>
>>
>> Michael Dondrup
>> Postdoctoral fellow
>> Sea Lice Research Centre/Department of Informatics
>> University of Bergen
>> Thormøhlensgate 55, N-5008 Bergen,
>> Norway
>>
>>
>> #!/usr/bin/env perl
>>
>> use strict;
>> use warnings;
>> use Net::SAML;
>> use CGI::Fast qw(:standard);
>>
>> use Bio::Graphics::Browser2;
>> use Bio::Graphics::Browser2::Render::HTML;
>>
>> while (my $q = CGI::Fast->new) {
>> my $username ="valid user";
>> # it's not really important where this comes from,
>> # the user information is coming from an authentication module using Net::SAML
>> my $fullname = "Fully Valid";
>> my $mail = "[hidden email]";
>>
>>  if ($username) {
>>
>> my $p = "https://url";
>> my $myurl = "https://url/gbrowse/lsalmonis/";
>> my $htmlhead = <<HTML
>> <script src="$p/gbrowse2/js/login.js" type="text/javascript"></script>
>> <script src="$p/gbrowse2/js/controller.js" type="text/javascript"></script>
>> HTML
>> ;
>>        ## STEP 1:
>>         ## get the session and initialize it
>>
>>         my $session = $render->session;
>>         $session->lock();
>>         $session->username($username);
>>         $session->flush;
>>
>> ## STEP 2:
>>         ## authorization handling:
>> my $userdb = $render->userdb;
>>         my $id = $userdb->check_or_add_named_session($session->id,$username);
>>         $userdb->set_fullname_from_username($username=>$fullname,$mail) if defined $fullname;
>>         warn "username ".$session->username. " stored in session ".$session->id();
>>         # now authenticate
>>         my ($sid, $nonce) = $render->authorize_user($username,$id, 1,undef);
>>         my $is_authorized = $render->user_authorized_for_source($username);
>>
>>         ## STEP 3:
>>         ## prepare for JavaScript invocation
>>         ## seems like the final step is to invoke login_load_account to make the UI aware of the login
>>
>> # convert the login data to json
>>         my $result = to_json { userOK  => 1,
>>                 sessionid => $id,
>>                 username  => $username,
>>                 message   => 'login ok',
>>               };
>>
>> ## STEP 5:
>>         ## print an intermediate web page to invoke javascript
>> print header(-type=>"text/html");
>>       print start_html(-head=>$htmlhead);
>>       print b("user $username". (($is_authorized)?" is ": "is not ") . "authorized!");
>>         print script({-type=>'text/javascript'},
>> <<SCRIPT
>> var p = $result;
>> login_load_account("$myurl",p);
>> SCRIPT
>> );
>> $session->unlock();
>> print end_html();
>>  }
>>
>>
>>
>>
>>
>>
>>
>>
>> ------------------------------------------------------------------------------
>> Learn Graph Databases - Download FREE O'Reilly Book
>> "Graph Databases" is the definitive new guide to graph databases and
>> their applications. This 200-page book is written by three acclaimed
>> leaders in the field. The early access version is available now.
>> Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
>> _______________________________________________
>> Gmod-gbrowse mailing list
>> [hidden email]
>> https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse
>
>
> ------------------------------------------------------------------------------
> Learn Graph Databases - Download FREE O'Reilly Book
> "Graph Databases" is the definitive new guide to graph databases and
> their applications. This 200-page book is written by three acclaimed
> leaders in the field. The early access version is available now.
> Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
> _______________________________________________
> Gmod-gbrowse mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse


------------------------------------------------------------------------------
Try New Relic Now & We'll Send You this Cool Shirt
New Relic is the only SaaS-based application performance monitoring service
that delivers powerful full stack analytics. Optimize and monitor your
browser, app, & servers with just a few lines of code. Try New Relic
and get this awesome Nerd Life shirt! http://p.sf.net/sfu/newrelic_d2d_may
_______________________________________________
Gmod-gbrowse mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse
Reply | Threaded
Open this post in threaded view
|

Re: Need documentation on Gbrowse session handling

Lincoln Stein
Hi,

I apologize for the state of the internal documentation.

If someone is willing to contribute documentation to the repository, both I and the community will be very grateful! The procedure for this is to clone the repository in github, add the documentation to the "docs" subdirectory, and then issue a "pull" request.

Lincoln


On Fri, May 24, 2013 at 5:48 AM, Michael Dondrup <[hidden email]> wrote:
=pod

Dear Ryan,

thank you so much for the source code. I have implemented a solution based on the code
found in your authentication module, and it worked! In the end, it turned out that I was
failing to set the session cookie, something that one has to do yourself if one attempts authentication
outside of the ordinary GBrowse control flow. I must admit that this was kinda stupid mistake.

For the sake of adding to the developer documentation - I found that GBrowse could really need some
improvement of the internal code documentation, there is hardly anything - I wish to provide a
little more detail about my setting and code.

I am implementing SAML based authentication for our local GBrowse installation. This setting is very similar to
described by Ryan. The authentication is provided by a SAML Identity provider (IdP) for single sign-on,
in this case simpleSAMLphp.
When a restricted resource is encountered, the authentication plugin redirects to the IdP, which maintains its
own session with the client. After a successful login at the IdP, the IdP sends an encrypted message with the
credentials to GBrowse, this can be done via different mechanisms, but in this case the message is sent via
HTTP POST. The receiver (Net::SAML in this case) decrypts the message and returns the user credentials.

In some settings (mod_fcgid) I had experienced problems with sudden crashes (e.g. sig_pipe) of the
receiving process. For reasons I have to further investigate, crashes occur if
I just let the gbrowse cgi script receive the post message and dispatch it to the
authentication plugin.

In order not to mess with the original gbrowse cgi, I implemented another
cgi script as a receiver of the post data. Using my own script to initialize the session and authenticate
the users also means that I am totally responsible for setting the session up correctly. One of the things
that need to be done in this case is to generate the session cookie, this is not necessary if one is implementing
the authentication through the plugin because gbrowse will handle setting the cookie.

As a result, the complete sequence of commands to initialize a session with an external perl script
and load the interface with the user logged in, (given _parse_saml() is a function returning  some credentials)
is given below for completeness.

=cut

#!/usr/bin/env perl
use strict;
use warnings;
use Bio::Graphics::Browser2;
Bio::Graphics::Browser2::UserDB;
use CGI::Fast qw(:standard);
use CGI::Cookie;
use JSON;
my $DEBUG = 1;

my $myurl = "http://localhost/fgb2/gbrowse/yeast"; # or whatever to load

while (my $q = CGI::Fast->new) {
 my ($userid, $displayName, $email) = (_parse_saml());
 if ($userid) {
      my $globals = Bio::Graphics::Browser2->open_globals;
      my $userdb = Bio::Graphics::Browser2::UserDB->new($globals);
      ## get the session
      my $session = $globals->session;
      my $sessionid = $session->id;
      ## set the username for the session
      $session->username($userid);
      $session->flush();
      ## check if the user exists already
      my $confirmedUserId = $userdb->userid_from_username($userid);
      if ( $confirmedUserId eq "") {
         print STDERR "User $userid does not yet exist; will create.\n" if $DEBUG;
         print STDERR "Flushed session.  Will now create user using session.\n" if $DEBUG;
         my ($status,undef,$message) = $userdb->do_add_user($userid,$email,$displayName,'dummy-password',$sessionid);
         print STDERR "Results from do_add_user: Status: $status\n" if $DEBUG;
         print STDERR "Results from do_add_user: Message: $message\n" if $DEBUG;
         $userdb->set_confirmed_from_username($userid);
         print STDERR "User set as confirmed.\n" if $DEBUG;
         ## set the full name, but only once
         $userdb->set_fullname_from_username($userid, $displayName, $email) if $displayName;
      } else {
        print STDERR "Found existing user with ID: $confirmedUserId so skipping creation.\n" if $DEBUG;
      }

      ## now generate the html page that will initialize the session
      ## start with the session cookie:
      my $cookie = CGI::Cookie->new(-name => 'gbrowse_sess',
      -path => '/fgb2/',
      -expires => '+1M',
      -value => $sessionid);

      ## some JSON data is required for calling the java script:
       my $result = to_json { userOK  => 1,
                  sessionid => $sessionid,
                  username  => $username,
                  message   => 'login ok',
                 };
      ## import required javascript functions
      my $htmlhead = <<HTML
<script src="gbrowse2/js/login.js" type="text/javascript"></script>
<script src="/gbrowse2/js/controller.js" type="text/javascript"></script>
HTML
;

   print header(-type=>"text/html", -cookie=>$cookie);
   print start_html(-head=>$htmlhead);
   print script({-type=>'text/javascript'},
<<SCRIPT
var p = $result;
login_load_account("$myurl", p);
SCRIPT
);
   print end_html();
} else {
  die "I should never receive invalid userid from external IdP";
}

sub _parse_saml {
 ## return some dummy data, this part is a bit simplyfied:
return ('joe', 'joe user', '[hidden email]');
}

__END__

This script should generate a page setting the session cookie, and the javascript that loads the
gbrowse session. Hope this is useful in the future.

Best
Michael

On May 8, 2013, at 6:01 PM, Ryan Doherty wrote:

> Hi Micheal,
>
> I'm not on the GBrowse team, but have been trying to do a similar thing,
> with success.  Let me tell you what I've done and maybe you can take the
> pieces of it you need.
>
> We have a system which establishes a session separate from gbrowse; when
> a user logged into that system, I wanted to "automatically" log the user
> into his corresponding gbrowse account (i.e. log in to both systems
> simultaneously).  Also, if the user exists in our main system, but does
> NOT exist in gbrowse (yet), we wanted to be able to create a new account
> for him on the fly.  It is working; however I'm still working on some
> details regarding configuration and postgres support on the backend.
>
> Here's how it works:
>
> 1. Our system's login process (java on tomcat) sets a custom cookie on
> the client for our main system, which contains the userid and a
> checksum, and then redirects to a stand-alone HTML page, passing along a
> URL that the user will eventually be redirected to.
> 2. The HTML page loads javascript that submits the information in the
> cookie (via AJAX) as the username and "password" to gbrowse.
> 3. A custom gbrowse authentication plugin connects to a web service,
> asking if the username and checksum are valid and retrieving the user's
> email and display name if so.
> 4. If the creds are valid, the plugin looks to see if the user exists in
> gbrowse (i.e. has a gbrowse account), and creates one if not,
> establishing a session for the new user.
> 5. The 'authority' value (which confirms the login was successful), is
> returned to the client, where a second AJAX call uses it to request the
> user's session ID.
> 6. The gbrowse session ID and auth ID are returned to the client, where
> more javascript sets them as normal gbrowse session cookies.
> 7. The user is redirected to the URL originally passed to the standalone
> HTML page.
>
> At the end of this process, both our system's normal login cookie, and
> the needed gbrowse cookies are set on the client, so the user can visit
> a gbrowse page and is already logged in.  We never display the
> Login/Account/Logout links in gbrowse itself (hidden with CSS).
> Instead, we have a logout link for our whole system which expires not
> only our normal cookie, but the gbrowse cookies as well.  Obviously,
> this requires our regular system and gbrowse to share a domain, and
> there are a few other details I'm glossing over.
>
> The thing that might help you out the most is the authentication plugin,
> which lives (for now) here:
>
> https://www.cbil.upenn.edu/svn/apidb/ApiCommonShared/branches/gbrowse_login/Model/lib/gbrowse/plugins/WdkSessionAuthenticator.pm
>
> If you're interested in the javascript that creates the session, let me
> know and I'll point it to you.  I had to make some modifications to
> functions in controller.js and login.js.  As I said, I'm not an expert
> and don't know everything about how gbrowse maintains its sessions, but
> I'll answer any questions you have the best I can.
>
> Ryan
>
>
> On 5/7/13 7:31 AM, Michael Dondrup wrote:
>> Dear Gbrowse list,
>>
>> I have, with a little desperation, started to search look for documentation on the Gbrowse2 Session module. In particular, I am
>> interested in how to *correctly* initialize and build up a Gbrowse session which is fully authorized for a user. Let's assume the
>> task is to: write a cgi script (in addition to the gbrowse cgi) to initialize a gbrowse session with an authenticated user, such that in
>> the next invocation of gbrowse, the user is authenticated and logged in.
>>
>> I found by reading through the source code and reverse
>> engineering a sequence of commands that will *almost* get me there. I am seemingly missing one step only:
>> - the example code below works in case I already have a Gbrowse session
>> - the example doesn't work when there is no session at all, because subsequent calls to gbrowse make a new session which then is not authenticated.
>>
>> So, what is the correct way to initialize a Gbrowse2 Session programmatically? Am I missing something.
>>
>> I'd really appreciate your help, because now I am definitely stuck.
>>
>>
>>
>> Michael Dondrup
>> Postdoctoral fellow
>> Sea Lice Research Centre/Department of Informatics
>> University of Bergen
>> Thormøhlensgate 55, N-5008 Bergen,
>> Norway
>>
>>
>> #!/usr/bin/env perl
>>
>> use strict;
>> use warnings;
>> use Net::SAML;
>> use CGI::Fast qw(:standard);
>>
>> use Bio::Graphics::Browser2;
>> use Bio::Graphics::Browser2::Render::HTML;
>>
>> while (my $q = CGI::Fast->new) {
>> my $username ="valid user";
>> # it's not really important where this comes from,
>> # the user information is coming from an authentication module using Net::SAML
>> my $fullname = "Fully Valid";
>> my $mail = "[hidden email]";
>>
>>  if ($username) {
>>
>>      my $p = "https://url";
>>      my $myurl = "https://url/gbrowse/lsalmonis/";
>>      my $htmlhead = <<HTML
>> <script src="$p/gbrowse2/js/login.js" type="text/javascript"></script>
>> <script src="$p/gbrowse2/js/controller.js" type="text/javascript"></script>
>> HTML
>> ;
>>        ## STEP 1:
>>         ## get the session and initialize it
>>
>>         my $session = $render->session;
>>         $session->lock();
>>         $session->username($username);
>>         $session->flush;
>>
>>      ## STEP 2:
>>         ## authorization handling:
>>      my $userdb = $render->userdb;
>>         my $id = $userdb->check_or_add_named_session($session->id,$username);
>>         $userdb->set_fullname_from_username($username=>$fullname,$mail) if defined $fullname;
>>         warn "username ".$session->username. " stored in session ".$session->id();
>>         # now authenticate
>>         my ($sid, $nonce) = $render->authorize_user($username,$id, 1,undef);
>>         my $is_authorized = $render->user_authorized_for_source($username);
>>
>>         ## STEP 3:
>>         ## prepare for JavaScript invocation
>>         ## seems like the final step is to invoke login_load_account to make the UI aware of the login
>>
>>      # convert the login data to json
>>         my $result = to_json { userOK  => 1,
>>                 sessionid => $id,
>>                 username  => $username,
>>                 message   => 'login ok',
>>               };
>>
>>      ## STEP 5:
>>         ## print an intermediate web page to invoke javascript
>>      print header(-type=>"text/html");
>>              print start_html(-head=>$htmlhead);
>>              print b("user $username". (($is_authorized)?" is ": "is not ") . "authorized!");
>>         print script({-type=>'text/javascript'},
>> <<SCRIPT
>> var p = $result;
>> login_load_account("$myurl",p);
>> SCRIPT
>> );
>>      $session->unlock();
>>      print end_html();
>>  }
>>
>>
>>
>>
>>
>>
>>
>>
>> ------------------------------------------------------------------------------
>> Learn Graph Databases - Download FREE O'Reilly Book
>> "Graph Databases" is the definitive new guide to graph databases and
>> their applications. This 200-page book is written by three acclaimed
>> leaders in the field. The early access version is available now.
>> Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
>> _______________________________________________
>> Gmod-gbrowse mailing list
>> [hidden email]
>> https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse
>
>
> ------------------------------------------------------------------------------
> Learn Graph Databases - Download FREE O'Reilly Book
> "Graph Databases" is the definitive new guide to graph databases and
> their applications. This 200-page book is written by three acclaimed
> leaders in the field. The early access version is available now.
> Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
> _______________________________________________
> Gmod-gbrowse mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse


------------------------------------------------------------------------------
Try New Relic Now & We'll Send You this Cool Shirt
New Relic is the only SaaS-based application performance monitoring service
that delivers powerful full stack analytics. Optimize and monitor your
browser, app, & servers with just a few lines of code. Try New Relic
and get this awesome Nerd Life shirt! http://p.sf.net/sfu/newrelic_d2d_may
_______________________________________________
Gmod-gbrowse mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse



--
Lincoln D. Stein
Director, Informatics and Biocomputing Platform
Ontario Institute for Cancer Research
101 College St., Suite 800
Toronto, ON, Canada M5G0A3
416 673-8514
Assistant: Renata Musa <[hidden email]>

------------------------------------------------------------------------------
Try New Relic Now & We'll Send You this Cool Shirt
New Relic is the only SaaS-based application performance monitoring service
that delivers powerful full stack analytics. Optimize and monitor your
browser, app, & servers with just a few lines of code. Try New Relic
and get this awesome Nerd Life shirt! http://p.sf.net/sfu/newrelic_d2d_may
_______________________________________________
Gmod-gbrowse mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse
Reply | Threaded
Open this post in threaded view
|

Re: Need documentation on Gbrowse session handling

Lishuang_shen@meei.harvard.edu
In reply to this post by Michael Dondrup-3
Michael Dondrup <michael.dondrup@...> writes:

>
> =pod
>
> Dear Ryan,
>
> thank you so much for the source code. I have implemented a solution based
on the code
> found in your authentication module, and it worked! In the end, it turned
out that I was
> failing to set the session cookie, something that one has to do yourself
if one attempts authentication
> outside of the ordinary GBrowse control flow. I must admit that this was
kinda stupid mistake.
>
> For the sake of adding to the developer documentation - I found that
GBrowse could really need some
> improvement of the internal code documentation, there is hardly anything -
I wish to provide a
> little more detail about my setting and code.
>
> I am implementing SAML based authentication for our local GBrowse
installation. This setting is very
> similar to
> described by Ryan. The authentication is provided by a SAML Identity
provider (IdP) for single sign-on,
> in this case simpleSAMLphp.
> When a restricted resource is encountered, the authentication plugin
redirects to the IdP, which
> maintains its
> own session with the client. After a successful login at the IdP, the IdP
sends an encrypted message with the
> credentials to GBrowse, this can be done via different mechanisms, but in
this case the message is sent via
> HTTP POST. The receiver (Net::SAML in this case) decrypts the message and
returns the user credentials.
>
> In some settings (mod_fcgid) I had experienced problems with sudden
crashes (e.g. sig_pipe) of the
> receiving process. For reasons I have to further investigate, crashes
occur if
> I just let the gbrowse cgi script receive the post message and dispatch it
to the
> authentication plugin.
>
> In order not to mess with the original gbrowse cgi, I implemented another
> cgi script as a receiver of the post data. Using my own script to
initialize the session and authenticate
> the users also means that I am totally responsible for setting the session
up correctly. One of the things
> that need to be done in this case is to generate the session cookie, this
is not necessary if one is implementing
> the authentication through the plugin because gbrowse will handle setting
the cookie.
>
> As a result, the complete sequence of commands to initialize a session
with an external perl script
> and load the interface with the user logged in, (given _parse_saml() is a
function returning  some credentials)

> is given below for completeness.  
>
> =cut
>
> #!/usr/bin/env perl
> use strict;
> use warnings;
> use Bio::Graphics::Browser2;
> Bio::Graphics::Browser2::UserDB;
> use CGI::Fast qw(:standard);
> use CGI::Cookie;
> use JSON;
> my $DEBUG = 1;
>
> my $myurl = "http://localhost/fgb2/gbrowse/yeast"; # or whatever to load
>
> while (my $q = CGI::Fast->new) {
>  my ($userid, $displayName, $email) = (_parse_saml());
>  if ($userid) {
>       my $globals = Bio::Graphics::Browser2->open_globals;
>       my $userdb = Bio::Graphics::Browser2::UserDB->new($globals);
>       ## get the session
>       my $session = $globals->session;
>       my $sessionid = $session->id;
>       ## set the username for the session
>       $session->username($userid);
>       $session->flush();
>       ## check if the user exists already
>       my $confirmedUserId = $userdb->userid_from_username($userid);
>       if ( $confirmedUserId eq "") {
>          print STDERR "User $userid does not yet exist; will create.\n" if
$DEBUG;
>          print STDERR "Flushed session.  Will now create user using
session.\n" if $DEBUG;
>          my ($status,undef,$message) =
$userdb->do_add_user($userid,$email,$displayName,'dummy-password',$sessionid);
>          print STDERR "Results from do_add_user: Status: $status\n" if $DEBUG;
>          print STDERR "Results from do_add_user: Message: $message\n" if
$DEBUG;
>          $userdb->set_confirmed_from_username($userid);
>          print STDERR "User set as confirmed.\n" if $DEBUG;
>          ## set the full name, but only once
>          $userdb->set_fullname_from_username($userid, $displayName,
$email) if $displayName;
>       } else {
>         print STDERR "Found existing user with ID: $confirmedUserId so
skipping creation.\n" if $DEBUG;

>       }
>
>       ## now generate the html page that will initialize the session
>       ## start with the session cookie:
>       my $cookie = CGI::Cookie->new(-name => 'gbrowse_sess',
>       -path => '/fgb2/',
>       -expires => '+1M',
>       -value => $sessionid);
>
>       ## some JSON data is required for calling the java script:
>        my $result = to_json { userOK  => 1,
>                   sessionid => $sessionid,
>                   username  => $username,
>                   message   => 'login ok',
>                  };
>       ## import required javascript functions
>       my $htmlhead = <<HTML
> <script src="gbrowse2/js/login.js" type="text/javascript"></script>
> <script src="/gbrowse2/js/controller.js" type="text/javascript"></script>
> HTML
> ;
>
>    print header(-type=>"text/html", -cookie=>$cookie);
>    print start_html(-head=>$htmlhead);
>    print script({-type=>'text/javascript'},


Hello:

I am following similar strategy for 3rd party login done with PHP. I handled
the information with perl PHP::session and able to read the PHP generated
session and validated with session information in Gbrowse mysql.

I use database to store the user and session information, not using files.
So I am trying to activate my validated session information into Gbrowse.
But stuck here regarding how to set cookie. Do you have experience to share
in such situation?

Thank you,

Lishuang




------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Gmod-gbrowse mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gmod-gbrowse