Squid authentication via POP or IMAP

Why do this?

It is of­ten ob­vi­ous­ly need­ed to re­strict web ac­cess based on user­names and pass­word­s, rather than IP num­ber­s, spe­cial­ly if users switch com­put­ers of­ten (ex­am­ple, a com­put­er lab in a school).

The usu­al ways to han­dle this are:

PAM authentication for Squid
This makes Squid use the system’s list of users to identify the clients. The problem is, of course, that then you need to have all the users defined in the Squid system, or something involving remote PAM authentication, which is non-trivial sometimes.
NTLM authentication for Squid
This uses the windows session credentials to check identity against a Windows Domain Controller. The issues here for Linux clients are obvious. Besides, sometimes people don’t start sessions, or have generic sessions shared between many users.
Apache style password files
The same problems as PAM, and you don’t have the chance to authenticate remotely.

So, here’s an­oth­er so­lu­tion: make Squid check the us­er and pass­word against a POP or IMAP ac­coun­t. As long as ev­ery­one has a mail ac­count on some serv­er (all users in the same server, if you want this to be sim­ple), this should work.

External Authentication Programs

Squid us­es ex­ter­nal pro­grams to han­dle the au­then­ti­ca­tion. Here are sim­ple ver­sions writ­ten in Python. feel free ­to write bet­ter ones in oth­er lan­guages and send them to me.

POP3 external authentication program for Squid
#!/usr/bin/env python

from poplib import POP3
import sys


#POP server against which we authenticate
server="127.0.0.1"
#Port number for POP server. Usually 110
port=110


#Below here you shouldn't need to edit anything

while 1:

    #Read user and password from stdin, remove the newline, split at the space
    #and assign to the user and password variables

    line=sys.stdin.readline()[:-1]
    [user,password]=line.split(' ')

    #Connect to the POP server

    p=POP3(server,port)

    #Try to authenticate. If it doesn't work, it throws an exception

    try:
            p.user(user)
            p.pass_(password)
    except:

            #If it threw an exception, log in cache.log the ayth booboo
            sys.stderr.write("ERR authenticating %s\n"%user)
            #Then deny access
            sys.stdout.write("ERR\n")
            #IMPORTANT!!!!!!!!!!!! Flush stdout
            sys.stdout.flush()
            continue

    #If it didn't throw exceptions, that means it authenticated

    #Log success to cache.log
    sys.stderr.write("OK authenticated %s\n"%user)
    #Then allow access
    sys.stdout.write("OK\n")
    sys.stdout.flush()

The IMAP ver­sion is bet­ter be­cause POP ac­cess of­ten locks the mail­box, so you could have au­then­ti­ca­tion fail­ures in the proxy is the us­er is read­ing his mail at the same time. As you can see, the pro­grams are pret­ty much the same.

Of course, it is pos­si­ble to write ver­sions that use se­cure POP, or TL­S, or APOP. Since I don’t need them, I won’t write them, but it is pos­si­ble if you write them ;-)

IMAP external authentication program for Squid
#!/usr/bin/env python

from imaplib import IMAP4
import sys


#IMAP server against which we authenticate
server="127.0.0.1"
#Port number for IMAP server. Usually 143
port=143


#Below here you shouldn't need to edit anything

while 1:

    #Read user and password from stdin, remove the newline, split at the space
    #and assign to the user and password variables

    line=sys.stdin.readline()[:-1]
    [user,password]=line.split(' ')

    #Connect to the IMAP server

    p=IMAP4(server,port)

    #Try to authenticate. If it doesn't work, it throws an exception

    try:
            p.login(user,password)
    except:

            #If it threw an exception, log in cache.log the auth booboo
            sys.stderr.write("ERR authenticating %s\n"%user)
            #Then deny access
            sys.stdout.write("ERR\n")
            #IMPORTANT!!!!!!!!!!!! Flush stdout
            sys.stdout.flush()
            continue

    #If it didn't throw exceptions, that means it authenticated

    #Log success to cache.log
    sys.stderr.write("OK authenticated %s\n"%user)
    #Then allow access
    sys.stdout.write("OK\n")
    sys.stdout.flush()

Making Squid use this

Save the script you want to use some­where, like /us­r/bin/squidauth.py and make sure it has ex­e­cu­tion per­mis­sion for the squid us­er.

Then you have to ad­d, in your squid.­con­f, a line like this:

au­then­ti­cate_pro­gram /us­r/bin/squidauth.py

That al­lows squid to use our au­then­ti­ca­tion prog­gy. Now, you can start adding ACLs of type prox­y_auth, and y­ou can use them in http_ac­cess com­mand­s.

For ex­am­ple, this cre­ates an ACL called users and al­lows on­ly users with a valid POP ac­count to ac­cess the we­b:

Squid Configuration File Snippet (Squid 2.4)
authenticate_program /usr/bin/squidauth.py
acl users proxy_auth REQUIRED
http_access allow users
http_access deny all
Squid Configuration File Snippet (Squid 2.5)
auth_param basic program /usr/bin/squidauth.py
auth_param basic realm Proxy Server
acl users proxy_auth REQUIRED
http_access allow users
http_access deny all

You can find a much bet­ter de­scrip­tion of how to con­fig­ure this in the Squid guide. Spe­cial­ly here and here

Important URLs

Comments

Comments powered by Disqus
Contents © 2000-2013 Roberto Alsina
Share