Added Session::Cookie middleware which utilizes Cookie as both state and store.
[catagits/Web-Session.git] / lib / Plack / Middleware / Session / Cookie.pm
CommitLineData
d326e755 1package Plack::Middleware::Session::Cookie;
2use strict;
3use parent qw(Plack::Middleware::Session);
4
5use Plack::Util::Accessor qw(secret session_key domain expires path secure);
6
7use Digest::HMAC_SHA1;
8use MIME::Base64 ();
9use Storable ();
10use Time::HiRes;
11use Plack::Util;
12
13use Plack::Session::State::Cookie;
14
15sub prepare_app {
16 my $self = shift;
17
18 $self->session_class("Plack::Session");
19 $self->session_key("plack_session") unless $self->session_key;
20
21 my $state_cookie = Plack::Session::State::Cookie->new;
22 for my $attr (qw(session_key path domain expires secure)) {
23 $state_cookie->$attr($self->$attr);
24 }
25
26 my $state = Plack::Util::inline_object
27 generate => sub { $self->_serialize({}) },
28 extract => sub {
29 my $cookie = $state_cookie->get_session_id(@_) or return;
30
31 my($time, $b64, $sig) = split /:/, $cookie, 3;
32 $self->sig($b64) eq $sig or return;
33
34 return $cookie;
35 },
36 expire_session_id => sub { $state_cookie->expire_session_id(@_) },
37 finalize => sub {
38 my($id, $response, $session) = @_;
39 my $cookie = $self->_serialize($session->dump);
40 $state_cookie->finalize($cookie, $response);
41 };
42
43 my $store = Plack::Util::inline_object
44 fetch => sub {
45 my $id = shift;
46 my($time, $b64, $sig) = split /:/, $id, 3;
47 Storable::thaw(MIME::Base64::decode($b64));
48 },
49 store => sub { },
50 cleanup => sub { };
51
52 $self->state($state);
53 $self->store($store);
54}
55
56sub _serialize {
57 my($self, $session) = @_;
58
59 my $now = Time::HiRes::gettimeofday;
60 my $b64 = MIME::Base64::encode( Storable::freeze($session), '' );
61 join ":", $now, $b64, $self->sig($b64);
62}
63
64sub sig {
65 my($self, $b64) = @_;
66 return '.' unless $self->secret;
67 Digest::HMAC_SHA1::hmac_sha1_hex($b64, $self->secret);
68}
69
701;
71
72__END__
73
74=head1 NAME
75
76Plack::Middleware::Session::Cookie - Session middleware that saves session data in the cookie
77
78=head1 SYNOPSIS
79
80 enable "Session::Cookie";
81
82=head1 DESCRIPTION
83
84This middleware component allows you to use the cookie as a sole
85cookie state and store, without any server side storage to do the
86session management. This middleware utilizes its own state and store
87automatically for you, so you can't override the objects.
88
89=head1 CONFIGURATIONS
90
91This middleware is a subclass of L<Plack::Middleware::Session> and
92accepts most configuration of the parent class. In addition, following
93options are accepted.
94
95=over 4
96
97=item secret
98
99Server side secret to sign the session data using HMAC SHA1. Defaults
100to nothing (i.e. do not sign) but B<strongly recommended> to set your
101own secret string.
102
103=item session_key, domain, expires, path, secure
104
105Accessors for the cookie attribuets. See
106L<Plack::Session::State::Cookie> for these options.
107
108=back
109
110=head1 AUTHOR
111
112Tatsuhiko Miyagawa
113
114=head1 SEE ALSO
115
116Rack::Session::Cookie L<Dancer::Session::Cookie>
117
118=cut
119