Project

General

Profile

Actions

Mod auth » History » Revision 53

« Previous | Revision 53/91 (diff) | Next »
Anonymous, 2020-05-05 16:36


Module mod_auth - Using Authentication

Warning

mod_rewrite rules (url.rewrite*, not url.rewrite-if-not-file) are always executed before everything else, and the request gets restarted. So your mod_auth configuration must match the rewritten urls!

Supported Methods

lighttpd supports authentication methods described by
RFC 7616 and RFC 7617:

basic

The Basic method transfers the username and the password in
cleartext over the network (base64 encoded). It is strongly
recommended that Basic auth be used over an encrypted
channel between client and server.

digest

The Digest method only transfers a hashed value over the
network which is much safer than Basic auth, but still
cryptographically weak. It is strongly recommended
that Digest auth be used over an encrypted channel
between client and server.

Backends

Depending on the method lighttpd provides various way to store
the credentials used for the authentication.

For basic auth:
  • plain
  • htpasswd
  • htdigest
  • ldap
  • gssapi
  • mysql
  • pam
  • sasl
For digest auth:
  • plain
  • htdigest

plain (mod_authn_file)

A file which contains username and the cleartext password
seperated by a colon. Each entry is terminated by a single
newline.

e.g.:

agent007:secret

htpasswd (mod_authn_file)

A file which contains username and the crypt()'ed password
seperated by a colon. Each entry is terminated by a single
newline.

e.g.:

agent007:XWY5JwrAVBXsQ

You can use htpasswd from the apache distribution to manage
those files.

$ htpasswd lighttpd.user.htpasswd agent007

Keep in mind that not all versions of htpasswd default to use
Apache's modified MD5 algorithm for passwords, which is
required by lighttpd. You can force most to use MD5 with:

$ htpasswd -m <pwfile> <username>

htdigest (mod_authn_file)

A file which contains a line per user identification. Each line contains the username, realm and a MD5 value separated by colons.

e.g.:

agent007:download area:8364d0044ef57b3defcfa141e8f77b65

The MD5 value is the checksum of a string concatenating the username, realm and password, separated by colons.
That way, there is a sort of recursion. An example consecuent with the previous one is:

e.g.:

agent007:download area:secret

You can use htdigest from the apache distribution to manage
that kind of files.

$ htdigest lighttpd.user.htdigest 'download area' agent007

Using md5sum can also generate the password-hash:

#!/bin/sh
user=$1
realm=$2
pass=$3

hash=`echo -n "$user:$realm:$pass" | md5sum | cut -b -32`

echo "$user:$realm:$hash" 

To use it (spaces between arguments!):

$ htdigest.sh 'agent007' 'download area' 'secret'
agent007:download area:8364d0044ef57b3defcfa141e8f77b65

follow code is improved when you use for service:

#!/bin/sh

export PATH="/bin:/usr/bin:/usr/sbin:$PATH" 

# when input ctrl-c, remove lockfile and exit
trap '[ $lockstart -eq 1 ] && unlock $pfile && exit 0 || exit 0' INT

pfile="/etc/lighttpd/conf.d/lighttpd.user" 
lockstart=0 
remove=0

errmsg() {
    echo "$1" > /dev/stderr
}

user_check() {
    check_user=$1
    grep "^${check_user}:" ${pfile} >& /dev/null
    return $?
}

lock() {
    lockfile="$1" 
    lockfile="${lockfile}.lock" 

    [ -f "${lockfile}" ] && {
        errmsg "WARNING: lock file ${lockfile} is already exists" 
        errmsg "         Wait minites for end of previous working ..." 
    }

    while [ -f "${lockfile}" ]; do echo >& /dev/null ; done
    touch ${lockfile} 
    lockstart=1
}

unlock() {
    lockfile="$1" 
    lockfile="${lockfile}.lock" 

    [ -f "${lockfile}" ] && rm -f ${lockfile} && lockstart=0
}

