1use strict; 2use warnings; 3use FindBin qw/$Bin/; 4use lib "$Bin/lib"; 5use Test::More; 6use Test::Needs { 7 'Test::WWW::Mechanize::Catalyst' => '0.51', 8 'Catalyst::Plugin::Cache' => '0', 9 'Cache::FileCache' => undef, 10}; 11 12plan tests => 19; 13 14use Digest::MD5; 15use HTTP::Request; 16 17sub do_test { 18 my ($username, $uri, $emulate_dotnet, $fail) = @_; 19 my $app = $fail ? 'AuthDigestTestApp' : 'AuthDigestDotnetTestApp'; 20 my $mech = Test::WWW::Mechanize::Catalyst->new(catalyst_app => $app); 21 $mech->get("http://localhost/moose"); 22 is( $mech->status, 401, "status is 401" ); 23 my $www_auth = $mech->res->headers->header('WWW-Authenticate'); 24 my %www_auth_params = map { 25 my @key_val = split /=/, $_, 2; 26 $key_val[0] = lc $key_val[0]; 27 $key_val[1] =~ s{"}{}g; # remove the quotes 28 @key_val; 29 } split /, /, substr( $www_auth, 7 ); #7 == length "Digest " 30 $mech->content_lacks( "foo", "no output" ); 31 my $response = ''; 32 { 33 my $password = 'Circle Of Life'; 34 my $realm = $www_auth_params{realm}; 35 my $nonce = $www_auth_params{nonce}; 36 my $cnonce = '0a4f113b'; 37 my $opaque = $www_auth_params{opaque}; 38 my $nc = '00000001'; 39 my $method = 'GET'; 40 my $qop = 'auth'; 41 $uri ||= '/moose'; 42 my $auth_uri = $uri; 43 if ($emulate_dotnet) { 44 $auth_uri =~ s/\?.*//; 45 } 46 my $ctx = Digest::MD5->new; 47 $ctx->add( join( ':', $username, $realm, $password ) ); 48 my $A1_digest = $ctx->hexdigest; 49 $ctx = Digest::MD5->new; 50 $ctx->add( join( ':', $method, $auth_uri ) ); 51 my $A2_digest = $ctx->hexdigest; 52 my $digest = Digest::MD5::md5_hex( 53 join( ':', 54 $A1_digest, $nonce, $qop ? ( $nc, $cnonce, $qop ) : (), $A2_digest ) 55 ); 56 57 $response = qq{Digest username="$username", realm="$realm", nonce="$nonce", uri="$auth_uri", qop=$qop, nc=$nc, cnonce="$cnonce", response="$digest", opaque="$opaque"}; 58 } 59 my $r = HTTP::Request->new( GET => "http://localhost" . $uri ); 60 $mech->request($r); 61 $r->headers->push_header( Authorization => $response ); 62 $mech->request($r); 63 if ($fail) { 64 is( $mech->status, 400, "status is 400" ); 65 } else { 66 is( $mech->status, 200, "status is 200" ); 67 $mech->content_contains( $username, "Mufasa output" ); 68 } 69} 70 71do_test('Mufasa'); 72do_test('Mufasa2'); 73# Test with query string 74do_test('Mufasa2', '/moose?moose_id=1'); 75# Test with query string, emulating .NET, which omits the query string 76# from the Authorization header 77do_test('Mufasa2', '/moose?moose_id=1', 1); 78 79# Test with query string, emulating .NET, against app without .NET setting; 80# authorization should fail 81do_test('Mufasa2', '/moose?moose_id=1', 1, 1); 82