Add debian packaging

This commit is contained in:
Benjamin Dauvergne 2010-04-26 12:50:44 +02:00
parent a2a3242889
commit 0cbbfc5cd8
42 changed files with 25 additions and 3573 deletions

1
debian/authentic-ifef.default vendored Normal file
View File

@ -0,0 +1 @@
OPTIONS="--port 4001"

View File

@ -5,17 +5,17 @@
# Required-Stop: $local_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Authentic IdP (Pr@tic)
# Description: Authentic Identity Provider (with Pr@tic extension)
# Short-Description: Authentic IdP (IFEF)
# Description: Authentic Identity Provider (with IFEF extension)
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="Authentic (+Pr@tic)"
NAME=authentic-pratic
DESC="Authentic (+IFEF)"
NAME=authentic-ifef
DAEMON=/usr/sbin/authenticctl
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
OPTIONS="--extra /usr/share/python-support/authentic-pratic/extra"
OPTIONS="--extra /usr/share/python-support/authentic-ifef/extra"
# Gracefully exit if the package has been removed.
test -x $DAEMON || exit 0

View File

@ -1,15 +1,15 @@
# Automatically added by dh_installinit
if [ -x "/etc/init.d/authentic-pratic" ]; then
update-rc.d authentic-pratic defaults >/dev/null
if [ -x "/etc/init.d/authentic-ifef" ]; then
update-rc.d authentic-ifef defaults >/dev/null
if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
invoke-rc.d authentic-pratic start || exit $?
invoke-rc.d authentic-ifef start || exit $?
else
/etc/init.d/authentic-pratic start || exit $?
/etc/init.d/authentic-ifef start || exit $?
fi
fi
# End automatically added section
# Automatically added by dh_pysupport
if [ "$1" = "configure" ] && which update-python-modules >/dev/null 2>&1; then
update-python-modules -i /usr/share/python-support/authentic-pratic
update-python-modules -i /usr/share/python-support/authentic-ifef
fi
# End automatically added section

View File

@ -1,5 +1,5 @@
# Automatically added by dh_installinit
if [ "$1" = "purge" ] ; then
update-rc.d authentic-pratic remove >/dev/null || exit $?
update-rc.d authentic-ifef remove >/dev/null || exit $?
fi
# End automatically added section

View File

@ -1,14 +1,14 @@
# Automatically added by dh_installinit
if [ -x "/etc/init.d/authentic-pratic" ]; then
if [ -x "/etc/init.d/authentic-ifef" ]; then
if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
invoke-rc.d authentic-pratic stop || exit $?
invoke-rc.d authentic-ifef stop || exit $?
else
/etc/init.d/authentic-pratic stop || exit $?
/etc/init.d/authentic-ifef stop || exit $?
fi
fi
# End automatically added section
# Automatically added by dh_pysupport
if which update-python-modules >/dev/null 2>&1; then
update-python-modules -c -i /usr/share/python-support/authentic-pratic
update-python-modules -c -i /usr/share/python-support/authentic-ifef
fi
# End automatically added section

View File

@ -1,2 +0,0 @@
/etc/init.d/authentic-pratic
/etc/ldap/schema/cdg59.schema

View File

@ -1,17 +0,0 @@
Package: authentic-pratic
Version: 1.0.7
Section: web
Priority: optional
Architecture: all
Depends: python (<< 2.5), python (>= 2.4), python-support (>= 0.2), authentic, python-ldap
Installed-Size: 328
Maintainer: Frederic Peters <fpeters@entrouvert.com>
Description: Liberty Alliance Identity Server - Pr@tic Extension
Authentic is a Liberty-compliant identity provider aiming to address a broad
range of needs, from simple to complex setups. Its Liberty compliance relies
on Lasso, a free (GNU GPL) implementation of the Liberty Alliance
specifications.
.
It is a quixote application and is commonly runned inside Apache web server.
.
This package provides an extension to Authentic for Pr@tic specific features.

View File

@ -1,23 +0,0 @@
af710403211af4e3353b3aa9755ca87e usr/share/python-support/authentic-pratic/extra/pratic.py
b0135901e1f38f5e52dbac9f426833d3 usr/share/python-support/authentic-pratic/extra/modules/services_ui.ptl
2236ca43b6ccaf4dc556466ec456b068 usr/share/python-support/authentic-pratic/extra/modules/__init__.py
e876c0cb7ce6cabf9914a4e0647a7413 usr/share/python-support/authentic-pratic/extra/modules/admin.ptl
c1715a0ede0df8c48da35f42a5f70c57 usr/share/python-support/authentic-pratic/extra/modules/saml2.py
aacd1462dfc10c45b1e00a13ff5cdcd7 usr/share/python-support/authentic-pratic/extra/modules/backoffice.ptl
35f853a46594d7533b0256d0756acfbd usr/share/python-support/authentic-pratic/extra/modules/directory.py
f1180dd2890095d68654a23cfd9bb499 usr/share/python-support/authentic-pratic/extra/modules/identities_ui.ptl
b3da052a0e221c3b5217cdb3bf2a99e4 usr/share/python-support/authentic-pratic/extra/modules/root.ptl
61bca76d2d7f1093f49d270d4b909736 usr/share/python-support/authentic-pratic/extra/modules/store.py
70b2f67684d725e077cce308fcf58dea usr/share/python-support/authentic-pratic/extra/modules/sessions.py
79b14f906aaecef8e10c05d6ea882982 usr/share/python-support/authentic-pratic/.version
b7b41078dad08cc8a30f84dd1a858821 usr/share/locale/fr/LC_MESSAGES/pratic.mo
624cf0d50f3b5de3dee54d1b284ac4f3 usr/share/doc/authentic-pratic/changelog.gz
5e26bd0b3f505abe48145c640477d01c usr/share/doc/authentic-pratic/copyright
747b47c0fdeea68525721041f64620fc usr/share/authentic/themes/pratic/admon-tip.png
952c2420523acebc86616b51d76bcb63 usr/share/authentic/themes/pratic/deg.png
09caf398658ea160aac106d6496f3804 usr/share/authentic/themes/pratic/desc.xml
b3cada1c583ed17b1aedb20bca762106 usr/share/authentic/themes/pratic/template.ezt
5dc7c3d0b91c243ea8504ef221438144 usr/share/authentic/themes/pratic/path18223.png
feec7d22f2fdc7c0b6cdbb8a02d383ba usr/share/authentic/themes/pratic/lockscreen-bg.png
e5259c303e69488d08cb6e5627d451f7 usr/share/authentic/themes/pratic/lockscreen.png
34c1990c0a8232c6a4cd56539acad0fd usr/share/authentic/themes/pratic/authentic.css

View File

@ -1,17 +0,0 @@
#!/bin/sh
set -e
# Automatically added by dh_installinit
if [ -x "/etc/init.d/authentic-pratic" ]; then
update-rc.d authentic-pratic defaults >/dev/null
if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
invoke-rc.d authentic-pratic start || exit $?
else
/etc/init.d/authentic-pratic start || exit $?
fi
fi
# End automatically added section
# Automatically added by dh_pysupport
if [ "$1" = "configure" ] && which update-python-modules >/dev/null 2>&1; then
update-python-modules -i /usr/share/python-support/authentic-pratic
fi
# End automatically added section

View File

@ -1,7 +0,0 @@
#!/bin/sh
set -e
# Automatically added by dh_installinit
if [ "$1" = "purge" ] ; then
update-rc.d authentic-pratic remove >/dev/null || exit $?
fi
# End automatically added section

View File

@ -1,16 +0,0 @@
#!/bin/sh
set -e
# Automatically added by dh_installinit
if [ -x "/etc/init.d/authentic-pratic" ]; then
if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
invoke-rc.d authentic-pratic stop || exit $?
else
/etc/init.d/authentic-pratic stop || exit $?
fi
fi
# End automatically added section
# Automatically added by dh_pysupport
if which update-python-modules >/dev/null 2>&1; then
update-python-modules -c -i /usr/share/python-support/authentic-pratic
fi
# End automatically added section

View File

@ -1,95 +0,0 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: authentic
# Required-Start: $local_fs $network
# Required-Stop: $local_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Authentic IdP (Pr@tic)
# Description: Authentic Identity Provider (with Pr@tic extension)
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="Authentic (+Pr@tic)"
NAME=authentic-pratic
DAEMON=/usr/sbin/authenticctl
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
OPTIONS="--extra /usr/share/python-support/authentic-pratic/extra"
# Gracefully exit if the package has been removed.
test -x $DAEMON || exit 0
# Read config file if it is present.
if [ -r /etc/default/$NAME ]
then
. /etc/default/$NAME
fi
#
# Function that starts the daemon/service.
#
d_start() {
start-stop-daemon --start --quiet --pidfile $PIDFILE \
--chuid www-data:www-data --make-pidfile --background --exec $DAEMON -- start $OPTIONS
}
#
# Function that stops the daemon/service.
#
d_stop() {
start-stop-daemon --stop --quiet --pidfile $PIDFILE
}
#
# Function that sends a SIGHUP to the daemon/service.
#
d_reload() {
start-stop-daemon --stop --quiet --pidfile $PIDFILE \
--make-pidfile --background --signal 1
}
case "$1" in
start)
echo -n "Starting $DESC: $NAME"
d_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
d_stop
echo "."
;;
#reload)
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
# If the daemon responds to changes in its config file
# directly anyway, make this an "exit 0".
#
# echo -n "Reloading $DESC configuration..."
# d_reload
# echo "done."
#;;
restart|force-reload)
#
# If the "reload" option is implemented, move the "force-reload"
# option to the "reload" entry above. If not, "force-reload" is
# just the same as "restart".
#
echo -n "Restarting $DESC: $NAME"
d_stop
sleep 1
d_start
echo "."
;;
*)
# echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0

View File

