From ceb74195789fa4e7cb40a7116adc33f336584b34 Mon Sep 17 00:00:00 2001 From: Graham Todd Date: Thu, 6 Nov 2014 13:00:52 -0500 Subject: [PATCH 1/3] Add auth_imap plugin. --- plugins/auth/auth_imap | 99 +++++++++++++++++++++++++++++++++++ t/plugin_tests/auth/auth_imap | 25 +++++++++ 2 files changed, 124 insertions(+) create mode 100644 plugins/auth/auth_imap create mode 100644 t/plugin_tests/auth/auth_imap diff --git a/plugins/auth/auth_imap b/plugins/auth/auth_imap new file mode 100644 index 0000000..56e5b36 --- /dev/null +++ b/plugins/auth/auth_imap @@ -0,0 +1,99 @@ +#!/usr/bin/perl -w + +=head1 NAME auth_imap - Authenticate to an IMAP server + +=head1 DESCRIPTION This plugin authenticates against any IMAP server you wish (it also supports SSL). +You need to specify the IMAP server and port number in the plugins configuration file like so: + +auth/auth_imap 192.168.0.1 143 + +Without any options, it defaults to connecting to the IMAP server on localhost on port 143. + +This plugin requires the Net::IMAP::Simple::SSL CPAN module. Options from that module can be +added to the $server->() constructor below if your IMAP server requires older versions of SSL +rather than TLS, or for connection debugging ( debug => 1, ssl_version => "SSLv3", etc.). +While you can adjust these settings, the plugin should work as is for a typical IMAP server. + +See the Net::IMAP::Simple POD for details on how tune the constructor parameters. + +Note that auth_imap requires that you use AUTH PLAIN or AUTH LOGIN mechanisms which means +that communication between your e-mail client and Qpsmtpd - and between Qpsmtpd and your IMAP server - +should be encrypted. There are several approaches to enabling encrypted password storage +on the IMAP server as well. For dovecot2 see: http://wiki2.dovecot.org/HowTo/CRAM-MD5 + +This plugin is suited for authorizing user connections to a Qpsmtp SMTP server acting as a +relay or a primary mail server. The principal benefit is ease of adminstration when +an existing IMAP service is already established. + +head1 AUTHOR Christopher Heschong + +Edits to add SSL support and updated for latest qpsmtpd version - James Turnbull + +=head1 COPYRIGHT AND LICENSE Copyright (c) 2004 Christopher Heschong +This plugin is licensed under the same terms as the qpsmtpd package itself. +Please see the LICENSE file included with qpsmtpd for details. + +=cut + + +sub register { + my ($self, $qp, @args) = @_; + + if (@args > 0) { + if ($args[0] =~ /^([\.\w_-]+)$/) { + $self->{_imap_server} = $1; + } + else { + die "Bad data in imap server: $args[0]"; + } + $self->{_imap_port} = 143; + if (@args > 1 and $args[1] =~ /^(\d+)$/) { + $self->{_imap_port} = $1; + } + $self->log(LOGWARN, "WARNING: Ignoring additional arguments.") if (@args > 2); + } + else { + die("No IMAP server specified in plugins file."); + } + +# set any values that are not already + $self->{_imap_server} ||= "127.0.0.1"; + $self->{_imap_port} ||= 143; + + $self->register_hook( "auth-login", "auth_imap" ); + $self->register_hook( "auth-plain", "auth_imap" ); +} + +sub auth_imap { + +use Net::IMAP::Simple::SSL; + + my ($self, $transaction, $mechanism, $user, $clearPassword, $hashPassword, $ticket) = @_; + my ($imaphost, $imapport, $imapserver); + +# pull values in from config + $imaphost = $self->{_imap_server}; + $imapport = $self->{_imap_port}; + $imapserver = "$imaphost:$imapport"; + + $self->log(LOGINFO, "SMTP server requires IMAP authentication before sending"); + +# connect to IMAP server +my $server = Net::IMAP::Simple->new( $imapserver, ssl_version => "TLSv1", ); + +if ( $server ) { + $self->log(LOGINFO, "Using $mechanism mechanism with server: $imapserver"); +} +else { + return ( DENY, "auth_imap - could not connect to $imapserver" ); +} + +if ( $server->login( $user, $clearPassword, ) ) { + $self->log(LOGINFO, "Authenticating user: $user with IMAP"); + return OK, "auth_imap/$mechanism" ; +} +else { + return ( DENY, "auth_imap - invalid password for $user at $imapserver" ); +} + +} diff --git a/t/plugin_tests/auth/auth_imap b/t/plugin_tests/auth/auth_imap new file mode 100644 index 0000000..d5339dd --- /dev/null +++ b/t/plugin_tests/auth/auth_imap @@ -0,0 +1,25 @@ +#!perl -w +use Test::More tests => 2; +use strict; +use lib 't'; + + +use_ok('Net::IMAP::Simple'); + +sub auth_imap { + + use Net::IMAP::Simple::SSL; + + my ($imaphost, $imapport, $imapserver); + + $imaphost = "imap.gmail.com"; + $imapport = "993"; + $imapserver = "$imaphost:$imapport"; + + my $server = Net::IMAP::Simple->new($imapserver, use_ssl => 1,) + or return ("auth_imap - could not connect to $imapserver"); +} + + +ok(auth_imap, "auth_imap, connected to imap.gmail.com"); + From fc50cc26298a16bc3128665b16fde37042b2aeb6 Mon Sep 17 00:00:00 2001 From: Graham Todd Date: Thu, 6 Nov 2014 15:37:40 -0500 Subject: [PATCH 2/3] Update pull request with suggested changes from feedback. --- plugins/auth/auth_imap | 116 ++++++++++++++++++---------------- t/plugin_tests/auth/auth_imap | 5 +- 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/plugins/auth/auth_imap b/plugins/auth/auth_imap index 56e5b36..f8cadb3 100644 --- a/plugins/auth/auth_imap +++ b/plugins/auth/auth_imap @@ -1,5 +1,5 @@ -#!/usr/bin/perl -w - +#!perl -w + =head1 NAME auth_imap - Authenticate to an IMAP server =head1 DESCRIPTION This plugin authenticates against any IMAP server you wish (it also supports SSL). @@ -11,7 +11,7 @@ Without any options, it defaults to connecting to the IMAP server on localhost o This plugin requires the Net::IMAP::Simple::SSL CPAN module. Options from that module can be added to the $server->() constructor below if your IMAP server requires older versions of SSL -rather than TLS, or for connection debugging ( debug => 1, ssl_version => "SSLv3", etc.). +rather than TLS or for connection debugging ( debug => 1, ssl_version => "SSLv3", etc.). While you can adjust these settings, the plugin should work as is for a typical IMAP server. See the Net::IMAP::Simple POD for details on how tune the constructor parameters. @@ -19,7 +19,7 @@ See the Net::IMAP::Simple POD for details on how tune the constructor parameters Note that auth_imap requires that you use AUTH PLAIN or AUTH LOGIN mechanisms which means that communication between your e-mail client and Qpsmtpd - and between Qpsmtpd and your IMAP server - should be encrypted. There are several approaches to enabling encrypted password storage -on the IMAP server as well. For dovecot2 see: http://wiki2.dovecot.org/HowTo/CRAM-MD5 +on the IMAP server. For dovecot2 see: http://wiki2.dovecot.org/HowTo/CRAM-MD5 This plugin is suited for authorizing user connections to a Qpsmtp SMTP server acting as a relay or a primary mail server. The principal benefit is ease of adminstration when @@ -35,65 +35,69 @@ Please see the LICENSE file included with qpsmtpd for details. =cut - -sub register { - my ($self, $qp, @args) = @_; - +use Net::IMAP::Simple; + +sub register { + my ($self, $qp, @args) = @_; + if (@args > 0) { - if ($args[0] =~ /^([\.\w_-]+)$/) { - $self->{_imap_server} = $1; + if ($args[0] =~ /^([\.\w_-]+)$/) { + $self->{_imap_server} = $1; + } + else { + die "Bad data in imap server: $args[0]"; + } + $self->{_imap_port} = 143; + if (@args > 1 and $args[1] =~ /^(\d+)$/) { + $self->{_imap_port} = $1; + } + $self->log(LOGWARN, "WARNING: Ignoring additional arguments.") + if (@args > 2); } else { - die "Bad data in imap server: $args[0]"; + die("No IMAP server specified in plugins file."); } - $self->{_imap_port} = 143; - if (@args > 1 and $args[1] =~ /^(\d+)$/) { - $self->{_imap_port} = $1; - } - $self->log(LOGWARN, "WARNING: Ignoring additional arguments.") if (@args > 2); - } - else { - die("No IMAP server specified in plugins file."); - } - -# set any values that are not already + + # set any values that are not already $self->{_imap_server} ||= "127.0.0.1"; - $self->{_imap_port} ||= 143; + $self->{_imap_port} ||= 143; - $self->register_hook( "auth-login", "auth_imap" ); - $self->register_hook( "auth-plain", "auth_imap" ); -} - -sub auth_imap { - -use Net::IMAP::Simple::SSL; - - my ($self, $transaction, $mechanism, $user, $clearPassword, $hashPassword, $ticket) = @_; - my ($imaphost, $imapport, $imapserver); - -# pull values in from config - $imaphost = $self->{_imap_server}; - $imapport = $self->{_imap_port}; - $imapserver = "$imaphost:$imapport"; - - $self->log(LOGINFO, "SMTP server requires IMAP authentication before sending"); - -# connect to IMAP server -my $server = Net::IMAP::Simple->new( $imapserver, ssl_version => "TLSv1", ); - -if ( $server ) { - $self->log(LOGINFO, "Using $mechanism mechanism with server: $imapserver"); -} -else { - return ( DENY, "auth_imap - could not connect to $imapserver" ); + $self->register_hook("auth-login", "auth_imap"); + $self->register_hook("auth-plain", "auth_imap"); } -if ( $server->login( $user, $clearPassword, ) ) { - $self->log(LOGINFO, "Authenticating user: $user with IMAP"); - return OK, "auth_imap/$mechanism" ; -} -else { - return ( DENY, "auth_imap - invalid password for $user at $imapserver" ); -} +sub auth_imap { + + my ($self, $transaction, $mechanism, $user, $clearPassword, $hashPassword, + $ticket) + = @_; + my ($imaphost, $imapport, $imapserver); + + # pull values in from config + $imaphost = $self->{_imap_server}; + $imapport = $self->{_imap_port}; + $imapserver = "$imaphost:$imapport"; + + $self->log(LOGINFO, + "SMTP server requires IMAP authentication before sending"); + + # connect to IMAP server + my $server = Net::IMAP::Simple->new($imapserver, ssl_version => "TLSv1",); + + if ($server) { + $self->log(LOGINFO, + "Using $mechanism mechanism with server: $imapserver"); + } + else { + return (DENY, "auth_imap - could not connect to $imapserver"); + } + + if ($server->login($user, $clearPassword,)) { + $self->log(LOGINFO, "Authenticating user: $user with IMAP"); + return OK, "auth_imap/$mechanism"; + } + else { + return (DENY, "auth_imap - invalid password for $user at $imapserver"); + } } diff --git a/t/plugin_tests/auth/auth_imap b/t/plugin_tests/auth/auth_imap index d5339dd..2c2c76f 100644 --- a/t/plugin_tests/auth/auth_imap +++ b/t/plugin_tests/auth/auth_imap @@ -18,8 +18,9 @@ sub auth_imap { my $server = Net::IMAP::Simple->new($imapserver, use_ssl => 1,) or return ("auth_imap - could not connect to $imapserver"); + sleep 1; + $server->quit; } -ok(auth_imap, "auth_imap, connected to imap.gmail.com"); - +ok(auth_imap, "auth_imap, connected to imap.gmail.com for a sec"); From 29f12626a0a922d52924c5be7b6f18c23acaa1a0 Mon Sep 17 00:00:00 2001 From: Graham Todd Date: Sat, 15 Nov 2014 08:40:34 -0500 Subject: [PATCH 3/3] perltidy -b t/plugin_tests/auth/auth_imap --- t/plugin_tests/auth/auth_imap | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/t/plugin_tests/auth/auth_imap b/t/plugin_tests/auth/auth_imap index 2c2c76f..0998452 100644 --- a/t/plugin_tests/auth/auth_imap +++ b/t/plugin_tests/auth/auth_imap @@ -3,24 +3,22 @@ use Test::More tests => 2; use strict; use lib 't'; - use_ok('Net::IMAP::Simple'); sub auth_imap { - use Net::IMAP::Simple::SSL; + use Net::IMAP::Simple::SSL; - my ($imaphost, $imapport, $imapserver); + my ($imaphost, $imapport, $imapserver); - $imaphost = "imap.gmail.com"; - $imapport = "993"; - $imapserver = "$imaphost:$imapport"; + $imaphost = "imap.gmail.com"; + $imapport = "993"; + $imapserver = "$imaphost:$imapport"; - my $server = Net::IMAP::Simple->new($imapserver, use_ssl => 1,) - or return ("auth_imap - could not connect to $imapserver"); - sleep 1; - $server->quit; + my $server = Net::IMAP::Simple->new($imapserver, use_ssl => 1,) + or return ("auth_imap - could not connect to $imapserver"); + sleep 1; + $server->quit; } - ok(auth_imap, "auth_imap, connected to imap.gmail.com for a sec");