usage() {
    errmsg
    errmsg "lightdigest: lighttpd htdigest password generation program" 
    errmsg "Scripted by JoungKyun.Kim <http://oops.org>" 
    errmsg
    errmsg "Usage: $0 -[hd] -u user -p pass -r realm [-f password_file]" 
    errmsg "Options:" 
    errmsg "    -h          print this help messages" 
    errmsg "    -u user     username" 
    errmsg "    -p pass     password" 
    errmsg "    -r realm    realm name" 
    errmsg "    -f filename password file [default: /etc/lighttpd/conf.d/lighttpd.user" 
    errmsg "    -d          remove user" 
    errmsg

    [ $lockstart -eq 1 ] && rm -f ${pfile}.lock

    exit 1
}   

opts=$(getopt df:hp:r:u: $*)
[ $? != 0 ] && usage

set -- ${opts}
for i
do
    case "$i" in
        -d) remove=1; shift;;
        -f) pfile="$2"; shift; shift;;
        -p) pass="$2"; shift; shift;;
        -r) realm="$2"; shift; shift;;
        -u) user="$2"; shift; shift;;
        --) shift; break;
    esac
done

#echo $user
#echo $realm
#echo $pass
#echo $pfile
#echo $remove

[ -z "$user" ] && errmsg "ERROR: User is none!!" && usage
[ ${remove} -eq 0 -a -z "${realm}" ] && errmsg "ERROR: Realm is none!!" && usage

if [ -z "${pass}" -a ${remove} -eq 0 ]; then
    echo -n "Input new password : " 
    read newpass
    echo -n "Reinput password for confirm : " 
    read renewpass

    if [ "${newpass}" != "${renewpass}" ]; then
        errmsg "ERROR: Password is not match" 
        exit 1
    fi

    pass=${newpass}
fi

lock ${pfile}

if [ ${remove} -eq 0 ]; then
    # User Add Mode
    hash=$(echo -n "${user}:${realm}:${pass}" | md5sum | cut -b -32)
    user_check ${user}
    already=$?

    [ -f "${pfile}" ] && cp -af ${pfile} ${pfile}.bak
    if [ ${already} -eq 0 ]; then
        # already exists
        perl -pi -e "s/^${user}:.*$/${user}:${realm}:${hash}/g" ${pfile}
    else
        # add new user
        echo "${user}:${realm}:${hash}" >> ${pfile}
    fi
else
    # User Remove Mode
    tmp_htdigest="/tmp/lighttpd-htdiges.tmp.$$" 
    cp -af ${pfile} ${pfile}.bak
    grep -v "^${user}:" ${pfile} > ${tmp_htdigest}
    mv -f ${tmp_htdigest} ${pfile}
fi

unlock ${pfile}

exit 0

