Checking in changes prior to tagging of version 1.003. Changelog diff is:
[catagits/Catalyst-Authentication-Credential-HTTP.git] / t / basic.t
CommitLineData
2022b950 1#!/usr/bin/perl
2022b950 2use strict;
3use warnings;
f1f73b53 4use Test::More tests => 31;
2022b950 5use Test::MockObject::Extends;
6use Test::MockObject;
d9914dd2 7use Test::Exception;
2022b950 8use HTTP::Headers;
9
513d8ab6 10my $m; BEGIN { use_ok($m = "Catalyst::Authentication::Credential::HTTP") }
11can_ok( $m, "authenticate" );
2022b950 12can_ok( $m, "authorization_required_response" );
490754a8 13
2022b950 14my $req = Test::MockObject->new;
15my $req_headers = HTTP::Headers->new;
2022b950 16$req->set_always( headers => $req_headers );
2022b950 17my $res = Test::MockObject->new;
2022b950 18my $status;
19$res->mock(status => sub { $status = $_[1] });
f366138e 20my $content_type;
21$res->mock(content_type => sub { $content_type = $_[1] });
22my $body;
513d8ab6 23my $headers;
f366138e 24$res->mock(body => sub { $body = $_[1] });
2022b950 25my $res_headers = HTTP::Headers->new;
26$res->set_always( headers => $res_headers );
513d8ab6 27my $user = Test::MockObject->new;
490754a8 28$user->mock(get => sub { return shift->{$_[0]} });
29my $find_user_opts;
30my $realm = Test::MockObject->new;
513d8ab6 31$realm->mock( find_user => sub { $find_user_opts = $_[1]; return $user; });
32$realm->mock( name => sub { 'foo' } );
33my $c = Test::MockObject->new;
007935b8 34my $cache = Test::MockObject->new;
35$cache->mock(set => sub { shift->{$_[0]} = $_[1] });
36$cache->mock(get => sub { return shift->{$_[0]} });
37$c->mock(cache => sub { $cache });
4e8cbd42 38$c->mock(debug => sub { 0 });
2022b950 39my @login_info;
40$c->mock( login => sub { shift; @login_info = @_; 1 } );
513d8ab6 41my $authenticated = 0;
42$c->mock( set_authenticated => sub { $authenticated++; } );
2022b950 43$c->set_always( config => {} );
44$c->set_always( req => $req );
45$c->set_always( res => $res );
513d8ab6 46$c->set_always( request => $req );
47$c->set_always( response => $res );
490754a8 48
49sub new_self {
50 my $config = { @_ };
51 my $raw_self = $m->new($config, $c, $realm);
52 return Test::MockObject::Extends->new( $raw_self );
53}
54
55# Normal auth, simple as possible.
56# No credentials
57my $self = new_self( type => 'any', password_type => 'clear', password_field => 'password' );
58throws_ok {
59 $self->authenticate( $c, $realm );
60} qr/^ $Catalyst::DETACH $/x, 'Calling authenticate for http auth without header detaches';
61$user->{password} = 'bar';
62
63# Wrong credentials
64$req_headers->authorization_basic( qw/foo quux/ );
65throws_ok {
66 $self->authenticate( $c, $realm );
67} qr/^ $Catalyst::DETACH $/x, 'Calling authenticate for http auth without header detaches';
68
69# Correct credentials
2022b950 70$req_headers->authorization_basic( qw/foo bar/ );
513d8ab6 71ok($self->authenticate($c, $realm), "auth successful with header");
72is($authenticated, 1, 'authenticated once');
513d8ab6 73is_deeply( $find_user_opts, { username => 'foo'}, "login delegated");
490754a8 74
75# Test all the headers look good.
2022b950 76$req_headers->clear;
bf399285 77$res_headers->clear;
2022b950 78$c->clear;
d9914dd2 79throws_ok {
513d8ab6 80 $self->authenticate( $c, $realm );
d9914dd2 81} qr/^ $Catalyst::DETACH $/x, "detached on no authorization required with bad auth";
2022b950 82is( $status, 401, "401 status code" );
f366138e 83is( $content_type, 'text/plain' );
84is( $body, 'Authorization required.' );
007935b8 85like( ($res_headers->header('WWW-Authenticate'))[0], qr/^Digest/, "WWW-Authenticate header set: digest");
513d8ab6 86like( ($res_headers->header('WWW-Authenticate'))[0], qr/realm="foo"/, "WWW-Authenticate header set: digest realm");
007935b8 87like( ($res_headers->header('WWW-Authenticate'))[1], qr/^Basic/, "WWW-Authenticate header set: basic");
513d8ab6 88like( ($res_headers->header('WWW-Authenticate'))[1], qr/realm="foo"/, "WWW-Authenticate header set: basic realm");
6afc3665 89
bf399285 90$res_headers->clear;
490754a8 91# Check password_field works
92{
93 my $self = new_self( type => 'any', password_type => 'clear', password_field => 'the_other_password' );
94 local $user->{password} = 'bar';
95 local $user->{the_other_password} = 'the_other_password';
96 $req_headers->authorization_basic( qw/foo the_other_password/ );
97 ok($self->authenticate($c, $realm), "auth successful with header and alternate password field");
98 $c->clear;
99 $req_headers->authorization_basic( qw/foo bar/ );
100 throws_ok {
101 $self->authenticate( $c, $realm );
102 } qr/^ $Catalyst::DETACH $/x, "detached on bad password (different password field)";
103}
104
105$req_headers->clear;
bf399285 106$res_headers->clear;
513d8ab6 107throws_ok {
108 $self->authenticate( $c, $realm, { realm => 'myrealm' }); # Override realm object's name method by doing this.
490754a8 109} qr/^ $Catalyst::DETACH $/x, "detached on no authorization supplied, overridden realm value";
513d8ab6 110is( $status, 401, "401 status code" );
111is( $content_type, 'text/plain' );
112is( $body, 'Authorization required.' );
bf399285 113like( ($res_headers->header('WWW-Authenticate'))[0], qr/realm="myrealm"/, "WWW-Authenticate header set: digest realm overridden");
114like( ($res_headers->header('WWW-Authenticate'))[1], qr/realm="myrealm"/, "WWW-Authenticate header set: basic realm overridden");
115
05512a69 116# Check authorization_required_message works
117$req_headers->clear;
118$res_headers->clear;
119$c->clear;
120{
121 my $self = new_self( type => 'any', password_type => 'clear',
122 authorization_required_message => 'foobar'
123 );
124 throws_ok {
125 $self->authenticate( $c, $realm );
126 } qr/^ $Catalyst::DETACH $/x, "detached";
127 is( $body, 'foobar', 'Body is supplied auth message');
128}
129
f1f73b53 130# Check undef authorization_required_message suppresses crapping in
131# the body.
05512a69 132$req_headers->clear;
133$res_headers->clear;
134$c->clear;
135{
136 my $self = new_self( type => 'any', password_type => 'clear',
137 authorization_required_message => undef
138 );
139 throws_ok {
140 $self->authenticate( $c, $realm );
141 } qr/^ $Catalyst::DETACH $/x, "detached";
142 is( $body, undef, 'Body is not set - user overrode auth message');
f1f73b53 143}
144
145# Check domain config works
146$req_headers->clear;
147$res_headers->clear;
148$c->clear;
149{
150 my $self = new_self( type => 'any', password_type => 'clear',
151 #use_uri_for => 1,
152 );
153 throws_ok {
154 $self->authenticate( $c, $realm, {domain => [qw/dom1 dom2/]} );
155 } qr/^ $Catalyst::DETACH $/x, "detached";
156 like( ($res_headers->header('WWW-Authenticate'))[0], qr/domain="dom1 dom2"/, "WWW-Authenticate header set: digest domains set");
157 like( ($res_headers->header('WWW-Authenticate'))[1], qr/domain="dom1 dom2"/, "WWW-Authenticate header set: basic domains set");
158}