package Net::IMAP::Server::DefaultAuth;

use warnings;
use strict;

use base 'Class::Accessor';
__PACKAGE__->mk_accessors(qw(user));

=head1 NAME

Net::IMAP::Server::DefaultAuth - Encapsulates per-connection
authorization information for an IMAP user.

=head1 DESCRIPTION

IMAP credentials are passed in one of two ways: using the L<LOGIN>
command, or the C<AUTHENTICATE> command.  L<LOGIN> sends the password
unencrypted; note, however, that L<Net::IMAP::Server> will not allow
the LOGIN command unless the connection is protected by either SSL or
TLS.  Thus, even when the C<LOGIN> command is used, the password is
not sent in the clear.

The default implementation accepts any username and password.  Most
subclasses will simply want to override L</auth_plain>, unless they
need to implement other forms of authorization than C<LOGIN> or
C<AUTHENTICATE PLAIN>.

=cut

=head1 METHODS

=head2 user [VALUE]

Gets or sets the plaintext username of the authenticated user.

=head2 provides_plain

If L</provides_plain> returns true (the default), C<LOGIN> capability
will be advertised when under a layer, and L</auth_plain> will be
called if the user sends the C<LOGIN> command.

=cut

sub provides_plain { return 1; }

=head2 auth_plain USER, PASSWORD

Returns true if the given C<USER> is allowed to log in using the
provided C<PASSWORD>.  This should also set L</user> to the username
if login was successful.  This path is used by both C<LOGIN> and
C<AUTHENTICATE PLAIN> commands.

=cut

sub auth_plain {
    my $self = shift;
    my ( $user, $pass ) = @_;
    $self->user($user);
    return 1;
}

=head2 sasl_provides

The C<AUTHENTICATE> command checks that the provided SASL
authentication type is in the list that L</sasl_provides> returns.  It
defaults to only C<PLAIN>.

=cut

sub sasl_provides {
    my $self = shift;
    return ("PLAIN");
}

=head2 sasl_plain

Called when the client requests C<PLAIN> SASL authentication.  This
parses the SASL protocol, and defers to L</auth_plain> to determine if
the username and password is actually allowed to log in.

=cut

sub sasl_plain {
    my $self = shift;
    return sub {
        my $line = shift;
        return \"" unless $line;

        my ( $authz, $user, $pass ) = split /\x{0}/, $line, 3;
        return $self->auth_plain( $user, $pass );
    };
}

=head1 IMPLEMENTING NEW SASL METHODS

The L</sasl_plain> method is a simple example of implementing a SASL
protocol, albeit a very simple one.  SASL authentication methods
should expect to be called with no arguments, and should return an
anonymous function, which will be called each time the client
transmits more information.

Each time it is called, it will be passed the client data, which will
already have been base-64 decoded (the exception being the first time
it is called, when it will be called with the empty string).

If the function returns a scalar reference, the scalar will be base-64
encoded and transmitted to the client.  Anything which is not a scalar
reference will be interpreted as a boolean, as to whether the
authentication was successful.  Successful authentications should be
sure to set L</user> themselves.

=cut

1;
