Différences entre versions de « CoSign »

De Cliss XXI
Sauter à la navigation Sauter à la recherche
imported>SylvainBeucler
m
imported>SylvainBeucler
m (sample ldap factor)
Ligne 172 : Ligne 172 :
 
  /usr/local/sbin/cosignd -y cosignd.crt -z cosignd.key -x /usr/local/cosign/certs/CA/
 
  /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
 
  # 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 ==
 
== Test ==

Version du 16 mai 2007 à 14:00

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 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.
  • 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 service is 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 :)