CoSign
HOWTO: I found it difficult to install CoSign 2.0.2a because the documentation contains inaccuracies, 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 try to use FHS-compliant paths.
./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.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
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
Apache2 configuration
/etc/apache2/sites-available/default:
# Automatically added in /etc/apache2/httpd.conf by 'make install-all' 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 Alias /cosign/ "/var/lib/cosign/html/" ScriptAlias /cosign-bin/ "/var/lib/cosign/cgi-ssl/" Include sites-available/common.inc </VirtualHost> <VirtualHost *:80> Include sites-available/common.inc </VirtualHost>
/etc/apache2/sites-available/common.inc:
CosignProtected Off CosignHostname localhost # Don't redirect to https if we come from http CosignHttpOnly On CosignRedirect https://localhost/cosign-bin/cosign.cgi CosignPostErrorRedirect https://localhost/cosign/post_error.html CosignService simpleservice CosignCrypto /usr/local/cosign/certs/mod_cosign.key /usr/local/cosign/certs/mod_cosign.crt /usr/local/cosign/certs/CA Alias /cosign/ "/var/lib/cosign/html/" ScriptAlias /cosign-bin/ "/var/lib/cosign/cgi-ssl/" Alias /services/ "/usr/local/cosign/services/" <Directory "/usr/local/cosign/services"> CosignProtected On </Directory>
CoSign configuration
Pitfalls:
- The
cgidoesn't take more than 1 parameter - only service does. set cosignhostis used by cgi, not cosignd. It specifies the host where cosignd runs, and is not related to replication.- Afaics 'factor' lines will always be ran and returns the name of the validated factor. This among others allows to filter which users can access to which service.
- TODO: fix documentation
- TODO: explain what
serviceis for
/etc/cosign.conf:
# Allow CGI access from this host cgi localhost set cosignhost localhost set cosigncadir /etc/cosign/certs/CA/ set cosigncert /etc/cosign/certs/cgi.crt set cosignkey /etc/cosign/certs/cgi.key # Grant the given session type if credentials match the given factor cookie cosign-simpleservice reauth FACTOR-LDAP # Argument 3 and later are name of <FORM> fields from the template factor /usr/share/cosign/factor/ldap login password set cosignlogouturl http://localhost/ set cosignloopurl https://localhost/cosign/looping.html
Certificates generation
We'll generate our own Certificate Authority.
TODO: during tests it's frequent to remove and rebuild everything. Typing password is really inconvenient in this case, and -passin doesn't work for 'ca'. Please find a way to make this unattented!
# Base OpenSSL install mkdir -p -m 755 /etc/cosign/certs/CA cd mkdir -p /etc/cosign/certs umask 0027 mkdir -m 700 demoCA pushd demoCA mkdir -m 755 newcerts mkdir -m 700 private echo "01" > serial touch index.txt popd # Root CA # subj model from `openssl x509 -noout -text -in machin.cert` openssl req -new -subj "/C=FR/ST=NPDC/L=Lievin/O=Cliss XXI/OU=SSO/CN=Root CA/" \ -x509 -days 365 -keyout demoCA/private/cakey.pem -out demoCA/cacert.pem 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" # CGI openssl req -new -subj "/C=FR/ST=NPDC/L=Lievin/O=Cliss XXI/OU=SSO cgi/CN=localhost/" \ -nodes -keyout "cgi.key" -out "cgi.csr" # Sign certificate openssl ca -in "cgi.csr" -out "cgi.crt" 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=localhost/" \ -nodes -keyout "mod_cosign.key" -out "mod_cosign.csr" # Sign certificate openssl ca -in "mod_cosign.csr" -out "mod_cosign.crt" # 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 sslclient cgi.crt mod_cosign.crt openssl verify -CApath CA/ -purpose sslserver cosignd.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)
cosignd server start
TODO: use/adapt scripts/startup/cosignd
# Launch server with different keys just in case: cd /var/lib/cosign/certs/ /usr/local/sbin/cosignd -y cosignd.crt -z cosignd.key -x /usr/local/cosign/certs/CA/ # CA path must be a full path, because cosignd chdir to /var/lib/cosign/daemon
Factor
Here's a simple LDAP factor:
#!/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 = "ldap://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;
use Net::LDAP::LDIF;
my $debug = 0;
sub debug {
if ($debug) {
print "DEBUG:";
print @_;
print "\n";
}
}
# Grab CoSign parameters from standard input
my $login = <STDIN>; chomp $login;
debug($login);
my $pass = <STDIN>; chomp $pass;
debug($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 "Unknown user: $login\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 "FACTOR-LDAP\n"; # factor name
exit 0; # success
Test
Now hit https://localhost/services/
Beyond
Check what monsterd is :)