Authenticating Users with SASL for Postfix
Continued from setting up Postfix - SMTP and TLS - on an Amazon Cloud EC2 instance:http://websitenotebook.blogspot.com/2013/03/configuring-tls-on-postfix-redhat-aws.html
Simple Authentication and Security Layer
http://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer
Simple Authentication and Security Layer (SASL) is a framework for authentication and data security in Internet protocols. It decouples authentication mechanisms from application protocols, in theory allowing any authentication mechanism supported by SASL to be used in any application protocol that uses SASL.
saslauthd is not a part of Postfix per se. It is a used by and integrated with Postfix to support authentication of users (users login functionality).
Postfix works with two different implementations of SASL: Cyrus and Dovecot
Not a fan of the curly braces configuration files in Dovecot so going to try Cyrus.
Basically when you type testsaslauthd you aren't testing Postfix. You are just testing that a user can authenticate with saslauthd. If you don't have the correct hook up between Postfix and saslauthd then you'll authenticate but won't get you to Postfix functionality.
Now let's try to decipher the Postfix documentation...
Configuring Cyrus saslauthd implementation to work with PAM for Postfix
http://www.postfix.org/SASL_README.html
Configuring Cyrus SASL
There may be a different configuration file for each application Cyrus provides authentication for within Postfix (SMTP, POP, IMAP, etc).The first step configuring Cyrus SASL is to determine name andlocation of a configuration file that describes how the PostfixSMTP server will use the SASL framework.
The name of the configuration file (default:
smtpd.conf
)is configurable.The configuration file used by Cyrus is a concatentation of the value in the configuration file (smtpd by default) and .conf.
i.e. by default the value in your config file is smtpd + .conf so the default configuration file is smtpd.conf
Configuration variables in main.cf for smtpd:
/etc/postfix/main.cf: # Postfix 2.3 and later smtpd_sasl_path = smtpd # Postfix < 2.3 smtpd_sasl_application_name = smtpd
Cyrus SASL configuration file directory
The location where Cyrus SASL searches for the named file dependson the Cyrus SASL version and the OS/distribution used. [Worked fine on my AWS ec2 instance. Skipping the details]
Note Cyrus SASL searches /usr/lib/sasl2/
first. If itfinds the specified configuration file there, it will not examineother locations. [On my Amazon EC2 instance -- I did find sasl2 in this directory.]
Postfix to Cyrus SASL user databases
The SASL library uses one of the following for user database which are discussed in the Postfix documentation.
authentication backend password verification service / plugin /etc/shadow saslauthd PAM saslauthd IMAP server saslauthd sasldb sasldb MySQL, PostgreSQL, SQLite sql LDAP ldapdb
saslauthd - Cyrus SASL password verification service
Communication between the Postfix SMTP server (read: Cyrus SASL'slibsasl
) and the saslauthd
server takesplace over a UNIX-domain socket.saslauthd
usually establishes the UNIX domainsocket in /var/run/saslauthd/
and waits for authenticationrequests. The Postfix SMTP server must have read+execute permissionto this directory or authentication attempts will fail. Important Some distributions require the userThe following example configures the Cyrus SASL library tocontactpostfix
to bemember of a special group e.g.sasl
, otherwise itwill not be able to access thesaslauthd
socketdirectory. [Note: I did not see this group on my AWS EC2 instance]
saslauthd
as its password verification service:/etc/sasl2/smtpd.conf: pwcheck_method: saslauthd mech_list: PLAIN LOGIN
Important Do not specify any other mechanisms inmech_list
thanPLAIN
orLOGIN
when usingsaslauthd
! It can only handle these two mechanisms,and authentication will fail if clients are allowed to choose othermechanisms.
Important Plaintext mechanisms (Additionally thePLAIN
,LOGIN
)send credentials unencrypted. This information should be protectedby an additional security layer such as a TLS-encrypted SMTP session [see my last post:(http://websitenotebook.blogspot.com/2013/03/configuring-tls-on-postfix-redhat-aws.html)]
saslauthd
server itself must beconfigured. It must be told which authentication backend to turnto for password verification. The backend is selected with asaslauthd
command-line option and will be shown in thefollowing examples. Note Some distributions use a configuration file to provide saslauthdcommand line options to set e.g. the authentication backend. Typicallocations are/etc/sysconfig/saslauthd
or/etc/default/saslauthd
.
Using saslauthd with /etc/shadow
Access to the/etc/shadow
system password filerequires root
privileges. [I stopped here. Next option...]Using saslauthd with PAM
Cyrus SASL can use the PAM framework to authenticate credentials.saslauthd
uses the PAM framework when started likethis: %saslauthd -a pam
In other words, stop saslauthd if already running and start it again as shown above
sudo service saslauthd stop
sudo saslauthd -a pam
Note PAM configuration for the Postfix SMTP server is usually givenin /etc/pam.d/smtp
and is beyond the scope of thisdocument.
See section "Testing saslauthdauthentication" for test instructions.Using saslauthd with an IMAP server
[Not doing this...so skipping]
Testing saslauthd authentication
[
Um...it would have explained that users for this option are system users on the Linux box, unlike other options listed in the documentation.
useradd newuser
passwd newuser [enter new password at prompt).
For this option you do *not* use saslpasswd or saslpasswd2
]
Cyrus SASL provides the
testsaslauthd
utility totest saslauthd
authentication.[For the record the user name should *not* have the domain name on it like other options. You may find some documentation for other variants which indicate domain name is needed - not in this case
]
[the above worked for me. I didn't need any of the following mumbo jumbo]%testsaslauthd -u username -p password
0: OK "Success."
Note Sometimes theSpecify an additional "testsaslauthd
program is not distributedwith a the Cyrus SASL main package. In that case, it may bedistributed with-devel
,-dev
or-debug
packages.
-s smtp
" if saslauthd
was configured to contact the PAM authentication framework, andspecify an additional "-f /path/to/socketdir/mux
"if saslauthd
establishes the UNIX-domain socket in anon-default location.If authentication succeeds, proceed with the section "Enabling SASL authentication and authorizationin the Postfix SMTP server".
Cyrus SASL Plugins - auxiliary propertyplugins
Didn't use any of these...The sasldb plugin
Or this..tried it with no success but I can tell you that you should add a 2 to the end of most commands if using the latest version.Enabling SASL authentication andauthorization in the Postfix SMTP server
By default the Postfix SMTP server uses the Cyrus SASLimplementation.[skipping Dovecot text here]
Enabling SASL authenticationin the Postfix SMTP server
Regardless of the SASL implementation type, enabling SMTPauthentication in the Postfix SMTP server always requires settingthe
smtpd_sasl_auth_enable
option: After a "postfix reload", SMTP clients will see the additionalcapability AUTH in an SMTP session, followed by a list ofauthentication mechanisms the server supports:/etc/postfix/main.cf: smtpd_sasl_auth_enable = yes
However not all clients recognize the AUTH capability as definedby the SASL authentication RFC. Some historical implementations expect theserver to send an "% telnet server.example.com 25...220 server.example.com ESMTP PostfixEHLO client.example.com250-server.example.com250-PIPELINING250-SIZE 10240000250-AUTH DIGEST-MD5 PLAIN CRAM-MD5...
=
" as separator between the AUTHverb and the list of mechanisms that follows it. The
broken_sasl_auth_clients
configuration optionlets Postfix repeat the AUTH statement in a form that these brokenclients understand: /etc/postfix/main.cf: broken_sasl_auth_clients = yes
Note Enable this option for Outlook up to and including version 2003and Outlook Express up to version 6. This option does not hurt otherclients.After "postfix reload", the Postfix SMTP server will propagatethe AUTH capability twice - once for compliant and once for brokenclients:
% telnet server.example.com 25...220 server.example.com ESMTP PostfixEHLO client.example.com250-server.example.com250-PIPELINING250-SIZE 10240000250-AUTH DIGEST-MD5 PLAIN CRAM-MD5250-AUTH=DIGEST-MD5 PLAIN CRAM-MD5...
Postfix SMTP Server policy- SASL mechanism properties
The Postfix SMTP server supports policies that limit the SASLmechanisms that it makes available to clients, based on the propertiesof those mechanisms. The next two sections give examples of howthese policies are used.Property | Description |
---|---|
noanonymous | Don't use mechanisms that permitanonymous authentication. |
noplaintext | Don't use mechanisms that transmitunencrypted username and password information. |
nodictionary | Don't use mechanisms that arevulnerable to dictionary attacks. |
forward_secrecy | Require forward secrecy betweensessions (breaking one session does not break earlier sessions). |
mutual_auth | Use only mechanisms that authenticateboth the client and the server to each other. |
Unencrypted SMTP session
The default policy is to allow any mechanism in the Postfix SMTP serverexcept for those based on anonymous authentication:/etc/postfix/main.cf: # Specify a list of properties separated by comma or whitespace smtpd_sasl_security_options = noanonymous
Important Always set at least the noanonymous
option.Otherwise, the Postfix SMTP server can give strangers the sameauthorization as a properly-authenticated client.
Encrypted SMTP session (TLS)
A separate parameter controls Postfix SASL mechanism policyduring a TLS-encrypted SMTP session. The default is to copy thesettings from the unencrypted session:A more sophisticated policy allows plaintext mechanisms, butonly over a TLS-encrypted connection:/etc/postfix/main.cf: smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
To offer SASL authentication only after a TLS-encrypted session has beenestablished specify this:/etc/postfix/main.cf: smtpd_sasl_security_options = noanonymous, noplaintext smtpd_sasl_tls_security_options = noanonymous
/etc/postfix/main.cf: smtpd_tls_auth_only = yes
Enabling SASL authorization in the PostfixSMTP server
After the client has authenticated with SASL, the Postfix SMTPserver decides what the remote SMTP client will be authorizedfor. Examples of possible SMTP clients authorizations are:- Send a message to a remote recipient.
- Use a specific envelope sender in the MAIL FROM command.
Mail relay authorization
Withpermit_sasl_authenticated
the Postfix SMTPserver can allowSASL-authenticated SMTP clients to send mail to remote destinations.Examples:# With Postfix 2.10 and later, the mail relay policy is# preferably specified under smtpd_relay_restrictions./etc/postfix/main.cf: smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated reject_unauth_destination# Older configurations combine relay control and spam control under# smtpd_recipient_restrictions. To use this example with Postfix ≥# 2.10 specify "smtpd_relay_restrictions="./etc/postfix/main.cf: smtpd_recipient_restrictions = permit_mynetworks permit_sasl_authenticated reject_unauth_destination ...other rules...
Skipping other options
Testing SASL authentication in the Postfix SMTP Server
To test the server side, connect (for example, withtelnet
) to the Postfix SMTP server port and you shouldbe able to have a conversation as shown below. Information sent bythe client (that is, you) is shown in bold font.% telnet server.example.com 25...220 server.example.com ESMTP PostfixEHLO client.example.com250-server.example.com250-PIPELINING250-SIZE 10240000250-ETRN250-AUTH DIGEST-MD5 PLAIN CRAM-MD5250 8BITMIMEAUTH PLAIN AHRlc3QAdGVzdHBhc3M=235 Authentication successful
And...let the errors begin...checking the logs I see:
I set up port 25 with no tls to test plain login (since testing on a secure TLS port can't see anything). I didn't exactly read the above and with TLS you first must establish the TLS connection, then do the authentication, which you can't do through Telent (see next test).
The problem is a mis-match between smtpd_sasl_security_options
(e.g., noplaintext) and the available server mechanisms (e.g.,
plaintext only).
In otherwords remove noplaintext from main.cf because we're using TLS to encrypt traffic. OK now I can connect again...
And I see AUTH PLAIN LOGIN when I telnet to the server on port 25 and do an EHLO (see previous post for more info)
Next error. Tried test above to test a login from Telnet
AUTH PLAIN AHRlc3QAdGVzdHBhc3M=
Ok darnitalll now we have a new error...I test using the telnet example shown above and I get this error:
535 5.7.8 Error: authentication failed: no mechanism available.
I found that in my smtpd.conf file I had a space instead of an underscore in pw
Restart - no dice.
Out of curiosity I search for smtpd.conf and find three versions:
/usr/lib/sasl2/smtpd.conf
/var/run/saslauthd/smtpd.conf
/etc/sasl2/smtpd.conf
Which one is being used? The documentation above says the first in the list.
Not true!! Argh.
/var/run/saslauthd/smtpd.conf was empty. I renamed it and restarted - same error.
Then I checked /etc/sasl2/smtpd.conf and I had altered that file at some point. I changed pwd_check back to saslauthd.
Restart.
Authentication successful! Oh the agony of unhelpful error messages and inaccurate documentation and open source crypticness....yes I just made that word up.
Now. Let's see about authentication over TLS...crossing fingers.
So first I test from an app that was working fine before I moved everything to the Amazon cloud. Sending an email from a web site. No dice.
I can see that my web app is able to connect to and negotiate a connection with the mail server because I see the connection attempt in the maillog
sudo tail -f /var/log/maillog
lost connection after UNKNOWN from unknown
disconnect from unknown
I can only assume at this point it's some kind of problem with TLS or relay.
So let's try this example below and see what happens...
To test this over a connection that is encrypted with TLS, use
openssl s_client
instead of telnet
:Lovely. Again no worky. Does anyone find this as painful as I do yet?% openssl s_client -connect server.example.com:25 -starttls smtp...220 server.example.com ESMTP PostfixEHLO client.example.com...see above example for more...
getaddrinfo: Name or service not known
connect:errno=2
Oops. Typed the example and forgot to change domain name.
Here's a page with some error codes:
http://tud.at/programm/apache-ssl-win32-howto.php3
ok typing with correct domain it seems to attempt to connect to TLS but times out:
socket: Connection timed out
connect:errno=110
And in the case of a local connection from the same box using domain name it times out so maybe it's VPC/firewall thing. Try the local IP: 127.0.0.1 instead of the domain name.
Ok something useful at least. Maybe:
139834971027272:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:766:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 228 bytes and written 206 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
I found some sites suggesting to take the passphrase off the key -- same error
http://www.mnxsolutions.com/apache/removing-a-passphrase-from-an-ssl-key.html
Could be a problem with OpenSSL library - not sure yet.
http://comments.gmane.org/gmane.mail.postfix.user/228998
Instead of
AHRlc3QAdGVzdHBhc3M=
, specify thebase64-encoded form of \0username\0password
(the \0is a null byte). The example above is for a user named `test
'with password `testpass
'. Caution When posting logs of the SASL negotiations to public lists,please keep in mind that username/password information is trivialto recover from the base64-encoded form.You can use one of the following commands to generate base64encoded authentication information:
- Using a recent version of the bash shell:
% echo -ne '\000username\000password' | openssl base64
- Using the printf command:
% printf '\0%s\0%s' 'username' 'password' | openssl base64% printf '\0%s\0%s' 'username' 'password' | mmencode
- Using Perl MIME::Base64:
% perl -MMIME::Base64 -e \ 'print encode_base64("\0username\0password");'