Différences entre versions de « CoSign »
imported>SylvainBeucler m (→Factor) |
imported>SylvainBeucler m (→Factor) |
||
Ligne 240 : | Ligne 240 : | ||
monster | monster | ||
− | == | + | == Factors == |
* Here's a simple LDAP factor (<code>/usr/lib/cosign/factor/ldap</code>): | * Here's a simple LDAP factor (<code>/usr/lib/cosign/factor/ldap</code>): |
Version du 30 mai 2007 à 13:38
HOWTO: I found it difficult to install CoSign 2.0.2a because the documentation contains inaccuracies (TODO: submit a patch), and because it can be hard to debug configuration errors. Here's a working test configuration:
CoSign is composed of 3 main parts:
- filter: this is mod_cosign, allowing Apache to automatically check the user's CoSign cookie
- cgi: cosign.cgi and logout.cgi, for initial login and full logout
- cosignd: the daemon that centralises authentication sessions, can be called from different computers where filter and cgi are installed
Compilation and Installation
I'm using Apache2 here. Let's also try to use FHS-compliant paths.
Dependencies as Debian packages:
aptitude install build-essential apache2-dev openssl-dev
./configure --enable-apache2=/usr/bin/apxs2 \ --prefix=/var/lib/cosign \ --sbindir=/usr/local/sbin \ --mandir=/usr/local/share/man \ --with-filterdb=/var/lib/cosign/filter \ --with-cosigndb=/var/lib/cosign/daemon \ --with-cosignconf=/etc/cosign/cosign.conf \ --with-cosigncadir=/etc/cosign/certs/CA \ --with-cosigncert=/etc/cosign/certs/cert.pem \ --with-cosignkey=/etc/cosign/certs/key.pem
TODO: use /usr/lib and /usr/share appropriately, also allowing using the standard --prefix=/usr/local. Use FHS-compliant /usr/lib/cosign/cgi-ssl
Old versions of apxs (eg. Debian Sarge's) may not provide the libapr include path, resulting in lengthy compilation errors. In this case, provide it manually by prexifing the configure call with a CPPFLAGS variable:
CPPFLAGS=-I/usr/include/apr-0 ./configure --enable-apache2=...
Next:
make everything \ && sudo make install-all \ && sudo invoke-rc.d apache2 stop && sleep 1 && sudo invoke-rc.d apache2 start
# mod_cosign dir mkdir -p -m 750 /var/lib/cosign/filter chown www-data: /var/lib/cosign/filter # cosignd dir mkdir -p -m 750 /var/lib/cosign/daemon useradd cosign chown cosign /var/lib/cosign/daemon
# Copy customizable files somewhere else # so they're not overwritten by an unfortunate 'make install'.. cp -a /var/lib/cosign/templates /var/lib/cosign/templates-local cp -a /var/lib/cosign/html /var/lib/cosign/html-local cp -a /var/lib/cosign/services /var/lib/cosign/services-local
Apache2 configuration
/etc/apache2/sites-available/default:
# Automatically added in /etc/apache2/httpd.conf by 'make install-all' (via apxs2
)
LoadModule cosign_module /usr/lib/apache2/modules/mod_cosign.so
NameVirtualHost *:80
NameVirtualHost *:443
# TLS VirtualHost 'cause CoSign requires https login
<VirtualHost *:443>
SSLEngine On
SSLCertificateFile /etc/apache2/ssl/cert.pem
SSLCertificateKeyFile /etc/apache2/ssl/key.pem
Include sites-available/common.inc
</VirtualHost>
<VirtualHost *:80>
# Don't redirect to https if we come from http
CosignHttpOnly On
Include sites-available/common.inc
</VirtualHost>
/etc/apache2/sites-available/common.inc:
CosignProtected Off CosignHostname localhost CosignRedirect https://localhost/cosign-bin/cosign.cgi CosignPostErrorRedirect https://localhost/cosign/post_error.html CosignCrypto /etc/cosign/certs/mod_cosign.key /etc/cosign/certs/mod_cosign.crt /etc/cosign/certs/CA Alias /cosign/ "/var/lib/cosign/html-local/" ScriptAlias /cosign-bin/ "/var/lib/cosign/cgi-ssl/" Alias /services/ "/var/lib/cosign/services-local/" <Directory "/var/lib/cosign/services-local/"> CosignProtected On CosignService list </Directory> <Directory "/var/www/mygroupware/"> CosignProtected On CosignService mygroupware </Directory>
If you're using Debian, you can easily enable SSL through:
a2enmod ssl echo "Listen 443" >> /etc/apache2/ports.conf
and restarting Apache.
If you need a simple self-signed certificate:
cd /etc/apache2/ssl/ openssl req -subj "/C=FR/ST=NPDC/L=Lievin/O=Cliss XXI/OU=SABDFL/CN=*/emailAddress=me@home/" \ -new -x509 -nodes -days 10000 -keyout key.pem -out cert.pem # check openssl x509 -noout -text -in cert.pem
Certificates generation
We'll generate our own Certificate Authority for the CoSign system.
OpenSSL constraint: the country and organization must be the same for the CA and the certificates it signs.
Note: the Apache2 certificate (the https one, not the mod_cosign one) was treated separately because it is not involved in the CoSign protocol (communication between cgi, filter and cosignd), so it need not be part of this CA tree.
# Base OpenSSL install mkdir -p -m 755 /etc/cosign/certs cd /etc/cosign/certs PREVIOUS_UMASK=`umask` umask 0027 # no read access to private keys! mkdir -m 700 demoCA pushd demoCA mkdir -m 755 newcerts mkdir -m 700 private echo "01" > serial touch index.txt popd # Generate a secure password pwgen -s1 > pass.txt # Root CA # subj model from `openssl x509 -noout -text -in stuff.crt` openssl req -new -subj "/C=FR/ST=NPDC/L=Lievin/O=Cliss XXI/OU=SSO/CN=Root CA/" \ -x509 -days 3650 -keyout demoCA/private/cakey.pem -out demoCA/cacert.pem \ -passout file:pass.txt chmod a+r demoCA/cacert.pem # Certificate request and private key # cosignd openssl req -new -subj "/C=FR/ST=NPDC/L=Lievin/O=Cliss XXI/OU=SSO cosignd/CN=localhost/" \ -nodes -keyout "cosignd.key" -out "cosignd.csr" # Sign certificate openssl ca -in "cosignd.csr" -out "cosignd.crt" -days 3650 -batch -passin file:pass.txt # CGI openssl req -new -subj "/C=FR/ST=NPDC/L=Lievin/O=Cliss XXI/OU=SSO cgi/CN=cgi-1/" \ -nodes -keyout "cgi.key" -out "cgi.csr" # Sign certificate openssl ca -in "cgi.csr" -out "cgi.crt" -days 3650 -batch -passin file:pass.txt chgrp www-data cgi.key cgi.crt # mod_cosign openssl req -new -subj "/C=FR/ST=NPDC/L=Lievin/O=Cliss XXI/OU=SSO mod_cosign/CN=mod_cosign-1/" \ -nodes -keyout "mod_cosign.key" -out "mod_cosign.csr" # Sign certificate openssl ca -in "mod_cosign.csr" -out "mod_cosign.crt" -days 3650 -batch -passin file:pass.txt # Return to normal permissions umask $PREVIOUS_UMASK unset PREVIOUS_UMASK # Allowed certs path mkdir -m 755 CA ln demoCA/cacert.pem CA/ c_rehash CA/ # Tests - cf. http://www.umich.edu/~umweb/software/cosign/faq.html openssl verify -CApath CA/ -purpose sslserver cosignd.crt openssl verify -CApath CA/ -purpose sslclient cgi.crt mod_cosign.crt openssl s_client -connect localhost:6663 -cert cgi.crt -key cgi.key -CApath CA/ \ -showcerts -state -debug -crlf -starttls smtp # DO CHECK THAT YOU GET "Verify return code: 0 (ok)"!!! # (s_client won't stop on error) # Remove password (remember it :)) rm pass.txt
CoSign configuration
Pitfalls:
- The
cgi
doesn't take more than 1 parameter - only service does. set cosignhost
is used by cgi, not cosignd. It specifies the host where cosignd runs, and is not related to replication.- TODO: fix documentation
/etc/cosign/cosign.conf:
## [Common to cgi and cosignd] # TLS parameters set cosigncadir /etc/cosign/certs/CA/ set cosigncert /etc/cosign/certs/cgi.crt set cosignkey /etc/cosign/certs/cgi.key ## [cosignd-specific] # Allow access to cosignd with cgi-level privileges (REGISTER new sessions) # from this CommonName (CN is from the TLS certificate) cgi cgi-1 # Allow cosignd access with service-level privileges (CHECK existing sessions) # from these CN (they need not match the source IP or domaine name) service mod_cosign-1 0 service mod_cosign-2 0 ## [cgi-specific] # cosignd host (it must match the server's CN!) set cosignhost localhost # Grab this user's factor: # - argument 3 and later are name(s) of <FORM>/POST fields from the template # - at least one factor is required for authentication to succeed # - a factor executable only returns 1 factor name # - factor names can be used by mod_cosign (CosignRequireFactor) factor /usr/lib/cosign/factor/ldap login password # Override the default template directories, # so our changes won't be overwritten by an unfortunate 'make install' set cosigntmpldir /var/lib/cosign/templates-local set cosignlogouturl http://localhost/ set cosignloopurl http://localhost/cosign/looping.html
Also describe cosign as a known service:
echo "cosign 6663/tcp" >> /etc/services
cosignd server start
TODO: use/adapt scripts/startup/cosignd
# Launch server with different keys than cgi, just in case: cd /etc/cosign/certs/ /usr/local/sbin/cosignd -y cosignd.crt -z cosignd.key -x /etc/cosign/certs/CA/ # CA path must be a full path, because cosignd chdir to /var/lib/cosign/daemon # Start the monster daemon, so that old sessions are cleaned-up monster
Factors
- Here's a simple LDAP factor (
/usr/lib/cosign/factor/ldap
):
#!/usr/bin/perl # Basic LDAP "factor" for CoSign # Copyright (C) 2007 Cliss XXI # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Author: Sylvain Beucler <beuc@beuc.net> use strict; # Base configuration my $base = "ou=users,dc=cliss21,dc=com"; my $host = "ldaps://192.168.1.149"; my $user_filter = "(objectClass=posixAccount)"; # ----- # If authentication is successful, the external authenticator writes # the factor name on stdout (file descriptor 1) and exits with a value # of 0. If an error occurs, the external authenticator writes an # error message on stdout and exits with a value of 1. All other exit # values are reserved for future use. # -- cosign.conf(5) use Net::LDAP; # aptitude install libnet-ldap-perl libio-socket-ssl-perl # Grab CoSign parameters from standard input my $login = <STDIN>; chomp $login; my $pass = <STDIN>; chomp $pass; # Get the login's DN my $binddn = ""; my $bindpw = ""; my $filter = "&$user_filter(uid=$login)"; my $attrs = []; my $ldap = Net::LDAP->new($host); if (!defined($ldap)) { # Be sure to catch the error manually and not use die, otherwise # the return code will be different than 1, making CoSign unhappy, # and the error will be print on stderr, so will be missing in the # web interface print "Cannot connect to LDAP server $host\n"; exit 1; } $ldap->bind("$binddn", password => "$bindpw", version => 3); my $mesg = $ldap->search(base => $base, filter => $filter, attrs => $attrs); my $count = $mesg->count; if ($count == 0) { print "Login failed: user '$login' does not exist.\n"; exit 1; } elsif ($count > 1) { print "Login failed: several users '$login' exist!\n"; exit 1; } my $entry = $mesg->entry(); my $dn = $entry->dn(); # Try to login with the DN $binddn = $dn; $bindpw = $pass; my $result = $ldap->bind("$binddn", password => "$bindpw", version => 3); if ($result->code()) { print "Login failed (LDAP error: " . $result->error . ")\n"; exit 1; } $ldap->unbind(); print "ldap\n"; # factor name exit 0; # success
- Here's a secondary factor, used restrict access (CosignRequireFactor) to admins:
#!/usr/bin/perl # Is the user an admin? # Copyright (C) 2007 Cliss XXI # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Author: Sylvain Beucler <beuc@beuc.net> use strict; # Base configuration my $base = "ou=users,dc=cliss21,dc=com"; my $host = "ldaps://192.168.1.149"; # ----- use Net::LDAP; # aptitude install libnet-ldap-perl # Grab CoSign parameters from standard input my $login = <STDIN>; chomp $login; # Check group membership my $binddn = ""; my $bindpw = ""; my $filter = "(&(cn=Admins)(memberuid=$login))"; my $attrs = [ 'cn' ]; my $ldap = Net::LDAP->new($host); if (!defined($ldap)) { print "Cannot connect to LDAP server $host\n"; exit 1; } $ldap->bind("$binddn", password => "$bindpw", version => 3); my $mesg = $ldap->search(base => $base, filter => $filter, attrs => $attrs); my $count = $mesg->count; $ldap->unbind(); if ($count > 0) { print "admin\n"; } exit 0;
Test
Now hit https://localhost/services/