1#!/usr/bin/perl
2#
3# Tests for factor token handling
4#
5# Written by Jon Robertson <jonrober@stanford.edu>
6# Copyright 2013
7#     The Board of Trustees of the Leland Stanford Junior University
8#
9# See LICENSE for licensing terms.
10
11use strict;
12use warnings;
13
14use Test::More tests => 15;
15
16# Ensure we don't pick up the system webkdc.conf.
17BEGIN { $ENV{WEBKDC_CONFIG} = '/nonexistent' }
18
19use lib ('t/lib', 'lib', 'blib/arch');
20use Util qw (contents get_userinfo getcreds create_keyring);
21
22use CGI;
23use CGI::Cookie;
24use Date::Parse;
25use WebAuth qw(3.00 :const);
26use WebKDC ();
27use WebKDC::Config;
28use WebLogin;
29
30# Set our method to not have password tests complain.
31$ENV{REQUEST_METHOD} = 'POST';
32
33# Override the WebKDC package in order to put in our own version of a function
34# for testing.
35our ($TEST_STATUS, $TEST_ERROR);
36package WebKDC;
37no warnings 'redefine';
38sub make_request_token_request {
39    return ($TEST_STATUS, $TEST_ERROR);
40}
41use warnings 'redefine';
42package main;
43
44#############################################################################
45# Wrapper functions
46#############################################################################
47
48# Initialize the weblogin object, as we'll have to keep touching this over
49# and again.
50sub init_weblogin {
51    my $query = CGI->new ({});
52    $query->request_method ('POST');
53
54    my $weblogin = WebLogin->new (QUERY  => $query);
55    $weblogin->cgiapp_prerun;
56    $weblogin->param ('debug', 0);
57    $weblogin->param ('logging', 0);
58    $weblogin->param ('script_name', '/login');
59
60    return $weblogin;
61}
62
63#############################################################################
64# Environment setup
65#############################################################################
66
67# Disable all the memcached stuff for now.
68@WebKDC::Config::MEMCACHED_SERVERS = ();
69
70# Expiration to test against, as epoch seconds and text.
71my $expires_epoch = 1577865600;
72my $expires_text  = 'Wed, 01-Jan-2020 08:00:00 GMT';
73
74# For the tests, we want to assume we are remembering device login unless
75# otherwise told..
76$WebKDC::Config::REMEMBER_FALLBACK = 'yes';
77
78#############################################################################
79# Tests
80#############################################################################
81
82my ($status, $error);
83
84# Set up the KDC request with a factor cookie and verify it was found.
85my $weblogin = init_weblogin;
86my $cookie = CGI::Cookie->new (-name => 'webauth_wft', -value => 'test');
87$ENV{HTTP_COOKIE} = "$cookie";
88my %cart = CGI::Cookie->fetch;
89$status = $weblogin->setup_kdc_request (%cart);
90ok (!$status, 'setup_kdc_request with factor cookie works');
91ok ($weblogin->{request}->factor_token, '... and factor_token set');
92is ($weblogin->{request}->factor_token, 'test', '... to the right value');
93
94# Check again with no factor cookie.
95$weblogin = init_weblogin;
96$status = $weblogin->setup_kdc_request;
97$ENV{HTTP_COOKIE} = "";
98ok (!$status, 'setup_kdc_request without factor cookie works');
99is ($weblogin->{request}->factor_token, undef, '... and factor_token not set');
100
101# Check to see if we set a factor cookie when we should.  Requires digging
102# into the CGI::Application object a little.
103$weblogin = init_weblogin;
104$status = $weblogin->setup_kdc_request;
105$weblogin->{response}->cookie ('webauth_wft', 'test', $expires_epoch);
106my %args = (cookies => $weblogin->{response}->cookies);
107$weblogin->print_headers (\%args);
108$cookie = undef;
109for my $c (@{ $weblogin->{'__HEADER_PROPS'}{'-cookie'} }) {
110    if ($c->name eq 'webauth_wft') {
111        $cookie = $c;
112    }
113}
114is ($cookie->name, 'webauth_wft', 'Factor cookie was set');
115is ($cookie->expires, $expires_text, '... with the correct expiration time');
116
117# Check clearing the webauth cookie by giving it an empty value.
118$weblogin = init_weblogin;
119$status = $weblogin->setup_kdc_request;
120$weblogin->{response}->cookie ('webauth_wft', '', $expires_epoch);
121%args = (cookies => $weblogin->{response}->cookies);
122$weblogin->print_headers (\%args);
123$cookie = undef;
124for my $c (@{ $weblogin->{'__HEADER_PROPS'}{'-cookie'} }) {
125    if ($c->name eq 'webauth_wft') {
126        $cookie = $c;
127    }
128}
129is ($cookie->name, 'webauth_wft', 'Factor cookie was set');
130my $expires = str2time ($cookie->expires);
131is ($expires, time - 60 * 60 * 24, '... with the correct expiration time');
132
133# Check clearing the webauth cookie by setting the remember_login checkbox.
134$weblogin = init_weblogin;
135$weblogin->query->request_method ('GET');
136$status = $weblogin->setup_kdc_request;
137$weblogin->query->param (remember_login => 'no');
138$weblogin->{response}->cookie ('webauth_wft', 'test', $expires_epoch);
139%args = (
140    cookies      => $weblogin->{response}->cookies,
141    confirm_page => 1,
142);
143$weblogin->print_headers (\%args);
144$cookie = undef;
145for my $c (@{ $weblogin->{'__HEADER_PROPS'}{'-cookie'} }) {
146    if ($c->name eq 'webauth_wft') {
147        $cookie = $c;
148    }
149}
150is ($cookie->name, 'webauth_wft', 'Factor cookie on public computer was set');
151$expires = str2time ($cookie->expires);
152is ($expires, time - 60 * 60 * 24, '... and set to expire now');
153
154# Check that the webkdc-factor token is left unmodified when no cookies are
155# returned.
156$weblogin = init_weblogin;
157$status = $weblogin->setup_kdc_request;
158%args = (cookies => $weblogin->{response}->cookies);
159$weblogin->{request}->factor_token ('foo');
160$weblogin->print_headers (\%args);
161$cookie = undef;
162for my $c (@{ $weblogin->{'__HEADER_PROPS'}{'-cookie'} }) {
163    if ($c->name eq 'webauth_wft') {
164        $cookie = $c;
165    }
166}
167is ($cookie, undef, 'Factor token is left alone if no cookies are returned');
168
169# Check clearing the webauth cookie by not explicitly passing it.
170$weblogin = init_weblogin;
171$status = $weblogin->setup_kdc_request;
172%args = (cookies => $weblogin->{response}->cookies);
173$weblogin->{request}->factor_token ('foo');
174$weblogin->{response}->cookie ('webauth_wpt_krb5', 'test', $expires_epoch);
175$weblogin->print_headers (\%args);
176$cookie = undef;
177for my $c (@{ $weblogin->{'__HEADER_PROPS'}{'-cookie'} }) {
178    if ($c->name eq 'webauth_wft') {
179        $cookie = $c;
180    }
181}
182is ($cookie->name, 'webauth_wft',
183    'Factor cookie expired when not explicitly passed');
184$expires = str2time ($cookie->expires);
185is ($expires, time - 60 * 60 * 24, '... and set to expire now');
186
187# Check clearing the webauth cookie by not explicitly passing it when there
188# was no token from the client..
189$weblogin = init_weblogin;
190$status = $weblogin->setup_kdc_request;
191%args = (cookies => $weblogin->{response}->cookies);
192$weblogin->print_headers (\%args);
193$cookie = undef;
194for my $c (@{ $weblogin->{'__HEADER_PROPS'}{'-cookie'} }) {
195    if ($c->name eq 'webauth_wft') {
196        $cookie = $c;
197    }
198}
199is ($cookie, undef, 'Factor cookie not expired when not explicitly passed '
200    .'and none existed before');
201