To use it (don't use realm value! getopt of some bash version has bug.) :

  # if you add or change
  $ lightdigest -u USERNAME -r REALM_NAME -f PASSWORD_FILE_PATH
  # if you want to remove use  
  $ lightdigest -d -u USERNAME

ldap (mod_authn_ldap)

The ldap backend performs the following steps to authenticate a user

  1. Init the LDAP connection
  2. Set Protocol version to LDAPv3
  3. If StartTLS if configured -> Configure CA certificate if supplied
  4. If StartTLS if configured -> Activate TLS using StartTLS
  5. If Bind DN is included -> Simple bind with Bind-DN and Bind-Password
  6. If there is no Bind-DN -> Simple bind anonymously
  7. Try up to two times a SUBTREE search of the base-DN with the filter applied.
  8. Retrieve the DN of the user matching the filter.
  9. Finally, re-init the connection (following the steps above), this time using the DN found using the filter and the password supplied by the user.

If all 9 steps are performed without any error the user is authenticated.

gssapi (mod_authn_gssapi) (kerberos5) (since lighttpd 1.4.42)

The gssapi backend authenticates the user against Kerberos5 infrastructure

mysql (mod_authn_mysql) (since lighttpd 1.4.42)

The mysql backend authenticates the user against MySQL/MariaDB infrastructure

pam (mod_authn_pam) (since lighttpd 1.4.51)

The pam backend authenticates the user against PAM infrastructure

sasl (mod_authn_sasl) (since lighttpd 1.4.48)

The sasl backend authenticates the user against SASL infrastructure

Configuration template

After setting up the backend, edit the authentication configuration file to reflect your backend selected. The following is a configuration template.

################

## type of backend 
# plain, htpasswd, htdigest (mod_authn_file); ldap (mod_authn_ldap); gssapi (mod_authn_gssapi); mysql (mod_authn_mysql); pam (mod_authn_pam); sasl (mod_authn_sasl)
server.modules += ( "mod_authn_file" )

# filename of the password storage for plain
auth.backend = "plain" 
auth.backend.plain.userfile = "lighttpd-plain.user" 

## for htpasswd
auth.backend = "htpasswd" 
auth.backend.htpasswd.userfile = "/full/path/to/lighttpd-htpasswd.user" 

## for htdigest
auth.backend = "htdigest" 
auth.backend.htdigest.userfile = "lighttpd-htdigest.user" 

################

## for ldap
# the $ in auth.backend.ldap.filter is replaced by the 
# 'username' from the login dialog
# since lighttpd 1.4.46, '?' can be used as placeholder
# instead of '$', e.g. "(uid=?)" 
server.modules += ( "mod_authn_ldap" )
auth.backend = "ldap" 
auth.backend.ldap.hostname = "localhost" 
auth.backend.ldap.base-dn  = "dc=my-domain,dc=com" 
auth.backend.ldap.filter   = "(uid=$)" 
# if enabled, startTLS needs a valid (base64-encoded) CA 
# certificate unless the certificate has been stored
# in a c_hashed directory and referenced in ldap.conf
auth.backend.ldap.starttls   = "enable" 
auth.backend.ldap.ca-file   = "/etc/CAcertificate.pem" 
# If you need to use a custom bind to access the server
auth.backend.ldap.bind-dn  = "uid=admin,dc=my-domain,dc=com" 
auth.backend.ldap.bind-pw  = "mysecret" 
# If you want to allow empty passwords
# "disable" for requiring passwords, "enable" for allowing empty passwords
auth.backend.ldap.allow-empty-pw = "disable" 
# LDAP group (https://redmine.lighttpd.net/issues/1817)
#auth.backend.ldap.groupmember = "mygroup" 

################

## for gssapi
server.modules += ( "mod_authn_gssapi" )
auth.backend = "gssapi" 
auth.backend.gssapi.keytab = "/path/to/lighttpd.keytab" 
auth.backend.gssapi.principal = "myhost" 

################

## for mysql
server.modules += ( "mod_authn_mysql" )
auth.backend = "mysql" 
#auth.backend.mysql.host = "" 
#auth.backend.mysql.user = "" 
#auth.backend.mysql.pass = "" 
#auth.backend.mysql.db = "" 
#auth.backend.mysql.port = "" 
#auth.backend.mysql.socket = "" 
auth.backend.mysql.users_table = "mysql_users_table" 
#auth.backend.mysql.col_user = "user" 
#auth.backend.mysql.col_pass = "password" 
#auth.backend.mysql.col_realm = "realm" 
# defaults above result in query: SELECT password FROM mysql_users_table WHERE user='%s' AND realm='%s'

################

## for pam
server.modules += ( "mod_authn_pam" )
auth.backend = "pam" 
#auth.backend.pam.opts = ( "service" => "http" )  # default "http" 

################

## for sasl
server.modules += ( "mod_authn_sasl" )
auth.backend = "sasl" 
#auth.backend.sasl.opts = ( "service"        => "http",      # default "http" 
#                           "fqdn"           => "hostname",  # default current host
#                           "pwcheck_method" => "saslauthd", # default "saslauthd", else one of "saslauthd","auxprop","sasldb" 
#                           "sasldb_path"    => "path-to-db" # if needed
#                         )

################

# check REMOTE_USER (if set) against require rules prior to applying auth.backend
# REMOTE_USER might be set by another module, e.g. mod_openssl client cert verification
# and REMOTE_USER configured with ssl.verifyclient.username)
# (since lighttpd 1.4.46)
#auth.extern-authn = "enable" 

################
################

## restrictions
# set restrictions:
#
# auth.require =
# ( <left-part-of-the-url> =>
#   ( "method" => "digest"/"basic",
#     "realm" => <realm>,
#     "require" => "user=<username>" )
# )
#
# <left-part-of-the-url> is relative to the 'server.document-root'
#
# <algorithm> is the digest algorithm to use with "method" => "digest" 
#   The default digest algorithm MD5 is no longer considered secure.
#   lighttpd can be configured to use SHA-256 (since lighttpd 1.4.54)
#   If not specified, MD5 is used for backwards compatibility.
#
# "algorithm" => "SHA-256"  (since 1.4.54)
#
# <realm> is a string to display in the dialog 
#         presented to the user and is also used for the 
#         digest-algorithm and has to match the realm in the 
#         htdigest file (if used)
#
# "require" => "valid-user" will authorize any authenticated user
#

server.modules += ( "mod_auth" )

auth.require = ( "/download/" =>
                 (
                 # method must be either basic or digest
                   "method"    => "digest",
                   "algorithm" => "SHA-256",
                   "realm"     => "download archiv",
                   "require"   => "user=agent007|user=agent008" 
                 ),
                 "/server-info" =>
                 (
                 # limit access to server information
                   "method"    => "digest",
                   "algorithm" => "SHA-256",
                   "realm"     => "download archiv",
                   "require"   => "valid-user" 
                 )
                 "/protected-folder/" =>
                 (
                 # 
                   "method"    => "digest",
                   "algorithm" => "SHA-256",
                   "realm"     => "download archiv",
                   "require"   => "valid-user" 
                 )
               )

# Or, using regular expressions:
$HTTP["url"] =~ "^/download|^/server-info" {
  auth.require = ( "" =>
                   (
                     "method"    => "digest",
                     "algorithm" => "SHA-256",
                     "realm"     => "download archiv",
                     "require"   => "user=agent007|user=agent008" 
                   )
                 )
}

# Or, if *only* using certificate based authentication along with mod_openssl configured to require client certificates
#  # client side authentification       
#  ssl.verifyclient.activate = "enable" 
#  ssl.verifyclient.enforce = "enable" 
#  # this line instructs client cert CN value to be extracted
#  # for use in require user=agent007... in auth.require
#  ssl.verifyclient.username = "SSL_CLIENT_S_DN_CN" 
auth.require = ( "" =>
                 (
                   "method"  => "extern",
                   "realm"   => "certificate",
                   "require" => "user=agent007|user=agent008" 
                 )
               )

When completed, enable the authentication configuration module. The way to enable the module varies from different distributions.

Limitations

  • The implementation of digest method is not compliant with the standard. (i.e. not secure) (Fixed in lighttpd 1.4.41 (#1844))
    Excerpt from https://www.rfc-editor.org/rfc/rfc7616.txt Section 5.13:
    The bottom line is that any compliant implementation will be
    relatively weak by cryptographic standards, but any compliant
    implementation will be far superior to Basic Authentication.
  • The implementation of digest method still allows various replay attacks. (#2976)
  • Digest algorithm="md5-sess" is not correctly implemented in lighttpd, and probably never will be, and so its use is not recommend. (#806) Apache mod_auth_digest also does not implement algorithm="md5-sess".
  • LDAP authentication only allows alphanumeric uid's that do not contain punctuations. i.e.) john.doe will come up as "ldap: invalid character (a-zA-Z0-9 allowed) in username: john.doe" (This issue appears to be solved since r2526. See issue #1941) (Fixed in lighttpd 1.4.46)
  • As of 1.4.19 the group field inside the require directive is not yet implemented. So auth.backend.plain.groupfile is of no use at this moment. (Note: group support for LDAP is available since lighttpd 1.4.46 (#1817))
  • When loaded together with mod_fastcgi, mod_auth must be loaded before mod_fastcgi. Or else users will experience long delays when login in and sysadmins will probably not find out the source of the problem due to the lack of meaningful error messages.

See Also

Updated by Anonymous almost 4 years ago · 53 revisions