package OATHusers; #---AUTOPRAGMASTART--- use 5.012; use strict; use warnings; use diagnostics; use mro 'c3'; use English qw( -no_match_vars ); use Carp; our $VERSION = 0.996; #---AUTOPRAGMAEND--- use Authen::OATH; sub new { my $class = shift; my $self = bless {}, $class; my %seeds = ( 'tye' => { key_id => '000001', pin => '2412', seed => uc('aaaaaaaaabbbbbbbbbbbbbbccccccccccddddddd'), }, 'browseruk'=> { key_id => '222222', pin => '4242', seed => uc('0101010101010101010101010101010101010101'), }, 'reaper' => { key_id => '9', pin => 'SIGKILL', seed => uc('1231231231231231231231231231231231231231'), }, ); $self->{seeds} = \%seeds; return $self; } sub validate { my ($self, $username, $password) = @_; # Missing fields if(!defined($username) || !defined($password) || $username eq '' || $password eq '') { return 0; } # Unknown username if(!defined($self->{seeds}->{$username})) { return 0; } # For the easy part: Check length of password if(length($password) != (length($self->{seeds}->{$username}->{pin}) + 6)) { return 0; } my $oath = Authen::OATH->new(timestep => 60); my $valid = 0; my $now = time; my $userseed = $self->{seeds}->{$username}->{seed}; for(my $i = -300; $i <= 300; $i += 60) { # Search +/- 5 minutes my $totp = $oath->totp($userseed, $now + $i); my $fullpass = $self->{seeds}->{$username}->{pin} . $totp; if($fullpass eq $password) { print "$username key drift $i\n"; $valid = 1; last; } } return $valid; } 1;