Auth-Kokolores

 view release on metacpan or  search on metacpan

lib/Auth/Kokolores/Protocol/DovecotAuth.pm  view on Meta::CPAN


use MIME::Base64;

has 'major_version' => ( is => 'ro', isa => 'Int', default => 1 );
has 'minor_version' => ( is => 'ro', isa => 'Int', default => 1 );

has 'client_major_version' => ( is => 'rw', isa => 'Maybe[Str]' );
has 'client_minor_version' => ( is => 'rw', isa => 'Maybe[Str]' );
has 'client_pid' => ( is => 'rw', isa => 'Maybe[Str]' );

sub read_command {
  my ( $self, $expected ) = @_;
  my $line = $self->handle->getline;
  $line =~ s/[\r\n]*$//;
  my @fields = split("\t", $line);
  $self->log(4, 'recv cmd: '.join(', ', @fields));
  if( ! defined $fields[0] ) {
    die('protocol error: no command specified on line');
  }
  if( defined $expected && $fields[0] ne $expected ) {
    die('protocol error: expected command '.$expected.' got '.$fields[0]);
  }
  return @fields;
}

sub send_command {
  my ( $self, @cmd ) = @_;
  $self->log(4, 'send cmd: '.join(', ', @cmd));
  $self->handle->print( join("\t", @cmd)."\n" );
  return;
}

sub init_connection {
  my ( $self ) = @_;
  my ( $cmaj, $cmin, $cpid );
  ( undef, $cmaj, $cmin ) = $self->read_command('VERSION');
  ( undef, $cpid ) = $self->read_command('CPID');
  if( $cmaj ne $self->major_version ) {
    die('wrong major protocol version');
  }
  $self->client_major_version( $cmaj );
  $self->client_minor_version( $cmin );
  $self->client_pid( $cpid );
  $self->send_command('VERSION', $self->major_version, $self->minor_version);
  $self->send_command('SPID', $$);
  foreach my $mech ( keys %{$self->mechanisms} ) {
    $self->send_command('MECH', $mech,
      @{$self->mechanisms->{$mech}->{'parameters'}} );
  }
  $self->send_command('DONE');
  return;
}

sub shutdown_connection {
  my ( $self ) = @_;
  $self->last_auth_id(0);
  return:
}

has 'mechanisms' => (
  is => 'ro', isa => 'HashRef', lazy => 1,
  default => sub { {
    'LOGIN' => {
      parameters => [ 'plaintext '],
      handler => \&handle_login,
    },
    'PLAIN' => {
      parameters => [ 'plaintext '],
      handler => \&handle_plain,
    },
  } },
);

has 'last_auth_id' => ( is => 'rw', isa => 'Int', default => 0 );

sub read_auth_command {
  my $self = shift;
  my $cmd = {};
  my ( undef, $id, $mech, @params ) = $self->read_command('AUTH');

  while( my $p = shift @params ) {
    if( $p =~ /^resp=/ ) { # everything next is resp
      my $resp = join("\t", $p, @params);
      $resp = substr($resp, 5);
      $cmd->{'resp'} = $resp;
      last;
    } elsif( $p =~ /=/ ) {
      my ( $key, $value ) = split('=', $p, 2);
      $cmd->{$key} = $value;
    } else {
      $cmd->{$p} = 1;
    }
  }
  $cmd->{'mech'} = $mech;
  $cmd->{'id'} = $id;
  $self->{'last_auth_id'} = $id;

  return( $cmd );
}

sub _check_auth_id {
  my ( $self, $id ) = @_;
  if( defined $self->last_auth_id
      && $self->last_auth_id ne $id ) {
    die('protocol error: missmatch of AUTH ID');
  }
  return;
}

sub handle_login {
  my ( $self, $cmd ) = @_;
  my ( $id, $username, $password );

  $self->send_command('CONT', $self->last_auth_id,
    encode_base64('Username:'));
  ( undef, $id, $username ) = $self->read_command('CONT');
  $self->_check_auth_id( $id );
  $username = decode_base64( $username );

  $self->send_command('CONT', $self->last_auth_id,
    encode_base64('Password:'));



( run in 0.671 second using v1.01-cache-2.11-cpan-5511b514fd6 )