2

I have a Starman based server -

#!/usr/bin/perl
use strict;
use warnings;
use Data::Printer;
use Plack::Builder;

my $app = sub {
    my $env = shift;
    my $session = $env->{'psgix.session'};

    # Print environment variables
    p($env);

    return [
        200,
        [ 'Content-Type' => 'text/plain' ],
        [ "Hello, you've been here for ", $session->{counter}++, "th   time!" ],
    ];
};

my $default = sub {
    my $env = shift;
    p($env);
    return [
        '200', [ 'Content-Type' => 'text/html' ],
        ["Welcome to default page"],
    ];
};

builder {
    mount "/validate" => builder {
        enable "Middleware::Authentication"
        enable "Session";
        $app;
    };
    mount "/" => builder { $default };
};

My own middleware "Authentication" authenticate the user and return session information(expiry time, session key etc) for the session management, So how can i make use of these information in the Session Middleware?

CodeQuestor
  • 881
  • 1
  • 11
  • 25

2 Answers2

2

If I understand right, your problem is only in the order of the middleware. Enable the Session before your Auth.

Check the following, using the File storage, the sessions are stored persistently. Try it, restart your Starman and the counter will be reloaded. (I using inline middleware as an replacement to your Authentication.)

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Printer;
use Plack::Builder;

my $app = sub {
    my $env = shift;
    my $session = $env->{'psgix.session'};
    return [
        200,
        [ 'Content-Type' => 'text/html' ],
        [
            "My app page is visited ",
            $session->{counter}++,
            "th times! Validation is done at:",
            $session->{mwaretime},
            q{<br><a href="/validate">go validate again</a> --- <a href="/">reload this page</a>}
        ],
    ];
};

my $validate = sub {
    my $env = shift;
    my $session = $env->{'psgix.session'};
    $session->{counter} = 0;
    return [
        '200', [ 'Content-Type' => 'text/html' ],
        [
            "Resetting the counter:",
            $session->{counter},
             ". Time from middleware: ",
            $session->{mwaretime},
            q{<br> <a href="/validate">reload this page</a> --- <a href="/">go to index</a> }
        ],
    ];
};

builder {
    #the session will be stored persistently
    #enable the Session BEFORE your middleware
    enable 'Session', store => 'File';

    mount "/validate" => builder {
        #enable "Authentication";
        #following is same as an middleware
        enable sub {
            my $app = shift;
            return sub {
                my $env = shift;
                my $session = $env->{'psgix.session'};
                $session->{mwaretime} = time();
                $app->($env);
            };
        };
        #end of the middleware
        $validate;
    };
    mount "/" => $app 
};
clt60
  • 62,119
  • 17
  • 107
  • 194
  • Thanks jm666 for your response. I was looking for the serialization of middlewares i.e. after the user authentication from the Auth middleware it returns the session id(token), user login time etc which i want to use in the Session middleware to manage the session. So how can i pass the output of one middleware to the another. Is this approach is OK? – CodeQuestor Mar 23 '15 at 04:38
  • @CodeQuestor The best what you can do, [search metacpan](https://metacpan.org/search?q=Plack%3A%3AMiddleware%3A%3AAuth&size=500) for some `Plack::Middleware::Auth` modules and check the sources how they uses the Session middleware. I'm not sure about the `session ID` because it is generated by the Session middleware itself using the `Plack::Session::State` (where you can pass your own coderef what returns the SID.) – clt60 Mar 23 '15 at 10:03
  • Thanks for the directions jm666, let me try more on this. – CodeQuestor Mar 24 '15 at 04:02
1

From your question, it's hard to tell what your requirements look like exactly. But if you want this much control over session management, it might be better to write your own middleware. That said, there are some ways to adapt Plack::Middleware::Session to certain scenarios. But most of them use more or less undocumented features. This means that you have to familiarize yourself with the source, and that these features might be changed or go away in later versions.

If you want to provide your own session keys, you can pass a custom SID generator and validator to Plack::Session::State:

enable 'Session',
    state => Plack::Session::State->new(
        sid_generator => $my_generator,
        sid_validator => $my_validator,
    );

The documentation of sid_generator says basically to "just read the source".

You can also implement your own Plack::Session::Store backend. But in this case, it probably makes more sense to switch to a custom solution.

Regarding cookie expiration times, you can set the expires option in $env->{'psgix.session.options'} before a new cookie is created:

$env->{'psgix.session.options'}{expires} = $my_expires;

This is not a timeout but a time in seconds since the UNIX epoch, or any value accepted by Cookie::Baker.

Maybe you should just rethink if your authentication middleware really has to generate the session keys. Like @jm666 said, you typically run the session middleware before authentication. Then your authentication code can access all the session information. The session ID is typically an implementation detail of session management that doesn't have to concern other parts of your code. To change the expiration time, see my answer to this question.

Community
  • 1
  • 1
nwellnhof
  • 32,319
  • 7
  • 89
  • 113
  • Thanks for your response nwellnhof. Actually the session will be maintained per user and user has to be authenticated before entering to some session. The session key/token is going to be shared with other servers and when user will send some command to those server this session key/token is going to be validated. That is why i was generating the session key in my authentication middleware. – CodeQuestor Mar 24 '15 at 15:07