@ -1,187 +0,0 @@
# Schéma LDAP
#
objectIdentifier Cdg59Root 1.1
objectIdentifier Cdg59LDAP Cdg59Root:2
objectIdentifier Cdg59LDAPAttribute Cdg59LDAP:1
objectIdentifier Cdg59LDAPObjectClass Cdg59LDAP:2
attributetype ( Cdg59LDAPAttribute:1 NAME 'cdg59siretCode'
DESC 'Collectivity SIRET code'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SINGLE-VALUE)
attributetype ( Cdg59LDAPAttribute:2 NAME 'cdg59direction'
DESC 'Collectivity Direction'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( Cdg59LDAPAttribute:3 NAME 'cdg59isAdmin'
DESC 'Admin or not'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7)
attributetype ( Cdg59LDAPAttribute:4 NAME 'cdg59isDisabled'
DESC 'Acccount disabled or not'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7)
attributetype ( Cdg59LDAPAttribute:5 NAME 'cdg59sid'
DESC 'Service Id'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( Cdg59LDAPAttribute:6 NAME 'cdg59siid'
DESC 'Service Instance Id'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( Cdg59LDAPAttribute:7 NAME 'cdg59serviceType'
DESC 'Service Type'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( Cdg59LDAPAttribute:8 NAME 'cdg59URL'
DESC 'Generic URL'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26)
attributetype ( Cdg59LDAPAttribute:9 NAME 'cdg59metadataURL'
DESC 'Service Metadata URL'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26)
attributetype ( Cdg59LDAPAttribute:10 NAME 'cdg59serviceAccesses'
DESC 'Services an agent can access'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( Cdg59LDAPAttribute:11 NAME 'cdg59collectivitySirhCode'
DESC 'Collectivity SIRH code'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
SINGLE-VALUE)
attributetype ( Cdg59LDAPAttribute:12 NAME 'cdg59collectivitySirhLabel'
DESC 'Collectivity SIRH Label'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( Cdg59LDAPAttribute:13 NAME 'cdg59regionCode'
DESC 'Collectivity "Region" Code'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
attributetype ( Cdg59LDAPAttribute:14 NAME 'cdg59departementCode'
DESC 'Collectivity "Departement" Code'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
attributetype ( Cdg59LDAPAttribute:15 NAME 'cdg59arrondissementCode'
DESC 'Collectivity "Arrondissement" Code'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
attributetype ( Cdg59LDAPAttribute:16 NAME 'cdg59cantonCode'
DESC 'Collectivity "Canton" Code'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
attributetype ( Cdg59LDAPAttribute:17 NAME 'cdg59inseeCode'
DESC 'Collectivity INSEE Code'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
attributetype ( Cdg59LDAPAttribute:18 NAME 'cdg59streetNumber'
DESC 'Collectivity street number'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
attributetype ( Cdg59LDAPAttribute:19 NAME 'cdg59distOffice'
DESC 'Collectivity distribution office'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( Cdg59LDAPAttribute:20 NAME 'cdg59addressCompl'
DESC 'Collectivity complementary address infomation'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( Cdg59LDAPAttribute:21 NAME 'cdg59addressMention'
DESC 'Collectivity particular mention on address'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( Cdg59LDAPAttribute:22 NAME 'cdg59agentSirhCode'
DESC 'Collectivity SIRH code'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
SINGLE-VALUE)
attributetype ( Cdg59LDAPAttribute:23 NAME 'cdg59isGlobal'
DESC 'Global service, or not'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7)
attributetype ( Cdg59LDAPAttribute:24 NAME 'cdg59ssoRelayState'
DESC 'URL for redirection after a single sign on'
EQUALITY caseIgnoreMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
attributetype ( Cdg59LDAPAttribute:25 NAME 'cdg59lastConnectionTime'
DESC 'Last connection time'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27)
attributetype ( Cdg59LDAPAttribute:26 NAME 'cdg59lastConnectionDuration'
DESC 'Last connection duration'
EQUALITY integerMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27)
# CDG 59 Collectivity
objectclass ( Cdg59LDAPObjectClass:1
NAME 'cdg59collectivity'
DESC 'CDG 59 Collectivity Objectclass'
STRUCTURAL
SUP organizationalUnit
MAY ( cdg59siretCode $ cdg59collectivitySirhCode $ cdg59collectivitySirhLabel $ cn $ mail $ cdg59URL $ cdg59regionCode $ cdg59departementCode $ cdg59arrondissementCode $ cdg59cantonCode $ cdg59inseeCode $ cdg59streetNumber $ cdg59distOffice $ cdg59addressCompl $ cdg59addressMention ))
# CDG 59 Agent
objectclass (Cdg59LDAPObjectClass:2
NAME 'cdg59agent'
DESC 'CDG 59 Agent Objectclass'
STRUCTURAL
SUP inetOrgPerson
MUST ( uid )
MAY ( cdg59isAdmin $ cdg59direction $ cdg59isDisabled $ cdg59serviceAccesses $ cdg59agentSirhCode $ cdg59lastConnectionTime $ cdg59lastConnectionDuration ))
# CDG 59 Service
objectclass ( Cdg59LDAPObjectClass:3
NAME 'cdg59service'
DESC 'CDG 59 Service Objectclass'
STRUCTURAL
MUST ( cdg59sid )
MAY ( cn $ description $ cdg59URL $ cdg59isGlobal $ cdg59metadataURL $ cdg59ssoRelayState ))
# CDG 59 Service Instance
objectclass ( Cdg59LDAPObjectClass:4
NAME 'cdg59serviceInstance'
DESC 'CDG 59 Service Instance Objectclass'
STRUCTURAL
MUST ( cdg59siid )
MAY ( cdg59serviceType $ cdg59URL $ cdg59metadataURL $ cdg59ssoRelayState ))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,147 +0,0 @@
@import url(/css/authentic-common.css);
body {
font-family: sans-serif;
margin: 0 auto;
padding: 0;
background: #eee;
color: black;
max-width: 50em;
}
a {
color: #0072b8;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
#page {
border: 1px solid #0072b8;
border-width: 0px 2px;
background: white url(lockscreen.png) top right no-repeat;
}
#top {
margin-top: 20px;
border-top: 2px solid #0072b8;
background: #52bce5 url(lockscreen.png) top right no-repeat;
padding-bottom: 1em;
}
#top h1 {
margin: 1em 150px 0 10px;
text-align: right;
color: white;
}
#content {
padding: 1em 2em 3em 2em;
position: relative;
/* background: url(lockscreen-bg.png) bottom right no-repeat; */
background: url(path18223.png) 90% 0% no-repeat;
}
p#breadcrumb {
margin: 0 150px 0 0;
font-size: 80%;
background: #d9dde8 url(deg.png) top right repeat-y;
padding: 0.5ex;
}
#footer {
border-bottom: 2px solid #0072b8;
border-top: 1px solid #0072b8;
background: #28a5dc;
color: white;
}
#footer p {
font-weight: bold;
margin: 0;
text-align: right;
font-size: smaller;
font-style: italic;
padding: 1ex 1em 2px 0;
}
p#forgot-password {
position: absolute;
right: 30px;
top: 60px;
}
p#register {
position: absolute;
right: 30px;
top: 100px;
}
p#cookies {
border: 1px solid #888;
background: #ccf url(admon-tip.png) 5px 5px no-repeat;
padding-left: 60px;
height: 60px;
line-height: 60px;
}
ul {
list-style: circle;
}
ul.FederationsWidget {
font-weight: bold;
}
ul.FederationsWidget a.terminate {
font-weight: normal;
display: block;
margin-left: 5em;
margin-bottom: 1em;
}
/* pratic stuff */
ul#services {
width: 65%;
float: left;
}
p#commands {
clear: both;
border-top: 2px solid #0072b8;
padding-top: 1em;
}
div#platform-status {
float: right;
width: 25%;
border: 2px solid #0072b8;
background: white;
background: rgba(255, 255, 255, 0.5);
-moz-border-radius: 5px;
}
div#platform-status h3 {
background: #0072b8;
font-size: 100%;
text-align: center;
color: white;
margin: 0;
}
div#platform-status div {
padding: 0 1ex;
}
div#platform-status p#report-issue {
border-top: 2px solid #0072b8;
text-align: center;
margin: 0;
}
dl.profile dd {
font-weight: bold;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 B

View File

@ -1,6 +0,0 @@
<?xml version="1.0"?>
<theme name="pratic" version="1.0">
<label>Pr@tic</label>
<desc>Pr@tic Theme</desc>
<author>Frederic Peters &amp; artists</author>
</theme>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,21 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>[page_title]</title>
<link rel="stylesheet" type="text/css" href="[css]"/>
[script]
</head>
<body[if-any onload] onload="[onload]"[end]>
<div id="page">
<div id="top"> <h1>Authentic</h1> </div>
[if-any breadcrumb]<p id="breadcrumb">[breadcrumb]</p>[end]
<div id="content">
<div id="info-box"><h1>[if-any title][title][else][site_name][end]</h1> </div>
[prelude]
[body]
</div>
<div id="footer"><p id="lasso">Powered by Lasso</p></div>
</div>
</body>
</html>

View File

@ -1,26 +0,0 @@
This package was debianized by Frederic Peters <dlaniel@entrouvert.com> on
Wed, 03 Sep 2008 15:48:49 +0200.
Upstream Author: Frederic Peters <fpeters@entrouvert.com>
Copyright (c) 2005 Entr'ouvert;
Copyright (c) 2003-2005 dotclear for the graphics.
License is GNU GPL v2 or later plus OpenSSL exception clause.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
St, Fifth Floor, Boston, MA 02110-1301, USA.
On Debian GNU/Linux systems, the complete text of the GNU General Public
License can be found in `/usr/share/common-licenses/GPL'.

View File

@ -1,5 +0,0 @@
try:
from quixote.ptl import compile_package
compile_package(__path__)
except ImportError:
pass

View File

@ -1,8 +0,0 @@
import authentic.admin.root
class AdminRootDirectory(authentic.admin.root.RootDirectory):
menu_items = [
('logger/', N_('Logs')),
('settings/', N_('Settings')),
('debug/', N_('Debug')),
('/', N_('Authentic Identity Server'))]

View File

@ -1,225 +0,0 @@
import lasso
from quixote import get_request, get_response, get_session, redirect
from quixote.directory import AccessControlled, Directory
from qommon.publisher import get_publisher_class
from qommon.backoffice.menu import html_top
from qommon import errors, get_cfg
from qommon.form import *
from authentic import misc
import identities_ui
import services_ui
import directory
class BackofficeRootDirectory(AccessControlled, Directory):
_q_exports = ['', 'identities', 'services', 'editcol']
items = [
('identities/', N_('Identities Management')),
('services/', N_('Services Management')),
('/', N_('Pr@tic Backoffice'))]
identities = identities_ui.IdentitiesDirectory()
services = services_ui.ServicesDirectory()
collectivity = None
def _q_access(self):
get_response().breadcrumb.append( ('backoffice/', _('Back Office')) )
user = get_session().get_user_object()
if not user.is_admin() and not user.is_local_admin():
raise errors.AccessForbiddenError()
if user.is_admin():
# reset directory attributes
self.collectivity = None
self.identities.collectivity = None
self.services.collectivity = None
else:
self.collectivity = user.get_collectivity()
self.identities.collectivity = self.collectivity
self.services.collectivity = self.collectivity
def _q_index [html] (self):
html_top(_('Back Office'))
if not self.collectivity:
user = get_session().get_user_object()
agent = user.get_as_agent()
collectivity = directory.get_collectivity(agent.get_collectivity())
service_instances = directory.get_service_instances(collectivity)
if service_instances:
providers = get_cfg('providers', {})
'<h3>%s</h3>' % _('Services')
'<ul>'
for service in service_instances:
service_type = directory.get_service(service.cdg59serviceType)
service_label = service_type.cn
service_description = service_type.description
if service_type.cdg59isGlobal:
url = service_type.cdg59URL
else:
url = service.cdg59URL
metadata_url = service.cdg59metadataURL or service_type.cdg59metadataURL
if metadata_url:
try:
klp = [x for x, y in providers.items() if \
metadata_url == y.get('metadata_url')] [0]
except IndexError:
# bad, unregistered saml provider
pass
else:
try:
provider, unused_label = misc.get_provider_and_label(klp)
except KeyError:
pass
else:
if provider.getProtocolConformance() == lasso.PROTOCOL_SAML_2_0:
url = '../saml/sp/%s/login' % klp
else:
url = '../liberty/sp/%s/login' % klp
if not url:
continue
if url in (service_type.cdg59URL, service.cdg59URL):
label = _('Go to %s') % service_label
else:
label = _('Log on %s') % service_label
'<li><a href="%s">%s</a>' % (url, label)
'</li>'
'</ul>'
'<h3>%s</h3>' % _('Collectivities')
'<ul class="biglist">'
for collectivity in directory.get_sorted_collectivities():
'<li class="biglistitem">'
'<strong class="label">%s</<strong>' % collectivity.cn
'<p class="commands">'
if collectivity.ou != 'admin':
' <a href="%s/">%s</a> - ' % (collectivity.ou, _('Edit'))
' <a href="identities/%s/">%s</a>' % (collectivity.ou, _('Identities'))
' - '
' <a href="services/%s/">%s</a> ' % (collectivity.ou, _('Services'))
'</p>'
'</li>'
'</ul>'
else:
'<h3>%s</h3>' % self.collectivity.cn
'\n<dl>\n'
for k, l, a in self.collectivity.get_attrs():
if k == 'cn':
continue
if getattr(self.collectivity, k):
' <dt>%s</dt>' % _(l)
' <dd>%s</dd>\n' % getattr(self.collectivity, k)
'\n</dl>'
'<p>'
'<a href="editcol">%s</a>' % _('Edit Collectivity')
' - '
'<a href="identities/">%s</a>' % _('Identities')
' - '
'<a href="services/">%s</a>' % _('Services')
'</p>'
def _q_lookup(self, component):
if not self.collectivity:
for collectivity in directory.get_collectivities():
if collectivity.ou == component:
return CollectivityDirectory(collectivity)
raise errors.TraversalError()
def editcol [html] (self):
if not self.collectivity:
raise errors.TraversalError()
form = Form(enctype='multipart/form-data')
for k, l, attrs in self.collectivity.get_attrs():
if k in ('cn', 'cdg59collectivityId'):
continue
form.add(StringWidget, k, title = _(l),
value = getattr(self.collectivity, k),
**attrs)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('..')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('edit', _('Edit')))
html_top(self.collectivity.cn)
'<h2>%s</h2>' % self.collectivity.cn
form.render()
else:
self.submit_col(form)
return redirect('..')
def submit_col(self, form):
changed = []
for k, l, a in self.collectivity.get_attrs():
if k in ('cn', 'cdg59collectivityId'):
continue
widget = form.get_widget(k)
if widget:
v = widget.parse()
old_v = getattr(self.collectivity, k)
if v != old_v:
setattr(self.collectivity, k, v)
changed.append(k)
self.collectivity.save(changed)
class CollectivityDirectory(Directory):
_q_exports = ['']
def __init__(self, collectivity):
get_response().breadcrumb.append((collectivity.ou + '/', collectivity.cn))
self.collectivity = collectivity
def _q_index [html] (self):
form = Form(enctype='multipart/form-data')
for k, l, attrs in self.collectivity.get_attrs():
form.add(StringWidget, k, title = _(l),
value = getattr(self.collectivity, k),
**attrs)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('..')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('edit', _('Edit')))
html_top(self.collectivity.cn)
'<h2>%s</h2>' % self.collectivity.cn
form.render()
else:
self.submit(form)
return redirect('..')
def submit(self, form):
changed = []
for k, l, a in self.collectivity.get_attrs():
widget = form.get_widget(k)
if widget:
v = widget.parse()
old_v = getattr(self.collectivity, k)
if v != old_v:
setattr(self.collectivity, k, v)
changed.append(k)
self.collectivity.save(changed)
get_publisher_class().backoffice_directory_class = BackofficeRootDirectory

View File

@ -1,634 +0,0 @@
import sys
from sha import sha
import base64
import re
try:
import ldap
import ldap.async
import ldap.modlist
import ldap.filter
except ImportError:
print >> sys.stderr, 'Missing LDAP module'
ldap = None
from qommon import get_publisher
from qommon import emails
from qommon.admin.emails import EmailsDirectory
def utf8toiso(s):
return unicode(s, 'utf-8').encode('iso-8859-1')
def isotoutf8(s):
return unicode(s, 'iso-8859-1').encode('utf-8')
class UnconfiguredError(Exception):
pass
def get_store():
store = get_publisher().store
if not hasattr(store, 'pratic_ldap_url'):
raise UnconfiguredError()
return store
class Collectivity:
dn = None
ou = None
cn = None
postalAddress = None
telephoneNumber = None
facsimileTelephoneNumber = None
mail = None
cdg59URL = None
cdg59collectivityId = None
ldap_entry = None
def __init__(self, entry):
self.ldap_entry = entry
self.dn = entry[0]
data = entry[1]
for attribute in ('ou', 'cn', 'postalAddress', 'telephoneNumber',
'facsimileTelephoneNumber', 'mail', 'cdg59URL',
'cdg59collectivityId'):
v = data.get(attribute)
if v:
setattr(self, attribute, utf8toiso(data.get(attribute)[0]))
def save(self, changed):
if not changed:
return
new_entry = self.ldap_entry[1].copy()
for attribute in changed:
if attribute in ('cn','postalAddress',):
new_entry[attribute] = isotoutf8(getattr(self, attribute))
else:
new_entry[attribute] = getattr(self, attribute)
if not new_entry[attribute]:
new_entry[attribute] = []
mod_list = ldap.modlist.modifyModlist(self.ldap_entry[1], new_entry)
store = get_store()
store.ldap_conn.modify_s(self.ldap_entry[0], mod_list)
def delete(self):
store = get_store()
store.ldap_conn.delete_s(self.ldap_entry[0])
def get_attrs(self):
return [ ('cn', N_('Name'), {'required': True}),
('postalAddress', N_('Geopostal Address'), {}),
('telephoneNumber', N_('Telephone Number'), {}),
('facsimileTelephoneNumber', N_('Fax Number'), {}),
('mail', N_('Mail'), {}),
('cdg59URL', N_('Website'), {}),
('cdg59collectivityId', N_('Collectivity Code'), {})
]
def get_collectivities():
store = get_store()
result = store.ldap_conn.search_s(store.pratic_ldap_base,
ldap.SCOPE_SUBTREE, 'objectClass=cdg59collectivity')
return [Collectivity(x) for x in result]
def get_collectivity(ou):
store = get_store()
result = store.ldap_conn.search_s(store.pratic_ldap_base,
ldap.SCOPE_SUBTREE, ldap.filter.filter_format('(&(ou=%s)(objectclass=cdg59collectivity))', (ou,)))
if not result:
raise KeyError()
return Collectivity(result[0])
def get_sorted_collectivities():
result = get_collectivities()
def cmp_collectivities(x, y):
if x.dn == y.dn:
return 0
if x.ou == 'admin':
return 1
if y.ou == 'admin':
return -1
return cmp(x.cn, y.cn)
result.sort(cmp_collectivities)
return result
class Agent:
uid = None
cn = None
mail = None
cdg59isAdmin = False
cdg59isDisabled = False
sn = None
givenName = None
cdg59direction = None
ou = None
employeeType = None
postalAddress = None
telephoneNumber = None
facsimileTelephoneNumber = None
mobile = None
cdg59agentSirhCode = None
cdg59serviceAccesses = None
cdg59lastConnectionTime = None
cdg59lastConnectionDuration = None
ldap_entry = None
def __init__(self, entry):
self.ldap_entry = entry
self.dn = entry[0]
data = entry[1]
for attribute in ('cn', 'mail', 'sn', 'givenName', 'cdg59direction',
'ou', 'employeeType', 'postalAddress', 'telephoneNumber',
'facsimileTelephoneNumber', 'mobile', 'cdg59isAdmin',
'cdg59isDisabled', 'cdg59agentSirhCode'):
v = data.get(attribute)
if v:
setattr(self, attribute, utf8toiso(data.get(attribute)[0]))
self.cdg59isAdmin = (self.cdg59isAdmin == 'TRUE')
self.cdg59isDisabled = (self.cdg59isDisabled == 'TRUE')
if data.get('cdg59serviceAccesses'):
self.cdg59serviceAccesses = [utf8toiso(x) for x in data.get('cdg59serviceAccesses')]
else:
self.cdg59serviceAccesses = []
if data.get('cdg59lastConnectionTime'):
self.cdg59lastConnectionTime = int(data.get('cdg59lastConnectionTime')[0])
if data.get('cdg59lastConnectionDuration'):
self.cdg59lastConnectionDuration = int(data.get('cdg59lastConnectionDuration')[0])
self.username = data.get('uid')[0]
def save(self, changed):
if not changed:
return
new_entry = self.ldap_entry[1].copy()
for attribute in changed:
new_entry[attribute] = getattr(self, attribute)
if type(new_entry[attribute]) is int:
new_entry[attribute] = [str(new_entry[attribute])]
if type(new_entry[attribute]) is str:
new_entry[attribute] = isotoutf8(new_entry[attribute])
if new_entry[attribute] is None:
new_entry[attribute] = []
if 'cdg59agentSirhCode' in changed:
# check for an existing agent with such SIRH code
try:
get_agent_by_sirh(self.cdg59agentSirhCode)
except KeyError:
pass
else:
raise ldap.ALREADY_EXISTS('cdg59agentSirhCode')
if 'mail' in changed:
# check for an existing agent with such mail
try:
get_agent_by_email(self.mail)
except KeyError:
pass
else:
raise ldap.ALREADY_EXISTS('mail')
if 'cdg59isAdmin' in changed:
if self.cdg59isAdmin:
new_entry['cdg59isAdmin'] = 'TRUE'
else:
new_entry['cdg59isAdmin'] = ''
if 'cdg59isDisabled' in changed:
if self.cdg59isDisabled:
new_entry['cdg59isDisabled'] = 'TRUE'
else:
new_entry['cdg59isDisabled'] = ''
if 'sn' in changed or 'givenName' in changed:
# change common name too
new_entry['cn'] = '%s %s' % (self.givenName, self.sn)
new_entry['cn'] = isotoutf8(new_entry['cn'])
mod_list = ldap.modlist.modifyModlist(self.ldap_entry[1], new_entry)
store = get_store()
store.ldap_conn.modify_s(self.ldap_entry[0], mod_list)
def change_password(self, password):
userPassword = ['{sha}%s' % base64.encodestring(sha(password).digest()).strip()]
mod_list = [(ldap.MOD_REPLACE, 'userPassword', userPassword)]
store = get_store()
store.ldap_conn.modify_s(self.ldap_entry[0], mod_list)
def delete(self):
store = get_store()
store.ldap_conn.delete_s(self.ldap_entry[0])
_collectivity = None
def get_collectivity(self):
if self._collectivity:
return self._collectivity
self._collectivity = self.dn.split(',')[1].split('=')[1]
return self._collectivity
def get_admin_agents(self):
'''Get this agent "superiors"'''
store = get_store()
if self.cdg59isAdmin:
request_str = '(objectclass=cdg59agent)'
base_dn = 'ou=admin,' + store.pratic_ldap_base
else:
request_str = '(&(cdg59isAdmin=TRUE)(objectclass=cdg59agent))'
base_dn = 'ou=%s,%s' % (self.get_collectivity(), store.pratic_ldap_base)
result = store.ldap_conn.search_s(base_dn, ldap.SCOPE_SUBTREE, request_str)
agents = [Agent(x) for x in result]
return agents
def notify_access_changes(self):
if not self.mail:
return
all_services = get_services()
services = []
for service in all_services:
if service.cdg59sid in self.cdg59serviceAccesses:
services.append(service.cn)
services.sort()
services = ' - ' + '\n - '.join(services)
data = {
'agent': self.cn,
'services': services,
}
emails.custom_ezt_email('pratic-agent-access-changes', data,
[self.mail], fire_and_forget = True)
def notify_enabled(self):
if not self.mail:
return
data = { 'agent': self.cn }
emails.custom_ezt_email('pratic-agent-enabled', data,
[self.mail], fire_and_forget = True)
def notify_disabled(self):
if not self.mail:
return
data = { 'agent': self.cn }
emails.custom_ezt_email('pratic-agent-disabled', data,
[self.mail], fire_and_forget = True)
def search_agents(collectivity, search, sorted = False):
store = get_store()
request_str = ldap.filter.filter_format('(&(|(sn=%s*)(cn=%s*)(cdg59agentSirhCode=%s))(objectclass=cdg59agent))',
(search, search, search))
if collectivity:
base_dn = collectivity.dn
else:
store = get_store()
base_dn = store.pratic_ldap_base
result = store.ldap_conn.search_s(base_dn, ldap.SCOPE_SUBTREE, request_str)
agents = [Agent(x) for x in result]
if sorted:
agents.sort(lambda x,y: cmp(x.sn.lower(), y.sn.lower()))
return agents
def get_agents(collectivity, first_letter = None, sorted = False):
store = get_store()
if first_letter:
request_str = ldap.filter.filter_format('(&(sn=%s*)(objectclass=cdg59agent))', (first_letter,))
else:
request_str = 'objectClass=cdg59agent'
result = store.ldap_conn.search_s(collectivity.dn, ldap.SCOPE_SUBTREE, request_str)
agents = [Agent(x) for x in result]
if sorted:
agents.sort(lambda x,y: cmp(x.sn.lower(), y.sn.lower()))
return agents
def get_agent(collectivity, username):
store = get_store()
result = store.ldap_conn.search_s(collectivity.dn,
ldap.SCOPE_SUBTREE, ldap.filter.filter_format('(&(uid=%s)(objectclass=cdg59agent))', (username,)))
if not result:
raise KeyError()
return Agent(result[0])
def get_agent_by_sirh(sirh):
store = get_store()
result = store.ldap_conn.search_s(store.pratic_ldap_base,
ldap.SCOPE_SUBTREE, ldap.filter.filter_format('(&(cdg59agentSirhCode=%s)(objectclass=cdg59agent))', (sirh,)))
if not result:
raise KeyError()
return Agent(result[0])
def get_agent_by_email(email):
store = get_store()
result = store.ldap_conn.search_s(store.pratic_ldap_base,
ldap.SCOPE_SUBTREE, ldap.filter.filter_format('(&(mail=%s)(objectclass=cdg59agent))', (email,)))
if not result:
raise KeyError()
return Agent(result[0])
def get_collectivity_name(collectivity):
store = get_store()
result = store.ldap_conn.search_s(store.pratic_ldap_base,
ldap.SCOPE_SUBTREE, ldap.filter.filter_format('(&(ou=%s)(objectClass=cdg59collectivity))', (collectivity,)))
if not result:
raise KeyError()
return utf8toiso(result[0][1].get('cn')[0])
def add_agent(collectivity, data):
uid = data.get('uid')
dn = 'uid=%s, %s' % (data.get('uid'), collectivity.dn)
password = None
if data.get('password'):
password = data.get('password')
del data['password']
data['cn'] = '%s %s' % (data['givenName'], data['sn'])
for k in data:
data[k] = [isotoutf8(data[k])]
data['objectClass'] = 'cdg59agent'
if data.get('cdg59agentSirhCode'):
# check for an existing agent with such SIRH code
try:
get_agent_by_sirh(data.get('cdg59agentSirhCode')[0])
except KeyError:
pass
else:
raise ldap.ALREADY_EXISTS('cdg59agentSirhCode')
if data.get('mail'):
# check for an existing agent with such SIRH code
try:
get_agent_by_email(data.get('mail')[0])
except KeyError:
pass
else:
raise ldap.ALREADY_EXISTS('mail')
store = get_store()
mod_list = ldap.modlist.addModlist(data)
store.ldap_conn.add_s(dn, mod_list)
if password:
agent = get_agent(collectivity, uid)
agent.change_password(password)
def add_service(data):
store = get_store()
dn = 'cdg59sid=%s,%s' % (data.get('cdg59sid'), store.pratic_ldap_base)
for k in data:
if k == 'cdg59isGlobal':
if data[k]:
data['cdg59isGlobal'] = 'TRUE'
else:
data['cdg59isGlobal'] = 'FALSE'
else:
data[k] = [isotoutf8(data[k])]
data['objectClass'] = 'cdg59service'
mod_list = ldap.modlist.addModlist(data)
store.ldap_conn.add_s(dn, mod_list)
class ServiceInstance:
dn = None
cdg59siid = None
cdg59URL = None
cdg59metadataURL = None
cdg59serviceType = None
ldap_entry = None
def __init__(self, entry = None):
if not entry:
return
self.ldap_entry = entry
self.dn = entry[0]
data = entry[1]
for attribute in ('cdg59siid', 'cdg59URL', 'cdg59metadataURL', 'cdg59serviceType'):
v = data.get(attribute)
if v:
setattr(self, attribute, utf8toiso(data.get(attribute)[0]))
def save(self, changed):
if not changed:
return
new_entry = self.ldap_entry[1].copy()
for attribute in changed:
new_entry[attribute] = getattr(self, attribute)
if not new_entry[attribute]:
new_entry[attribute] = []
mod_list = ldap.modlist.modifyModlist(self.ldap_entry[1], new_entry)
store = get_store()
store.ldap_conn.modify_s(self.ldap_entry[0], mod_list)
_name = None
def get_name(self):
if self._name:
return self._name
store = get_store()
result = store.ldap_conn.search_s(store.pratic_ldap_base,
ldap.SCOPE_SUBTREE, ldap.filter.filter_format('(&(cdg59sid=%s)(objectClass=cdg59service))', (self.cdg59siid,)))
try:
self._name = utf8toiso(result[0][1]['cn'][0])
except IndexError:
self._name = '%s (e)' % self.cdg59siid
return self._name
name = property(get_name)
def delete(self):
store = get_store()
store.ldap_conn.delete_s(self.ldap_entry[0])
def add(self, collectivity):
data = {}
dn = 'cdg59siid=%s, %s' % (self.cdg59siid, collectivity.dn)
data['objectClass'] = 'cdg59serviceInstance'
data['cdg59siid'] = self.cdg59siid
data['cdg59serviceType'] = self.cdg59serviceType
if self.cdg59URL:
data['cdg59URL'] = self.cdg59URL
if self.cdg59metadataURL:
data['cdg59metadataURL'] = self.cdg59metadataURL
mod_list = ldap.modlist.addModlist(data)
store = get_store()
store.ldap_conn.add_s(dn, mod_list)
def get_service_instances(collectivity):
store = get_store()
result = store.ldap_conn.search_s(collectivity.dn,
ldap.SCOPE_SUBTREE, 'objectClass=cdg59serviceInstance')
service_instances = [ServiceInstance(x) for x in result]
# fill missing fields for global services
services = get_services()
for si in service_instances:
try:
s = get_service(si.cdg59serviceType)
if s and s.cdg59isGlobal:
si.cdg59metadataURL = s.cdg59metadataURL
si.cdg59URL = s.cdg59URL
except KeyError:
# ignore error for removed service type
continue
return service_instances
def get_service_instances_by_service_type(sid):
store = get_store()
result = store.ldap_conn.search_s(store.pratic_ldap_base,
ldap.SCOPE_SUBTREE, ldap.filter.filter_format('(&(objectClass=cdg59serviceInstance)(cdg59serviceType=%s))', (sid,)))
service_instances = [ServiceInstance(x) for x in result]
# fill missing fields for global services
services = get_services()
for si in service_instances:
try:
s = get_service(si.cdg59serviceType)
if s and s.cdg59isGlobal:
si.cdg59metadataURL = s.cdg59metadataURL
si.cdg59URL = s.cdg59URL
except KeyError:
# ignore error for removed service type
continue
return service_instances
def get_service_instance(collectivity, siid):
store = get_store()
result = store.ldap_conn.search_s(collectivity.dn,
ldap.SCOPE_SUBTREE, ldap.filter.filter_format('(&(cdg59siid=%s)(objectclass=cdg59serviceInstance))', (siid,)))
if not result:
raise KeyError()
si = ServiceInstance(result[0])
# fix missing field values for global services
try:
s = get_service(si.cdg59serviceType)
if s and s.cdg59isGlobal:
si.cdg59metadataURL = s.cdg59metadataURL
si.cdg59URL = s.cdg59URL
except KeyError:
# ignore error for removed service type
pass
return si
class Service:
dn = None
cn = None
cdg59sid = None
description = None
cdg59isGlobal = False
cdg59URL = None
cdg59metadataURL = None
ldap_entry = None
def __init__(self, entry):
self.ldap_entry = entry
self.dn = entry[0]
data = entry[1]
for attribute in ('cn', 'cdg59sid', 'description', 'cdg59isGlobal', 'cdg59URL',
'cdg59metadataURL'):
v = data.get(attribute)
if v:
setattr(self, attribute, utf8toiso(data.get(attribute)[0]))
self.cdg59isGlobal = (self.cdg59isGlobal == 'TRUE')
def delete(self):
store = get_store()
store.ldap_conn.delete_s(self.ldap_entry[0])
def save(self, changed):
if not changed:
return
mod_list = []
for attribute in changed:
value = getattr(self, attribute)
if value:
if attribute == 'cdg59isGlobal':
if value:
value = 'TRUE'
else:
value = 'FALSE'
else:
value = isotoutf8(value)
if value:
mod_list.append((ldap.MOD_REPLACE, attribute, value))
else:
mod_list.append((ldap.MOD_DELETE, attribute, None))
store = get_store()
store.ldap_conn.modify_s(self.ldap_entry[0], mod_list)
def get_service(sid):
store = get_store()
result = store.ldap_conn.search_s(store.pratic_ldap_base,
ldap.SCOPE_SUBTREE, ldap.filter.filter_format('(&(cdg59sid=%s)(objectclass=cdg59service))', (sid,)))
if not result:
raise KeyError()
return Service(result[0])
def get_services():
store = get_store()
result = store.ldap_conn.search_s(store.pratic_ldap_base,
ldap.SCOPE_SUBTREE, 'objectClass=cdg59service')
return [Service(x) for x in result]
EmailsDirectory.register('pratic-agent-access-changes',
N_('Pr@tic Agent Access Changes'),
N_('Available variables: agent, services'),
default_subject = N_('Change of access'),
default_body = N_('''\
Hello [agent],
There were changes to your service authorizations, you may now access
the followind services:
[services]
'''))
EmailsDirectory.register('pratic-agent-enabled',
N_('Pr@tic Agent Enabled'),
N_('Available variables: agent'),
default_subject = N_('Pr@tic Account Enabled'),
default_body = N_('''\
Hello [agent],
Your Pr@tic account has been enabled.
'''))
EmailsDirectory.register('pratic-agent-disabled',
N_('Pr@tic Agent Disabled'),
N_('Available variables: agent'),
default_subject = N_('Pr@tic Account Disabled'),
default_body = N_('''\
Hello [agent],
Your Pr@tic account has been disabled.
'''))

View File

@ -1,621 +0,0 @@
import ldap
import re
from quixote import get_request, get_response, get_session, redirect
from quixote.directory import Directory
from qommon.backoffice.menu import html_top
from qommon.admin.menu import command_icon
from qommon import errors, get_cfg
from qommon.form import *
import string
import directory
def generate_password():
passwords_cfg = get_cfg('passwords', {})
min_len = passwords_cfg.get('min_length', 0)
max_len = passwords_cfg.get('max_length', 0)
if min_len == 0 and max_len == 0:
password_len = 6
elif min_len == 0:
password_len = min(6, max_len)
elif max_len == 0:
password_len = max(6, min_len)
else:
password_len = (max_len + min_len) / 2
return ''.join([random.choice(string.letters) for x in range(password_len)])
class AgentDirectory(Directory):
_q_exports = ['', 'edit', 'delete', 'disable', 'enable', 'password']
attrs = [
('cdg59agentSirhCode', N_('SIRH Code'), {'required': True, 'size': 30}),
('sn', N_('Last Name'), {'required': True, 'size': 30}),
('givenName', N_('First Name'), {'required': True, 'size': 30}),
('cdg59direction', N_('Direction'), {'size': 30}),
('ou', N_('Service'), {'size': 30}),
('employeeType', N_('Functions'), {'size': 30}),
('postalAddress', N_('Geopostal Address'), {'size': 30}),
('mail', N_('Mail'), {'size': 30, 'required': True}),
('telephoneNumber', N_('Telephone Number'), {'size': 30}),
('facsimileTelephoneNumber', N_('Fax Number'), {'size': 30}),
('mobile', N_('Professional Mobile Number'), {'size': 30}),
('cdg59isAdmin', N_('Collectivity Admin'), {'widget_class': CheckboxWidget}),
]
def __init__(self, agent):
self.agent = agent
get_response().breadcrumb.append((self.agent.username + '/', self.agent.cn))
def _q_index [html] (self):
html_top('identities', title = _('Agent: %s') % self.agent.cn)
'<h2>%s</h2>' % _('Agent: %s') % self.agent.cn
if self.agent.cdg59isDisabled:
'<p>'
_('This account is disabled.')
'</p>'
'\n<dl>\n'
'<dt>%s</dt>' % _('Username')
'<dd>%s</dd>\n' % self.agent.username
for k, l, attrs in self.attrs:
if getattr(self.agent, k):
' <dt>%s</dt>' % _(l)
' <dd>%s</dd>\n' % getattr(self.agent,k)
'\n</dl>'
'<p>'
'<a href="edit">%s</a> - ' % _('Edit')
user = get_session().get_user_object()
if user.is_admin() or user.is_local_admin():
if self.agent.cdg59isDisabled:
'<a href="enable">%s</a> - ' % _('Enable Account')
else:
'<a href="disable">%s</a> - ' % _('Disable Account')
if user.is_admin():
'<a href="delete" rel="popup">%s</a> - ' % _('Delete')
'<a href="password">%s</a>' % _('Change Password')
'</p>'
def edit [html] (self):
user = get_session().get_user_object()
form = Form(enctype='multipart/form-data')
for k, l, attrs in self.attrs:
if not user.is_admin() and k in ('cdg59agentSirhCode', 'sn', 'givenName'):
continue
if attrs.has_key('widget_class'):
widget_class = attrs.get('widget_class')
attrs = attrs.copy()
del attrs['widget_class']
else:
widget_class = StringWidget
form.add(widget_class, k, title = _(l),
value = getattr(self.agent, k),
**attrs)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('..')
if form.is_submitted() and not form.has_errors():
if self.submit(form):
return redirect('..')
get_response().breadcrumb.append(('edit', _('Edit')))
html_top('identities', title = _('Agent: %s') % self.agent.cn)
'<h2>%s</h2>' % self.agent.cn
form.render()
def submit(self, form):
changed = []
for k, l, attrs in self.attrs:
widget = form.get_widget(k)
if widget:
v = widget.parse()
old_v = getattr(self.agent, k)
if v != old_v:
setattr(self.agent, k, v)
changed.append(k)
try:
self.agent.save(changed)
except ldap.ALREADY_EXISTS, error:
if type(error.args[0]) is dict: # native ldap exception
form.set_error('uid', _('This username is already in use.'))
elif error.args[0] == 'cdg59agentSirhCode':
form.set_error('cdg59agentSirhCode', _('This SIRH code is already in use.'))
elif error.args[0] == 'mail':
form.set_error('mail', _('This email is already in use.'))
return False
return True
def disable(self):
user = get_session().get_user_object()
if user.is_admin() or user.is_local_admin():
self.agent.cdg59isDisabled = True
self.agent.save(['cdg59isDisabled'])
self.agent.notify_disabled()
return redirect('.')
else:
raise errors.AccessForbiddenError()
def enable(self):
user = get_session().get_user_object()
if user.is_admin() or user.is_local_admin():
self.agent.cdg59isDisabled = False
self.agent.save(['cdg59isDisabled'])
self.agent.notify_enabled()
return redirect('.')
else:
raise errors.AccessForbiddenError()
def delete [html] (self):
user = get_session().get_user_object()
if not user.is_admin():
raise errors.AccessForbiddenError()
form = Form(enctype='multipart/form-data')
form.widgets.append(HtmlWidget('<p>%s</p>' % _(
'You are about to irrevocably delete this agent.')))
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('..')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('delete', _('Delete')))
html_top('identities', title = _('Delete Agent'))
'<h2>%s</h2>' % _('Deleting Agent: %s') % self.agent.cn
form.render()
else:
self.agent.delete()
return redirect('..')
def password [html] (self):
form = Form(enctype='multipart/form-data')
form.add(PasswordWidget, 'new_password', title=_('New Password'), required=True)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('password', _('Change Password')))
html_top('identities', title = _('Agent: %s') % self.agent.cn)
'<h2>%s</h2>' % self.agent.cn
form.render()
else:
self.agent.change_password(str(form.get_widget('new_password').parse()))
return redirect('..')
class IdentitiesDirectory(Directory):
_q_exports = ['', 'new', 'lookup_sirh', 'authorizations', 'csv']
collectivity = None
def __init__(self, collectivity = None):
Directory.__init__(self)
self.collectivity = collectivity
def _q_traverse(self, path):
user = get_session().get_user_object()
if not self.collectivity:
get_response().breadcrumb.append(('identities/', _('Identity Management')))
if not user.is_admin():
self.collectivity = user.get_collectivity()
else:
if not user.is_admin():
get_response().breadcrumb.append(('identities/', _('Identity Management')))
return Directory._q_traverse(self, path)
def _q_index [html] (self):
html_top('identities', _('Identity Management'))
get_session().display_message()
user = get_session().get_user_object()
if user.is_admin() and not self.collectivity:
# list all collectivities
form = Form()
form.add(StringWidget, 'search', title = _('Search'))
form.render()
if form.is_submitted():
return self.all_search_results(form.get_widget('search').parse())
'<ul>'
for collectivity in directory.get_sorted_collectivities():
'<li><a href="%s/">' % collectivity.ou
collectivity.cn
'</a></li>'
'</ul>'
else:
'<h2>'
self.collectivity.cn
'</h2>'
'<p>'
if user.is_admin():
'<a href="../../services/%s/">%s</a> - ' % (
self.collectivity.ou, _('Services Management'))
else:
'<a href="../services/">%s</a> - ' % _('Services Management')
if user.is_admin():
'<a href="new">%s</a> - ' % _('Add a new Agent')
'<a href="csv">%s</a> - ' % _('Import CSV File')
if (user.is_admin() or user.is_local_admin()) and (self.collectivity.ou != 'admin'):
'<a href="authorizations">%s</a>' % _('Manage Authorizations')
'</p>'
form = Form()
form.add(StringWidget, 'search', title = _('Search'))
form.render()
if form.is_submitted():
agents = directory.search_agents(self.collectivity,
form.get_widget('search').parse(), sorted = True)
else:
current_letter = get_request().form.get('letter', 'A')
if str(current_letter) not in list(string.letters) + ['all']:
current_letter = 'A'
'<div class="letters-nav">'
for letter in string.uppercase:
if letter == current_letter:
'<span class="current-letter">%s</span>' % letter
else:
'<a href="?letter=%s">%s</a>' % (letter, letter)
'-'
if letter == string.uppercase[-1]:
letter = N_('all')
if letter == current_letter:
'<span class="current-letter">(%s)</span>' % _(letter)
else:
'<a href="?letter=%s">(%s)</a>' % (letter, _(letter))
'</div>'
if current_letter == 'all':
agents = directory.get_agents(self.collectivity, sorted = True)
else:
agents = directory.get_agents(self.collectivity,
first_letter = current_letter, sorted = True)
'<ul class="biglist">'
for agent in agents:
if agent.cdg59isDisabled:
'<li class="biglistitem disabled">'
elif agent.cdg59isAdmin:
'<li class="biglistitem admin">'
else:
'<li class="biglistitem">'
'<strong class="label">%s</strong>' % agent.cn
'<p class="commands">'
command_icon('%s/' % agent.username, 'view')
command_icon('%s/edit' % agent.username, 'edit')
if user.is_admin():
command_icon('%s/delete' % agent.username, 'remove', popup = True)
'</p></li>'
'</ul>'
if user.is_admin():
'<p>'
'<a href="../">%s</a>' % _('Back')
'</p>'
def all_search_results [html] (self, query):
agents = directory.search_agents(None, query, sorted = True)
user = get_session().get_user_object()
agents.sort(lambda x,y: cmp(x.get_collectivity(), y.get_collectivity()))
last_col = None
for agent in agents:
agent_col = agent.get_collectivity()
if agent_col != last_col:
if last_col is not None:
'</ul>'
try:
'<h2>%s</h2>' % directory.get_collectivity_name(agent_col)
except KeyError:
'<h2>%s</h2>' % _('Unknown Collectivity')
'<ul class="biglist">'
last_col = agent_col
if agent.cdg59isDisabled:
'<li class="biglistitem disabled">'
elif agent.cdg59isAdmin:
'<li class="biglistitem admin">'
else:
'<li class="biglistitem">'
'<strong class="label">%s</strong>' % agent.cn
'<p class="commands">'
command_icon('%s/%s/' % (agent_col, agent.username), 'view')
command_icon('%s/%s/edit' % (agent_col, agent.username), 'edit')
if user.is_admin():
command_icon('%s/%s/delete' % (agent_col, agent.username),
'remove', popup = True)
'</p></li>'
if last_col is not None:
'</ul>'
def authorizations [html] (self):
if not self.collectivity:
raise errors.TraversalError()
user = get_session().get_user_object()
if not (user.is_admin() or user.is_local_admin()):
raise errors.AccessForbiddenError()
if get_request().get_method() == 'POST':
return self.authorizations_submit()
html_top('identities', _('Authorizations Management'))
get_response().breadcrumb.append(('authorizations', _('Authorizations Management')))
get_session().display_message()
services = directory.get_service_instances(self.collectivity)
current_letter = get_request().form.get('letter', 'A')
if str(current_letter) not in list(string.letters) + ['all']:
current_letter = 'A'
'<div class="letters-nav">'
for letter in string.uppercase:
if letter == current_letter:
'<span class="current-letter">%s</span>' % letter
else:
'<a href="?letter=%s">%s</a>' % (letter, letter)
'-'
if letter == string.uppercase[-1]:
letter = N_('all')
if letter == current_letter:
'<span class="current-letter">(%s)</span>' % _(letter)
else:
'<a href="?letter=%s">(%s)</a>' % (letter, _(letter))
'</div>'
if current_letter == 'all':
agents = directory.get_agents(self.collectivity, sorted = True)
else:
agents = directory.get_agents(self.collectivity,
first_letter = current_letter, sorted = True)
'<form method="post">'
'<input type="hidden" name="letter" value="%s"/>' % current_letter
'<table>'
'<thead>'
'<tr>'
'<td></td>'
saml_services = []
for service in services:
if service.cdg59metadataURL:
saml_services.append(service)
else:
service_type = directory.get_service(service.cdg59serviceType)
if service_type.cdg59metadataURL:
saml_services.append(service)
else:
continue
'<th>%s</th>' % service.name
'</tr>'
'</thead>'
'<tbody>'
for agent in agents:
if agent.cdg59isDisabled:
'<tr class="disabled">'
else:
'<tr>'
'<th>%s</th>' % agent.cn
for service in saml_services:
'<td>'
'<input name="%s" type="checkbox" value="%s"' % (agent.username, service.cdg59siid)
if service.cdg59siid in agent.cdg59serviceAccesses:
' checked="checked"'
'/>'
'</td>'
'</tr>'
'</tbody>'
'</table>'
'<input type="submit" value="%s"/>' % _('Submit')
'</form>'
def authorizations_submit(self):
current_letter = get_request().form.get('letter', 'A')
if current_letter == 'all':
agents = directory.get_agents(self.collectivity, sorted = True)
else:
agents = directory.get_agents(self.collectivity,
first_letter = current_letter, sorted = True)
form = get_request().form
for agent in agents:
accesses = agent.cdg59serviceAccesses
new_value = form.get(agent.username, [])
if sorted(accesses) != sorted(new_value):
agent.cdg59serviceAccesses = new_value
agent.save(changed = ['cdg59serviceAccesses'])
agent.notify_access_changes()
get_session().message = ('info', _('New authorizations saved succesfully.'))
return redirect('authorizations?letter=%s' % current_letter)
def lookup_sirh(self):
form = Form(action = 'lookup_sirh')
form.add(StringWidget, 'sirh', title = _('Search on SIRH Code'), size = 10,
required = True)
if not form.is_submitted() or form.has_errors():
get_session().message = ('error', _('Error looking up agent'))
return redirect('.')
sirh = form.get_widget('sirh').parse()
try:
agent = directory.get_agent_by_sirh(sirh)
except KeyError:
get_session().message = ('error', _('No agent found with this SIRH'))
return redirect('.')
uid, collectivity, foobar = agent.dn.split(',', 2)
uid = uid.split('=')[1]
collectivity = collectivity.split('=')[1]
if self.collectivity:
return redirect('../%s/%s/' % (collectivity, uid))
else:
return redirect('%s/%s/' % (collectivity, uid))
def new [html] (self):
user = get_session().get_user_object()
if not user.is_admin():
raise errors.AccessForbiddenError()
form = Form(enctype='multipart/form-data')
form.add(StringWidget, 'uid', title = _('Pr@tic Username'), required = True, size = 30)
form.add(StringWidget, 'cdg59agentSirhCode', title = _('SIRH Code'), required = True,
size = 30)
form.add(StringWidget, 'sn', title = _('Last Name'), required = True, size = 30)
form.add(StringWidget, 'givenName', title = _('First Name'), required = True, size = 30)
form.add(StringWidget, 'mail', title = _('Mail'), size = 30, required = True)
form.add(StringWidget, 'password', title = _('Password'), size = 30, required = True,
value = generate_password())
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted():
uid = form.get_widget('uid').parse()
if uid and not re.match(str('^[A-Za-z0-9\.-]+$'), uid):
form.set_error('uid', _('wrong format'))
if form.is_submitted() and not form.has_errors():
agent = self.submit_new(form)
if agent:
return self.newly_created_agent(form, agent)
get_response().breadcrumb.append(('new', _('New')))
html_top('identities', title = _('New Agent'))
'<h2>%s</h2>' % _('New Agent')
form.render()
def newly_created_agent [html] (self, form, agent):
get_response().breadcrumb.append(('new', _('New')))
html_top('identities', title = _('New Agent'))
'<h2>%s</h2>' % _('New Agent')
'<p>'
_('A new agent has been created in the LDAP directory, you may want to send '
'those login informations :')
'</p>'
'<ul>'
'<li>%s</li>' % _('Username: %s') % agent.username
'<li>%s</li>' % _('Password: %s') % form.get_widget('password').parse()
'</ul>'
'<p>'
'<a href="new">%s</a>' % _('Add another agent')
' - '
'<a href="%s/edit">%s</a>' % (agent.username, _('Edit other fields'))
'</p>'
def submit_new(self, form):
try:
directory.add_agent(self.collectivity, {
'uid': form.get_widget('uid').parse(),
'sn': form.get_widget('sn').parse(),
'givenName': form.get_widget('givenName').parse(),
'cdg59agentSirhCode': form.get_widget('cdg59agentSirhCode').parse(),
'password': form.get_widget('password').parse(),
'mail': form.get_widget('mail').parse()})
except ldap.ALREADY_EXISTS, error:
if type(error.args[0]) is dict: # native ldap exception
form.set_error('uid', _('This username is already in use.'))
elif error.args[0] == 'cdg59agentSirhCode':
form.set_error('cdg59agentSirhCode', _('This SIRH code is already in use.'))
elif error.args[0] == 'mail':
form.set_error('mail', _('This email is already in use.'))
return None
return directory.get_agent(self.collectivity, form.get_widget('uid').parse())
def csv [html] (self):
user = get_session().get_user_object()
if not user.is_admin():
raise errors.AccessForbiddenError()
form = Form(enctype='multipart/form-data')
form.add(FileWidget, 'csv', title = _('CSV File'), required = True)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('csv', _('CSV Import')))
html_top('identities', title = _('CSV Import'))
'<h2>%s</h2>' % _('CSV Import')
'<p>'
_('Fields must be separated by ; and in the following order.')
'</p>'
'<p>'
_('You will get a CSV file with generated identifies and passwords appended.')
'</p>'
'<ul>'
for i, attr in enumerate(AgentDirectory.attrs):
'<li>%s</li>' % _(attr[1])
'</ul>'
form.render()
else:
return self.csv_submit(form)
def csv_submit(self, form):
output = []
for line in form.get_widget('csv').parse().fp.readlines():
fields = line.strip().split(';')
data = {}
for i, attr in enumerate(AgentDirectory.attrs):
if fields[i]:
data[attr[0]] = fields[i]
data['uid'] = ('%s.%s' % (data['givenName'], data['sn'])).lower()
data['password'] = generate_password()
output.append(line.strip() + ';%s;%s' % (data['uid'], data['password']))
try:
directory.add_agent(self.collectivity, data)
except:
output[-1] = output[-1] + ';ERROR'
response = get_response()
response.set_content_type('text/csv')
response.set_header('content-disposition', 'attachment; filename=result.csv')
return '\n'.join(output)
def _q_lookup(self, component):
if not self.collectivity:
for collectivity in directory.get_collectivities():
if collectivity.ou == component:
get_response().breadcrumb.append((component + '/', collectivity.cn))
return IdentitiesDirectory(collectivity)
else:
# lookup for agent
try:
agent = directory.get_agent(self.collectivity, component)
except KeyError:
pass
else:
return AgentDirectory(agent)
raise errors.TraversalError()

View File

@ -1,351 +0,0 @@
import lasso
import Cookie
from quixote import redirect, get_session
from qommon import get_cfg, get_logger
from qommon.form import *
from qommon import template
import authentic.root
from qommon.admin.texts import TextsDirectory
from qommon.admin.emails import EmailsDirectory
from qommon import emails
from qommon import errors
from authentic import identities
from authentic import misc
import directory
import store
import admin
OldRootDirectory = authentic.root.RootDirectory
from saml2 import AlternateSaml2Directory
from identities_ui import AgentDirectory
class AlternateRootDirectory(OldRootDirectory):
backoffice = None
admin = admin.AdminRootDirectory()
saml = AlternateSaml2Directory()
def __init__(self):
OldRootDirectory.__init__(self)
self._q_exports = OldRootDirectory._q_exports + [
'backoffice', 'profile', 'issue', 'password']
def _q_index [html] (self):
session = get_session()
if not session or not session.user:
return self.login()
user = get_session().get_user_object()
if user.is_admin():
return redirect('/backoffice/')
agent = user.get_as_agent()
template.html_top(_('Welcome, %s') % agent.cn)
if hasattr(session, str('previousConnectionTime')):
'<p>'
_('Last session started: %s') % misc.localstrftime(
time.localtime(session.previousConnectionTime))
if session.previousConnectionDuration:
_(' (duration: %dm)') % int(session.previousConnectionDuration/60)
'</p>'
all_services = directory.get_services()
collectivity = directory.get_collectivity(agent.get_collectivity())
service_instances = directory.get_service_instances(collectivity)
providers = get_cfg('providers', {})
accesses = user.get_as_agent().cdg59serviceAccesses or []
'<ul id="services">'
for service in service_instances:
try:
service_type = directory.get_service(service.cdg59serviceType)
except KeyError:
# ignore service type that has been removed globally
continue
service_label = service_type.cn
service_description = service_type.description
if service_type.cdg59isGlobal:
url = service_type.cdg59URL
else:
url = service.cdg59URL
metadata_url = service.cdg59metadataURL or service_type.cdg59metadataURL
if not service.cdg59siid in accesses and metadata_url:
# only skip access to liberty/saml services
continue
if metadata_url:
try:
klp = [x for x, y in providers.items() if \
metadata_url == y.get('metadata_url')] [0]
except IndexError:
# bad, unregistered saml provider
pass
else:
try:
provider, unused_label = misc.get_provider_and_label(klp)
except KeyError:
pass
else:
if provider.getProtocolConformance() == lasso.PROTOCOL_SAML_2_0:
url = 'saml/sp/%s/login' % klp
else:
url = 'liberty/sp/%s/login' % klp
if not url:
continue
if url in (service_type.cdg59URL, service.cdg59URL):
label = _('Go to %s') % service_label
else:
label = _('Log on %s') % service_label
'<li><a href="%s">%s</a>' % (url, label)
if service_description:
' <p class="service_description">%s</p>' % service_description
'</li>'
'</ul>'
t = TextsDirectory.get_html_text('pratic-platform-status')
if t:
'<div id="platform-status">'
'<h3>%s</h3>' % _('Platform Status')
'<div>'
htmltext(t)
'</div>'
if not user.is_admin():
'<p id="report-issue">'
'<a href="/issue">%s</a>' % _('Report an issue')
'</p>'
'</div>'
'<p id="commands">'
'<a href="/profile">%s</a> - ' % _('View Profile')
passwords_cfg = get_cfg('passwords', {})
if passwords_cfg.get('can_change', False):
'<a href="/password">%s</a> - ' % _('Change Password')
if user.is_admin():
'<a href="/admin/">%s</a> - ' % _('Administration Interface')
'<a href="/backoffice/">%s</a> - ' % _('Back Office Interface')
'<a href="/singleLogout">%s</a>' % _('Logout')
elif user.is_local_admin():
'<a href="/backoffice/">%s</a> - ' % _('Back Office Interface')
'<a href="/singleLogout">%s</a>' % _('Logout')
else:
'<a href="/singleLogout">%s</a>' % _('Logout')
'</p>'
def _q_traverse(self, path):
get_publisher().store = identities.load_store()
try:
store = directory.get_store()
except directory.UnconfiguredError:
if path and path[0] not in ['admin', 'qo', 'css', 'themes', 'js']:
return template.error_page(_('Directory must first be configured'))
if not self.backoffice:
self.backoffice = get_publisher().backoffice_directory_class()
session = get_session()
if session:
identities.get_store().connect(session)
return OldRootDirectory._q_traverse(self, path)
def get_login_form(self):
form = OldRootDirectory.get_login_form(self)
try:
collectivities = directory.get_sorted_collectivities()
except directory.UnconfiguredError:
return form
collectivities = [(x.dn, x.cn) for x in collectivities]
password_widget = form.widgets[-1]
form.widgets.remove(password_widget)
try:
collectivity = get_request().cookies['collectivity']
except KeyError:
collectivity = None
if collectivity not in [x[0] for x in collectivities]:
collectivity = None
form.add(SingleSelectWidget, 'collectivity', title = _('Collectivity'), required = True,
value = collectivity, options = collectivities)
form.widgets.append(password_widget)
return form
def login_submit(self, form):
try:
store = directory.get_store()
except directory.UnconfiguredError:
return OldRootDirectory.login_submit(self, form)
username = form.get_widget('username').parse()
password = form.get_widget('password').parse()
collectivity = form.get_widget('collectivity').parse()
identity = store.get_identity_for_account(username, password, collectivity)
if identity is None:
get_logger().warn('Authentication Failure (un: %s)' % username)
raise authentic.root.LoginError()
session = get_session()
session.set_user(identity.id)
get_request().user = identity.id
store.init_session(session, password)
identity.register_new_session()
get_response().set_cookie('collectivity', collectivity, path = '/',
expires = Cookie._getdate(90*86400))
return self.login_success(identity)
def forgot_password(self):
raise NotImplementedError()
def profile [html] (self):
if not get_request().user:
raise errors.AccessUnauthorizedError()
get_response().breadcrumb.append(('profile', _('Your Profile')))
template.html_top(_('Your Profile'))
user = get_session().get_user_object()
agent = user.get_as_agent()
'<dl class="profile">'
for k, l, attrs in AgentDirectory.attrs:
if k in ('cdg59isAdmin',):
continue
if attrs.has_key('widget_class'):
widget_class = attrs.get('widget_class')
attrs = attrs.copy()
del attrs['widget_class']
else:
widget_class = StringWidget
'<dt>%s</dt>' % _(l)
if getattr(agent, k):
'<dd>%s</dd>' % getattr(agent, k)
else:
'<dd>-</dd>'
'</dl>'
'<p>'
'<a href=".">%s</a>' % _('Home')
def password [html] (self):
passwords_cfg = get_cfg('passwords', {})
if not passwords_cfg.get('can_change', False):
raise errors.AccessForbiddenError()
if not get_request().user:
raise errors.AccessUnauthorizedError()
form = Form(enctype='multipart/form-data')
form.add(PasswordWidget, 'new_password', title=_('New Password'), required=True)
form.add(PasswordWidget, 'new2_password', title=_('New Password (confirmation)'),
required=True)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted() and not form.has_errors():
new_password = form.get_widget('new_password').parse()
new2_password = form.get_widget('new2_password').parse()
if new_password != new2_password:
form.set_error('new2_password', _('Passwords do not match'))
else:
min_length = int(passwords_cfg.get('min_length', 0))
if len(new_password) < min_length:
form.set_error('new_password',
_('Password is too short. It must be at least %d characters.') % min_length)
max_length = int(passwords_cfg.get('max_length', 0))
if max_length and len(new_password) > max_length:
form.set_error('new_password',
_('Password is too long. It must be at most %d characters.') % max_length)
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('password', _('Change Password')))
template.html_top(_('Change Password'))
form.render()
else:
user = get_session().get_user_object()
agent = user.get_as_agent()
agent.change_password(str(form.get_widget('new_password').parse()))
return redirect('..')
def issue [html] (self):
user = get_session().get_user_object()
if user.is_admin():
return template.error_page(_('You are not one to report issues.'))
form = Form(enctype='multipart/form-data')
form.add(TextWidget, 'description', title = _('Description'), cols = 60, rows = 10)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('issue', _('Issue Report')))
template.html_top(_('Reporting an Issue'))
'<p>'
if user.is_local_admin():
_('The issue will be sent to Pr@tic administrators.')
else:
_('The issue will be sent to your local administrators.')
'</p>'
form.render()
else:
self.issue_submit(form)
return redirect('.')
def issue_submit(self, form):
user = get_session().get_user_object()
agent = user.get_as_agent()
description = form.get_widget('description').parse()
admins = agent.get_admin_agents()
admin_emails = [x.mail for x in admins if x.mail]
data = {
'agent': agent.cn,
'description': description,
}
emails.custom_ezt_email('pratic-issue-report', data, admin_emails, fire_and_forget = True)
from qommon.publisher import get_publisher_class
get_publisher_class().root_directory_class = AlternateRootDirectory
TextsDirectory.register('pratic-platform-status', N_('Pr@tic Platform Status'))
EmailsDirectory.register('pratic-issue-report',
N_('Pr@tic Issue Report'),
N_('Available variables: agent, description'),
default_subject = N_('Pr@tic Issue'),
default_body = N_('''\
Agent [agent] reported the following problem:
[description]
'''))

View File

@ -1,101 +0,0 @@
from quixote import get_session
from qommon import get_cfg
from qommon import errors
from qommon import template
import liberty.saml2
import misc
import directory
def check_access_authorizations(provider_key):
session = get_session()
if not session or session.user is None:
return False
user = get_session().get_user_object()
if user.is_admin():
return True
collectivity = user.get_collectivity()
service_instances = directory.get_service_instances(collectivity)
providers = get_cfg('providers', {})
accesses = user.get_as_agent().cdg59serviceAccesses or []
for service in service_instances:
try:
service_type = directory.get_service(service.cdg59serviceType)
except KeyError:
# ignore service type removed globally
continue
if not service.cdg59siid in accesses:
continue
# handle global services
if service_type.cdg59isGlobal:
cdg59metadataURL = service_type.cdg59metadataURL
else:
cdg59metadataURL = service.cdg59metadataURL
if not cdg59metadataURL:
continue
try:
klp = [x for x, y in providers.items() if \
cdg59metadataURL == y.get('metadata_url')] [0]
except IndexError:
continue
if provider_key == klp:
return True
return False
class AccessControlSpUI(liberty.saml2.SpUI):
def _q_access(self):
authorized = check_access_authorizations(self.provider_key)
if not authorized:
if get_session():
raise errors.AccessForbiddenError()
else:
raise errors.AccessUnauthorizedError()
def login(self, encryption_mode = None, method = None, nid_format = None, relay_state = None):
return liberty.saml2.SpUI.login(self, encryption_mode, method, nid_format, 'backoffice')
class AccessControlSpDir(liberty.saml2.SpDir):
def _q_lookup(self, component):
return AccessControlSpUI(component)
class AlternateSaml2Directory(liberty.saml2.RootDirectory):
sp = AccessControlSpDir()
def check_access_authorizations(self, login):
provider_id = login.remoteProviderId
provider_key = misc.get_provider_key(provider_id)
return check_access_authorizations(provider_key)
def sso_after_authentication(self, login, user_authenticated, proxied = False):
if user_authenticated:
if not self.check_access_authorizations(login):
provider_id = login.remoteProviderId
provider_key = misc.get_provider_key(provider_id)
try:
label = misc.get_provider_and_label(provider_key)[1]
except KeyError:
return template.error_page(_('''\
You do not have required authorizations to access the service,
you should contact the administration of your collectivity.'''))
return template.error_page(_('''\
You do not have required authorizations to access the "%s" service,
you should contact the administration of your collectivity.''') % label)
return liberty.saml2.RootDirectory.sso_after_authentication(
self, login, user_authenticated, proxied=proxied)

View File

@ -1,600 +0,0 @@
import lasso
import tempfile
import re
import urllib2
import ldap.dn
import ldap
from quixote import get_request, get_response, get_session, redirect, get_publisher
from quixote.directory import Directory
from quixote.html import htmltext, htmlescape, url_quote
from qommon.backoffice.menu import html_top
from qommon.admin.menu import command_icon
from qommon import errors
from qommon import misc
from qommon.form import *
from qommon import template
import directory
class ServiceInstanceDirectory(Directory):
_q_exports = ['', 'edit', 'delete', 'update']
attrs = [
('cdg59URL', _('URL to service root'),
{'widget_class': ValidUrlWidget, 'size': 80}),
('cdg59metadataURL', _('URL to service metadata'),
{'widget_class': ValidUrlWidget, 'size': 80}),
]
def __init__(self, service):
self.service = service
try:
self.service_type = directory.get_service(self.service.cdg59serviceType)
except KeyError:
raise
get_response().breadcrumb.append((self.service.cdg59siid + '/', self.service.name))
def _q_index [html] (self):
html_top('services', title = _('Service: %s') % self.service.name)
'<h2>%s</h2>' % _('Service: %s') % self.service.name
get_session().display_message()
'<p>'
if not self.service_type.cdg59isGlobal:
'<a href="edit">%s</a> - ' % _('Edit')
'<a href="delete" rel="popup">%s</a>' % _('Unsubscribe')
if self.service.cdg59metadataURL:
' - <a href="update">%s</a>' % _('Update SAML Metadata')
'</p>'
def edit [html] (self):
if self.service_type.cdg59isGlobal:
get_response().breadcrumb.append(('edit', _('Edit')))
html_top('services', title = _('Service: %s') % self.service.name)
'<p>'
_('Global Service, nothing to do here')
'</p>'
'<p><a href=".">%s</a></p>' % _('Back')
else:
form = Form(enctype='multipart/form-data')
for k, l, attrs in self.attrs:
if not attrs:
attrs = {}
if attrs.has_key('widget_class'):
widget_class = attrs.get('widget_class')
attrs = attrs.copy()
del attrs['widget_class']
else:
widget_class = StringWidget
form.add(widget_class, k, title = _(l),
value = getattr(self.service, k),
**attrs)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('..')
if form.is_submitted() and not form.has_errors():
self.submit(form)
if not form.has_errors():
return redirect('..')
get_response().breadcrumb.append(('edit', _('Edit')))
html_top('services', title = _('Service: %s') % self.service.name)
'<h2>%s</h2>' % self.service.name
form.render()
def submit(self, form):
old_metadata_url = self.service.cdg59metadataURL
changed = []
for k, l, attrs in self.attrs:
widget = form.get_widget(k)
if widget:
v = widget.parse()
old_v = getattr(self.service, k)
if v != old_v:
setattr(self.service, k, v)
changed.append(k)
if 'cdg59metadataURL' in changed:
if not self.service.cdg59metadataURL:
d = get_cfg('providers', {})
for k in d.keys():
if d[k].get('metadata_url') == old_metadata_url:
del d[k]
get_publisher().write_cfg()
break
else:
try:
rfd = urllib2.urlopen(self.service.cdg59metadataURL)
except:
raise
form.set_error('cdg59metadataURL', _('Failed to retrieve file'))
return
s = rfd.read()
(bfd, metadata_pathname) = tempfile.mkstemp('.metadata')
open(metadata_pathname, 'w').write(s)
try:
p = lasso.Provider(lasso.PROVIDER_ROLE_SP, metadata_pathname, None, None)
except lasso.Error:
form.set_error('cdg59metadataURL',
_('Failed to create Lasso provider with those metadata'))
return
key_provider_id = misc.get_provider_key(p.providerId)
dir = get_publisher().app_dir
metadata_fn = 'provider-%s-metadata.xml' % key_provider_id
d = get_cfg('providers', {})
get_publisher().cfg['providers'] = d
d[key_provider_id] = {}
d[key_provider_id]['role'] = lasso.PROVIDER_ROLE_SP
d[key_provider_id]['metadata'] = metadata_fn
d[key_provider_id]['metadata_url'] = self.service.cdg59metadataURL
file(misc.get_abs_path(metadata_fn), 'w').write(s)
get_publisher().write_cfg()
self.service.save(changed)
def update(self):
try:
rfd = urllib2.urlopen(self.service.cdg59metadataURL)
except:
get_session().message = ('error', _('Failed to load metadata'))
return redirect('.')
s = rfd.read()
(bfd, metadata_pathname) = tempfile.mkstemp('.metadata')
open(metadata_pathname, 'w').write(s)
try:
p = lasso.Provider(lasso.PROVIDER_ROLE_SP, metadata_pathname, None, None)
except lasso.Error:
get_session().message = ('error',
_('Failed to create Lasso provider with those metadata'))
return redirect('.')
key_provider_id = misc.get_provider_key(p.providerId)
dir = get_publisher().app_dir
metadata_fn = 'provider-%s-metadata.xml' % key_provider_id
d = get_cfg('providers', {})
get_publisher().cfg['providers'] = d
d[key_provider_id] = {}
d[key_provider_id]['role'] = lasso.PROVIDER_ROLE_SP
d[key_provider_id]['metadata'] = metadata_fn
d[key_provider_id]['metadata_url'] = self.service.cdg59metadataURL
file(misc.get_abs_path(metadata_fn), 'w').write(s)
get_publisher().write_cfg()
get_session().message = ('info', _('Metadata have been successfully updated.'))
return redirect('.')
def delete [html] (self):
form = Form(enctype='multipart/form-data')
form.widgets.append(HtmlWidget('<p>%s</p>' % _(
'You are about to unsubscribe the collectivity from this service.')))
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('..')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('delete', _('Delete')))
html_top('services', title = _('Unsubscribing from Service'))
'<h2>%s</h2>' % _('Unsubscring from Service: %s') % self.service.name
form.render()
else:
self.service.delete()
# XXX: remove lasso provider if it exists
return redirect('..')
class ServiceDirectory(Directory):
_q_exports = ['', 'edit', 'delete', 'update']
attrs = [
('cn', _('Name'), {'required': True}),
('description', _('Description'), {'widget_class': TextWidget, 'cols': 60, 'rows': 5}),
('cdg59URL', _('URL to service root'),
{'widget_class': ValidUrlWidget, 'size': 80}),
('cdg59metadataURL', _('URL to service metadata'),
{'widget_class': ValidUrlWidget, 'size': 80}),
('cdg59isGlobal', _('Global Service'), {'widget_class': CheckboxWidget}),
]
def __init__(self, service):
self.service = service
def _q_index [html] (self):
html_top('services', title = _('Service: %s') % self.service.cn)
'<h2>%s</h2>' % self.service.cn
get_session().display_message()
'<p>'
self.service.description
'</p>'
'<p>'
'<a href="edit">%s</a> - ' % _('Edit')
'<a href="delete" rel="popup">%s</a>' % _('Delete')
if self.service.cdg59metadataURL:
' - <a href="update">%s</a>' % _('Update SAML Metadata')
'</p>'
def edit [html] (self):
form = Form(enctype='multipart/form-data')
for k, l, attrs in self.attrs:
if not attrs:
attrs = {}
if attrs.has_key('widget_class'):
widget_class = attrs.get('widget_class')
attrs = attrs.copy()
del attrs['widget_class']
else:
widget_class = StringWidget
form.add(widget_class, k, title = _(l),
value = getattr(self.service, k),
**attrs)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('../..')
if form.is_submitted() and not form.has_errors():
self.submit(form)
if not form.has_errors():
return redirect('..')
get_response().breadcrumb.append(('edit', _('Edit')))
html_top('services', title = _('Service: %s') % self.service.cn)
'<h2>%s</h2>' % self.service.cn
form.render()
def submit(self, form):
changed = []
old_metadata_url = self.service.cdg59metadataURL
for k, l, attrs in self.attrs:
widget = form.get_widget(k)
if widget:
v = widget.parse()
old_v = getattr(self.service, k)
if v != old_v:
setattr(self.service, k, v)
changed.append(k)
if 'cdg59metadataURL' in changed:
if not self.service.cdg59metadataURL:
d = get_cfg('providers', {})
for k in d.keys():
if d[k].get('metadata_url') == old_metadata_url:
del d[k]
get_publisher().write_cfg()
break
else:
try:
rfd = urllib2.urlopen(self.service.cdg59metadataURL)
except:
form.set_error('cdg59metadataURL', _('Failed to retrieve file'))
return
s = rfd.read()
(bfd, metadata_pathname) = tempfile.mkstemp('.metadata')
open(metadata_pathname, 'w').write(s)
try:
p = lasso.Provider(lasso.PROVIDER_ROLE_SP, metadata_pathname, None, None)
except lasso.Error:
form.set_error('cdg59metadataURL',
_('Failed to create Lasso provider with those metadata'))
return
key_provider_id = misc.get_provider_key(p.providerId)
dir = get_publisher().app_dir
metadata_fn = 'provider-%s-metadata.xml' % key_provider_id
d = get_cfg('providers', {})
get_publisher().cfg['providers'] = d
d[key_provider_id] = {}
d[key_provider_id]['role'] = lasso.PROVIDER_ROLE_SP
d[key_provider_id]['metadata'] = metadata_fn
d[key_provider_id]['metadata_url'] = self.service.cdg59metadataURL
file(misc.get_abs_path(metadata_fn), 'w').write(s)
get_publisher().write_cfg()
self.service.save(changed)
def update(self):
try:
rfd = urllib2.urlopen(self.service.cdg59metadataURL)
except:
get_session().message = ('error', _('Failed to load metadata'))
return redirect('.')
s = rfd.read()
(bfd, metadata_pathname) = tempfile.mkstemp('.metadata')
open(metadata_pathname, 'w').write(s)
try:
p = lasso.Provider(lasso.PROVIDER_ROLE_SP, metadata_pathname, None, None)
except lasso.Error:
get_session().message = ('error',
_('Failed to create Lasso provider with those metadata'))
return redirect('.')
key_provider_id = misc.get_provider_key(p.providerId)
dir = get_publisher().app_dir
metadata_fn = 'provider-%s-metadata.xml' % key_provider_id
d = get_cfg('providers', {})
get_publisher().cfg['providers'] = d
d[key_provider_id] = {}
d[key_provider_id]['role'] = lasso.PROVIDER_ROLE_SP
d[key_provider_id]['metadata'] = metadata_fn
d[key_provider_id]['metadata_url'] = self.service.cdg59metadataURL
file(misc.get_abs_path(metadata_fn), 'w').write(s)
get_publisher().write_cfg()
get_session().message = ('info', _('Metadata have been successfully updated.'))
return redirect('.')
def delete [html] (self):
form = Form(enctype='multipart/form-data')
form.widgets.append(HtmlWidget('<p>%s</p>' % _(
'You are about to irrevocably delete this service.')))
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('../..')
service_instances = directory.get_service_instances_by_service_type(self.service.cdg59sid)
if service_instances:
error_text = htmltext('<p>%s :</p>' % _('Cannot delete service. There are still service instances for this service'))
error_text += htmltext('<ul>')
for si in service_instances:
sid=si.cdg59siid
try:
ou=[x[0][1] for x in ldap.dn.str2dn(si.dn, flags=ldap.DN_FORMAT_LDAPV3) if x[0][0] == 'ou' ][0]
collectivity = directory.get_collectivity(ou)
ou = collectivity.ou
link = url_quote("../../%s/%s/delete" % (ou,sid))
error_text += htmltext('<li> %s - %s <a href="%s" target="_delete_%s">%s</a></li>' % (collectivity.cn, si.name, link, ou, _('Delete')))
except KeyError:
error_text += htmltext('<li>%s</li>' % htmlescape(si.dn))
error_text += htmltext('</ul>')
get_session().message = ('error', error_text)
if not form.is_submitted() or form.has_errors() or service_instances:
get_response().breadcrumb.append(('delete', _('Delete')))
html_top('services', title = _('Delete Service'))
get_session().display_message()
'<h2>%s</h2>' % _('Deleting Service: %s') % self.service.cn
form.render()
else:
self.service.delete()
return redirect('../..')
class ServiceLookupDirectory(Directory):
_q_exports = ['', 'new']
def _q_index(self):
return redirect('..')
def new [html] (self):
form = Form(enctype='multipart/form-data')
form.add(StringWidget, 'cdg59sid', title = _('Service Identifier'), required = True,
hint = _('All lowercase, no space or special characters'))
for k, l, attrs in ServiceDirectory.attrs:
if not attrs:
attrs = {}
if attrs.has_key('widget_class'):
widget_class = attrs.get('widget_class')
attrs = attrs.copy()
del attrs['widget_class']
else:
widget_class = StringWidget
form.add(widget_class, k, title = _(l), **attrs)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('../..')
if form.is_submitted():
sid = form.get_widget('cdg59sid').parse() or ''
if sid and misc.simplify(sid) != sid:
form.get_widget('cdg59sid').set_error(
_('All lowercase, no space or special characters'))
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('edit', _('Edit')))
html_top('services', title = _('New Service Declaration'))
'<h2>%s</h2>' % _('New Service Declaration')
form.render()
else:
return self.submit_new(form)
def submit_new(self, form):
values = {}
values['cdg59sid'] = form.get_widget('cdg59sid').parse()
for k, l, attrs in ServiceDirectory.attrs:
widget = form.get_widget(k)
if widget:
v = widget.parse()
if v:
values[k] = v
directory.add_service(values)
return redirect(form.get_widget('cdg59sid').parse() + '/')
def _q_lookup(self, component):
# lookup for service instance
try:
service = directory.get_service(component)
get_response().breadcrumb.append(('service/' + component + '/', service.cn))
return ServiceDirectory(service)
except KeyError:
raise errors.TraversalError()
return Directory._q_lookup(self, component)
class ServicesDirectory(Directory):
_q_exports = ['', 'service', 'subscribe']
collectivity = None
service = ServiceLookupDirectory()
def __init__(self, collectivity = None):
Directory.__init__(self)
self.collectivity = collectivity
def _q_traverse(self, path):
user = get_session().get_user_object()
if (user.is_admin() and not self.collectivity) or (not user.is_admin()):
get_response().breadcrumb.append(('services/', _('Services Management')))
return Directory._q_traverse(self, path)
def _q_index [html] (self):
html_top('services', _('Service Management'))
user = get_session().get_user_object()
if user.is_admin() and not self.collectivity:
'<h3>%s</h3>' % _('List of Services')
'<ul>'
for service in directory.get_services():
'<li><a href="service/%s/">' % service.cdg59sid
service.cn
'</a></li>'
'</ul>'
'<p><a href="service/new">%s</a></p>' % _('Declare new service')
'<h3>%s</h3>' % _('List of Collectivities')
# list all collectivities, but the admin group
'<ul>'
for collectivity in directory.get_sorted_collectivities():
if collectivity.ou == 'admin':
continue
'<li><a href="%s/">' % collectivity.ou
collectivity.cn
'</a></li>'
'</ul>'
else:
'<h2>'
self.collectivity.cn
'</h2>'
'<p>'
if user.is_admin():
'<a href="../../identities/%s/">%s</a>' % (
self.collectivity.ou, _('Identities Management'))
else:
'<a href="../identities/">%s</a>' % _('Identities Management')
'</p>'
'<ul class="biglist">'
service_instances = directory.get_service_instances(self.collectivity)
for service in service_instances:
'<li class="biglistitem">'
'<strong class="label">%s</strong>' % service.name
'<p class="commands">'
command_icon('%s/' % service.cdg59siid, 'view')
command_icon('%s/edit' % service.cdg59siid, 'edit')
command_icon('%s/delete' % service.cdg59siid, 'remove', popup = True)
'</p></li>'
'</ul>'
if user.is_admin():
all_services = directory.get_services()
instanciated_services = [x.cdg59serviceType for x in service_instances]
available_services = []
for service in all_services:
if not service.cdg59sid in instanciated_services:
available_services.append((service.cdg59sid, service.cn, service.cdg59sid))
if available_services:
'<div id="new-field">'
form = Form(enctype='multipart/form-data', action = 'subscribe')
form.widgets.append(HtmlWidget('<table><tr><td>'))
form.add(SingleSelectWidget, 'sid', title = _('Subscribe to new service:'),
options = available_services)
form.widgets.append(HtmlWidget('</td></tr></table>'))
form.widgets.append(HtmlWidget(
'<p class="commands">%s</p>' % command_icon(None, 'add')))
form.render()
'</div>'
if user.is_admin():
'<p>'
'<a href="../">%s</a>' % _('Back')
'</p>'
def subscribe(self):
user = get_session().get_user_object()
if not user.is_admin():
raise errors.AccessForbiddenError()
if not self.collectivity:
raise TraversalError()
all_services = directory.get_services()
available_services = [x.cdg59sid for x in all_services]
form = Form(enctype='multipart/form-data', action = 'subscribe')
form.add(SingleSelectWidget, 'sid', title = _('Subscribe to new service:'),
options = available_services, required = True)
if form.has_errors() or not form.is_submitted():
return redirect('.')
sid = form.get_widget('sid').parse()
si = directory.ServiceInstance()
si.cdg59siid = sid
si.cdg59serviceType = sid
associated_service = [x for x in all_services if x.cdg59sid == sid][0]
si.add(self.collectivity)
if associated_service.cdg59isGlobal:
return redirect('.')
else:
return redirect(sid + '/edit')
def _q_lookup(self, component):
if not self.collectivity:
for collectivity in directory.get_collectivities():
if collectivity.ou == component:
get_response().breadcrumb.append((component + '/', collectivity.cn))
return ServicesDirectory(collectivity)
else:
# lookup for service instance
try:
service = directory.get_service_instance(self.collectivity, component)
except KeyError:
pass
else:
try:
return ServiceInstanceDirectory(service)
except KeyError:
return template.error_page(_('Invalid Service Type (was it removed?)'))
raise errors.TraversalError()

View File

@ -1,65 +0,0 @@
import os
import time
try:
import elementtree.ElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
from quixote import get_request, get_session
from qommon.publisher import get_publisher, get_publisher_class
import authentic.sessions
class PraticIdPSession(authentic.sessions.BasicSession):
def get_xml_dir(cls):
xml_dir = os.path.join(get_publisher().app_dir, 'sessions-xml')
if not os.path.exists(xml_dir):
os.makedirs(xml_dir)
return xml_dir
get_xml_dir = classmethod(get_xml_dir)
def store(self):
authentic.sessions.BasicSession.store(self)
session_xml_path = os.path.join(self.get_xml_dir(), self.id)
if self.user:
node = ET.Element('session')
ET.SubElement(node, 'uid').text = self.user
fd = file(session_xml_path, 'w')
ET.ElementTree(node).write(fd)
fd.close()
else:
if os.path.exists(session_xml_path):
os.unlink(session_xml_path)
def remove_object(cls, id):
authentic.sessions.BasicSession.remove_object(id)
session_xml_path = os.path.join(cls.get_xml_dir(), id)
if os.path.exists(session_xml_path):
os.unlink(session_xml_path)
remove_object = classmethod(remove_object)
class StorageSessionManager(authentic.sessions.StorageSessionManager):
def __init__(self, session_class = PraticIdPSession):
authentic.sessions.StorageSessionManager.__init__(self,
session_class = PraticIdPSession)
def expire_session(self):
request = get_request()
session = get_session()
if request.user:
user = get_session().get_user_object()
agent = user.get_as_agent()
agent.cdg59lastConnectionDuration = int(time.time() - session.get_creation_time())
try:
agent.save(['cdg59lastConnectionDuration'])
except:
# too bad it failed.
pass
authentic.sessions.StorageSessionManager.expire_session(self)
get_publisher_class().session_manager_class = StorageSessionManager

View File

@ -1,251 +0,0 @@
import sys
try:
import ldap
import ldap.async
import ldap.modlist
except ImportError:
pass
import lasso
from quixote import get_session, get_publisher
from qommon.form import *
from qommon.storage import StorableObject
from authentic import identities
import directory
class IdentitiesStorePratic:
label = N_('Pr@tic Directory')
admin_keys = ('pratic_ldap_url', 'pratic_ldap_base')
def is_bootstrapping(self):
return False
def fill_admin_form(self, form, data_source):
form.add(StringWidget, 'pratic_ldap_url', title = _('LDAP URL'), required = True,
hint = htmltext(_('Example: <tt>ldap://directory.example.com</tt>')),
value = data_source.get('pratic_ldap_url', ''))
form.add(StringWidget, 'pratic_ldap_base', title = _('LDAP Base'), required = True,
hint = htmltext(_('Example: <tt>dc=example, dc=com</tt>')),
value = data_source.get('pratic_ldap_base', ''))
def has_identity(self, uid):
try:
self.get_identity(uid)
except KeyError:
return False
return True
def load_identities(self):
pass
def get_identity_for_account(self, username, password, collectivity):
store = directory.get_store()
ldap_conn = ldap.initialize(store.pratic_ldap_url)
# python-ldap only accept UTF8 encoded string so to pass string to python-ldap
# API you must always .encode('utf8') them.
#
# String coming from our own application are encoded with
# get_publisher().site_charset, so you must decode them before trying to use
# them.
uid = 'uid=%s,%s' % (ldap.dn.escape_dn_chars(username.decode(get_publisher().site_charset)), collectivity)
try:
ldap_conn.simple_bind_s(uid.encode('utf8'), password.decode(get_publisher().site_charset).encode('utf8'))
except ldap.INVALID_CREDENTIALS:
return None
identity = self.get_identity(uid)
if identity:
agent = identity.get_as_agent()
if agent.cdg59isDisabled:
return None
return identity
def get_identity_for_name_identifier(self, name_identifier):
for i in MiniIdentityPratic.values():
if not (i.lasso_dump or i.lasso_proxy_dump):
continue
if not ((name_identifier in (i.lasso_dump or '')) or (
name_identifier in (i.lasso_proxy_dump or ''))):
continue # shortcut so it doesn't do the whole thing if not necessary
identity = lasso.Identity.newFromDump(i.lasso_dump)
for p in identity.providerIds:
federation = identity.getFederation(p)
if federation.localNameIdentifier and \
federation.localNameIdentifier.content == name_identifier:
return self.get_identity(i.id)
if federation.remoteNameIdentifier and \
federation.remoteNameIdentifier.content == name_identifier:
return self.get_identity(i.id)
if i.lasso_proxy_dump:
identity = lasso.Identity.newFromDump(i.lasso_proxy_dump)
for p in identity.providerIds:
federation = identity.getFederation(p)
if federation.localNameIdentifier and \
federation.localNameIdentifier.content == name_identifier:
return i
if federation.remoteNameIdentifier and \
federation.remoteNameIdentifier.content == name_identifier:
return i
return None
def init_session(self, session, password):
session.pratic_ldap_password = password
self._ldap_conn = None
_ldap_conn = None
def get_ldap_conn(self):
if self._ldap_conn:
return self._ldap_conn
store = directory.get_store()
self._ldap_conn = ldap.initialize(store.pratic_ldap_url)
session = get_session()
if session and hasattr(session, 'pratic_ldap_password'):
uid = session.user
password = session.pratic_ldap_password
try:
self._ldap_conn.simple_bind_s(uid, password)
except ldap.INVALID_CREDENTIALS:
pass # XXX?
return self._ldap_conn
ldap_conn = property(get_ldap_conn)
def connect(self, session):
if session and session.user and hasattr(session, 'pratic_ldap_password'):
# bind to the LDAP directory so it can access its attributes
try:
self.ldap_conn.simple_bind_s(session.user,
session.pratic_ldap_password)
except ldap.INVALID_CREDENTIALS:
return
def get_identity(self, uid):
try:
identity = MiniIdentityPratic.get(uid)
except KeyError:
identity = MiniIdentityPratic(id = uid)
return identity
def save(self, identity):
identity.store()
class MiniIdentityPratic(StorableObject):
_names = 'pratic_identities'
lasso_dump = None
lasso_proxy_dump = None
resource_id = None
roles = None
accounts = None
def get_name(self):
return str(self.id).split(',')[0].split('=')[1]
name = property(get_name)
def get_locked_down(self):
return False
locked_down = property(get_locked_down)
def get_disabled(self):
agent = self.get_as_agent()
if agent.cdg59isDisabled:
return True
return False
disabled = property(get_disabled)
def register_new_session(self):
agent = self.get_as_agent()
session = get_session()
session.previousConnectionTime = agent.cdg59lastConnectionTime
session.previousConnectionDuration = agent.cdg59lastConnectionDuration
agent.cdg59lastConnectionTime = str(int(time.time()))
agent.cdg59lastConnectionDuration = None
agent.save(['cdg59lastConnectionTime', 'cdg59lastConnectionDuration'])
def is_admin(self):
return ',ou=admin,' in str(self.id)
def is_local_admin(self):
if not 'ou=' in str(self.id):
return False
store = directory.get_store()
ldap_conn = ldap.initialize(store.pratic_ldap_url)
try:
record = ldap_conn.search_s(str(self.id), ldap.SCOPE_BASE)[0][1]
except:
return False
return 'TRUE' in record.get('cdg59isAdmin', [])
def get_display_name(self):
return self.id[:self.id.index(',')]
display_name = property(get_display_name)
def get_collectivity(self):
collectivity_ou = self.id[self.id.index(',')+1:]
collectivity_ou = collectivity_ou[:collectivity_ou.index(',')].strip().split('=')[1]
return directory.get_collectivity(collectivity_ou)
def get_attributes(self):
agent = self.get_as_agent()
attributes = {}
for k in ('username', 'cn', 'mail'):
v = getattr(agent, k)
if v is None:
continue
attributes[k] = [ unicode(v, 'iso-8859-1'), ]
if agent.cdg59isAdmin:
attributes['local-admin'] = [ 'true', ]
if self.is_admin():
attributes['super-admin'] = [ 'true', ]
else:
attributes['collectivity'] = [ unicode(self.get_collectivity().ou, 'iso-8859-1'), ]
return attributes
attributes = property(get_attributes)
_agent = None
def get_as_agent(self):
if self._agent:
return self._agent
store = directory.get_store()
ldap_conn = ldap.initialize(store.pratic_ldap_url)
record = ldap_conn.search_s(self.id, ldap.SCOPE_BASE)[0]
self._agent = directory.Agent(record)
return self._agent
def __str__(self):
# used for logging
if type(self.id) is not str:
return ''
if not self.id:
return ''
if not '=' in self.id:
# logger system could make self.id be 'unlogged'...
return self.id
return '/'.join([x.split('=', 1)[1] for x in self.id.split(',')[:2]])
# don't pickle _agent cache
def __getstate__(self):
odict = self.__dict__
if odict.has_key('_agent'):
del odict['_agent']
return odict
def __setstate__(self, dict):
self.__dict__ = dict
self._agent = None
identities.stores['pratic'] = IdentitiesStorePratic

View File

@ -1,24 +0,0 @@
from quixote import get_publisher, get_session
from qommon.publisher import get_publisher_class
import modules.sessions
import modules.store
import modules.root
import modules.backoffice
get_publisher_class().register_translation_domain('pratic')
def get_admin_help_url(*args):
user = get_session().get_user_object()
if user and user.is_admin():
return {
'fr': 'http://wiki.entrouvert.org/Pratic/Guide_de_l%27administrateur_g%C3%A9n%C3%A9ral'
}
else:
return {
'fr': 'https://wiki.entrouvert.org/Pratic/Guide_de_l%27administrateur_local',
}
get_publisher_class().admin_help_url = property(get_admin_help_url)
get_publisher_class().backoffice_help_url = property(get_admin_help_url)

104
debian/changelog vendored
View File

@ -1,103 +1,5 @@
authentic-pratic (1.0.7) pratic; urgency=low
authentic-ifef (1.0.0) stable; urgency=low
* Patches from aeb6585052fb30c2a33625863df07cb6d2584526 to 43b5c68ef0c958df619539a4f2ad62099ab998b8
* Check collectivity exists when loading it from cookie
* Convert encoding for Collectivity field contained non-ascii characters
* update slapd.conf with parameters in production
* Accept dots and dashes in usernames
* Initial package
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Thu, 03 Dec 2009 12:05:29 +0100
authentic-pratic (1.0.6) pratic; urgency=low
* Install theme in correct directory
* Correctly pass DN value to LDAP library (that is as UTF-8)
* Check character used for new users identifiers
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Thu, 22 Oct 2009 18:58:49 +0200
authentic-pratic (1.0.5) pratic; urgency=low
* Forbid to remove service for existing service instances.
* Fix access to service instance of global services.
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Mon, 21 Sep 2009 18:37:35 +0200
authentic-pratic (1.0.4) pratic; urgency=low
* Make home page not throws when service type of an existing service has
been removed.
* Signal absenc of the service type when trying to edit a service using this
service type.
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Fri, 11 Sep 2009 16:17:00 +0200
authentic-pratic (1.0.3) pratic; urgency=low
* Check for duplicate sirh/email on edit (seo#55)
-- Frederic Peters <fpeters@entrouvert.com> Wed, 15 Apr 2009 08:24:17 +0200
authentic-pratic (1.0.2) pratic; urgency=low
* Fixed get_collectivity_name function, quote filter arguments only one time.
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Tue, 14 Apr 2009 21:26:32 +0200
authentic-pratic (1.0.1) pratic; urgency=low
* Fixed display of error page on SSO request from unauthorized SP.
-- Frederic Peters <fpeters@debian.org> Tue, 14 Apr 2009 18:45:57 +0200
authentic-pratic (1.0.0-8) pratic; urgency=low
* Stop unauthorized user right on IdP (beo#267)
* Do not fail when displaying the collectivity of an agent whose
collectivity is unknown.
-- Frederic Peters <fpeters@debian.org> Tue, 14 Apr 2009 16:13:32 +0200
authentic-pratic (1.0.0-7) stable; urgency=low
* Mise à jour gratuite :)
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Mon, 06 Apr 2009 15:37:50 +0200
authentic-pratic (1.0.0-6) stable; urgency=low
* Mise à jour des traductions.
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Mon, 06 Apr 2009 15:25:17 +0200
authentic-pratic (1.0.0-5) stable; urgency=low
* Inclu le support des attributs unicode et la gestion des types de
services qui disparaissent.
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Mon, 16 Mar 2009 22:19:51 +0100
authentic-pratic (1.0.0-4) stable; urgency=low
* Déjà fait.
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Mon, 16 Mar 2009 22:19:43 +0100
authentic-pratic (1.0.0-3) stable; urgency=low
* Fix missing converion to UTF8 when setting assertions attributes.
* Use escaping in ldap filters generated with format.
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Tue, 27 Jan 2009 18:02:46 +0100
authentic-pratic (1.0.0-2) stable; urgency=low
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Tue, 27 Jan 2009 16:08:59 +0100
authentic-pratic (1.0.0-1) stable; urgency=low
* Initial package.
-- Damien Laniel <dlaniel@entrouvert.com> Wed, 03 Sep 2008 15:48:49 +0200
-- Benjamin Dauvergne <bdauvergne@entrouvert.com> Mon, 26 Apr 2010 12:38:27 +0200

6
debian/control vendored
View File

@ -1,13 +1,13 @@
Source: authentic-pratic
Source: authentic-ifef
Section: web
Priority: optional
Maintainer: Frederic Peters <fpeters@entrouvert.com>
Maintainer: Benjamin Dauvergne <bdauvergne@entrouvert.com>
Build-Depends: debhelper (>= 5.0.37.2), python
Build-Depends-Indep: python-support (>= 0.4), gettext, python-quixote
Standards-Version: 3.8.0.1
XS-Python-Version: current
Package: authentic-pratic
Package: authentic-ifef
Architecture: all
Depends: ${python:Depends}, authentic, python-ldap
Description: Liberty Alliance Identity Server - Pr@tic Extension

1
debian/files vendored
View File

@ -1 +0,0 @@
authentic-pratic_1.0.7_all.deb web optional

6
debian/rules vendored
View File

@ -29,9 +29,9 @@ install: build
dh_clean -k
dh_installdirs
$(PYTHON) setup.py install --prefix=$(CURDIR)/debian/authentic-pratic/usr --no-compile
cd po && make install prefix=$(CURDIR)/debian/authentic-pratic/
cp ldap/cdg59.schema $(CURDIR)/debian/authentic-pratic/etc/ldap/schema/
$(PYTHON) setup.py install --prefix=$(CURDIR)/debian/authentic-ifef/usr --no-compile
cd po && make install prefix=$(CURDIR)/debian/authentic-ifef/
# cp ldap/ifef.schema $(CURDIR)/debian/authentic-ifef/etc/ldap/schema/
# Build architecture-independent files here.