Projet

Général

Profil

« Précédent | Suivant » 

Révision d03cb81c

Ajouté par Jérôme Schneider il y a presque 14 ans

  • ID d03cb81c13da6c4c0cd6c418321ca6c7bb7c9ef1

Tagging release 1.1.1

git-svn-id: svn+ssh://labs.libre-entreprise.org/svnroot/larpe@502 3ed937ae-f919-0410-9a43-8e6f19e4ba6e

Voir les différences:

larpe/tags/release-1.1.1/AUTHORS
1
Damien Laniel <dlaniel@entrouvert.com>
2

  
3
Artwork and administrave interface design taken from DotClear, version 1.2 and
4
2.0, released under the GNU General Public License; and GTK+, version 2.8,
5
released under the GNU Lesser General Public License.
larpe/tags/release-1.1.1/COPYING
1
		    GNU GENERAL PUBLIC LICENSE
2
		       Version 2, June 1991
3

  
4
 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
 Everyone is permitted to copy and distribute verbatim copies
7
 of this license document, but changing it is not allowed.
8

  
9
			    Preamble
10

  
11
  The licenses for most software are designed to take away your
12
freedom to share and change it.  By contrast, the GNU General Public
13
License is intended to guarantee your freedom to share and change free
14
software--to make sure the software is free for all its users.  This
15
General Public License applies to most of the Free Software
16
Foundation's software and to any other program whose authors commit to
17
using it.  (Some other Free Software Foundation software is covered by
18
the GNU Lesser General Public License instead.)  You can apply it to
19
your programs, too.
20

  
21
  When we speak of free software, we are referring to freedom, not
22
price.  Our General Public Licenses are designed to make sure that you
23
have the freedom to distribute copies of free software (and charge for
24
this service if you wish), that you receive source code or can get it
25
if you want it, that you can change the software or use pieces of it
26
in new free programs; and that you know you can do these things.
27

  
28
  To protect your rights, we need to make restrictions that forbid
29
anyone to deny you these rights or to ask you to surrender the rights.
30
These restrictions translate to certain responsibilities for you if you
31
distribute copies of the software, or if you modify it.
32

  
33
  For example, if you distribute copies of such a program, whether
34
gratis or for a fee, you must give the recipients all the rights that
35
you have.  You must make sure that they, too, receive or can get the
36
source code.  And you must show them these terms so they know their
37
rights.
38

  
39
  We protect your rights with two steps: (1) copyright the software, and
40
(2) offer you this license which gives you legal permission to copy,
41
distribute and/or modify the software.
42

  
43
  Also, for each author's protection and ours, we want to make certain
44
that everyone understands that there is no warranty for this free
45
software.  If the software is modified by someone else and passed on, we
46
want its recipients to know that what they have is not the original, so
47
that any problems introduced by others will not reflect on the original
48
authors' reputations.
49

  
50
  Finally, any free program is threatened constantly by software
51
patents.  We wish to avoid the danger that redistributors of a free
52
program will individually obtain patent licenses, in effect making the
53
program proprietary.  To prevent this, we have made it clear that any
54
patent must be licensed for everyone's free use or not licensed at all.
55

  
56
  The precise terms and conditions for copying, distribution and
57
modification follow.
58

  
59
		    GNU GENERAL PUBLIC LICENSE
60
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61

  
62
  0. This License applies to any program or other work which contains
63
a notice placed by the copyright holder saying it may be distributed
64
under the terms of this General Public License.  The "Program", below,
65
refers to any such program or work, and a "work based on the Program"
66
means either the Program or any derivative work under copyright law:
67
that is to say, a work containing the Program or a portion of it,
68
either verbatim or with modifications and/or translated into another
69
language.  (Hereinafter, translation is included without limitation in
70
the term "modification".)  Each licensee is addressed as "you".
71

  
72
Activities other than copying, distribution and modification are not
73
covered by this License; they are outside its scope.  The act of
74
running the Program is not restricted, and the output from the Program
75
is covered only if its contents constitute a work based on the
76
Program (independent of having been made by running the Program).
77
Whether that is true depends on what the Program does.
78

  
79
  1. You may copy and distribute verbatim copies of the Program's
80
source code as you receive it, in any medium, provided that you
81
conspicuously and appropriately publish on each copy an appropriate
82
copyright notice and disclaimer of warranty; keep intact all the
83
notices that refer to this License and to the absence of any warranty;
84
and give any other recipients of the Program a copy of this License
85
along with the Program.
86

  
87
You may charge a fee for the physical act of transferring a copy, and
88
you may at your option offer warranty protection in exchange for a fee.
89

  
90
  2. You may modify your copy or copies of the Program or any portion
91
of it, thus forming a work based on the Program, and copy and
92
distribute such modifications or work under the terms of Section 1
93
above, provided that you also meet all of these conditions:
94

  
95
    a) You must cause the modified files to carry prominent notices
96
    stating that you changed the files and the date of any change.
97

  
98
    b) You must cause any work that you distribute or publish, that in
99
    whole or in part contains or is derived from the Program or any
100
    part thereof, to be licensed as a whole at no charge to all third
101
    parties under the terms of this License.
102

  
103
    c) If the modified program normally reads commands interactively
104
    when run, you must cause it, when started running for such
105
    interactive use in the most ordinary way, to print or display an
106
    announcement including an appropriate copyright notice and a
107
    notice that there is no warranty (or else, saying that you provide
108
    a warranty) and that users may redistribute the program under
109
    these conditions, and telling the user how to view a copy of this
110
    License.  (Exception: if the Program itself is interactive but
111
    does not normally print such an announcement, your work based on
112
    the Program is not required to print an announcement.)
113

  
114
These requirements apply to the modified work as a whole.  If
115
identifiable sections of that work are not derived from the Program,
116
and can be reasonably considered independent and separate works in
117
themselves, then this License, and its terms, do not apply to those
118
sections when you distribute them as separate works.  But when you
119
distribute the same sections as part of a whole which is a work based
120
on the Program, the distribution of the whole must be on the terms of
121
this License, whose permissions for other licensees extend to the
122
entire whole, and thus to each and every part regardless of who wrote it.
123

  
124
Thus, it is not the intent of this section to claim rights or contest
125
your rights to work written entirely by you; rather, the intent is to
126
exercise the right to control the distribution of derivative or
127
collective works based on the Program.
128

  
129
In addition, mere aggregation of another work not based on the Program
130
with the Program (or with a work based on the Program) on a volume of
131
a storage or distribution medium does not bring the other work under
132
the scope of this License.
133

  
134
  3. You may copy and distribute the Program (or a work based on it,
135
under Section 2) in object code or executable form under the terms of
136
Sections 1 and 2 above provided that you also do one of the following:
137

  
138
    a) Accompany it with the complete corresponding machine-readable
139
    source code, which must be distributed under the terms of Sections
140
    1 and 2 above on a medium customarily used for software interchange; or,
141

  
142
    b) Accompany it with a written offer, valid for at least three
143
    years, to give any third party, for a charge no more than your
144
    cost of physically performing source distribution, a complete
145
    machine-readable copy of the corresponding source code, to be
146
    distributed under the terms of Sections 1 and 2 above on a medium
147
    customarily used for software interchange; or,
148

  
149
    c) Accompany it with the information you received as to the offer
150
    to distribute corresponding source code.  (This alternative is
151
    allowed only for noncommercial distribution and only if you
152
    received the program in object code or executable form with such
153
    an offer, in accord with Subsection b above.)
154

  
155
The source code for a work means the preferred form of the work for
156
making modifications to it.  For an executable work, complete source
157
code means all the source code for all modules it contains, plus any
158
associated interface definition files, plus the scripts used to
159
control compilation and installation of the executable.  However, as a
160
special exception, the source code distributed need not include
161
anything that is normally distributed (in either source or binary
162
form) with the major components (compiler, kernel, and so on) of the
163
operating system on which the executable runs, unless that component
164
itself accompanies the executable.
165

  
166
If distribution of executable or object code is made by offering
167
access to copy from a designated place, then offering equivalent
168
access to copy the source code from the same place counts as
169
distribution of the source code, even though third parties are not
170
compelled to copy the source along with the object code.
171

  
172
  4. You may not copy, modify, sublicense, or distribute the Program
173
except as expressly provided under this License.  Any attempt
174
otherwise to copy, modify, sublicense or distribute the Program is
175
void, and will automatically terminate your rights under this License.
176
However, parties who have received copies, or rights, from you under
177
this License will not have their licenses terminated so long as such
178
parties remain in full compliance.
179

  
180
  5. You are not required to accept this License, since you have not
181
signed it.  However, nothing else grants you permission to modify or
182
distribute the Program or its derivative works.  These actions are
183
prohibited by law if you do not accept this License.  Therefore, by
184
modifying or distributing the Program (or any work based on the
185
Program), you indicate your acceptance of this License to do so, and
186
all its terms and conditions for copying, distributing or modifying
187
the Program or works based on it.
188

  
189
  6. Each time you redistribute the Program (or any work based on the
190
Program), the recipient automatically receives a license from the
191
original licensor to copy, distribute or modify the Program subject to
192
these terms and conditions.  You may not impose any further
193
restrictions on the recipients' exercise of the rights granted herein.
194
You are not responsible for enforcing compliance by third parties to
195
this License.
196

  
197
  7. If, as a consequence of a court judgment or allegation of patent
198
infringement or for any other reason (not limited to patent issues),
199
conditions are imposed on you (whether by court order, agreement or
200
otherwise) that contradict the conditions of this License, they do not
201
excuse you from the conditions of this License.  If you cannot
202
distribute so as to satisfy simultaneously your obligations under this
203
License and any other pertinent obligations, then as a consequence you
204
may not distribute the Program at all.  For example, if a patent
205
license would not permit royalty-free redistribution of the Program by
206
all those who receive copies directly or indirectly through you, then
207
the only way you could satisfy both it and this License would be to
208
refrain entirely from distribution of the Program.
209

  
210
If any portion of this section is held invalid or unenforceable under
211
any particular circumstance, the balance of the section is intended to
212
apply and the section as a whole is intended to apply in other
213
circumstances.
214

  
215
It is not the purpose of this section to induce you to infringe any
216
patents or other property right claims or to contest validity of any
217
such claims; this section has the sole purpose of protecting the
218
integrity of the free software distribution system, which is
219
implemented by public license practices.  Many people have made
220
generous contributions to the wide range of software distributed
221
through that system in reliance on consistent application of that
222
system; it is up to the author/donor to decide if he or she is willing
223
to distribute software through any other system and a licensee cannot
224
impose that choice.
225

  
226
This section is intended to make thoroughly clear what is believed to
227
be a consequence of the rest of this License.
228

  
229
  8. If the distribution and/or use of the Program is restricted in
230
certain countries either by patents or by copyrighted interfaces, the
231
original copyright holder who places the Program under this License
232
may add an explicit geographical distribution limitation excluding
233
those countries, so that distribution is permitted only in or among
234
countries not thus excluded.  In such case, this License incorporates
235
the limitation as if written in the body of this License.
236

  
237
  9. The Free Software Foundation may publish revised and/or new versions
238
of the General Public License from time to time.  Such new versions will
239
be similar in spirit to the present version, but may differ in detail to
240
address new problems or concerns.
241

  
242
Each version is given a distinguishing version number.  If the Program
243
specifies a version number of this License which applies to it and "any
244
later version", you have the option of following the terms and conditions
245
either of that version or of any later version published by the Free
246
Software Foundation.  If the Program does not specify a version number of
247
this License, you may choose any version ever published by the Free Software
248
Foundation.
249

  
250
  10. If you wish to incorporate parts of the Program into other free
251
programs whose distribution conditions are different, write to the author
252
to ask for permission.  For software which is copyrighted by the Free
253
Software Foundation, write to the Free Software Foundation; we sometimes
254
make exceptions for this.  Our decision will be guided by the two goals
255
of preserving the free status of all derivatives of our free software and
256
of promoting the sharing and reuse of software generally.
257

  
258
			    NO WARRANTY
259

  
260
  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
262
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
266
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
267
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
REPAIR OR CORRECTION.
269

  
270
  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
POSSIBILITY OF SUCH DAMAGES.
279

  
280
		     END OF TERMS AND CONDITIONS
281

  
282
	    How to Apply These Terms to Your New Programs
283

  
284
  If you develop a new program, and you want it to be of the greatest
285
possible use to the public, the best way to achieve this is to make it
286
free software which everyone can redistribute and change under these terms.
287

  
288
  To do so, attach the following notices to the program.  It is safest
289
to attach them to the start of each source file to most effectively
290
convey the exclusion of warranty; and each file should have at least
291
the "copyright" line and a pointer to where the full notice is found.
292

  
293
    <one line to give the program's name and a brief idea of what it does.>
294
    Copyright (C) <year>  <name of author>
295

  
296
    This program is free software; you can redistribute it and/or modify
297
    it under the terms of the GNU General Public License as published by
298
    the Free Software Foundation; either version 2 of the License, or
299
    (at your option) any later version.
300

  
301
    This program is distributed in the hope that it will be useful,
302
    but WITHOUT ANY WARRANTY; without even the implied warranty of
303
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
304
    GNU General Public License for more details.
305

  
306
    You should have received a copy of the GNU General Public License along
307
    with this program; if not, write to the Free Software Foundation, Inc.,
308
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309

  
310
Also add information on how to contact you by electronic and paper mail.
311

  
312
If the program is interactive, make it output a short notice like this
313
when it starts in an interactive mode:
314

  
315
    Gnomovision version 69, Copyright (C) year name of author
316
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
    This is free software, and you are welcome to redistribute it
318
    under certain conditions; type `show c' for details.
319

  
320
The hypothetical commands `show w' and `show c' should show the appropriate
321
parts of the General Public License.  Of course, the commands you use may
322
be called something other than `show w' and `show c'; they could even be
323
mouse-clicks or menu items--whatever suits your program.
324

  
325
You should also get your employer (if you work as a programmer) or your
326
school, if any, to sign a "copyright disclaimer" for the program, if
327
necessary.  Here is a sample; alter the names:
328

  
329
  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
  `Gnomovision' (which makes passes at compilers) written by James Hacker.
331

  
332
  <signature of Ty Coon>, 1 April 1989
333
  Ty Coon, President of Vice
334

  
335
This General Public License does not permit incorporating your program into
336
proprietary programs.  If your program is a subroutine library, you may
337
consider it more useful to permit linking proprietary applications with the
338
library.  If this is what you want to do, use the GNU Lesser General
339
Public License instead of this License.
larpe/tags/release-1.1.1/MANIFEST.in
1
include Makefile
2
include setup.py
3
include larpectl
4
include apache2-vhost-larpe
5
include apache2.conf
6
include larpe-reload-apache2-script
7
include larpe-reload-apache2.c
8
include README COPYING MANIFEST.in MANIFEST NEWS AUTHORS
9
recursive-include larpe *.py *.ptl
10
recursive-include data *
11
recursive-include root *
12
recursive-include po *.po *.pot Makefile
13
recursive-include doc *.rst Makefile *.png *.sty custom.tex *.py *.sh *.css
larpe/tags/release-1.1.1/Makefile
1
prefix = /usr
2
config_prefix = /var
3
config_dir = $(config_prefix)/lib/larpe
4

  
5
INSTALL = /usr/bin/install -c
6
PYTHON = /usr/bin/python
7

  
8
LARPE_VERSION = 0.2.9
9

  
10
larpe-reload-apache2: larpe-reload-apache2.c
11

  
12
install: larpe-reload-apache2
13
	rm -rf build
14
	$(MAKE) -C po install
15
	$(PYTHON) setup.py install --root "$(DESTDIR)/" --prefix "$(prefix)" --no-compile
16
	$(INSTALL) -d $(DESTDIR)$(prefix)/sbin/
17
	$(INSTALL) larpectl $(DESTDIR)$(prefix)/sbin/
18
	$(INSTALL) -m 4550 larpe-reload-apache2 $(DESTDIR)$(prefix)/sbin/
19
	$(INSTALL) -d $(DESTDIR)/etc/larpe
20
	$(INSTALL) -m 644 conf/apache2-vhost-larpe-common $(DESTDIR)/etc/larpe
21
	$(INSTALL) -d $(DESTDIR)$(config_dir)
22
	$(INSTALL) -d $(DESTDIR)$(config_dir)/vhosts.d
23
	$(INSTALL) -d $(DESTDIR)$(config_dir)/vhost-locations.d
24
	$(INSTALL) -d $(DESTDIR)$(config_dir)/vhosts.d.disabled
25
	$(INSTALL) -d $(DESTDIR)$(config_dir)/vhost-locations.d.disabled
26

  
27
uninstall:
28
	$(MAKE) -C po uninstall
29
	-rm -f $(DESTDIR)$(prefix)/sbin/larpe-reload-apache2
30
	-rm -f $(DESTDIR)$(prefix)/sbin/larpe-reload-apache2-script
31
	-rm -f $(DESTDIR)$(prefix)/sbin/larpectl
32
	-rm -rf $(DESTDIR)$(prefix)/share/larpe/
33
	@echo
34
	@echo "Depending on your Python version, you will have to remove manually the files in /usr/lib/python(version)/site-packages/larpe/"
35

  
36
clean:
37
	$(MAKE) -C po clean
38
	$(MAKE) -C doc clean
39
	-$(PYTHON) setup.py clean
40
	-rm -f larpe-reload-apache2
41

  
42
dist: clean
43
	tar czf dist/larpe-$(LARPE_VERSION).tar.gz -C .. --transform s/trunk/larpe-$(LARPE_VERSION)/ --exclude-from=exclude_from_dist trunk
44

  
45
.PHONY: clean dist
larpe/tags/release-1.1.1/NEWS
1
NEWS
2
====
3

  
4
Version 1.0
5
-----------
6

  
7
- Adds Liberty Alliance to some sites without modying sites code
8
- SAML 2.0 and ID-FF 1.2 support (authentication and logout)
9
- Form prefilling with ID-WSF 2.0
10
- Configuration assistant (wizard-like) for configuring new sites
11
- Fully tested for several sites with very different behaviours
12
- Plugin system to handle specific behaviour of some sites
13
- Automatic Apache 2 configuration
14
- Automatic creation of Apache python filters to transform authentication boxes on the sites
15
- Support for proxies
16
- Logging and debug options
17
- Packages for Debian and Fedora (and children of both) distributions
larpe/tags/release-1.1.1/README
1
Larpe - Liberty Alliance Reverse Proxy
2
======================================
3

  
4
Description
5
-----------
6

  
7
Larpe is a Liberty Alliance Reverse Proxy.  It allows any service provider (that
8
is a website) to use Liberty Alliance features (Identity federation, Single
9
Sign On and Single Sign Logout) without changing the code of the service
10
provider itself.  It uses the Lasso library which is certified by the Liberty
11
Alliance consortium.
12

  
13

  
14
Documentation
15
-------------
16

  
17
* README, as you are doing;
18

  
19
* doc/en/ for English documentation, published as HTML on 
20
  http://larpe.labs.libre-entreprise.org/doc/en/larpe-admin.html
21

  
22

  
23
Copyright
24
---------
25

  
26
Larpe is copyrighted by Entr'ouvert and is licensed under the GNU General
27
Public Licence.  Artwork and administrative design are from DotClear and
28
released under the GNU General Public License by Olivier Meunier and others.
29
Some artwork comes from GTK+ (LGPL).
30

  
31
Read the COPYING file for the complete license text.  Read the AUTHORS file for
32
additional credits.
larpe/tags/release-1.1.1/TODO
1
- Tests
2
  - egroupware
3
  - http://labs.libre-entreprise.org/
4
  - logs.entrouvert.org
5

  
6
====== Roadmap de Larpe ======
7

  
8
===== 0.2 =====
9

  
10
  * Vérifier la compatibilité avec egroupware
11
  * Mettre le vhosts générés dans /var/lib/larpe/vhosts.d et mettre un include /var/lib/larpe/vhosts.d/* dans la conf générale
12
  * Supprimer debconf
13
  * Vérification des formulaires de configuration d'hôtes
14
    * Tests de valeurs erronés diverses
15
    * Erreur si on donne un label qui existe deja
16
  * Ne plus inclure le binaire larpe-reload-apache2 dans les sources
17
  * Corriger les avertissements debian
18
  * Ne pas demander la clé publique de l'idp
19
  * Compléter les traductions
20
  * Ajouter la possibilité de changer la langue dans l'interface d'administration
21
  * Mettre à jour la documentation
22
    * Ajouter un chapitre sur les sites testés et leurs options de configuration particulières
23
  * Traduire la documentation en français
24

  
25
===== 0.3 =====
26

  
27
  * Implémenter le SLO en SOAP
28
  * Supprimer un /liberty/ des urls
29
  * Voir comment activer le SSLProxyEngine quand on utilise un sous répertoire
30
  * Faire un site web pour présenter Larpe
31
  * Ajouter la possibilité d'envoyer les exceptions par courriel à l'administrateur
32
  * Améliorer la journalisation des accès et des erreurs
33

  
34
===== 1.0 =====
35

  
36
  * Support de SAML 2.0
37
  * Implémenter l'accès à un site nécessitant une authentification préalable avant tout accès
38
    * Choix de cette fonctionnalité par une option de configuration par site
39
  * Lors de la création d'un site, choix d'un moteur de site connu (mediawiki, squirrelmail, ...) qui pré-remplirait un ensemble d'options nécessaire à ce moteur
40
  * Documentation technique pour les développeurs ?
41

  
42
===== Non classés =====
43

  
44
  * Support des sites qui ont une authentification HTTP (à priori, nécessite de charger toute la configuration de larpe dans le filtre python d'apache)
45
  * Création de nouveaux comptes pour les sites, avec des jetons (déjà implémenté en partie ; est-ce utile ?)
46

  
47
Fait
48
====
49

  
50
- Serveur python principal
51
  - Fonctionnalités liberty
52
    - SSO (depuis le sp et depuis l'idp)
53
    - Fédération
54
    - SLO (depuis le sp et depuis l'idp)
55
    - Défédération (depuis l'idp) en SOAP et redirect
56
  - Support https
57
  - Possibilité d'utiliser toutes les combinaisons de sous domaines et de sous répertoires
58
    - RP par vhost (appli1.example.com, rp de appli1.interne)
59
    - RP par repertoire (www.example.com/appli1, rp de appl1.interne)
60
  - Récupère la configuration de l'IP des vhosts
61

  
62
- Administration
63
  - Authentification liberty sur l'admin
64
  - Créer de nouveaux sites (+ modifier, supprimer)
65
  - Écrire les vhosts correspondants
66
  - Rechargement de la configuration d'apache
67
    - Script + wrapper en C suid root
68
  - Gestion d'utilisateurs pour administrer le RP (Authentification http)
69
  - Gestion des traductions
70

  
71
- Filtre Python branché en sortie sur Apache à la suite du filtre de réécriture html (proxy_html)
72
  - Générique
73
  - Personalisable par site pour une meilleure intégration dans les pages
74

  
75
- Sites testés
76
  - Dotclear
77
  - Dacode
78
    - linuxfr.org
79
  - Sympa
80
    - listes.entrouvert.com
81
    - listes.libre-entreprise.org  
82
  - Mediawiki
83
    - all4dev.libre-entreprise.org
84
    - www.libre-entreprise.org
85
  - www.besancon.com
86
  - Egroupware
87
    - quintine.entrouvert.org/egroupware/
88
  - squirrelmail
89
  - Concerto Espace-famille
90
  - Ciril Net RH
91
  - Agirhe
92

  
93
- Documentation
94

  
95
- Paquets Debian
96
  - Debconf pour demander le nom de domaine et le courriel de l'admin, ainsi que le compte administrateur
97

  
98
- Installation sur lupin
99

  
100
- Batterie de tests de non-regression
101

  
larpe/tags/release-1.1.1/conf/apache2-vhost-larpe
1
<VirtualHost *>
2
    ServerName localhost
3
    ServerAdmin root@localhost
4

  
5
    include /etc/larpe/apache2-vhost-larpe-common
6
    include /var/lib/larpe/vhost-locations.d
7

  
8
    CustomLog /var/log/apache2/larpe-access.log combined
9
    ErrorLog /var/log/apache2/larpe-error.log
10
</VirtualHost>
11

  
12
include /var/lib/larpe/vhosts.d
larpe/tags/release-1.1.1/conf/apache2-vhost-larpe-common
1
# Static files
2
DocumentRoot /usr/share/larpe/web/
3

  
4
# Python application
5
SCGIMount / 127.0.0.1:3007
6

  
7
# Static files for larpe
8
<Location /larpe/>
9
    ProxyPass   !
10
    SCGIHandler off
11
</Location>
12

  
13
# Larpe python application
14
<Location /liberty/>
15
    ProxyPass   !
16
</Location>
17

  
18
# No gzip compression
19
RequestHeader unset Accept-Encoding
larpe/tags/release-1.1.1/conf/filters/output_ciril_net_rh.py
1
import re
2
import os
3
import pickle
4

  
5
from larpe import sessions
6
from mod_python import Cookie
7

  
8
def is_auth_ok(req):
9
    """ Test if you are authenticate on the Larpe server """
10
    cookies = Cookie.get_cookies(req, Cookie.MarshalCookie, secret='secret007')
11
    sessions_dir = os.path.join("%(larpe_dir)s", "sessions")
12
    for name, cookie in cookies.iteritems():
13
        value = cookie.value.replace('"', '')
14
        if "larpe-" in name and value in os.listdir(sessions_dir):
15
            try:
16
                file = open(os.path.join(sessions_dir, value), "rb")
17
                session = pickle.load(file)
18
                if not session.users or not session.id:
19
                    return False
20
                return True
21
            except Exception, err:
22
                return False
23
    return False
24

  
25

  
26
def filter_page(filter, page):
27
    r = re.compile(r"""(<a.*?href=["']).*?(["'].*?>D.*?connexion</a>)""")
28
    page = r.sub(r"""\1%(logout_url)s\2""", page)
29
    return page
30

  
31
def outputfilter(filter):
32
    """ Apache called this function by default """
33
    if not re.search("^/liberty/.*", filter.req.uri) and not is_auth_ok(filter.req):
34
        filter.write('<meta http-equiv="refresh" content="0; url=%(login_url)s" />')
35
        filter.close()
36
        return
37

  
38
    if filter.req.content_type is not None:
39
        is_html = re.search('text/html', filter.req.content_type)
40
    if filter.req.content_type is None or not is_html:
41
        filter.pass_on()
42
    else:
43
        if not hasattr(filter.req, 'temp_doc'):
44
            # Create a new attribute to hold the document
45
            filter.req.temp_doc = []
46
            # If content-length ended up wrong, Gecko browsers truncated data
47
            if 'Content-Length' in filter.req.headers_out:
48
                del filter.req.headers_out['Content-Length']
49

  
50
        temp_doc = filter.req.temp_doc
51
        s = filter.read()
52
        # Could get '' at any point, but only get None at end
53
        while s:
54
            temp_doc.append(s)
55
            s = filter.read()
56

  
57
        # The end
58
        if s is None:
59
            page = ''.join(temp_doc)
60
            page = filter_page(filter, page)
61
            filter.write(page)
62
            filter.close()
63

  
larpe/tags/release-1.1.1/conf/filters/output_replace_form.py
1
import re
2

  
3
def filter_page(filter, page):
4
    current_form = re.compile('<form [^>]*?action="%(auth_form_action)s".*?>.*?</form>', re.DOTALL)
5
    page = current_form.sub('<form method="post" action="/liberty/%(name)s/login"><input type="submit" value="Connexion" /></form>', page)
6
    return page
7

  
8
def outputfilter(filter):
9
    # Only filter html code
10
    if filter.req.content_type is not None:
11
        is_html = re.search('text/html', filter.req.content_type)
12
    if filter.req.content_type is None or not is_html:
13
        filter.pass_on()
14
    else:
15
        if not hasattr(filter.req, 'temp_doc'):
16
            # Create a new attribute to hold the document
17
            filter.req.temp_doc = []
18
            # If content-length ended up wrong, Gecko browsers truncated data
19
            if 'Content-Length' in filter.req.headers_out:
20
                del filter.req.headers_out['Content-Length']
21

  
22
        temp_doc = filter.req.temp_doc
23
        s = filter.read()
24
        # Could get '' at any point, but only get None at end
25
        while s:
26
            temp_doc.append(s)
27
            s = filter.read()
28

  
29
        # The end
30
        if s is None:
31
            page = ''.join(temp_doc)
32
            page = filter_page(filter, page)
33
            filter.write(page)
34
            filter.close()
35

  
larpe/tags/release-1.1.1/debian/changelog
1
larpe (1.1.1-1) unstable; urgency=low
2

  
3
  * Removing a useless import
4
  * Change Debian maintainer
5
  * Change architecture from any to all
6
  * Using pysupport instead of pycentral
7
  * Update Debian package dependencies
8

  
9
 -- Jerome Schneider <jschneider@entrouvert.com>  Mon, 19 Jul 2010 16:18:28 +0200
10

  
11
larpe (1.1-1) unstable; urgency=low
12

  
13
  * New release
14
    - Rewrite filter management
15
    - Filters are now customisable
16
    - Improve Ciril module
17
    - Improve plugins management
18
    - Support multi filters
19
    - Fix SAML 2 logout
20
    - Fix site authentification plugins management
21
    - Fix sessions management
22
    - Code cleaning
23

  
24
 -- Jerome Schneider <jschneider@entrouvert.com>  Mon, 19 Jul 2010 11:52:47 +0200
25

  
26
larpe (1.0-1) unstable; urgency=low
27

  
28
  * New release
29
    - SAML 2.0 and ID-FF 1.2 support (authentication and logout)
30
    - Form prefilling with ID-WSF 2.0
31
    - Configuration assistant (wizard-like) for configuring new sites
32
    - Fully tested for several sites with very different behaviours
33
    - Plugin system to handle specific behaviour of some sites
34
    - Automatic Apache 2 configuration
35
    - Automatic creation of Apache python filters to transform authentication
36
      boxes on the sites
37
    - Support for proxies
38
    - Logging and debug options
39

  
40
 -- Damien Laniel <dlaniel@entrouvert.com>  Mon, 09 Mar 2009 11:19:49 +0100
41

  
42
larpe (0.2.1-1) unstable; urgency=low
43

  
44
  * New release
45

  
46
 -- Damien Laniel <dlaniel@entrouvert.com>  Wed, 20 Jun 2007 15:43:16 +0200
47

  
48
larpe (0.2.0-1) unstable; urgency=low
49

  
50
  * New release
51

  
52
 -- Damien Laniel <dlaniel@entrouvert.com>  Tue, 30 Jan 2007 18:07:04 +0100
53

  
54
larpe (0.1.1-2) unstable; urgency=low
55

  
56
  * Use python2.4
57

  
58
 -- Damien Laniel <dlaniel@entrouvert.com>  Tue, 19 Dec 2006 17:21:05 +0100
59

  
60
larpe (0.1.1-1) unstable; urgency=low
61

  
62
  * New release
63

  
64
 -- Damien Laniel <dlaniel@entrouvert.com>  Thu,  5 Oct 2006 11:47:53 +0200
65

  
66
larpe (0.1.0-1) unstable; urgency=low
67

  
68
  * New release
69

  
70
 -- Damien Laniel <dlaniel@entrouvert.com>  Wed,  4 Oct 2006 10:19:26 +0200
71

  
72
larpe (0.0.4-1) unstable; urgency=low
73

  
74
  * New version, many improvements, more compatible sites, some bug fixes
75

  
76
 -- Damien Laniel <dlaniel@entrouvert.com>  Tue,  3 Oct 2006 20:44:06 +0200
77

  
78
larpe (0.0.3-1) unstable; urgency=low
79

  
80
  * New version, many improvements, more compatible sites, some bug fixes
81

  
82
 -- Damien Laniel <dlaniel@entrouvert.com>  Mon, 25 Sep 2006 11:11:36 +0200
83

  
84
larpe (0.0.2-1) unstable; urgency=low
85

  
86
  * Initial package.
87

  
88
 -- Damien Laniel <dlaniel@entrouvert.com>  Fri, 08 Sep 2006 16:00:00 +0200
89

  
larpe/tags/release-1.1.1/debian/compat
1
5
larpe/tags/release-1.1.1/debian/config
1
#!/bin/sh -e
2

  
3
# Source debconf library.
4
. /usr/share/debconf/confmodule
5

  
6
# Hostname
7
#db_input high larpe/hostname || true
8
#db_go
9

  
10
# Administrator email address
11
#db_input medium larpe/admin_email || true
12
#db_go
13

  
14
# Enable this vhost
15
#db_input high larpe/enable_vhost || true
16
#db_go
17

  
18
# Administrator login
19
#db_input high larpe/admin_username || true
20
#db_go
21

  
22
# Administrator password
23
#db_input high larpe/admin_password || true
24
#db_go
larpe/tags/release-1.1.1/debian/control
1
Source: larpe
2
Section: web
3
Priority: optional
4
Maintainer: Jérôme Schneider <jschneider@entrouvert.com>
5
Build-Depends: debhelper (>= 5.0.37.2), python, python-support (>= 0.4), gettext, python-quixote (>= 2.5)
6
Standards-Version: 3.8.0
7

  
8
Package: larpe
9
Architecture: all
10
Depends: ${shlibs:Depends}, ${python:Depends}, python-quixote (>= 2.5), python-lasso (>= 2.2.1), python-scgi, python-libxml2, apache2, libapache2-mod-scgi, libapache2-mod-python, libapache2-mod-proxy-html
11
XB-Python-Version: ${python:Versions}
12
Description: Liberty Alliance Reverse Proxy
13
 Larpe allows any service provider (that is a website) to use Liberty Alliance
14
 identity management and Single Sign On features without changing the code of
15
 the service provider itself.
16
 .
larpe/tags/release-1.1.1/debian/copyright
1
This package was debianized by Damien Laniel <dlaniel@entrouvert.com> on
2
Fri, 08 Sep 2006 16:00:00 +0200.
3

  
4
Upstream Author: Damien Laniel <dlaniel@entrouvert.com>
5

  
6
Copyright (c) 2005 Entr'ouvert;
7
copyright (c) 2003-2005 dotclear for some graphics.
8

  
9
License is GNU GPL v2 or later plus OpenSSL exception clause.
10

  
11
This program is free software; you can redistribute it and/or
12
modify it under the terms of the GNU General Public License
13
as published by the Free Software Foundation; either version 2
14
of the License, or (at your option) any later version.
15

  
16
This program is distributed in the hope that it will be useful,
17
but WITHOUT ANY WARRANTY; without even the implied warranty of
18
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
GNU General Public License for more details.
20

  
21
You should have received a copy of the GNU General Public License
22
along with this program; if not, write to the Free Software
23
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24

  
25
On Debian GNU/Linux systems, the complete text of the GNU General Public
26
License can be found in `/usr/share/common-licenses/GPL'.
27

  
larpe/tags/release-1.1.1/debian/dirs
1
etc/apache2/sites-available
2
etc/larpe
3
usr/sbin
4
var/lib/larpe
larpe/tags/release-1.1.1/debian/docs
1
README
2
AUTHORS
larpe/tags/release-1.1.1/debian/init
1
#! /bin/sh
2
### BEGIN INIT INFO
3
# Provides:          larpe
4
# Required-Start:    $local_fs $network
5
# Required-Stop:     $local_fs $network
6
# Default-Start:     2 3 4 5
7
# Default-Stop:      0 1 6
8
# Short-Description: Start Larpe Liberty Alliance reverse proxy
9
# Description:       Start Larpe Liberty Alliance reverse proxy
10
### END INIT INFO
11

  
12
set -e
13

  
14
# Gracefully exit if the package has been removed.
15
test -x $DAEMON || exit 0
16

  
17
# Source function library
18
. /lib/lsb/init-functions
19

  
20
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
21
DESC="larpe"
22
NAME=larpe
23
DAEMON=/usr/sbin/larpectl
24
PIDFILE=/var/run/$NAME.pid
25
SCRIPTNAME=/etc/init.d/$NAME
26

  
27

  
28
# Read config file if it is present.
29
if [ -r /etc/default/$NAME ]
30
then
31
    . /etc/default/$NAME
32
fi
33

  
34
#
35
# Function that starts the daemon/service.
36
#
37
d_start() {
38
    start-stop-daemon --start --quiet --pidfile $PIDFILE --oknodo \
39
		--chuid www-data:www-data --make-pidfile --background --exec $DAEMON -- start $OPTIONS
40
}
41

  
42
#
43
# Function that stops the daemon/service.
44
#
45
d_stop() {
46
    start-stop-daemon --stop --quiet --pidfile $PIDFILE --oknodo
47
    rm -f $PIDFILE
48
}
49

  
50
case "$1" in
51
    start)
52
        log_begin_msg "Starting $DESC: $NAME"
53
        d_start
54
        log_end_msg $?
55
        ;;
56

  
57
    stop)
58
        log_begin_msg "Stopping $DESC: $NAME"
59
        d_stop
60
        log_end_msg $?
61
        ;;
62

  
63
    restart|force-reload)
64
    #
65
    #	If the "reload" option is implemented, move the "force-reload"
66
    #	option to the "reload" entry above. If not, "force-reload" is
67
    #	just the same as "restart".
68
    #
69
        log_begin_msg "Restarting $DESC: $NAME"
70
        d_stop
71
        sleep 1
72
        d_start
73
        log_end_msg $?
74
        ;;
75
    
76
    *)
77
        echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
78
        exit 1
79
        ;;
80
esac
81

  
82
exit 0
larpe/tags/release-1.1.1/debian/larpe-reload-apache2-script
1
#!/bin/sh
2

  
3
/etc/init.d/apache2 reload
larpe/tags/release-1.1.1/debian/postinst
1
#! /bin/sh
2
# postinst script for larpe
3
#
4
# see: dh_installdeb(1)
5

  
6
set -e
7

  
8
# summary of how this script can be called:
9
#        * <postinst> `configure' <most-recently-configured-version>
10
#        * <old-postinst> `abort-upgrade' <new version>
11
#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
12
#          <new-version>
13
#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
14
#          <failed-install-package> <version> `removing'
15
#          <conflicting-package> <version>
16
# for details, see http://www.debian.org/doc/debian-policy/ or
17
# the debian-policy package
18
#
19
# quoting from the policy:
20
#     Any necessary prompting should almost always be confined to the
21
#     post-installation script, and should be protected with a conditional
22
#     so that unnecessary prompting doesn't happen if a package's
23
#     installation fails and the `postinst' is called with `abort-upgrade',
24
#     `abort-remove' or `abort-deconfigure'.
25

  
26
PACKAGE=larpe
27
VERSION=2.4
28
LIB="/usr/lib/python$VERSION"
29
DIRLIST="/usr/share/pycentral/larpe/site-packages/larpe/"
30

  
31
case "$1" in
32
    configure|abort-upgrade|abort-remove|abort-deconfigure)
33
        for i in $DIRLIST ; do
34
            /usr/bin/python$VERSION -O $LIB/compileall.py -q $i
35
            /usr/bin/python$VERSION $LIB/compileall.py -q $i
36
        done
37

  
38
        # Load Apache 2 modules
39
        for module in "proxy" "rewrite" "headers" "proxy_http"; do
40
            a2enmod ${module} > /dev/null || true
41
        done
42

  
43
        # Restart Apache 2
44
        set +e
45
        if [ -x /usr/sbin/invoke-rc.d ]; then
46
            invoke-rc.d apache2 restart || true
47
        else
48
            /etc/init.d/apache2 restart || true
49
        fi
50
        set -e
51
    ;;
52

  
53
    *)
54
        echo "postinst called with unknown argument \`$1'" >&2
55
        exit 1
56
    ;;
57
esac
58

  
59

  
60

  
61
# dh_installdeb will replace this with shell code automatically
62
# generated by other debhelper scripts.
63

  
64
#DEBHELPER#
65

  
66
exit 0
larpe/tags/release-1.1.1/debian/prerm
1
#! /bin/sh
2
# prerm script for larpe
3
#
4
# see: dh_installdeb(1)
5

  
6
set -e
7

  
8
# summary of how this script can be called:
9
#        * <prerm> `remove'
10
#        * <old-prerm> `upgrade' <new-version>
11
#        * <new-prerm> `failed-upgrade' <old-version>
12
#        * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
13
#        * <deconfigured's-prerm> `deconfigure' `in-favour'
14
#          <package-being-installed> <version> `removing'
15
#          <conflicting-package> <version>
16
# for details, see http://www.debian.org/doc/debian-policy/ or
17
# the debian-policy package
18

  
19

  
20
PACKAGE=larpe
21

  
22
case "$1" in
23
    remove|upgrade|deconfigure)
24
    	dpkg --listfiles $PACKAGE |
25
                  awk '$0~/\.py$/ {print $0"c\n" $0"o"}' |
26
                  xargs rm -f >&2
27
        ;;
28
    failed-upgrade)
29
        ;;
30
    *)
31
        echo "prerm called with unknown argument \`$1'" >&2
32
        exit 1
33
    ;;
34
esac
35

  
36
# dh_installdeb will replace this with shell code automatically
37
# generated by other debhelper scripts.
38

  
39
#DEBHELPER#
40

  
41
exit 0
larpe/tags/release-1.1.1/debian/pycompat
1
2
larpe/tags/release-1.1.1/debian/rules
1
#!/usr/bin/make -f
2
# GNU copyright 1997 to 1999 by Joey Hess.
3

  
4
# Uncomment this to turn on verbose mode.
5
#export DH_VERBOSE=1
6

  
7
PYTHON=/usr/bin/python
8

  
9
LARPE_USER = www-data
10
LARPE_GROUP = www-data
11

  
12
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
13
	CFLAGS += -g
14
endif
15
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
16
	INSTALL_PROGRAM += -s
17
endif
18

  
19
build: build-stamp
20

  
21
build-stamp:
22
	dh_testdir
23
	touch build-stamp
24

  
25
clean:
26
	dh_testdir
27
	dh_testroot
28
	rm -f build-stamp
29

  
30
	make clean
31

  
32
	dh_clean
33

  
34
install: build
35
	dh_testdir
36
	dh_testroot
37
	dh_clean -k
38
	dh_installdirs
39

  
40
	make install prefix=/usr DESTDIR=$(CURDIR)/debian/larpe
41
	# Apache Vhost
42
	dh_install conf/apache2-vhost-larpe etc/apache2/sites-available
43
	# Apache reload script
44
	dh_install debian/larpe-reload-apache2-script usr/sbin
45

  
46
	# Give files ownership to Larpe user and group
47
	chown -R $(LARPE_USER):$(LARPE_GROUP) $(CURDIR)/debian/larpe/usr/share/larpe/
48
	chown -R $(LARPE_USER):$(LARPE_GROUP) $(CURDIR)/debian/larpe/var/lib/larpe/
49
	chgrp $(LARPE_GROUP) $(CURDIR)/debian/larpe/usr/sbin/larpe-reload-apache2
50

  
51
# Build architecture-independent files here.
52
binary-indep: build install
53
# We have nothing to do by default.
54

  
55
# Build architecture-dependent files here.
56
binary-arch: build install
57
	dh_testdir
58
	dh_testroot
59
	dh_installdocs
60
	dh_installinit
61
	dh_installchangelogs
62
	dh_link
63
	dh_strip
64
	dh_compress
65
	dh_fixperms -X /var/lib/larpe -X /usr/sbin/larpe-reload-apache2
66
	dh_pysupport
67
	dh_installdeb
68
	dh_shlibdeps
69
	dh_gencontrol
70
	dh_md5sums
71
	dh_builddeb
72

  
73
binary: binary-indep binary-arch
74
.PHONY: build clean binary-indep binary-arch binary install
larpe/tags/release-1.1.1/doc/Makefile
1
all:
2
	$(MAKE) -C en
3

  
4
clean:
5
	$(MAKE) -C en clean
6

  
7
.PHONY: clean
8

  
larpe/tags/release-1.1.1/doc/en/Makefile
1
RST2HTML = rst2html
2
RST2LATEX = ../scripts/rst2latex.py
3
PDFLATEX = pdflatex
4
RM = rm -f
5

  
6
all: larpe-admin.pdf larpe-admin.html
7

  
8
%.html: %.rst
9
	$(RST2HTML) --stylesheet=default.css --link-stylesheet --language=en $? > $@
10

  
11
figures-no-alpha-stamp:
12
	-$(RM) -r figures-no-alpha/
13
	mkdir figures-no-alpha/
14
	for F in figures/*.png; do \
15
		../scripts/removealpha.sh $$F figures-no-alpha/`basename $$F`; \
16
	done
17
	touch figures-no-alpha-stamp
18

  
19
%.tex: %.rst #figures-no-alpha-stamp
20
	cat $? | sed -e 's/figures\//figures-no-alpha\//' \
21
			-e 's/ ::$$/ : ::/g' \
22
			-e 's/.. section-numbering:://' | $(RST2LATEX) --language=en > $@
23

  
24
%.pdf: %.tex custom.tex
25
	$(PDFLATEX) $?
26
	logfile=`echo "$@" |sed -r "s/(.*)....$$/\\1/"`.log; while [ -f "$$logfile" -a -n "`grep "Rerun to get cross-references right" $$logfile`" ]; do $(PDFLATEX) $< ; done
27

  
28
clean:
29
	-$(RM) *.aux *.toc *.log *.out
30
	-$(RM) larpe-admin.pdf
31
	-$(RM) larpe-admin.tex
32
	-$(RM) larpe-admin.html
33
	-$(RM) -r figures-no-alpha figures-no-alpha-stamp
34

  
35
.PHONY: all clean
larpe/tags/release-1.1.1/doc/en/custom.tex
1
\usepackage{float,fancyhdr,lscape,sectsty,colortbl,color,lastpage,setspace}
2
\usepackage[perpage,bottom]{footmisc}
3
\usepackage[hang]{caption2}
4
\usepackage{marvosym}
5

  
6
\usepackage{float,url,listings,tocbibind,fancyhdr,calc,placeins}
7

  
8
\usepackage{palatino}
9
\usepackage[Glenn]{fncychap}
10

  
11
\pagestyle{fancy}
12
\fancyhead{}
13
\fancyfoot{}
14
\fancyhead[L]{Authentic}
15
\fancyhead[R]{Administrator Guide}
16
\fancyfoot[C]{Page \thepage}
17
\addtolength{\headheight}{1.6pt}
18

  
19
\setlength\parindent{0pt}
20
\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex}
21
\setlength\abovecaptionskip{0.1ex}
22

  
23
\makeatletter
24
\renewcommand{\maketitle}{\begin{titlepage}%
25
    \let\footnotesize\small
26
    \let\footnoterule\relax
27
    \parindent \z@
28
    \reset@font
29
    \null\vfil
30
    \begin{flushleft}
31
      \huge \@title
32
    \end{flushleft}
33
    \par
34
    \hrule height 1pt
35
    \par
36
    \begin{flushright}
37
      \LARGE \@author \par
38
    \end{flushright}
39
    \vskip 60\p@
40
    \vfil\null
41
  \end{titlepage}%
42
  \setcounter{footnote}{0}%
43
}
44
\makeatother
45

  
larpe/tags/release-1.1.1/doc/en/default.css
1
body {
2
	font-family: sans-serif;
3
}
4

  
5

  
6
h1 a, h2 a, h3 a, h4 a {
7
	text-decoration: inherit;
8
	color: inherit;
9
}
10

  
11
pre.literal-block {
12
	background: #eee;
13
	border: 1px inset black;
14
	padding: 2px;
15
	margin: auto 10px;
16
	overflow: auto;
17
}
18

  
19
h1.title {
20
	text-align: center;
21
	background: #eef;
22
	border: 1px solid #aaf;
23
	letter-spacing: 1px;
24
}
25

  
26
div.section {
27
	margin-bottom: 2em;
28
}
29

  
30
div.section h1 {
31
	padding: 0 15px;
32
	background: #eef;
33
	border: 1px solid #aaf;
34
}
35

  
36
div.section h2 {
37
	padding: 0 15px;
38
	background: #eef;
39
	border: 1px solid #aaf;
40
}
41

  
42
div.document {
43
	margin-top: 1em;
44
	border-top: 1px solid #aaf;
45
	border-bottom: 1px solid #aaf;
46
}
47

  
48
div.section p,
49
div.section ul {
50
	text-align: justify;
51
}
52

  
53
div.contents {
54
	float: right;
55
	border: 1px solid black;
56
	margin: 1em;
57
	background: #eef;
58
	max-width: 33%;
59
}
60

  
61
div#building-liberty-services-with-lasso div#table-of-contents {
62
	max-width: inherit;
63
	float: none;
64
	background: white url(lasso.png) bottom right no-repeat;
65
}
66

  
67
div.contents ul {
68
	padding-left: 1em;
69
	list-style: none;
70
}
71

  
72
div.contents li {
73
	padding-bottom: 2px;
74
}
75

  
76
div.contents p {
77
	background: #ddf;
78
	text-align: center;
79
	border-bottom: 1px solid black;
80
	margin: 0;
81
}
82

  
83
th.docinfo-name {
84
	text-align: right;
85
	padding-right: 0.5em;
86
}
87

  
88
dd {
89
	margin-bottom: 1ex;
90
}
91

  
92
table.table {
93
	margin: 1ex 0;
94
	border-spacing: 0px;
95
}
96

  
97

  
98
table.table th {
99
	padding: 0px 1ex;
100
	background: #eef;
101
	font-weight: normal;
102
}
103

  
104

  
105
table.table td {
106
	padding: 0 0.5ex;
107
}
108

  
109
div.note, div.warning {
110
	padding: 0.3ex;
111
	padding-left: 60px;
112
	min-height: 50px;
113
	margin: 1ex 1em;
114
}
115

  
116
div.note {
117
	background: #ffa url(note.png) top left no-repeat;
118
	border: 1px solid #fd8;
119
}
120

  
121
div.warning {
122
	background: #ffd url(warning.png) top left no-repeat;
123
}
124

  
125
p.admonition-title {
126
	font-weight: bold;
127
	display: inline;
128
	display: none;
129
	padding-right: 1em;
130
}
131

  
132
div.figure {
133
	margin: 0 auto;
134
	width: 70%;
135
	min-width: 800px;
136
	text-align: center;
137
}
138

  
139
div.figure p.caption {
140
	font-style: italic;
141
	margin: 1ex 0 2em 0;
142
	text-align: center;
143
}
larpe/tags/release-1.1.1/doc/en/fncychap.sty
1
%%% Copyright   Ulf A. Lindgren
2
%%%
3
%%% Note        Premission is granted to modify this file under
4
%%%             the condition that it is saved using another
5
%%%             file and package name.
6
%%%
7
%%% Revision    1.1 (1997)
8
%%%
9
%%%             Jan. 8th Modified package name base date option
10
%%%             Jan. 22th Modified FmN and FmTi for error in book.cls
11
%%%                  \MakeUppercase{#}->{\MakeUppercase#}
12
%%%             Apr. 6th Modified Lenny option to prevent undesired 
13
%%%                  skip of line.
14
%%%             Nov. 8th Fixed \@chapapp for AMS
15
%%%
16
%%% Revision    1.2 (1998)
17
%%%
18
%%%             Feb. 11th Fixed appendix problem related to Bjarne
19
%%%             Aug. 11th Fixed problem related to 11pt and 12pt 
20
%%%                  suggested by Tomas Lundberg. THANKS!
21
%%%
22
%%% Revision    1.3 (2004)
23
%%%             Sep. 20th problem with frontmatter, mainmatter and
24
%%%                  backmatter, pointed out by Lapo Mori
25
%%%
26
%%% Revision    1.31 (2004)
27
%%%             Sep. 21th problem with the Rejne definition streched text
28
%%%                  caused ugly gaps in the vrule aligned with the title
29
%%%                  text. Kindly pointed out to me by Hendri Adriaens
30
%%%
31
%%% Revision    1.32 (2005)
32
%%%             Jun. 23th compatibility problem with the KOMA class 'scrbook.cls'
33
%%%                  a remedy is a redefinition of '\@schapter' in
34
%%%                  line with that used in KOMA. The problem was pointed
35
%%%                  out to me by Mikkel Holm Olsen
36
%%%
37
%%% Revision    1.33 (2005)
38
%%%             Aug. 9th misspelled ``TWELV'' corrected, the error was pointed
39
%%%                  out to me by George Pearson
40
%%%
41

  
42

  
43
%%% Last modified   Aug. 9th 2005
44

  
45
\NeedsTeXFormat{LaTeX2e}[1995/12/01]
46
\ProvidesPackage{fncychap}
47
             [2004/09/21 v1.33
48
                 LaTeX package (Revised chapters)]
49

  
50
%%%% DEFINITION OF Chapapp variables
51
\newcommand{\CNV}{\huge\bfseries}
52
\newcommand{\ChNameVar}[1]{\renewcommand{\CNV}{#1}}
53

  
54

  
55
%%%% DEFINITION OF TheChapter variables
56
\newcommand{\CNoV}{\huge\bfseries}
57
\newcommand{\ChNumVar}[1]{\renewcommand{\CNoV}{#1}}
58

  
59
\newif\ifUCN
60
\UCNfalse
61
\newif\ifLCN
62
\LCNfalse
63
\def\ChNameLowerCase{\LCNtrue\UCNfalse}
64
\def\ChNameUpperCase{\UCNtrue\LCNfalse}
65
\def\ChNameAsIs{\UCNfalse\LCNfalse}
66

  
67
%%%%% Fix for AMSBook 971008
68

  
69
\@ifundefined{@chapapp}{\let\@chapapp\chaptername}{}
70

  
71

  
72
%%%%% Fix for Bjarne and appendix 980211
73

  
74
\newif\ifinapp
75
\inappfalse
76
\renewcommand\appendix{\par
77
  \setcounter{chapter}{0}%
78
  \setcounter{section}{0}%
79
  \inapptrue%
80
  \renewcommand\@chapapp{\appendixname}%
81
  \renewcommand\thechapter{\@Alph\c@chapter}}
82

  
83
%%%%% Fix for frontmatter, mainmatter, and backmatter 040920
84

  
85
\@ifundefined{@mainmatter}{\newif\if@mainmatter \@mainmattertrue}{}
86

  
87
%%%%%
88

  
89

  
90

  
91
\newcommand{\FmN}[1]{%
92
\ifUCN
93
   {\MakeUppercase#1}\LCNfalse
94
\else
95
   \ifLCN
96
      {\MakeLowercase#1}\UCNfalse
97
   \else #1
98
   \fi
99
\fi}
100

  
101

  
102
%%%% DEFINITION OF Title variables
103
\newcommand{\CTV}{\Huge\bfseries}
104
\newcommand{\ChTitleVar}[1]{\renewcommand{\CTV}{#1}}
105

  
106
%%%% DEFINITION OF the basic rule width
107
\newlength{\RW}
108
\setlength{\RW}{1pt}
109
\newcommand{\ChRuleWidth}[1]{\setlength{\RW}{#1}}
110

  
111
\newif\ifUCT
112
\UCTfalse
113
\newif\ifLCT
114
\LCTfalse
115
\def\ChTitleLowerCase{\LCTtrue\UCTfalse}
116
\def\ChTitleUpperCase{\UCTtrue\LCTfalse}
117
\def\ChTitleAsIs{\UCTfalse\LCTfalse}
118
\newcommand{\FmTi}[1]{%
119
\ifUCT
120
   {\MakeUppercase#1}\LCTfalse
121
\else
122
   \ifLCT
123
      {\MakeLowercase#1}\UCTfalse
124
   \else {#1}
125
   \fi
126
\fi}
127

  
128

  
129

  
130
\newlength{\mylen}
131
\newlength{\myhi}
132
\newlength{\px}
133
\newlength{\py}
134
\newlength{\pyy}
135
\newlength{\pxx}
136

  
137

  
138
\def\mghrulefill#1{\leavevmode\leaders\hrule\@height #1\hfill\kern\z@}
139

  
140
\newcommand{\DOCH}{%
141
  \CNV\FmN{\@chapapp}\space \CNoV\thechapter
142
  \par\nobreak
143
  \vskip 20\p@
144
  }
145
\newcommand{\DOTI}[1]{%
146
    \CTV\FmTi{#1}\par\nobreak
147
    \vskip 40\p@
148
    }
149
\newcommand{\DOTIS}[1]{%
150
    \CTV\FmTi{#1}\par\nobreak
151
    \vskip 40\p@
152
    }
153

  
154
%%%%%% SONNY DEF
155

  
156
\DeclareOption{Sonny}{%
157
  \ChNameVar{\Large\sf}
158
  \ChNumVar{\Huge}
159
  \ChTitleVar{\Large\sf}
160
  \ChRuleWidth{0.5pt}
161
  \ChNameUpperCase
162
  \renewcommand{\DOCH}{%
163
    \raggedleft
164
    \CNV\FmN{\@chapapp}\space \CNoV\thechapter
165
    \par\nobreak
166
    \vskip 40\p@}
167
  \renewcommand{\DOTI}[1]{%
168
    \CTV\raggedleft\mghrulefill{\RW}\par\nobreak
169
    \vskip 5\p@
170
    \CTV\FmTi{#1}\par\nobreak
171
    \mghrulefill{\RW}\par\nobreak
172
    \vskip 40\p@}
173
  \renewcommand{\DOTIS}[1]{%
174
    \CTV\raggedleft\mghrulefill{\RW}\par\nobreak
175
    \vskip 5\p@
176
    \CTV\FmTi{#1}\par\nobreak
177
    \mghrulefill{\RW}\par\nobreak
178
    \vskip 40\p@}
179
}
180

  
181
%%%%%% LENNY DEF
182

  
183
\DeclareOption{Lenny}{%
184

  
185
  \ChNameVar{\fontsize{14}{16}\usefont{OT1}{phv}{m}{n}\selectfont}
186
  \ChNumVar{\fontsize{60}{62}\usefont{OT1}{ptm}{m}{n}\selectfont}
187
  \ChTitleVar{\Huge\bfseries\rm}
188
  \ChRuleWidth{1pt}
189
  \renewcommand{\DOCH}{%
190
    \settowidth{\px}{\CNV\FmN{\@chapapp}}
191
    \addtolength{\px}{2pt}
192
    \settoheight{\py}{\CNV\FmN{\@chapapp}}
193
    \addtolength{\py}{1pt}
194

  
195
    \settowidth{\mylen}{\CNV\FmN{\@chapapp}\space\CNoV\thechapter}
196
    \addtolength{\mylen}{1pt}
197
    \settowidth{\pxx}{\CNoV\thechapter}
198
    \addtolength{\pxx}{-1pt}
199

  
200
    \settoheight{\pyy}{\CNoV\thechapter}
201
    \addtolength{\pyy}{-2pt}
202
    \setlength{\myhi}{\pyy}
203
    \addtolength{\myhi}{-1\py}
204
    \par
205
    \parbox[b]{\textwidth}{%
206
    \rule[\py]{\RW}{\myhi}%
207
    \hskip -\RW%
208
    \rule[\pyy]{\px}{\RW}%
209
    \hskip -\px%
210
    \raggedright%
211
    \CNV\FmN{\@chapapp}\space\CNoV\thechapter%
212
    \hskip1pt%
213
    \mghrulefill{\RW}%
214
    \rule{\RW}{\pyy}\par\nobreak%
215
    \vskip -\baselineskip%
216
    \vskip -\pyy%
217
    \hskip \mylen%
218
    \mghrulefill{\RW}\par\nobreak%
219
    \vskip \pyy}%
220
    \vskip 20\p@}
221
 
222

  
223
  \renewcommand{\DOTI}[1]{%
224
    \raggedright
225
    \CTV\FmTi{#1}\par\nobreak
226
    \vskip 40\p@}
227

  
228
  \renewcommand{\DOTIS}[1]{%
229
    \raggedright
230
    \CTV\FmTi{#1}\par\nobreak
231
    \vskip 40\p@}
232
 }
233

  
234

  
235
%%%%%%% GLENN DEF
236

  
237

  
238
\DeclareOption{Glenn}{%
239
  \ChNameVar{\bfseries\Large\sf}
240
  \ChNumVar{\Huge}
241
  \ChTitleVar{\bfseries\Large\rm}
242
  \ChRuleWidth{1pt}
243
  \ChNameUpperCase
244
  \ChTitleUpperCase
245
  \renewcommand{\DOCH}{%
246
    \settoheight{\myhi}{\CTV\FmTi{Test}}
247
    \setlength{\py}{\baselineskip}
248
    \addtolength{\py}{\RW}
249
    \addtolength{\py}{\myhi}
250
    \setlength{\pyy}{\py}
251
    \addtolength{\pyy}{-1\RW}
252
     
253
    \raggedright
254
    \CNV\FmN{\@chapapp}\space\CNoV\thechapter
255
    \hskip 3pt\mghrulefill{\RW}\rule[-1\pyy]{2\RW}{\py}\par\nobreak}
256

  
257
  \renewcommand{\DOTI}[1]{%
258
    \addtolength{\pyy}{-4pt}
259
    \settoheight{\myhi}{\CTV\FmTi{#1}}
260
    \addtolength{\myhi}{\py}
261
    \addtolength{\myhi}{-1\RW}
262
    \vskip -1\pyy
263
    \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt
264
    \raggedleft\CTV\FmTi{#1}\par\nobreak
265
    \vskip 80\p@}
266

  
267
\newlength{\backskip}
268
  \renewcommand{\DOTIS}[1]{%
269
%    \setlength{\py}{10pt}
270
%    \setlength{\pyy}{\py}
271
%    \addtolength{\pyy}{\RW}
272
%    \setlength{\myhi}{\baselineskip}
273
%    \addtolength{\myhi}{\pyy}
274
%    \mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak
275
%    \addtolength{}{}
276
%\vskip -1\baselineskip
277
%    \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt
278
%    \raggedleft\CTV\FmTi{#1}\par\nobreak
279
%    \vskip 60\p@}
280
%% Fix suggested by Tomas Lundberg
281
    \setlength{\py}{25pt}  % eller vad man vill
282
    \setlength{\pyy}{\py}
283
    \setlength{\backskip}{\py}
284
    \addtolength{\backskip}{2pt}
285
    \addtolength{\pyy}{\RW}
286
    \setlength{\myhi}{\baselineskip}
287
    \addtolength{\myhi}{\pyy}
288
    \mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak
289
    \vskip -1\backskip
290
    \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 3pt %
291
    \raggedleft\CTV\FmTi{#1}\par\nobreak
292
    \vskip 40\p@}
293
 }
294

  
295
%%%%%%% CONNY DEF
296

  
297
\DeclareOption{Conny}{%
298
  \ChNameUpperCase
299
  \ChTitleUpperCase  
300
  \ChNameVar{\centering\Huge\rm\bfseries}
301
  \ChNumVar{\Huge}
302
  \ChTitleVar{\centering\Huge\rm}
303
  \ChRuleWidth{2pt}
304

  
305
  \renewcommand{\DOCH}{%
306
    \mghrulefill{3\RW}\par\nobreak
307
    \vskip -0.5\baselineskip
308
    \mghrulefill{\RW}\par\nobreak
309
    \CNV\FmN{\@chapapp}\space \CNoV\thechapter
310
    \par\nobreak
311
    \vskip -0.5\baselineskip
312
   }
313
  \renewcommand{\DOTI}[1]{%
314
    \mghrulefill{\RW}\par\nobreak
315
    \CTV\FmTi{#1}\par\nobreak
316
    \vskip 60\p@
317
    }
318
  \renewcommand{\DOTIS}[1]{%
319
    \mghrulefill{\RW}\par\nobreak
320
    \CTV\FmTi{#1}\par\nobreak
321
    \vskip 60\p@
322
    }
323
  }
324

  
325
%%%%%%% REJNE DEF
326

  
327
\DeclareOption{Rejne}{%
328

  
329
  \ChNameUpperCase
330
  \ChTitleUpperCase  
331
  \ChNameVar{\centering\Large\rm}
332
  \ChNumVar{\Huge}
333
  \ChTitleVar{\centering\Huge\rm}
334
  \ChRuleWidth{1pt}
335
  \renewcommand{\DOCH}{%
336
    \settoheight{\py}{\CNoV\thechapter}
337
    \parskip=0pt plus 1pt % Set parskip to default, just in case v1.31
338
    \addtolength{\py}{-1pt}
339
    \CNV\FmN{\@chapapp}\par\nobreak
340
    \vskip 20\p@
341
    \setlength{\myhi}{2\baselineskip}
342
    \setlength{\px}{\myhi}
343
    \addtolength{\px}{-1\RW}
344
    \rule[-1\px]{\RW}{\myhi}\mghrulefill{\RW}\hskip
345
    10pt\raisebox{-0.5\py}{\CNoV\thechapter}\hskip 10pt\mghrulefill{\RW}\rule[-1\px]{\RW}{\myhi}\par\nobreak
346
     \vskip -3\p@% Added -2pt vskip to correct for streched text v1.31
347
    }
348
  \renewcommand{\DOTI}[1]{%
349
    \setlength{\mylen}{\textwidth}
350
    \parskip=0pt plus 1pt % Set parskip to default, just in case v1.31
351
    \addtolength{\mylen}{-2\RW}
352
    {\vrule width\RW}\parbox{\mylen}{\CTV\FmTi{#1}}{\vrule width\RW}\par\nobreak%
353
    \vskip -3pt\rule{\RW}{2\baselineskip}\mghrulefill{\RW}\rule{\RW}{2\baselineskip}%
354
    \vskip 60\p@% Added -2pt in vskip to correct for streched text v1.31
355
    }
356
  \renewcommand{\DOTIS}[1]{%
357
    \setlength{\py}{\fboxrule}
358
    \setlength{\fboxrule}{\RW}
359
    \setlength{\mylen}{\textwidth}
360
    \addtolength{\mylen}{-2\RW}
361
    \fbox{\parbox{\mylen}{\vskip 2\baselineskip\CTV\FmTi{#1}\par\nobreak\vskip \baselineskip}} 
362
    \setlength{\fboxrule}{\py}
363
    \vskip 60\p@
364
    }
365
  }
366

  
367

  
368
%%%%%%% BJARNE DEF
369

  
370
\DeclareOption{Bjarne}{%
371
  \ChNameUpperCase
372
  \ChTitleUpperCase  
373
  \ChNameVar{\raggedleft\normalsize\rm}
374
  \ChNumVar{\raggedleft \bfseries\Large}
375
  \ChTitleVar{\raggedleft \Large\rm}
376
  \ChRuleWidth{1pt}
377

  
378

  
379
%% Note thechapter -> c@chapter fix appendix bug
380
%% Fixed misspelled 12
381

  
382
  \newcounter{AlphaCnt}
383
  \newcounter{AlphaDecCnt}
384
  \newcommand{\AlphaNo}{%
385
    \ifcase\number\theAlphaCnt
386
      \ifnum\c@chapter=0
387
        ZERO\else{}\fi
388
    \or ONE\or TWO\or THREE\or FOUR\or FIVE
389
    \or SIX\or SEVEN\or EIGHT\or NINE\or TEN
390
    \or ELEVEN\or TWELVE\or THIRTEEN\or FOURTEEN\or FIFTEEN
391
    \or SIXTEEN\or SEVENTEEN\or EIGHTEEN\or NINETEEN\fi
392
}
393

  
394
  \newcommand{\AlphaDecNo}{%
395
    \setcounter{AlphaDecCnt}{0}
396
    \@whilenum\number\theAlphaCnt>0\do
397
      {\addtocounter{AlphaCnt}{-10}
398
       \addtocounter{AlphaDecCnt}{1}}
399
     \ifnum\number\theAlphaCnt=0
400
     \else
401
       \addtocounter{AlphaDecCnt}{-1}
402
       \addtocounter{AlphaCnt}{10}
403
     \fi
404
     
405
     
406
    \ifcase\number\theAlphaDecCnt\or TEN\or TWENTY\or THIRTY\or
407
    FORTY\or FIFTY\or SIXTY\or SEVENTY\or EIGHTY\or NINETY\fi
408
    }
409
  \newcommand{\TheAlphaChapter}{%
410
    
411
    \ifinapp 
412
      \thechapter
413
    \else
414
      \setcounter{AlphaCnt}{\c@chapter}
415
      \ifnum\c@chapter<20
416
        \AlphaNo
417
      \else
418
        \AlphaDecNo\AlphaNo
419
      \fi
420
    \fi
421
    }  
422
  \renewcommand{\DOCH}{%
423
    \mghrulefill{\RW}\par\nobreak
424
    \CNV\FmN{\@chapapp}\par\nobreak 
425
    \CNoV\TheAlphaChapter\par\nobreak
426
    \vskip -1\baselineskip\vskip 5pt\mghrulefill{\RW}\par\nobreak
427
    \vskip 20\p@
428
    }
429
  \renewcommand{\DOTI}[1]{%
430
    \CTV\FmTi{#1}\par\nobreak
431
    \vskip 40\p@
432
    }
433
  \renewcommand{\DOTIS}[1]{%
434
    \CTV\FmTi{#1}\par\nobreak
435
    \vskip 40\p@
436
    }
437
}
438

  
439
\DeclareOption*{%
440
  \PackageWarning{fancychapter}{unknown style option}
441
  }
442

  
443
\ProcessOptions* \relax
444

  
445
\def\@makechapterhead#1{%
446
  \vspace*{50\p@}%
447
  {\parindent \z@ \raggedright \normalfont
448
    \ifnum \c@secnumdepth >\m@ne
449
      \if@mainmatter%%%%% Fix for frontmatter, mainmatter, and backmatter 040920
450
        \DOCH
451
      \fi
452
    \fi
453
    \interlinepenalty\@M
454
    \DOTI{#1}
455
  }}
456

  
457

  
458
%%% Begin: To avoid problem with scrbook.cls (fncychap version 1.32)
459

  
460
%%OUT:
461
%\def\@schapter#1{\if@twocolumn
462
%                   \@topnewpage[\@makeschapterhead{#1}]%
463
%                 \else
464
%                   \@makeschapterhead{#1}%
465
%                   \@afterheading
466
%                 \fi}
467

  
468
%%IN:
469
\def\@schapter#1{%
470
\if@twocolumn%
471
  \@makeschapterhead{#1}%
472
\else%
473
  \@makeschapterhead{#1}%
474
  \@afterheading%
475
\fi}
476

  
477
%%% End: To avoid problem with scrbook.cls (fncychap version 1.32)
478

  
479
\def\@makeschapterhead#1{%
480
  \vspace*{50\p@}%
481
  {\parindent \z@ \raggedright
482
    \normalfont
483
    \interlinepenalty\@M
484
    \DOTIS{#1}
485
    \vskip 40\p@
486
  }}
487

  
488
\endinput
489

  
490

  
larpe/tags/release-1.1.1/doc/en/larpe-admin.rst
1
=====================================
2
Larpe - Administrator Guide
3
=====================================
4

  
5
:author: Damien Laniel
6
:contact: dlaniel@entrouvert.com
7
:copyright: Copyright © 2006 Entr'ouvert
8

  
9
.. contents:: Table of contents
10

  
11
Overview
12
========
13

  
14
Larpe is a Liberty Alliance Reverse Proxy. It allows any service provider
15
(that is a website) to use Liberty Alliance features (Identity federation,
16
Single Sign On and Single Logout) without changing the code of
17
the service provider itself. It uses the Lasso_ library
18
which is certified by the `Liberty Alliance`_ consortium. Lasso_ and Larpe
19
are released under the terms of the `GNU GPL license`_.
20

  
21

  
22
How to get and install Larpe
23
============================
24

  
25
Installation under Debian_ Sarge
26
++++++++++++++++++++++++++++++++
27

  
28
To work correctly Larpe relies on :
29

  
30
* Apache2_ ;
31

  
32
* Lasso_ (0.6.3) ;
33

  
34
* Quixote_ (2.0) ;
35

  
36
* SCGI_ ;
37

  
38
* mod_python_ ;
39

  
40
* libxml2 ;
41

  
42
* mod_proxy_html.
43

  
44
You will also need a Liberty Alliance Identity Provider, be it on the same server or not.
45
We recommend Authentic_ for that need.
46

  
47
Package Installation
48
--------------------
49

  
50
You need to add the following line to your /etc/apt/sources.list; this will
51
give you access to the repository where Larpe is stored::
52

  
53
 deb http://deb.entrouvert.org/ sarge main
54

  
55
As root type::
56

  
57
 apt-get update
58
 apt-get install larpe
59

  
60
And follow the debconf wizard to set it up.
61

  
62
All the required packages are now installed and configured.
63

  
64
You might need to change the "<VirtualHost \*>" in your apache2 configuration
65
(/etc/apache2/sites-available/apache2-vhost-larpe) depending on how you
66
previously configured apache.
67

  
68
Don't forget to modify your /etc/hosts file if necessary. Larpe now works, the
69
administration interface is reachable at http://your_domain_name/admin. The username
70
and password are the ones you entered during the installation wizard.
71

  
72
If you don't want to modify your sources.list file, you can manually dowload and
73
install the required packages with the dpkg -i command :
74

  
75
* Larpe, Authentic and Lasso on http://deb.entrouvert.org/ ;
76

  
77
* Quixote 2.0 on http://authentic.labs.libre-entreprise.org/.
78

  
79
Installation with another Linux distribution
80
++++++++++++++++++++++++++++++++++++++++++++
81

  
82
We suppose Apache2_, SCGI_, mod_python_, libxml2 and mod_proxy_html are already installed. You need then to
83
download and install the following sources :
84

  
85
* Lasso http://lasso.entrouvert.org ;
86

  
87
* Quixote http://www.mems-exchange.org/software/Quixote/ ;
88

  
89
* Authentic http://authentic.labs.libre-entreprise.org/ ;
90

  
91
* Larpe http://labs.libre-entreprise.org/frs/?group_id=108.
92

  
93
To install Larpe, uncompress the sources you have downloaded and launch the
94
setup.py script ::
95

  
96
 tar xzf larpe*.tar.gz
97
 cd larpe*
98
 python setup.py install
99

  
100
You need then to configure Apache2_ correctly. You should use the provided apache2-vhost-larpe template and adapt to your configuration.
101

  
102
Don't forget to modify your /etc/hosts file if necessary. Larpe now works, the
103
administration interface is reachable at http://your_domain_name/admin.
104

  
105
Basic Larpe configuration
106
=========================
107

  
108
Identity Provider configuration
109
+++++++++++++++++++++++++++++++
110

  
111
If you don't have a configured Identity Provider yet, please read Authentic
112
manual to set it up. Then you must have the metadata and public key of the Identity
113
Provider to begin with Larpe.
114

  
115
Then in Larpe administration interface, click on "Settings", then "Identity Provider".
116
Fill in the metadata and public key that you've got from your Identity Provider then
117
click Submit.
118
Your Identity Provider is now configured in Larpe, you can then configure as many Service
119
Providers as you want.
120

  
121
Service Provider Configuration
122
++++++++++++++++++++++++++++++
123

  
124
Service Provider configuration
125
------------------------------
126

  
127
Click on "Hosts" then "New Host".
128

  
129
Fill in the following parameters :
130

  
131
* Label : the name you want to give to your Service Provider ;
132

  
133
* Original Site Address : the root URL of your Service Provider ;
134

  
135
* Authentication Page : if the page which contains the authentication form for
136
  your Service Provider is on a separate page, fill the url of this page here ;
137

  
138
* Authentication Form Page : if you didn't fill the previous field and if the
139
  authentication form if not on the first page of your Service Provider either,
140
  fill the url of the page which contains the authentication form here ;
141

  
142
* Logout Address : when you want Single Sign On and Identity Federation, you probably
143
  want Single Logout too. If so, fill the logout url of your original site here ;
144

  
145
* Reversed Host Name : the domain name where you want to access your Service Provider
146
  through the reverse proxy. It can be the domain name of Larpe or not ;
147

  
148
Then click "Submit". Wait a few seconds then go to http://reversed_host_name/reverse_directory/
149
to check if it works. If not, wait a bit more and try again. If it really doesn't work,
150
please submit a bug report at http://labs.libre-entreprise.org/tracker/?func=add&group_id=108&atid=512
151

  
152
Service Provider Example: Linuxfr
153
---------------------------------
154

  
155
To help you setup your own Service Provider, we provide an example of a working Service Provider
156
to guide you.
157

  
158
To setup Linuxfr, fill in the following parameters :
159

  
160
* Label : Linuxfr ;
161

  
162
* Original Site Address : http://linuxfr.org/ ;
163

  
164
* Authentication Page : Nothing here ;
165

  
166
* Authentication Form Page : http://linuxfr.org/pub/ ;
167

  
168
* Logout Address : http://linuxfr.org/close_session.html ;
169

  
170
* Reversed Host Name : linuxfr.reverse-proxy.example.com.
171

  
172
With "reverse-proxy.example.com" being the hostname you've set up before for your reverse-proxy
173

  
174
Don't forget to add this new hostname to your /etc/hosts as well.
175

  
176
You can then go to the reversed Linuxfr at http://linuxfr.reverse-proxy.example.com/
177

  
178
Service Provider Liberty Alliance final setup
179
---------------------------------------------
180

  
181
Now that you can access your Service Provider, you need a final step to use Liberty Alliance
182
features. Click on "Hosts", the click on the "Edit" icon of the Service Provider you've
183
just configured. Save the Service Provider Metadata (for ID-FF 1.2) and the Public Key
184
(right click then "Save as"). Configure this Service Provider on your Identity Provider
185
with these two files.
186

  
187
Licenses
188
========
189

  
190
Larpe, Authentic_, Candle_ and Lasso_ are released under the terms of the
191
`GNU GPL license`_.
192

  
193
.. _Lasso: http://lasso.entrouvert.org/
194
.. _`Liberty Alliance`: http://projectliberty.org/
195
.. _`GNU GPL License`: http://www.gnu.org/copyleft/gpl.html
196
.. _Debian: http://www.debian.org/
197
.. _Apache2: http://httpd.apache.org/
198
.. _Quixote: http://www.mems-exchange.org/software/Quixote
199
.. _mod_python: http://www.modpython.org/
200
.. _SCGI: http://www.mems-exchange.org/software/scgi/
201
.. _Candle: http://candle.labs.libre-entreprise.org/
202
.. _Authentic: http://www.entrouvert.com/fr/authentic/
larpe/tags/release-1.1.1/doc/scripts/removealpha.sh
1
#! /bin/sh
2

  
3
size=$(identify $1 | cut -d ' ' -f 3)
4
composite $1 -size $(identify $1 | cut -d ' ' -f3) xc:white $2
5

  
larpe/tags/release-1.1.1/doc/scripts/rst2latex.py
1
#! /usr/bin/python
2

  
3
"""A minimal reST frontend, to create appropriate LaTeX files."""
4

  
5
try:
6
    import locale
7
    locale.setlocale(locale.LC_ALL, '')
8
except:
9
    pass
10

  
11
from docutils.core import publish_cmdline, Publisher
12

  
13
def set_io(self, source_path=None, destination_path=None):
14
    Publisher.set_io_orig(self, source_path, destination_path='/dev/null')
15

  
16
Publisher.set_io_orig, Publisher.set_io = Publisher.set_io, set_io
17

  
18
output = publish_cmdline(writer_name='latex',
19
    settings_overrides = {
20
        'documentclass': 'report',
21
        'documentoptions': '11pt,a4paper,titlepage',
22
        'use_latex_toc': True,
23
        'use_latex_docinfo': True,
24
        'stylesheet': 'custom.tex'})
25

  
26
output = output.replace('\\includegraphics',
27
    '\\includegraphics[width=.9\\textwidth,height=15cm,clip,keepaspectratio]')
28
output = output.replace('\\begin{figure}[htbp]', '\\begin{figure}[H]')
29
print output
larpe/tags/release-1.1.1/exclude_from_dist
1
.svn
2
*.pyc
3
*.pyo
4
*.pye
5
*.ptle
6
*.swp
7
debian.sarge
8
make_debian_package.sh
9
build
10
dist
11
tests
12
larpe/filter
larpe/tags/release-1.1.1/fedora/larpe-reload-apache2-script
1
#!/bin/sh
2
#
3
# The command "/etc/init.d/httpd reload" on Fedora actually _restarts_ Apache
4
# We need to _reload_ it without closing existing connections
5

  
6
APACHE2CTL=/usr/sbin/apachectl
7

  
8
echo -n "Testing Apache config... "
9
if ! $APACHE2CTL configtest > /dev/null 2>&1; then
10
	$APACHE2CTL configtest || true
11
	echo "[FAILED]"
12
	exit 1
13
else
14
	echo "[OK]"
15
fi
16
echo -n "Reloading Apache config... "
17
if $APACHE2CTL graceful $2 ; then
18
	echo "[OK]"
19
else
20
	echo "[FAILED]"
21
fi
22

  
larpe/tags/release-1.1.1/fedora/larpe.init
1
#! /bin/bash
2
#
3
# larpe        Startup script for the Larpe reverse proxy
4
#
5
# description: Larpe is Liberty Alliance reverse proxy.  It is used to add Liberty Alliance \
6
#           features to some sites without modifying the sites themselves.
7
# processname: larpe
8
# config: /etc/httpd/conf.d/larpe.conf
9
# config: /etc/larpe/apache2-vhost-larpe-common
10
# config: /etc/sysconfig/larpe
11
# pidfile: /var/run/larpe.pid
12
#
13

  
14
### BEGIN INIT INFO
15
# Provides:          larpe
16
# Required-Start:    $local_fs $network
17
# Required-Stop:     $local_fs $network
18
# Default-Start:
19
# Default-Stop:      0 1 2 3 4 5 6
20
# Short-Description: Start Larpe Liberty Alliance reverse proxy
21
# Description:       Start Larpe Liberty Alliance reverse proxy
22
### END INIT INFO
23

  
24
prog=larpe
25
LARPECTL=/usr/sbin/larpectl
26
PIDFILE=/var/run/larpe.pid
27

  
28
# Source function library.
29
. /etc/rc.d/init.d/functions
30

  
31
# Source networking configuration.
32
. /etc/sysconfig/network
33

  
34
# Check that networking is up.
35
[ ${NETWORKING} = "no" ] && exit 0
36

  
37
[ -x $LARPECTL ] || exit 5
38

  
39
# Read config file if it is present.
40
if [ -f /etc/sysconfig/larpe ]; then
41
	. /etc/sysconfig/larpe
42
fi
43

  
44
RETVAL=0
45

  
46
#
47
# Function that starts the daemon/service.
48
#
49
start() {
50
	echo -n $"Starting $prog: "
51
	$LARPECTL start &
52
	RETVAL=$?
53
	if [ $RETVAL -eq 0 ]
54
	then
55
		touch /var/lock/subsys/$prog
56
	fi
57
	echo
58
	return $RETVAL
59
}
60

  
61
#
62
# Function that stops the daemon/service.
63
#
64
stop() {
65
	echo -n $"Stopping $prog: "
66
	killproc $LARPECTL
67
	RETVAL=$?
68
	if [ $RETVAL -eq 0 ]
69
	then
70
		rm -rf /var/lock/subsys/$prog
71
	fi
72
	echo
73
	return $RETVAL
74
}
75

  
76
# See how we were called.
77
case "$1" in
78
	start)
79
		start
80
	;;
81
	stop)
82
		stop
83
	;;
84
	status)
85
		status $prog
86
		RETVAL=$?
87
	;;
88
	restart)
89
		stop
90
		start
91
	;;
92
	condrestart)
93
		if [ -f ${PIDFILE} ] ; then
94
			stop
95
			start
96
		fi
97
	;;
98
	*)
99
		echo $"Usage: $prog {start|stop|restart|condrestart|status}"
100
		exit 1
101
esac
102

  
103
exit $RETVAL
104

  
larpe/tags/release-1.1.1/fedora/larpe.spec
1
%{!?python_sitearch: %define python_sitearch %(%{__python} -c 'from distutils import sysconfig; print sysconfig.get_python_lib(1)')}
2
# eval to 2.3 if python isn't yet present, workaround for no python in fc4 minimal buildroot
3
%{!?python_version: %define python_version %(%{__python} -c 'import sys; print sys.version.split(" ")[0]' || echo "2.3")}
4
%define apacheconfdir   %{_sysconfdir}/httpd/conf.d
5

  
6
Summary: Liberty Alliance Reverse Proxy
7
Name: larpe
8
Version: 0.2.9
9
Release: 2%{?dist}
10
License: GPL
11
Group: System Environment/Applications
12
Url: http://larpe.labs.libre-entreprise.org/
13
Source0: http://labs.libre-entreprise.org/frs/download.php/591/%{name}-%{version}.tar.gz
14
Buildroot: %{_tmppath}/%{name}-%{version}-%(id -u -n)
15
BuildRequires: python >= 2.3, python-quixote >= 2.0
16
BuildRequires: gettext
17
Requires: httpd >= 2.0, mod_scgi, mod_proxy_html
18
Requires: lasso-python >= 0.6.3, python-quixote >= 2.0, python-scgi
19
Requires: initscripts
20
Requires(post): /sbin/chkconfig
21
Requires(preun):/sbin/chkconfig
22
Requires(preun): /sbin/service
23

  
24
%description
25
Larpe is a Liberty Alliance Reverse Proxy. It allows any service provider (that is a website)
26
to use Liberty Alliance features (Identity federation, Single Sign On and Single Logout) without
27
changing the code of the service provider itself.
28

  
29
It uses the Lasso library which is certified by the Liberty Alliance consortium.
30

  
31
It is a quixote application and is commonly runned inside Apache web server.
32

  
33
%package doc
34
Summary: Documentation files for %{name} development.
35
Group: Documentation
36
BuildRequires: python-docutils, tetex-latex
37

  
38
%description doc
39
This package contains development documentation for %{name}.
40

  
41
%prep
42
%setup -q
43

  
44
# Change Apache vhost path in Larpe config
45
sed -i s#"/var/log/apache2/larpe-access.log"#"logs/larpe_access_log combined\n    TransferLog logs/larpe_access_log"# conf/apache2-vhost-larpe
46
sed -i s#"/var/log/apache2/larpe-error.log"#"logs/larpe_error_log"# conf/apache2-vhost-larpe
47
sed -i s#"APACHE_MAIN_VHOST.*$"#"APACHE_MAIN_VHOST='/etc/httpd/conf.d/larpe.conf'"# larpe/Defaults.py
48

  
49
%build
50

  
51
%install
52
rm -rf %{buildroot}
53

  
54
# install generic files
55
make install prefix=%{_prefix} DESTDIR=%{buildroot}
56

  
57
# install init script
58
install -d %{buildroot}/%{_initrddir}
59
install -p -m 0755 fedora/larpe.init %{buildroot}%{_initrddir}/larpe
60

  
61
# apache configuration
62
mkdir -p %{buildroot}%{apacheconfdir}
63
install -p -m 644 conf/apache2-vhost-larpe %{buildroot}%{apacheconfdir}/larpe.conf
64

  
65
# apache reload script
66
install -p -m 0755 fedora/larpe-reload-apache2-script %{buildroot}%{_sbindir}/
67

  
68
# install doc files
69
install -d -m 0755 %{buildroot}%{_datadir}/gtk-doc/html/larpe
70
make -C doc DESTDIR=%{buildroot}%{_datadir}/gtk-doc/html/larpe
71

  
72
%clean
73
rm -fr %{buildroot}
74

  
75
%post
76
/sbin/chkconfig --add %{name}
77

  
78
# manual post-installation
79
cat <<_EOF_
80
You must edit first %{apacheconfdir}/larpe.conf
81

  
82
You must enable Larpe with "chkconfig larpe on ; service larpe start"
83

  
84
You must also restart Apache with "service httpd restart"!
85
_EOF_
86

  
87
%preun
88
if [ $1 = 0 ]; then
89
	/sbin/service %{name} stop > /dev/null 2>&1
90
	/sbin/chkconfig --del %{name}
91
fi
92

  
93
%files
94
%defattr(-,root,root,755)
95
%config %{_initrddir}/larpe
96
%config(noreplace) %{apacheconfdir}/larpe.conf
97
%config(noreplace) %{_sysconfdir}/larpe/apache2-vhost-larpe-common
98
%{_sbindir}/larpectl
99
%{_sbindir}/larpe-reload-apache2
100
%{_sbindir}/larpe-reload-apache2-script
101
%{python_sitearch}/%{name}
102
%{_datadir}/%{name}
103
%{_datadir}/locale/fr/LC_MESSAGES/larpe.mo
104
/var/lib/larpe
105
%defattr(644,root,root,755)
106
%doc AUTHORS COPYING NEWS README
107

  
108
%files doc
109
%defattr(-,root,root)
110
%doc %{_datadir}/gtk-doc/html/%{name}
111

  
112
%changelog
113
* Tue Mar 05 2009 Jean-Marc Liger <jmliger@siris.sorbonne.fr> 0.2.9-2
114
- Added missing BuildRequires gettext
115
- Enabled larpe init script
116

  
117
* Mon Jan 19 2009 Damien Laniel <dlaniel@entrouvert.com> 0.2.9-1
118
- Updated to 0.2.9
119
- Use Larpe Makefile to install generic files
120
- Copy fedora specific files
121

  
122
* Sat Jan 17 2009 Jean-Marc Liger <jmliger@siris.sorbonne.fr> 0.2.1-2
123
- Added missing BuildRequires tetex-latex for doc subpackage
124
- Rebuilt on CentOS 4,5
125

  
126
* Wed Jan 14 2009 Jean-Marc Liger <jmliger@siris.sorbonne.fr> 0.2.1-1
127
- Updated to 0.2.1
128
- Added missing Requires lasso-python
129
- Added missing Requires python-scgi
130
- Rebuilt on CentOS 4,5
131

  
132
* Fri Mar 02 2007 Jean-Marc Liger <jmliger@siris.sorbonne.fr> 0.2.0-1
133
- Updated to 0.2.0
134
- Added BuildRequires python-quixote
135
- Built on Fedora Core 3 / RHEL 4 and Fedora Core 6 / RHEL 5
136

  
137
* Wed Jan 24 2007 Jean-Marc Liger <jmliger@siris.sorbonne.fr> 0.1.0-1
138
- First 0.1.0
139
- Built on Fedora Core 3 / RHEL 4 and Fedora Core 6 / RHEL 5
larpe/tags/release-1.1.1/larpe-reload-apache2.c
1
/*
2
  Template for a setuid program that calls a script.
3

  
4
  The script should be in an unwritable directory and should itself
5
  be unwritable.  In fact all parent directories up to the root
6
  should be unwritable.  The script must not be setuid, that's what
7
  this program is for.
8

  
9
  This is a template program.  You need to fill in the name of the
10
  script that must be executed.  This is done by changing the
11
  definition of FULL_PATH below.
12

  
13
  There are also some rules that should be adhered to when writing
14
  the script itself.
15

  
16
  The first and most important rule is to never, ever trust that the
17
  user of the program will behave properly.  Program defensively.
18
  Check your arguments for reasonableness.  If the user is allowed to
19
  create files, check the names of the files.  If the program depends
20
  on argv[0] for the action it should perform, check it.
21

  
22
  Assuming the script is a Bourne shell script, the first line of the
23
  script should be
24
  #!/bin/sh -
25
  The - is important, don't omit it.  If you're using esh, the first
26
  line should be
27
  #!/usr/local/bin/esh -f
28
  and for ksh, the first line should be
29
  #!/usr/local/bin/ksh -p
30
  The script should then set the variable IFS to the string
31
  consisting of <space>, <tab>, and <newline>.  After this (*not*
32
  before!), the PATH variable should be set to a reasonable value and
33
  exported.  Do not expect the PATH to have a reasonable value, so do
34
  not trust the old value of PATH.  You should then set the umask of
35
  the program by calling
36
  umask 077 # or 022 if you want the files to be readable
37
  If you plan to change directories, you should either unset CDPATH
38
  or set it to a good value.  Setting CDPATH to just ``.'' (dot) is a
39
  good idea.
40
  If, for some reason, you want to use csh, the first line should be
41
  #!/bin/csh -fb
42
  You should then set the path variable to something reasonable,
43
  without trusting the inherited path.  Here too, you should set the
44
  umask using the command
45
  umask 077 # or 022 if you want the files to be readable
46
*/
47

  
48
#include <unistd.h>
49
#include <stdlib.h>
50
#include <stdio.h>
51
#include <sys/types.h>
52
#include <sys/stat.h>
53
#include <string.h>
54

  
55
/* CONFIGURATION SECTION */
56

  
57
#ifndef FULL_PATH/* so that this can be specified from the Makefile */
58
  #define FULL_PATH	"/usr/sbin/larpe-reload-apache2-script"
59
#endif
60
#ifndef UMASK
61
  #define UMASK		077
62
#endif
63

  
64
/* END OF CONFIGURATION SECTION */
65

  
66
#if defined(__STDC__) && defined(__sgi)
67
#define environ _environ
68
#endif
69

  
70
/* don't change def_IFS */
71
char def_IFS[] = "IFS= \t\n";
72
/* you may want to change def_PATH, but you should really change it in */
73
/* your script */
74
#ifdef __sgi
75
char def_PATH[] = "PATH=/usr/bsd:/usr/bin:/bin:/usr/local/bin:/usr/sbin";
76
#else
77
char def_PATH[] = "PATH=/usr/ucb:/usr/bin:/bin:/usr/local/bin";
78
#endif
79
/* don't change def_CDPATH */
80
char def_CDPATH[] = "CDPATH=.";
81
/* don't change def_ENV */
82
char def_ENV[] = "ENV=:";
83

  
84
/*
85
  This function changes all environment variables that start with LD_
86
  into variables that start with XD_.  This is important since we
87
  don't want the script that is executed to use any funny shared
88
  libraries.
89

  
90
  The other changes to the environment are, strictly speaking, not
91
  needed here.  They can safely be done in the script.  They are done
92
  here because we don't trust the script writer (just like the script
93
  writer shouldn't trust the user of the script).
94
  If IFS is set in the environment, set it to space,tab,newline.
95
  If CDPATH is set in the environment, set it to ``.''.
96
  Set PATH to a reasonable default.
97
*/
98
void
99
clean_environ(void)
100
{
101
    char **p;
102
    extern char **environ;
103

  
104
    for (p = environ; *p; p++) {
105
	if (strncmp(*p, "LD_", 3) == 0)
106
	    **p = 'X';
107
	else if (strncmp(*p, "_RLD", 4) == 0)
108
	    **p = 'X';
109
	else if (strncmp(*p, "PYTHON", 6) == 0)
110
	    **p = 'X';
111
	else if (strncmp(*p, "IFS=", 4) == 0)
112
	    *p = def_IFS;
113
	else if (strncmp(*p, "CDPATH=", 7) == 0)
114
	    *p = def_CDPATH;
115
	else if (strncmp(*p, "ENV=", 4) == 0)
116
	    *p = def_ENV;
117
    }
118
    putenv(def_PATH);
119
}
120

  
121
int
122
main(int argc, char **argv)
123
{
124
    struct stat statb;
125
    gid_t egid = getegid();
126
    uid_t euid = geteuid();
127

  
128
    /*
129
      Sanity check #1.
130
      This check should be made compile-time, but that's not possible.
131
      If you're sure that you specified a full path name for FULL_PATH,
132
      you can omit this check.
133
    */
134
    if (FULL_PATH[0] != '/') {
135
	fprintf(stderr, "%s: %s is not a full path name\n", argv[0],
136
		FULL_PATH);
137
	fprintf(stderr, "You can only use this wrapper if you\n");
138
	fprintf(stderr, "compile it with an absolute path.\n");
139
	exit(1);
140
    }
141

  
142
    /*
143
      Sanity check #2.
144
      Check that the owner of the script is equal to either the
145
      effective uid or the super user.
146
    */
147
    if (stat(FULL_PATH, &statb) < 0) {
148
	perror("stat");
149
	exit(1);
150
    }
151
    if (statb.st_uid != 0 && statb.st_uid != euid) {
152
	fprintf(stderr, "%s: %s has the wrong owner\n", argv[0],
153
		FULL_PATH);
154
	fprintf(stderr, "The script should be owned by root,\n");
155
	fprintf(stderr, "and shouldn't be writeable by anyone.\n");
156
	exit(1);
157
    }
158

  
159
    if (setregid(egid, egid) < 0)
160
	perror("setregid");
161
    if (setreuid(euid, euid) < 0)
162
	perror("setreuid");
163

  
164
    clean_environ();
165

  
166
    umask(UMASK);
167

  
168
    while (**argv == '-')/* don't let argv[0] start with '-' */
169
	(*argv)++;
170
    execv(FULL_PATH, argv);
171
    fprintf(stderr, "%s: could not execute the script\n", argv[0]);
172
    exit(1);
173
}
larpe/tags/release-1.1.1/larpe/Defaults.py
1
'''Default global variables'''
2

  
3
APP_DIR = '/var/lib/larpe'
4
DATA_DIR = '/usr/share/larpe'
5
ERROR_LOG = None #'/var/log/larpe.log'
6
WEB_ROOT = 'larpe'
7
APACHE_MAIN_VHOST = '/etc/apache2/sites-available/apache2-vhost-larpe'
8
APACHE_VHOST_COMMON = '/etc/larpe/apache2-vhost-larpe-common'
9
APACHE_RELOAD = '/usr/sbin/larpe-reload-apache2'
larpe/tags/release-1.1.1/larpe/__init__.py
1
'''Setup path and load Lasso library'''
2
try:
3
    from quixote.ptl import compile_package
4
    compile_package(__path__)
5
except ImportError:
6
    pass
7

  
8
import sys
9
import os
10
sys.path.insert(0, os.path.dirname(__file__))
11

  
12
import qommon
13

  
14
try:
15
    import lasso
16
except ImportError:
17
    lasso = None
18

  
19
if lasso and not hasattr(lasso, 'SAML2_SUPPORT'):
20
    lasso.SAML2_SUPPORT = False
21

  
larpe/tags/release-1.1.1/larpe/admin/__init__.py
1
try:
2
    from quixote.ptl import compile_package
3
    compile_package(__path__)
4
except ImportError:
5
    pass
6
from root import RootDirectory
larpe/tags/release-1.1.1/larpe/admin/apache.py
1
import os
2
import re
3
import urllib
4
import base64
5

  
6
from quixote import get_publisher, get_request
7

  
8
from qommon import get_cfg
9

  
10
from larpe.hosts import Host
11
from larpe.Defaults import APP_DIR, APACHE_MAIN_VHOST, APACHE_VHOST_COMMON, APACHE_RELOAD
12

  
13
def write_apache2_vhosts():
14
    hosts = Host.select(lambda x: x.name != 'larpe')
15
    hosts.sort()
16
    vhosts_dir = os.path.join(APP_DIR, 'vhosts.d')
17
    vhost_locations_dir = os.path.join(APP_DIR, 'vhost-locations.d')
18
    vhosts_dir_disabled = os.path.join(APP_DIR, 'vhosts.d.disabled')
19
    vhost_locations_dir_disabled = os.path.join(APP_DIR, 'vhost-locations.d.disabled')
20
    vhost_file_name = get_request().get_server().split(':')[0]
21
    vhost_file = None
22
    reversed_hostname = ''
23
    vhost = None
24

  
25
    if get_publisher().cfg.get(str('allow_config_generation'), True):
26
        vhost_file = open(os.path.join(vhosts_dir, vhost_file_name), 'w')
27
        locations_file = open(os.path.join(vhost_locations_dir, vhost_file_name), 'w')
28
    else:
29
        vhost_file = open(os.path.join(vhosts_dir_disabled, vhost_file_name), 'w')
30
        locations_file = open(os.path.join(vhost_locations_dir_disabled, vhost_file_name), 'w')
31
    try:
32
        main_vhost = open(APACHE_MAIN_VHOST, 'r')
33
        file_content = main_vhost.read()
34
        regexp = re.compile('<VirtualHost (.*?)>')
35
        vhost_ip = regexp.findall(file_content)[0]
36
    except (IOError, IndexError):
37
        vhost_ip = '*'
38

  
39
    for host in hosts:
40
        if host.orig_site is None:
41
            # This site hasn't been fully configured
42
            continue
43
        if host.reversed_hostname != reversed_hostname \
44
                and host.reversed_hostname != get_cfg('proxy_hostname'):
45
            if vhost is not None:
46
                vhost.close()
47
            vhost = Vhost(host, vhost_ip)
48
            vhost.write(vhost_file)
49
            reversed_hostname = host.reversed_hostname
50

  
51
        if host.reversed_hostname == get_cfg('proxy_hostname'):
52
            conf_file = locations_file
53
        else:
54
            conf_file = vhost_file
55

  
56
        Location(host).write(conf_file)
57

  
58
    if vhost_file is not None:
59
        if vhost is not None:
60
            vhost.close()
61
        vhost_file.close()
62
    if locations_file is not None:
63
        locations_file.close()
64

  
65
    if get_publisher().cfg.get(str('allow_config_generation'), True):
66
        os.system(APACHE_RELOAD)
67

  
68

  
69
class Vhost(object):
70
    def __init__(self, host, main_ip_port):
71
        self.host = host
72
        self.main_ip_port = main_ip_port
73
        self.conf_file = None
74

  
75
    def get_ip_port(self):
76
        if self.host.scheme == 'https':
77
            return self.main_ip_port.replace(':80', ':443')
78
        else:
79
            return self.main_ip_port.replace(':443', ':80')
80
    ip_port = property(get_ip_port)
81

  
82
    def get_proxy_url(self):
83
        if get_cfg('proxy', {}).get('enabled') and self.host.use_proxy == True:
84
            return 'http://%(ip)s:%(port)s' % get_cfg('proxy', {})
85
        return None
86
    proxy_url = property(get_proxy_url)
87

  
88
    def get_proxy_auth(self):
89
        if self.get_proxy_url() and get_cfg('proxy', {}).get('user'):
90
            credentials = base64.encodestring(
91
                '%(user)s:%(password)s' % get_cfg('proxy', {}))[:-1]
92
            return '"Basic %s"' % credentials
93
        return None
94
    proxy_auth = property(get_proxy_auth)
95

  
96
    def get_cfg(self):
97
        return { 'ip_port': self.ip_port,
98
                 'reversed_hostname': self.host.reversed_hostname,
99
                 'proxy_url': self.proxy_url,
100
                 'proxy_auth': self.proxy_auth }
101
    cfg = property(get_cfg)
102

  
103
    def write(self, conf_file):
104
        self.conf_file = conf_file
105
        conf_lines = []
106
        # Start Virtual Host
107
        conf_lines.append('<VirtualHost %(ip_port)s>' % self.cfg)
108
        # Server name and administrator
109
        conf_lines.append('ServerName %(reversed_hostname)s' % self.cfg)
110
        conf_lines.append('# ServerAdmin root@localhost\n')
111
        # Include common vhost configuration
112
        conf_lines.append('include %s\n' % APACHE_VHOST_COMMON)
113
        # SSL
114
        if self.host.scheme == 'https':
115
            conf_lines.append('SSLEngine On\n')
116
        if self.host.orig_site.startswith('https'):
117
            conf_lines.append('SSLProxyEngine On\n')
118
        # Remote proxy configuration
119
        if self.proxy_url is not None:
120
            conf_lines.append('ProxyRemote * %(proxy_url)s' % self.cfg)
121
            if self.proxy_auth is not None:
122
                conf_lines.append(
123
                    'RequestHeader set Proxy-Authorization %(proxy_auth)s\n' % self.cfg)
124
        # Write it all
125
        conf_file.write('\n\t'.join(conf_lines))
126

  
127
    def close(self):
128
        if self.conf_file:
129
            self.conf_file.write('</VirtualHost>\n\n')
130

  
131

  
132
def apache_escape_chars(url):
133
    special_characters = ('\\', '.', '?', '*', '+', '^', '$', '|', '(', ')', '[', ']')
134
    for char in special_characters:
135
        url = url.replace(char, '\%s' % char)
136
    return url
137

  
138
class Location(object):
139
    def __init__(self, host):
140
        self.host = host
141

  
142
    def get_reversed_directory(self):
143
        if not self.host.reversed_directory:
144
            return '%s/' % get_request().environ['SCRIPT_NAME']
145
        else:
146
            return '%s/%s/' % (get_request().environ['SCRIPT_NAME'], self.host.reversed_directory)
147
    reversed_directory = property(get_reversed_directory)
148

  
149
    def get_python_path(self):
150
        if self.host.apache_output_python_filters and \
151
                self.host.apache_python_paths:
152
            python_path = 'PythonPath "sys.path'
153
            for path in self.host.apache_python_paths:
154
                python_path += "+['%s']" % path
155
            python_path += '"'
156
            return python_path
157
        else:
158
            return None
159
    python_path = property(get_python_path)
160

  
161
    def get_output_filters(self):
162
        python_filters = ''
163
        output_filters = []
164
        if self.host.apache_output_python_filters:
165
            i = 0
166
            for filter_file in self.host.apache_output_python_filters:
167
                filter_name = 'filter%d' % i
168
                python_filters += 'PythonOutputFilter %s %s\n\t\t' % (filter_file, filter_name)
169
                output_filters.append(filter_name)
170
                i += 1
171
        if self.host.apache_output_filters:
172
            for output_filter in self.host.apache_output_filters:
173
                output_filters.append(output_filter)
174
        if output_filters:
175
            return python_filters + 'SetOutputFilter ' + ';'.join(output_filters)
176
        else:
177
            return None
178
    output_filters = property(get_output_filters)
179

  
180
    def get_old_auth_url(self):
181
        old_auth_url = None
182
        if self.host.initiate_sso_url:
183
            old_auth_url = self.host.initiate_sso_url
184
        elif self.host.auth_url is not None:
185
            if self.host.auth_url.startswith('http://'):
186
                chars_to_skip = 5
187
            else:
188
                chars_to_skip = 6
189
            regexp = re.compile(self.host.orig_site[chars_to_skip:])
190
            old_auth_url_short = regexp.sub('', self.host.auth_url[chars_to_skip:])
191
            if old_auth_url_short.startswith('/'):
192
                old_auth_url = old_auth_url_short
193
            else:
194
                old_auth_url = '/' + old_auth_url_short
195
        if old_auth_url:
196
            old_auth_url = apache_escape_chars(old_auth_url)
197
        return old_auth_url
198
    old_auth_url = property(get_old_auth_url)
199

  
200
    def get_new_auth_url(self):
201
        if not hasattr(self.host, 'base_url'):
202
            return None
203
        base_url_tokens = self.host.base_url.split('/')
204
        base_url_tokens[-1] = 'login'
205
        return '/'.join(base_url_tokens)
206
    new_auth_url = property(get_new_auth_url)
207

  
208
    def get_old_logout_url(self):
209
        old_logout_url = None
210
        if self.host.logout_url is not None:
211
            if self.host.logout_url.startswith('http://'):
212
                chars_to_skip = 5
213
            else:
214
                chars_to_skip = 6
215
            regexp = re.compile(self.host.orig_site[chars_to_skip:])
216
            old_logout_url_short = regexp.sub('', self.host.logout_url[chars_to_skip:])
217
            if old_logout_url_short.startswith('/'):
218
                old_logout_url = old_logout_url_short
219
            else:
220
                old_logout_url = '/' + old_logout_url_short
221
            old_logout_url = apache_escape_chars(old_logout_url)
222
        return old_logout_url
223
    old_logout_url = property(get_old_logout_url)
224

  
225
    def get_new_logout_url(self):
226
        if not hasattr(self.host, 'base_url'):
227
            return None
228
        base_url_tokens = self.host.base_url.split('/')
229
        base_url_tokens[-1] = 'logout'
230
        return '/'.join(base_url_tokens)
231
    new_logout_url = property(get_new_logout_url)
232

  
233
    def get_orig_site_url_and_dir(self):
234
        # Split url
235
        if self.host.orig_site.startswith('http://'):
236
            orig_host, orig_query = urllib.splithost(self.host.orig_site[5:])
237
        else:
238
            orig_host, orig_query = urllib.splithost(self.host.orig_site[6:])
239
        # Add a trailing slash if necessary
240
        if self.host.orig_site.endswith('/'):
241
            orig_url = self.host.orig_site
242
            orig_dir = orig_query
243
        else:
244
            orig_url = self.host.orig_site + '/'
245
            orig_dir = orig_query + '/'
246
        return orig_url, orig_dir
247

  
248
    def get_orig_url(self):
249
        orig_url, orig_dir = self.get_orig_site_url_and_dir()
250
        return orig_url
251
    orig_url = property(get_orig_url)
252

  
253
    def get_orig_dir(self):
254
        orig_url, orig_dir = self.get_orig_site_url_and_dir()
255
        return orig_dir
256
    orig_dir = property(get_orig_dir)
257

  
258
    def get_cfg(self):
259
        return { 'reversed_directory': self.reversed_directory,
260
                 'old_auth_url': self.old_auth_url,
261
                 'new_auth_url': self.new_auth_url,
262
                 'old_logout_url': self.old_logout_url,
263
                 'new_logout_url': self.new_logout_url,
264
                 'orig_url': self.orig_url,
265
                 'orig_dir': self.orig_dir }
266
    cfg = property(get_cfg)
267

  
268
    def write(self, conf_file):
269
        conf_lines = []
270
        # Start Location
271
        conf_lines.append('\n\t<Location %(reversed_directory)s>' % self.cfg)
272
        # No user restriction
273
        conf_lines.append('Allow from all')
274
        # Apache output filters
275
        if self.python_path:
276
            conf_lines.append(self.python_path)
277
        if self.output_filters:
278
            conf_lines.append(self.output_filters)
279
        # Redirect rules
280
        # Redirect old authentication url to the new one
281
        if self.old_auth_url is not None and self.host.auth_form_places == 'form_once':
282
            conf_lines.append(
283
                'RedirectMatch         %(old_auth_url)s    %(new_auth_url)s' % self.cfg)
284
        # Redirect old logout url to the new one
285
        if self.old_logout_url is not None:
286
            conf_lines.append(
287
                'RedirectMatch         %(old_logout_url)s    %(new_logout_url)s' % self.cfg)
288
        # Redirect the home page to the login page
289
        if self.host.redirect_root_to_login is True:
290
            conf_lines.append('RedirectMatch        ^/$      %(new_auth_url)s' % self.cfg)
291
        # Convert urls in http headers to/from the new domain
292
        conf_lines.append('ProxyPass           %(orig_url)s' % self.cfg)
293
        conf_lines.append('ProxyPassReverse    %(orig_url)s' % self.cfg)
294
        # Convert urls in html pages to/from the new domain
295
        conf_lines.append('ProxyHTMLURLMap     %(orig_dir)s     %(reversed_directory)s' % self.cfg)
296
        conf_lines.append('ProxyHTMLURLMap     %(orig_url)s    %(reversed_directory)s' % self.cfg)
297
        # Write it all and close the Location
298
        conf_file.write('\n\t\t'.join(conf_lines))
299
        conf_file.write('\n\t</Location>\n')
300

  
larpe/tags/release-1.1.1/larpe/admin/fields_prefill.ptl
1
from quixote import get_response, redirect
2
from quixote.directory import Directory
3

  
4
from qommon.form import *
5
from qommon.admin.menu import html_top, command_icon
6

  
7
from field_prefill import FieldPrefill
8

  
9
class FieldUI:
10
    def __init__(self, field_prefill):
11
        self.field_prefill = field_prefill
12

  
13
    def form_edit(self):
14
        form = Form(enctype='multipart/form-data')
15
        form.add(StringWidget, 'name', title = _('Field name'), required = True,
16
            size = 50, value = self.field_prefill.name)
17
        form.add(StringWidget, 'xpath', title = _('Xpath of the attribute'), required = True,
18
            size = 50, value = self.field_prefill.xpath, hint=_('Example: /pp:PP/pp:InformalName'))
19
        form.add(IntWidget, 'number', title = _('Number of the field in the data'), required = True,
20
            size = 3, value = self.field_prefill.number,
21
            hint=_('Change it if there are multiple fields corresponding to the same Xpath and you want to get another than the first one'))
22
        form.add(CheckboxWidget, 'raw_xml', title=_('Get raw XML value'),
23
            value = self.field_prefill.raw_xml)
24
        form.add(StringWidget, 'regexp_match', title = _('Python regexp of a string to match'),
25
            size = 50, value = self.field_prefill.regexp_match)
26
        form.add(StringWidget, 'regexp_replacing', title = _('Python regexp of the replacing string'),
27
            size = 50, value = self.field_prefill.regexp_replacing)
28
        form.add(WidgetDict, 'select_options', title = _('Options mapping for a select field'),
29
                value = self.field_prefill.select_options, add_element_label = _('Add item'))
30
        form.add_submit('submit', _('Submit'))
31
        form.add_submit('cancel', _('Cancel'))
32
        return form
33

  
34
    def submit_edit(self, form):
35
        for f in ('name', 'xpath', 'number', 'raw_xml',  'regexp_match', 'regexp_replacing', 'select_options'):
36
            widget = form.get_widget(f)
37
            setattr(self.field_prefill, f, widget.parse())
38
        self.field_prefill.store()
39

  
40
class FieldPage(Directory):
41
    _q_exports = ['', 'delete']
42

  
43
    def __init__(self, field_id):
44
        self.field_prefill = FieldPrefill.get(field_id)
45
        self.field_ui = FieldUI(self.field_prefill)
46
        get_response().breadcrumb.append((field_id + '/', field_id))
47

  
48
    def _q_index [html] (self):
49
        form = self.field_ui.form_edit()
50
        redo = False
51

  
52
        if form.get_widget('cancel').parse():
53
            return redirect('..')
54

  
55
        if form.get_widget('select_options') and form.get_widget('select_options').get_widget('add_element').parse():
56
            form.clear_errors()
57
            redo = True
58

  
59
        if redo is False and form.is_submitted() and not form.has_errors():
60
            self.field_ui.submit_edit(form)
61
            return redirect('..')
62

  
63
        get_response().breadcrumb.append( ('edit', _('Edit')) )
64
        html_top('edit', title = _('Edit'))
65
        '<h2>%s</h2>' % _('Edit')
66

  
67
        form.render()
68

  
69
    def delete [html] (self):
70
        form = Form(enctype='multipart/form-data')
71
        form.widgets.append(HtmlWidget('<p>%s</p>' % _(
72
                        'You are about to irrevocably delete this field.')))
73
        form.add_submit('submit', _('Submit'))
74
        form.add_submit('cancel', _('Cancel'))
75
        if form.get_widget('cancel').parse():
76
            return redirect('..')
77
        if not form.is_submitted() or form.has_errors():
78
            get_response().breadcrumb.append(('delete', _('Delete')))
79
            html_top('delete_form', title = _('Delete Field'))
80
            '<h2>%s : %s</h2>' % (_('Delete Field'), self.field_prefill.id)
81
            form.render()
82
        else:
83
            self.field_prefill.remove_self()
84
            return redirect('..')
85

  
86

  
87
class FieldsDirectory(Directory):
88
    _q_exports = ['', 'new']
89

  
90
    def __init__(self, form_prefill):
91
        get_response().breadcrumb.append(('fields/', _('Fields')))
92
        self.form_prefill = form_prefill
93

  
94
    def _q_lookup(self, component):
95
        return FieldPage(component)
96

  
97
    def _q_index [html] (self):
98
        html_top('fields', title = _('Fields'))
99
        """<ul id="nav-fields-admin">
100
          <li><a href="new">%s</a></li>
101
        </ul>""" % _('New Field')
102

  
103
        '<ul class="biglist">'
104

  
105
        for field_prefill in FieldPrefill.select(lambda x: x.form_id == self.form_prefill.id):
106
            if not field_prefill.name:
107
                continue
108

  
109
            # Split too long xpath
110
            xpath = field_prefill.xpath
111
            xpath_tokens = xpath.split(str('/'))
112
            if len(xpath_tokens) > 3:
113
                xpath = str('.../') + str('/').join(xpath_tokens[-3:])
114

  
115
            '<li>'
116
            '<strong class="label">%s</strong>' % field_prefill.name
117
            '<br />%s' % xpath
118
            '<p class="commands">'
119
            command_icon('%s/' % field_prefill.id, 'edit')
120
            command_icon('%s/delete' % field_prefill.id, 'remove')
121
            '</p></li>'
122
        '</ul>'
123

  
124
    def new [html] (self):
125
        get_response().breadcrumb.append(('new', _('New')) )
126
        field_prefill = FieldPrefill()
127
        field_prefill.form_id = self.form_prefill.id
128
        field_prefill.store()
129
        return redirect('%s/' % field_prefill.id)
130

  
larpe/tags/release-1.1.1/larpe/admin/forms_prefill.ptl
1
from quixote import get_response, redirect
2
from quixote.directory import Directory
3

  
4
from qommon.form import *
5
from qommon.admin.menu import html_top, command_icon
6

  
7
from form_prefill import FormPrefill
8
from fields_prefill import FieldsDirectory
9

  
10
class FormUI:
11
    def __init__(self, form_prefill):
12
        self.form_prefill = form_prefill
13

  
14
    def form_edit(self):
15
        form = Form(enctype='multipart/form-data')
16
        form.add(StringWidget, 'name', title = _('Form name'), required = True,
17
            size = 50, value = self.form_prefill.name, hint=_('Only used for display'))
18
        form.add(UrlWidget, 'url', title = _('Form address'), required = True,
19
            size = 50, value = self.form_prefill.url)
20
        form.add(StringWidget, 'profile', title = _('ID-WSF data profile'), required = True,
21
            size = 50, value = self.form_prefill.profile, hint=_('Example: urn:liberty:id-sis-pp:2005-05'))
22
        form.add(StringWidget, 'prefix', title = _('ID-WSF data XML prefix'), required = True,
23
            size = 50, value = self.form_prefill.prefix, hint=_('Example: pp'))
24
        form.add_submit('submit', _('Submit'))
25
        form.add_submit('cancel', _('Cancel'))
26
        return form
27

  
28
    def submit_edit(self, form):
29
        for f in ('name', 'url', 'profile', 'prefix'):
30
            widget = form.get_widget(f)
31
            setattr(self.form_prefill, f, widget.parse())
32
        self.form_prefill.store()
33

  
34
class FormPage(Directory):
35
    _q_exports = ['', 'edit', 'delete']
36

  
37
    def __init__(self, form_id):
38
        self.form_prefill = FormPrefill.get(form_id)
39
        self.form_ui = FormUI(self.form_prefill)
40
        get_response().breadcrumb.append((form_id + '/', form_id))
41

  
42
    def _q_index [html] (self):
43
        html_top('forms_prefill', title = 'Form prefilling')
44

  
45
        '<h2>%s</h2>' % _('Form prefilling configuration')
46
        '<dl>'
47
        '<dt><a href="edit">%s</a></dt> <dd>%s</dd>' % (
48
                _('Edit'), _('Configure this form'))
49
        '<dt><a href="fields/">%s</a></dt> <dd>%s</dd>' % (
50
                _('Fields'), _('Configure the fields of this form'))
51
        '</dl>'
52

  
53
    def _q_lookup(self, component):
54
        if component == 'fields':
55
            return FieldsDirectory(self.form_prefill)
56

  
57
    def edit [html] (self):
58
        form = self.form_ui.form_edit()
59
        if form.get_widget('cancel').parse():
60
            return redirect('.')
61

  
62
        if form.is_submitted() and not form.has_errors():
63
            self.form_ui.submit_edit(form)
64
            return redirect('.')
65

  
66
        get_response().breadcrumb.append( ('edit', _('Edit')) )
67
        html_top('edit', title = _('Edit'))
68
        '<h2>%s</h2>' % _('Edit')
69

  
70
        form.render()
71

  
72
    def delete [html] (self):
73
        form = Form(enctype='multipart/form-data')
74
        form.widgets.append(HtmlWidget('<p>%s</p>' % _(
75
                        'You are about to irrevocably delete this form.')))
76
        form.add_submit('submit', _('Submit'))
77
        form.add_submit('cancel', _('Cancel'))
78
        if form.get_widget('cancel').parse():
79
            return redirect('..')
80
        if not form.is_submitted() or form.has_errors():
81
            get_response().breadcrumb.append(('delete', _('Delete')))
82
            html_top('delete_form', title = _('Delete Form'))
83
            '<h2>%s : %s</h2>' % (_('Delete Form'), self.form_prefill.id)
84
            form.render()
85
        else:
86
            self.form_prefill.remove_self()
87
            return redirect('..')
88

  
89

  
90
class FormsDirectory(Directory):
91
    _q_exports = ['', 'new']
92

  
93
    def __init__(self, host):
94
        get_response().breadcrumb.append(('forms_prefill/', _('Forms')))
95
        self.host = host
96

  
97
    def _q_lookup(self, component):
98
        return FormPage(component)
99

  
100
    def _q_index [html] (self):
101
        html_top('forms', title = _('Forms'))
102
        """<ul id="nav-forms-admin">
103
          <li><a href="new">%s</a></li>
104
        </ul>""" % _('New Form')
105

  
106
        '<ul class="biglist">'
107

  
108
        for form_prefill in FormPrefill.select(lambda x: x.host_id == self.host.id):
109
            if not form_prefill.name:
110
                continue
111
            '<li>'
112
            '<strong class="label">%s</strong>' % form_prefill.name
113
            url = form_prefill.url
114
            '<br /><a href="%s">%s</a>' % (url, url)
115
            '<p class="commands">'
116
            command_icon('%s/' % form_prefill.id, 'edit')
117
            command_icon('%s/delete' % form_prefill.id, 'remove')
118
            '</p></li>'
119
        '</ul>'
120

  
121
    def new [html] (self):
122
        get_response().breadcrumb.append(('new', _('New')) )
123
        form_prefill = FormPrefill()
124
        form_prefill.host_id = self.host.id
125
        form_prefill.store()
126
        return redirect('%s/edit' % form_prefill.id)
127

  
larpe/tags/release-1.1.1/larpe/admin/hosts.ptl
1
import os
2
import urllib
3
import urlparse
4

  
5
from quixote import redirect, get_request, get_response, get_publisher
6
from quixote.directory import Directory
7

  
8
import lasso
9

  
10
from qommon.admin.menu import html_top, command_icon
11
from qommon import get_cfg
12
from qommon.form import *
13
from qommon.misc import http_get_page, get_abs_path
14

  
15
from larpe import site_authentication
16
from larpe import errors
17
from larpe import misc
18
from larpe.hosts import Host
19
from larpe.admin.apache import Location
20
from larpe.admin.liberty_utils import *
21
from larpe.admin.apache import write_apache2_vhosts
22
from larpe.admin.forms_prefill import FormsDirectory
23
from larpe.Defaults import DATA_DIR
24
from larpe.plugins import site_authentication_plugins
25

  
26
def check_basic_configuration(form):
27
    get_publisher().reload_cfg()
28
    # Check reversed_hostname and reversed_directory
29
    reversed_hostname = form.get_widget('reversed_hostname').parse()
30
    reversed_directory = form.get_widget('reversed_directory').parse()
31
    if reversed_hostname == get_publisher().cfg['proxy_hostname'] and not reversed_directory:
32
        form.set_error('reversed_hostname',
33
            _('You must either choose a different hostname from Larpe or specify a reversed directory'))
34

  
35
def convert_label_to_name(label):
36
    '''Build host name from host label'''
37
    name = label.lower()
38
    invalid_characters = [' ', "'"]
39
    for char in invalid_characters:
40
        name = name.replace(char, '_')
41
    return name
42

  
43
class DictWidget(Widget):
44
    def render_content [html] (self):
45
        self.render_br = False
46
        if self.value['enabled'] is True:
47
            htmltag('input', xml_end=True, type='checkbox', name=self.name + '_enabled', checked='checked')
48
        else:
49
            htmltag('input', xml_end=True, type='checkbox', name=self.name + '_enabled')
50
        ' ' + self.name + ' &nbsp;'
51
        htmltag('input', xml_end=True, type='text', name=self.name, value=self.value['value'], size='35', **self.attrs)
52

  
53
    def _parse(self, request):
54
        enabled = request.form.get(self.name + '_enabled')
55
        value = request.form.get(self.name)
56
        self.value = { 'enabled': enabled, 'value': value }
57

  
58

  
59
class ConfigurationAssistant(Directory):
60
    _q_exports = ['start', 'check_new_address', 'modify_site_address_and_name',
61
                  'authentication_and_logout_adresses', 'check_auto_detected_configuration',
62
                  'credentials', 'send_authentication_request', 'check_authentication',
63
                  'see_authentication_response', 'see_response_html_page',
64
                  'see_bad_response_html_page', 'authentication_success_criteria',
65
                  'modify_authentication_request', 'auth_request_post_parameters',
66
                  'auth_request_http_headers', 'sso_init_link', 'metadatas',
67
                  'check_full_configuration', 'advanced_options']
68

  
69
    def __init__(self, host):
70
        self.host = host
71

  
72
    def html_top [html] (self, title):
73
        html_top('hosts', title)
74
        '<h2>%s</h2>' % title
75

  
76
    def start [html] (self):
77
        # Check the global domain name has been previously set
78
        get_publisher().reload_cfg()
79
        if not get_cfg('domain_names') or not get_cfg('domain_names')[0]:
80
            get_response().breadcrumb.append(('start', _('Basic configuration')))
81
            self.html_top(_('Need domain name configuration'))
82
            return htmltext(_('''Before configuring hosts, you must
83
<a href="../../../settings/domain_names">setup a global domain name</a> in
84
%(settings)s menu.''') % { 'settings': _('Settings') })
85

  
86
        form = self.form_start()
87

  
88
        if form.get_widget('cancel').parse():
89
            return redirect('../..')
90

  
91
        connection_failure = None
92
        if form.is_submitted() and not form.has_errors():
93
            try:
94
                self.submit_start_form(form)
95
            except Exception, e:
96
                connection_failure = e
97
            else:
98
                if form.get_widget('terminate').parse():
99
                    return redirect('..')
100
                return redirect('check_new_address')
101

  
102
        get_response().breadcrumb.append(('start', _('Basic configuration')))
103
        self.html_top(_('Step 1 - Basic configuration'))
104

  
105
        if connection_failure:
106
            '<div class="errornotice">%s</div>' % connection_failure
107

  
108
        form.render()
109

  
110
    def form_start(self):
111
        form = Form(enctype='multipart/form-data')
112
        form.add(UrlWidget, 'orig_site', title = _('Original site root address'), required = True,
113
                size = 50, value = self.host.orig_site,
114
                hint = _('If your site address is http://test.org/index.php, put http://test.org/ here'))
115
        get_publisher().reload_cfg()
116
        if get_cfg('proxy', {}).get('enabled'):
117
            form.add(CheckboxWidget, 'use_proxy', title = _('Use a proxy'),
118
                    hint = _("Uncheck it if Larpe doesn't need to use the proxy to connect to this site"),
119
                    value = self.host.use_proxy)
120
        else:
121
            form.add(HtmlWidget, htmltext('<p>%s</p>' % \
122
                _('''If Larpe needs to use a proxy to connect to this site, you must first configure
123
 it in <a href="../../../settings/proxy">global proxy parameters</a>.''')))
124
        form.add_submit('cancel', _('Cancel'))
125
        form.add_submit('submit', _('Next'))
126
        form.add_submit('terminate', _('Terminate'))
127
        return form
128

  
129
    def submit_start_form(self, form):
130
        fields = ['orig_site']
131
        use_proxy = get_cfg('proxy', {}).get('enabled')
132
        if use_proxy:
133
            fields += ['use_proxy']
134
        for f in fields:
135
            setattr(self.host, f, form.get_widget(f).parse())
136

  
137
        # If no proxy is setup yet, set use_proxy to False for new hosts in case a proxy is later configured
138
        if not use_proxy:
139
            self.host.use_proxy = False
140

  
141
        # Remove what is after the last '/'
142
        #self.host.orig_site = '/'.join(self.host.orig_site.split('/')[:-1])
143

  
144
        html_page = self.get_data_after_redirects(self.host.orig_site)
145

  
146
        if not self.host.label:
147
            # Look for html title in original site index page
148
            regexp = re.compile("""<title.*?>(.*?)</title>""", re.DOTALL | re.IGNORECASE)
149
            title = regexp.findall(html_page)
150
            if title:
151
                self.host.label = title[0]
152
            else:
153
                self.host.label = 'Untitled'
154
            # If another site already uses this site title, add trailings "_" until we find an available name
155
            existing_label = True
156
            while existing_label is True:
157
                for any_host in Host.select():
158
                    if any_host.id != self.host.id and self.host.label == any_host.label:
159
                        self.host.label += '_'
160
                        break
161
                else:
162
                    existing_label = False
163

  
164
            # Fill host.name attribute
165
            self.host.name = convert_label_to_name(self.host.label)
166

  
167
        if not self.host.scheme:
168
            # Get tokens from orig site url
169
            orig_scheme, rest = urllib.splittype(self.host.orig_site)
170
            orig_host, rest = urllib.splithost(rest)
171

  
172
            get_publisher().reload_cfg()
173
            # Set url scheme (HTTP or HTTPS)
174
            # TODO: Handle the option "Both"
175
            if get_cfg('sites_url_scheme'):
176
                self.host.scheme = get_cfg('sites_url_scheme')
177
            else:
178
                self.host.scheme = orig_scheme
179

  
180
        if not self.host.reversed_hostname:
181
            # Build a new domain name
182
            short_name = orig_host.split('.')[0]
183
            if short_name == 'www':
184
                short_name = orig_host.split('.')[1]
185
            self.host.reversed_hostname = '%s.%s' % (short_name, get_cfg('domain_names')[0])
186
            # If another site already uses this domain name, add some trailing "_" until we find an available name
187
            existing_domain = True
188
            while existing_domain is True:
189
                for any_host in Host.select():
190
                    if any_host.id != self.host.id and self.host.reversed_hostname == any_host.reversed_hostname:
191
                        self.host.reversed_hostname += '-'
192
                        break
193
                else:
194
                    existing_domain = False
195
            self.host.reversed_directory = None
196

  
197
        if not self.host.new_url:
198
            # New url for this host
199
            self.host.new_url = '%s://%s%s/' % (self.host.scheme, self.host.reversed_hostname, get_request().environ['SCRIPT_NAME'])
200
            # FIXME: Check if the new domain name already exists
201

  
202
            # New url for this host
203
            #        self.host.new_url = '%s://%s%s/' % (self.host.scheme, self.host.reversed_hostname, get_request().environ['SCRIPT_NAME'])
204
            #        if self.host.reversed_directory is not None:
205
            #            self.host.new_url += '%s/' % self.host.reversed_directory
206

  
207
        self.host.store()
208
        write_apache2_vhosts()
209

  
210
    # XXX: Should use the FancyURLopener class instead when it supports proxies
211
    def get_data_after_redirects(self, start_url):
212
        if not start_url:
213
            return ''
214
        status = 302
215
        location = None
216
        while status // 100 == 3:
217
            if location is None:
218
                url = start_url
219
            elif location.startswith('http'):
220
                # Location is an absolute path
221
                url = location
222
            else:
223
                # Location is a relative path
224
                url = urlparse.urljoin(start_url, location)
225
            response, status, data, auth_headers = http_get_page(url, use_proxy=self.host.use_proxy)
226
            location = response.getheader('Location', None)
227
        return data
228

  
229
    def create_dirs(self):
230
        # Hack : sites must use the configuration which is stored in main Larpe directory,
231
        # but they need to have a directory named with their hostname, which will contain the
232
        # main domain name for Larpe so they know where is the main configuration
233
        hostname_dir = get_abs_path(os.path.join('..', self.host.reversed_hostname))
234
        if not os.path.exists(hostname_dir):
235
            os.mkdir(hostname_dir)
236
        # Load the configuration from the main directory
237
        get_publisher().reload_cfg()
238
        # Write it in the site directory
239
        get_publisher().write_cfg(hostname_dir)
240

  
241
        # Storage directories
242
        if not self.host.reversed_directory:
243
            reversed_dir = 'default'
244
        else:
245
            reversed_dir = self.host.reversed_directory
246
        self.host.site_dir = \
247
            os.path.join(get_publisher().app_dir, 'sp', self.host.reversed_hostname, reversed_dir)
248
        user_dir = os.path.join(self.host.site_dir, 'users')
249
        token_dir = os.path.join(self.host.site_dir, 'tokens')
250
        filter_dir = os.path.join(self.host.site_dir, 'filters')
251
        for dir in (self.host.site_dir, user_dir, token_dir, filter_dir):
252
            if not os.path.isdir(dir):
253
                os.makedirs(dir)
254

  
255
    def generate_ssl_keys(self):
256
        # Generate SSL keys
257
        private_key_path = os.path.join(self.host.site_dir, 'private_key.pem')
258
        public_key_path = os.path.join(self.host.site_dir, 'public_key.pem')
259
        if not os.path.isfile(private_key_path) or not os.path.isfile(public_key_path):
260
            set_provider_keys(private_key_path, public_key_path)
261
        self.host.private_key = private_key_path
262
        self.host.public_key = public_key_path
263

  
264
    def generate_metadatas(self):
265
        metadata_cfg = {}
266

  
267
        # Organization name
268
        self.host.organization_name = self.host.label
269
        metadata_cfg['organization_name'] = self.host.organization_name
270

  
271
        # Base URL
272
        base_url = '%s://%s%s/liberty/%s/liberty' % (self.host.scheme,
273
                                                     self.host.reversed_hostname,
274
                                                     get_request().environ['SCRIPT_NAME'],
275
                                                     self.host.name)
276
        metadata_cfg['base_url'] = base_url
277
        self.host.base_url = base_url
278

  
279
        if lasso.SAML2_SUPPORT:
280
            saml2_base_url = '%s://%s%s/liberty/%s/saml' % (self.host.scheme,
281
                                                         self.host.reversed_hostname,
282
                                                         get_request().environ['SCRIPT_NAME'],
283
                                                         self.host.name)
284
            metadata_cfg['saml2_base_url'] = saml2_base_url
285
            self.host.saml2_base_url = saml2_base_url
286

  
287
        # Provider Id
288
        provider_id = '%s/metadata' % base_url
289
        metadata_cfg['provider_id'] = provider_id
290
        self.host.provider_id = provider_id
291

  
292
        if lasso.SAML2_SUPPORT:
293
            saml2_provider_id = '%s/metadata' % saml2_base_url
294
            metadata_cfg['saml2_provider_id'] = saml2_provider_id
295
            self.host.saml2_provider_id = saml2_provider_id
296

  
297
        # Read public key
298
        public_key = ''
299
        if self.host.public_key is not None and os.path.exists(self.host.public_key):
300
            metadata_cfg['signing_public_key'] = open(self.host.public_key).read()
301

  
302
        # Write metadatas
303
        metadata_path = os.path.join(self.host.site_dir, 'metadata.xml')
304
        open(metadata_path, 'w').write(get_metadata(metadata_cfg))
305
        self.host.metadata = metadata_path
306

  
307
        if lasso.SAML2_SUPPORT:
308
            saml2_metadata_path = os.path.join(self.host.site_dir, 'saml2_metadata.xml')
309
            open(saml2_metadata_path, 'w').write(get_saml2_metadata(metadata_cfg))
310
            self.host.saml2_metadata = saml2_metadata_path
311

  
312
    def check_new_address [html] (self):
313
        form = Form(enctype='multipart/form-data')
314
        form.add_submit('cancel', _('Previous'))
315
        form.add_submit('submit', _('Next'))
316
        form.add_submit('terminate', _('Terminate'))
317

  
318
        if form.get_widget('cancel').parse():
319
            return redirect('start')
320

  
321
        if form.is_submitted():
322
            self.create_dirs()
323
            if self.host.private_key is None:
324
                self.generate_ssl_keys()
325
            self.generate_metadatas()
326
            self.host.store()
327

  
328
            if form.get_widget('terminate').parse():
329
                return redirect('..')
330
            return redirect('authentication_and_logout_adresses')
331

  
332
        get_response().breadcrumb.append(('check_new_address', _('Check site address and name')))
333
        self.html_top(_('Step 2 - Check the new site address works'))
334

  
335
        '<h3>%s</h3>' % _('DNS configuration')
336

  
337
        '<p>%s</p>' % _('''Before opening the following link, ensure you have configured your DNS
338
for this address. If you don't have a DNS server and you just want to test Larpe, add this
339
domain name in the file "/etc/hosts".''')
340

  
341
        '<p>%s</p>' % _('''Then you can open this link in a new window or tab and see if your site
342
is displayed. If it's ok, you can click the "%(next)s" button. Otherwise, click the "%(previous)s"
343
button and check your settings.''') % {'next': _('Next'), 'previous': _('Previous')}
344

  
345
        '<h3>%s</h3>' % _('Site adress and name')
346

  
347
        '<p>%s' % _('The new address of this site is ')
348
        '<a href="%s">%s</a><br/>' % (self.host.new_url, self.host.new_url)
349
        '%s</p>' % _('The name of this site is "%s".') % self.host.label
350
        '<p>%s</p>' % htmltext(_('''You can also <a href="modify_site_address_and_name">
351
modify the address or the name of this site</a>'''))
352

  
353
        form.render()
354

  
355
    def modify_site_address_and_name [html] (self):
356
        form = self.form_modify_site_address_and_name()
357

  
358
        if form.get_widget('cancel').parse():
359
            return redirect('check_new_address')
360

  
361
        if form.is_submitted() and not form.has_errors():
362
            label = form.get_widget('label').parse()
363
            name = convert_label_to_name(label)
364
            for any_host in Host.select():
365
                if any_host.id != self.host.id and name == any_host.name:
366
                    form.set_error('label', _('An host with the same name already exists'))
367
                    break
368

  
369
        if form.is_submitted() and not form.has_errors():
370
            self.submit_modify_site_address_and_name_form(form)
371
            return redirect('check_new_address')
372

  
373
        get_response().breadcrumb.append(('modify_site_address_and_name', _('Modify site address and name')))
374
        self.html_top(_('Modify site address and name'))
375

  
376
        form.render()
377

  
378
    def form_modify_site_address_and_name(self):
379
        form = Form(enctype='multipart/form-data')
380
        form.add(UrlWidget, 'new_url', title = _('Address'), required = True,
381
                size = 50, value = self.host.new_url)
382
        form.add(StringWidget, 'label', title = _('Name'), required = True,
383
                size = 50, value = self.host.label)
384
        form.add_submit('submit', _('Submit'))
385
        form.add_submit('cancel', _('Cancel'))
386
        return form
387

  
388
    def submit_modify_site_address_and_name_form(self, form):
389
        fields = ['new_url', 'label']
390
        for f in fields:
391
            setattr(self.host, f, form.get_widget(f).parse())
392

  
393
        # Split url to retrieve components
394
        tokens = urlparse.urlparse(self.host.new_url)
395
        self.host.scheme = tokens[0]
396
        self.host.reversed_hostname = tokens[1]
397
        self.host.reversed_directory = tokens[2]
398
        if self.host.reversed_directory.startswith('/'):
399
            self.host.reversed_directory = self.host.reversed_directory[1:]
400

  
401
        # Fill host.name attribute
402
        self.host.name = convert_label_to_name(self.host.label)
403

  
404
        self.host.store()
405
        write_apache2_vhosts()
406

  
407
    def authentication_and_logout_adresses [html] (self):
408
        form = self.form_authentication_and_logout_adresses()
409

  
410
        if form.get_widget('cancel').parse():
411
            return redirect('check_new_address')
412

  
413
        if form.is_submitted() and not form.has_errors():
414
            self.submit_authentication_and_logout_adresses_form(form)
415
            if form.get_widget('terminate').parse():
416
                return redirect('..')
417
            return redirect('check_auto_detected_configuration')
418

  
419
        get_response().breadcrumb.append(('authentication_and_logout_adresses', _('Authentication and logout')))
420
        self.html_top(_('Step 3 - Configure authentication and logout pages'))
421

  
422
        form.render()
423

  
424
    def form_authentication_and_logout_adresses(self):
425
        form = Form(enctype='multipart/form-data')
426
        form.add(ValidUrlWidget, 'auth_url', title = _('Authentication form page address'),
427
                hint = _('Address of a page on the site which contains the authentication form'),
428
                required = True, size = 50, value = self.host.auth_url)
429
        form.add(ValidUrlWidget, 'logout_url', title = _('Logout address'), required = False,
430
                hint = _('Address of the logout link on the site'),
431
                size = 50, value = self.host.logout_url)
432
        form.add_submit('cancel', _('Previous'))
433
        form.add_submit('submit', _('Next'))
434
        form.add_submit('terminate', _('Terminate'))
435
        return form
436

  
437
    def submit_authentication_and_logout_adresses_form(self, form):
438
        fields = ['auth_url', 'logout_url']
439
        for f in fields:
440
            setattr(self.host, f, form.get_widget(f).parse())
441
        self.host.auth_form_url = self.host.auth_url
442

  
443
        if not self.host.http_headers:
444
            self.host.http_headers = {
445
                'Content-Type': { 'enabled': True, 'value': 'application/x-www-form-urlencoded', 'immutable': False },
446
                'X-Forwarded-For': { 'enabled': True, 'value': _('(computed automatically)'), 'immutable': True },
447
                'X-Forwarded-Host': { 'enabled': True, 'value': self.host.reversed_hostname, 'immutable': False },
448
            }
449

  
450
        self.auto_detect_configuration()
451
        self.host.store()
452
        write_apache2_vhosts()
453

  
454
    def check_auto_detected_configuration [html] (self):
455
        plugins_name = site_authentication_plugins.get_plugins_name()
456
        plugins_name.append(None)
457
        plugins_name.sort()
458
        form = Form(enctype='multipart/form-data')
459
        form.add(SingleSelectWidget, 'plugin', title = _('Plugin'), required = False,
460
                hint = _('You can force a plugin'),
461
                value = self.host.site_authentication_plugin,
462
                options = plugins_name)
463
        form.add_submit('cancel', _('Previous'))
464
        form.add_submit('submit', _('Next'))
465
        form.add_submit('terminate', _('Terminate'))
466

  
467
        if form.get_widget('cancel').parse():
468
            return redirect('authentication_and_logout_adresses')
469

  
470
        if form.is_submitted():
471
            self.host.site_authentication_plugin = form.get_widget('plugin').parse()
472
            self.host.store()
473
            if form.get_widget('terminate').parse():
474
                write_apache2_vhosts()
475
                return redirect('..')
476
            return redirect('credentials')
477

  
478
        get_response().breadcrumb.append(('check_auto_detected_configuration', _('Auto detected configuration')))
479
        self.html_top(_('Step 4 - Check automatically detected configuration for the authentication form'))
480

  
481
        host_attrs = (
482
            ('auth_check_url', _('Address where the authentication form must be sent')),
483
            ('login_field_name', _('Name of the login field')),
484
            ('password_field_name', _('Name of the password field')),
485
        )
486

  
487
        html_fields = ''
488
        success = True
489
        for attr, name in host_attrs:
490
            color = 'black'
491
            if attr in ('auth_check_url', 'login_field_name', 'password_field_name') and \
492
                    not getattr(self.host, str(attr)):
493
                color = 'red'
494
                success = False
495
            html_fields += '<div style="margin-bottom: 0.1em; font-weight: bold; color: %s;">%s</div>' % (color, name)
496
            html_fields += '<div style="margin-left: 1em; margin-bottom: 0.3em; color: %s;">%s</div>' % \
497
                (color, getattr(self.host, str(attr)))
498
            if getattr(self.host, str(attr)) == '':
499
                html_fields += '<br />'
500

  
501
        '<p>'
502
        if success:
503
            htmltext(_('''\
504
The following authentication form parameters have been detected. If they look right, you can go to the next step.
505
If you think they are wrong, go back and check your settings then try again.
506
'''))
507
        else:
508
            htmltext(_('''\
509
The following authentication form parameters in red haven't been correctly detected. Go back and check
510
your settings then try again.
511
'''))
512
        '</p>'
513

  
514
        html_fields
515
        form.render()
516

  
517
    def credentials [html] (self):
518
        form = self.form_credentials()
519

  
520
        if form.get_widget('cancel').parse():
521
            return redirect('check_auto_detected_configuration')
522

  
523
        if form.is_submitted() and not form.has_errors():
524
            self.submit_credentials_form(form)
525
            if form.get_widget('terminate').parse():
526
                return redirect('..')
527
            return redirect('send_authentication_request')
528

  
529
        get_response().breadcrumb.append(('credentials', _('Credentials')))
530
        self.html_top(_('Step 5 - Fill in a valid username/password for this site'))
531
        form.render()
532

  
533
    def form_credentials(self):
534
        form = Form(enctype='multipart/form-data')
535
        form.add(StringWidget, 'username', title = _('Username'), required = True,
536
                size = 30, value = self.host.valid_username)
537
        form.add(PasswordWidget, 'password', title = _('Password'), required = True,
538
                size = 30, value = self.host.valid_password)
539
        for name, values in self.host.select_fields.iteritems():
540
            options = []
541
            if values:
542
                for value in values:
543
                    options.append(value)
544
                form.add(SingleSelectWidget, name, title = name.capitalize(),
545
                    value = values[0], options = options)
546
        form.add_submit('cancel', _('Previous'))
547
        form.add_submit('submit', _('Next'))
548
        form.add_submit('terminate', _('Terminate'))
549
        return form
550

  
551
    def submit_credentials_form(self, form):
552
        self.host.valid_username = form.get_widget('username').parse()
553
        self.host.valid_password = form.get_widget('password').parse()
554
        self.host.valid_select = {}
555
        for name, values in self.host.select_fields.iteritems():
556
            if form.get_widget(name):
557
                self.host.valid_select[name] = form.get_widget(name).parse()
558

  
559
        self.host.store()
560

  
561
    def send_authentication_request(self):
562
        site_auth = site_authentication.get_site_authentication(self.host)
563

  
564
        # Request with good credentials
565
        self.host.auth_request_status, self.host.auth_request_data = site_auth.local_auth_check_dispatch(
566
            self.host.valid_username, self.host.valid_password, self.host.valid_select)
567
        self.host.auth_request_success, self.host.auth_request_return_content = \
568
            site_auth.check_auth(self.host.auth_request_status, self.host.auth_request_data)
569

  
570
        # Request with bad credentials
571
        self.host.auth_bad_request_status, self.host.auth_bad_request_data = site_auth.local_auth_check_dispatch(
572
            'this_is_a_bad_login', 'this_is_a_bad_password', {})
573
        self.host.auth_bad_request_success, self.host.auth_bad_request_return_content = \
574
            site_auth.check_auth(self.host.auth_bad_request_status, self.host.auth_bad_request_data)
575

  
576
        self.host.store()
577

  
578
        return redirect('check_authentication')
579

  
580
    def check_authentication [html] (self):
581
        form = Form(enctype='multipart/form-data')
582
        form.add_submit('cancel', _('Previous'))
583
        form.add_submit('submit', _('Next'))
584
        form.add_submit('terminate', _('Terminate'))
585

  
586
        if form.get_widget('cancel').parse():
587
            return redirect('credentials')
588

  
589
        if form.is_submitted():
590
            if form.get_widget('terminate').parse():
591
                return redirect('..')
592
            return redirect('sso_init_link')
593

  
594
        get_response().breadcrumb.append(('check_authentication', _('Check authentication')))
595
        self.html_top(_('Step 6 - Check the authentication process'))
596

  
597
        if self.host.auth_request_success:
598
            good_cred_status = 'Success <span style="color: green">[OK]</span>'
599
        else:
600
            good_cred_status = 'Failed <span style="color: red">[KO]</span'
601

  
602
        if not self.host.auth_bad_request_success:
603
            bad_cred_status = 'Failed <span style="color: green">[OK]</span>'
604
        else:
605
            bad_cred_status = 'Success <span style="color: red">[KO]</span>'
606

  
607
        '<p>Results of authentication requests :</p>\n'
608
        '<ul>\n'
609
        '\t<li>With good credentials : %s</li>' % good_cred_status
610
        '\t<li>With bad credentials : %s</li>' % bad_cred_status
611
        '</ul>\n'
612

  
613
        if self.host.auth_request_success and not self.host.auth_bad_request_success :
614
            '<p>%s</p>\n' % _('Authentication succeeded ! You can go to the next step.')
615
        else:
616
            '<p>%s</p>\n' % _('Authentication has failed. To resolve this problem, you can :')
617
            '<ul>\n'
618
            '\t<li><a href="send_authentication_request">%s</a></li>\n' % \
619
                _('Try authentication again')
620
            '\t<li><a href="see_authentication_response">%s</a></li>\n' % \
621
                _('See the response of the authentication requests')
622
            '\t<li><a href="modify_authentication_request">%s</a></li>\n' % \
623
                _('Modify the parameters of the authentication requests')
624
            '\t<li><a href="authentication_success_criteria">%s</a></li>\n' % \
625
                _('Change the way Larpe detects the authentication is successful or not')
626
            '\t<li>%s</li>\n' % _('Go back and change your username and/or password')
627
            '</ul>\n'
628

  
629
        form.render()
630

  
631
    def see_authentication_response [html] (self):
632
        get_response().breadcrumb.append(('see_authentication_response', _('Authentication response')))
633
        self.html_top(_('Authentication response'))
634

  
635
        '<h3>%s</h3>' % _('Response of the request with good credentials')
636

  
637
        '<div style="margin-bottom: 0.1em; font-weight: bold; color: black;">%s</div>' % \
638
            str(_('HTTP status code'))
639
        '<div style="margin-left: 1em; margin-bottom: 0.3em; color: black;">%s (%s)</div>' % \
640
            (self.host.auth_request_status, status_reasons[self.host.auth_request_status])
641

  
642
        '<dl>'
643
        '<dt><a href="see_bad_response_html_page">%s</a></dt>' % _('See HTML page')
644
        '</dl>'
645

  
646
        '<h3>%s</h3>' % _('Response of the request with bad credentials')
647

  
648
        '<div style="margin-bottom: 0.1em; font-weight: bold; color: black;">%s</div>' % \
649
            str(_('HTTP status code'))
650
        '<div style="margin-left: 1em; margin-bottom: 0.3em; color: black;">%s (%s)</div>' % \
651
            (self.host.auth_bad_request_status, status_reasons[self.host.auth_bad_request_status])
652

  
653
        '<dl>'
654
        '<dt><a href="see_response_html_page">%s</a></dt>' % _('See HTML page')
655
        '</dl>'
656

  
657
        '<div class="buttons"><a href="check_authentication"><input type="button" value="%s" /></a></div><br />' % _('Back')
658

  
659
    def see_response_html_page (self):
660
        return self.host.auth_request_data
661

  
662
    def see_bad_response_html_page (self):
663
        return self.host.auth_bad_request_data
664

  
665
    def authentication_success_criteria [html] (self):
666
        form = self.form_authentication_success_criteria()
667

  
668
        if form.get_widget('cancel').parse():
669
            return redirect('check_authentication')
670

  
671
        if form.is_submitted() and not form.has_errors():
672
            self.submit_authentication_success_criteria_form(form)
673
            return redirect('check_authentication')
674

  
675
        get_response().breadcrumb.append(('authentication_success_criteria', _('Authentication success criteria')))
676
        self.html_top(_('Authentication success criteria'))
677

  
678
        form.render()
679

  
680
    def form_authentication_success_criteria(self):
681
        form = Form(enctype='multipart/form-data')
682
        form.add(RadiobuttonsWidget, 'auth_system', title = _('Authentication system of the original site'),
683
                options=[
684
                    ('password', _('Check the existence of a password field'), 'password'),
685
                    ('match_text', _('Match some text to detect an authentication failure'), 'match_text'),
686
                ],
687
                sort=False,
688
                delim=htmltext('<br />'),
689
                value = self.host.auth_system)
690
        form.add(RegexStringWidget, 'auth_match_text', title = _('Text to match in case of authentication failure'),
691
                required = False, size = 50, value = self.host.auth_match_text)
692
        form.add_submit('submit', _('Submit'))
693
        form.add_submit('cancel', _('Cancel'))
694
        return form
695

  
696
    def submit_authentication_success_criteria_form(self, form):
697
        for f in ('auth_system', 'auth_match_text'):
698
            value = form.get_widget(f).parse()
699
            setattr(self.host, f, value)
700

  
701
        self.host.store()
702

  
703
    def modify_authentication_request [html] (self):
704
        get_response().breadcrumb.append(('modify_authentication_request', _('Authentication request')))
705
        self.html_top(_('Modify the parameters of the authentication requests'))
706

  
707
        '<dl>'
708
        '<dt><a href="auth_request_post_parameters">%s</a></dt> <dd>%s</dd>' % (
709
                _('Modify POST parameters'), _('Configure the form attributes that will be sent within the authentication POST requests'))
710
        '<dt><a href="auth_request_http_headers">%s</a></dt> <dd>%s</dd>' % (
711
                _('Modify HTTP headers'), _('Configure the HTTP headers of the authentication requests made by Larpe'))
712
        '</dl>'
713
        '<div class="buttons"><a href="check_authentication"><input type="button" value="%s" /></a></div><br />' % _('Back')
714

  
715
    def auth_request_post_parameters [html] (self):
716
        form = self.form_auth_request_post_parameters()
717

  
718
        if form.get_widget('cancel').parse():
719
            return redirect('modify_authentication_request')
720

  
721
        if form.is_submitted() and not form.has_errors():
722
            self.submit_auth_request_post_parameters_form(form)
723
            return redirect('modify_authentication_request')
724

  
725
        get_response().breadcrumb.append(('auth_request_post_parameters', _('POST parameters')))
726
        self.html_top(_('Configure POST parameters'))
727

  
728
        '<p>%s</p>' % _('''Here are the detected form fields that will be sent as parameters of the
729
authentication POST request. You can desactivate some or all of them, or change their value.''')
730

  
731
        form.render()
732

  
733
    def form_auth_request_post_parameters(self):
734
        form = Form(enctype='multipart/form-data')
735
        for name, value in self.host.post_parameters.iteritems():
736
            if value['immutable']:
737
                form.add(DictWidget, name, value, disabled = 'disabled')
738
            else:
739
                form.add(DictWidget, name, value)
740
        form.add_submit('submit', _('Submit'))
741
        form.add_submit('cancel', _('Cancel'))
742
        return form
743

  
744
    def submit_auth_request_post_parameters_form(self, form):
745
        for name, old_value in self.host.post_parameters.iteritems():
746
            value = form.get_widget(name).parse()
747
            if value['enabled'] == 'on':
748
                old_value['enabled'] = True
749
            else:
750
                old_value['enabled'] = False
751
            if old_value['immutable'] is False:
752
                old_value['value'] = value['value']
753
            self.host.post_parameters[name] = old_value
754
        self.host.store()
755

  
756
    def auth_request_http_headers [html] (self):
757
        form = self.form_auth_request_http_headers()
758

  
759
        if form.get_widget('cancel').parse():
760
            return redirect('modify_authentication_request')
761

  
762
        if form.is_submitted() and not form.has_errors():
763
            self.submit_auth_request_http_headers_form(form)
764
            return redirect('modify_authentication_request')
765

  
766
        get_response().breadcrumb.append(('auth_request_http_headers', _('HTTP headers')))
767
        self.html_top(_('Configure HTTP headers'))
768

  
769
        '<p>%s</p>' % _('''Here are the HTTP headers that will be sent within the authentication
770
POST request. You can desactivate some or all of them, or change their value.''')
771

  
772
        form.render()
773

  
774
    def form_auth_request_http_headers(self):
775
        form = Form(enctype='multipart/form-data')
776
        for name, value in self.host.http_headers.iteritems():
777
            if value['immutable']:
778
                form.add(DictWidget, name, value, disabled = 'disabled')
779
            else:
780
                form.add(DictWidget, name, value)
781
        form.add(HtmlWidget, htmltext('<p>%s</p>' % \
782
            _('The headers "Host", "Accept-Encoding" and "Content-Length" will also automatically be sent.')))
783
        if get_cfg('proxy', {}).get('enabled') and self.host.use_proxy:
784
            form.add(HtmlWidget, htmltext('<p>%s</p>' % \
785
                _('''As Larpe uses a proxy for this site, the headers "Proxy-Authorization",
786
"Proxy-Connection" and "Keep-Alive" will be sent as well.''')))
787
        form.add_submit('submit', _('Submit'))
788
        form.add_submit('cancel', _('Cancel'))
789
        return form
790

  
791
    def submit_auth_request_http_headers_form(self, form):
792
        for name, old_value in self.host.http_headers.iteritems():
793
            value = form.get_widget(name).parse()
794
            if value['enabled'] == 'on':
795
                old_value['enabled'] = True
796
            else:
797
                old_value['enabled'] = False
798
            if old_value['immutable'] is False:
799
                old_value['value'] = value['value']
800
            self.host.http_headers[name] = old_value
801
        self.host.store()
802

  
803
    def generate_apache_filters(self):
804
        self.host.apache_python_paths = []
805
        self.host.apache_output_python_filters = []
806
        site_auth = site_authentication.get_site_authentication(self.host)
807
        output_filters = site_auth.output_filters
808
        replace_login_form = self.host.auth_form_places == 'form_everywhere' and \
809
                self.host.auth_form_action
810
        if replace_login_form and not 'output_replace_form' in output_filters:
811
            output_filters.append('output_replace_form')
812
        if output_filters:
813
            location = Location(self.host)
814
            conf = { 'auth_form_action': self.host.auth_form_action,
815
                    'name': self.host.name,
816
                    'larpe_dir': get_publisher().app_dir,
817
                    'logout_url': location.new_logout_url,
818
                    'login_url': location.new_auth_url }
819
            # Set Python filter path for Apache configuration
820
            python_path = os.path.join(self.host.site_dir, 'filters')
821
            if python_path not in self.host.apache_python_paths:
822
                self.host.apache_python_paths.append(python_path)
823

  
824
            for filter in output_filters:
825
                python_file = open(
826
                        os.path.join(self.host.site_dir, 'filters', filter + ".py"),
827
                        'w')
828
                python_file.write(
829
                        open(os.path.join(DATA_DIR, "filters", filter + ".py")).read() % conf
830
                        )
831
                if not filter in self.host.apache_output_python_filters:
832
                    self.host.apache_output_python_filters.append(filter)
833

  
834
    def sso_init_link [html] (self):
835
        form = self.form_sso_init_link()
836

  
837
        if form.get_widget('cancel').parse():
838
            return redirect('check_authentication')
839

  
840
        if form.is_submitted() and not form.has_errors():
841
            self.submit_sso_init_link_form(form)
842
            if form.get_widget('terminate').parse():
843
                return redirect('..')
844
            return redirect('metadatas')
845

  
846
        get_response().breadcrumb.append(('sso_init_link', _('SSO initiation')))
847
        self.html_top(_('Step 7 - Configure how a Single Sign On can be initiated'))
848

  
849
        '<p>%s\n' % _('Most sites use one of the following 2 ways to allow users to initialise an authentication :')
850
        '\t<ol>\n'
851
        '\t\t<li>%s</li>\n' % \
852
            _('''The site has a single authentication page. It redirects users to this page when
853
they click a "Login" button or try to access a page which require users to be authenticated.''')
854
        '\t\t<li>%s</li>\n' % \
855
            _('''The site includes an authentication form in most or all of his pages. Users can
856
authenticate on any of these pages, and don't need to be redirected to a separate authentication page.''')
857
        '\t</ol>\n'
858
        '</p>\n'
859

  
860
        '<p>%s</p>' % _('Select the way your site works :')
861

  
862
        form.render()
863

  
864
    def form_sso_init_link(self):
865
        form = Form(enctype='multipart/form-data')
866
        form.add(RadiobuttonsWidget, 'auth_form_places',
867
                options=[
868
                    ('form_once', _('The site has a single authentication page'), 'form_once'),
869
                    ('form_everywhere', _('The site includes an authentication form in most or all pages'), 'form_everywhere'),
870
                ],
871
                sort=False, required = True, delim=htmltext('<br />'), value = self.host.auth_form_places)
872
        form.add_submit('cancel', _('Previous'))
873
        form.add_submit('submit', _('Next'))
874
        form.add_submit('terminate', _('Terminate'))
875
        return form
876

  
877
    def submit_sso_init_link_form(self, form):
878
        fields = [ 'auth_form_places', ]
879
        for f in fields:
880
            setattr(self.host, f, form.get_widget(f).parse())
881
        self.host.auth_form_url = self.host.auth_url
882
        self.generate_apache_filters()
883
        self.host.store()
884
        write_apache2_vhosts()
885

  
886
    def metadatas [html] (self):
887
        form = Form(enctype='multipart/form-data')
888
        form.add_submit('cancel', _('Previous'))
889
        form.add_submit('submit', _('Next'))
890
        form.add_submit('terminate', _('Terminate'))
891

  
892
        if form.get_widget('cancel').parse():
893
            return redirect('sso_init_link')
894

  
895
        if form.is_submitted():
896
            if form.get_widget('terminate').parse():
897
                return redirect('..')
898
            return redirect('advanced_options')
899

  
900
        get_response().breadcrumb.append(('metadatas', _('Metadatas')))
901
        self.html_top(_('Step 8 - Metadatas of %(site_name)s' % {'site_name': self.host.name}))
902

  
903
        '<p>%s</p>' % \
904
            _('''Download the metadatas and the public key for this site and
905
upload them on your identity provider in order to use Liberty Alliance features.''')
906

  
907
        '<dl>'
908
        if hasattr(self.host, str('base_url')):
909
            if lasso.SAML2_SUPPORT:
910
                saml2_metadata_url = '%s/metadata.xml' % self.host.saml2_base_url
911
                '<dt><a href="%s">%s</a></dt> <dd>%s</dd>' % (
912
                            saml2_metadata_url,
913
                            _('SAML 2.0 Metadata'),
914
                            _('Download SAML 2.0 metadata file'))
915
            metadata_url = '%s/metadata.xml' % self.host.base_url
916
            '<dt><a href="%s">%s</a></dt> <dd>%s</dd>' % (
917
                        metadata_url,
918
                        _('ID-FF 1.2 Metadata'),
919
                        _('Download ID-FF 1.2 metadata file'))
920
        else:
921
            '<p>%s</p>' % _('No metadata has been generated for this host.')
922

  
923
        if hasattr(self.host, str('base_url')) and self.host.public_key and os.path.exists(self.host.public_key):
924
            public_key_url = '%s/public_key' % self.host.base_url
925
            '<dt><a href="%s">%s</a></dt> <dd>%s</dd>' % (
926
                        public_key_url,
927
                        _('Public key'),
928
                        _('Download SSL Public Key file'))
929
        else:
930
            '<p>%s</p>' % _('No public key has been generated for this host.')
931
        '</dl>'
932

  
933
        form.render()
934

  
935
    def advanced_options [html] (self):
936
        form = self.form_advanced_options()
937

  
938
        if form.get_widget('cancel').parse():
939
            return redirect('metadatas')
940

  
941
        if not form.is_submitted() or form.has_errors():
942
            get_response().breadcrumb.append(('advanced_options', _('Advanced options')))
943
            self.html_top(_('Step 9 - Advanced options'))
944

  
945
            '<p>%s</p>' % _('Configure advanced options to setup the last details of your site.')
946
            '<p>%s</p>' % _('''If you don't know what to configure here, just click %(next)s and
947
come here later if needed.''') % {'next': _('Next')}
948

  
949
            form.render()
950
        else:
951
            self.submit_advanced_options_form(form)
952
            if form.get_widget('terminate').parse():
953
                return redirect('..')
954
            return redirect('check_full_configuration')
955

  
956
    def form_advanced_options(self):
957
        form = Form(enctype='multipart/form-data')
958
        form.add(CheckboxWidget, 'redirect_root_to_login',
959
                title=_('Redirect the root URL of the site to the login page.'),
960
                value = self.host.redirect_root_to_login)
961
        form.add(UrlOrAbsPathWidget, 'return_url', title = _('Return address'),
962
                hint = _('Where the user will be redirected after a successful authentication'),
963
                required = False, size = 50, value = self.host.return_url)
964
        form.add(UrlOrAbsPathWidget, 'root_url', title = _('Error address'),
965
                hint = _('Where the user will be redirected after a disconnection or an error'),
966
                required = False, size = 50, value = self.host.root_url)
967
        form.add(UrlOrAbsPathWidget, 'initiate_sso_url', title = _('URL which must initiate the SSO'),
968
                hint = _('''Address which must initiate the SSO. If empty, defaults to the previously
969
specified "%s"''') % _('Authentication form page address'),
970
                required = False, size = 50, value = self.host.initiate_sso_url)
971
        form.add(CheckboxWidget, 'proxy-html', title = _('Apache HTML proxy'),
972
                hint = _('''Converts urls in the HTML pages according to the host new domain name.
973
Disabled by default because it makes some sites not work correctly.'''),
974
                value = 'proxy-html' in self.host.apache_output_filters)
975

  
976
        form.add_submit('cancel', _('Previous'))
977
        form.add_submit('submit', _('Next'))
978
        form.add_submit('terminate', _('Terminate'))
979
        return form
980

  
981
    def submit_advanced_options_form(self, form):
982
        old_redirect_root_to_login = self.host.redirect_root_to_login
983

  
984
        for f in ('redirect_root_to_login', 'return_url', 'root_url', 'initiate_sso_url'):
985
            value = form.get_widget(f).parse()
986
            setattr(self.host, f, value)
987

  
988
        f = 'proxy-html'
989
        value = form.get_widget(f).parse()
990
        if value is True and f not in self.host.apache_output_filters:
991
            self.host.apache_output_filters.append(f)
992
        if value is False and f in self.host.apache_output_filters:
993
            self.host.apache_output_filters.remove(f)
994

  
995
        self.host.store()
996

  
997
        if self.host.initiate_sso_url or self.host.redirect_root_to_login is not old_redirect_root_to_login:
998
            write_apache2_vhosts()
999

  
1000
    def check_full_configuration [html] (self):
1001
        form = Form(enctype='multipart/form-data')
1002
        form.add_submit('cancel', _('Previous'))
1003
        form.add_submit('submit', _('Finish'))
1004

  
1005
        if form.get_widget('cancel').parse():
1006
            return redirect('advanced_options')
1007

  
1008
        if form.is_submitted():
1009
            return redirect('../..')
1010

  
1011
        get_response().breadcrumb.append(('check_full_configuration', _('Check everything works')))
1012
        self.html_top(_('Step 10 - Check everything works'))
1013

  
1014
        '<p>%s</p>' % \
1015
            _('''Now you can fully test your site, start from the home page, initiate a
1016
Single Sign On, federate your identities and do a Single Logout.''')
1017

  
1018
        '<p>%s' % _('The address of your site is : ')
1019
        '<a href="%s">%s</a>' % (self.host.new_url, self.host.new_url)
1020
        '</p>'
1021

  
1022
        '<p>%s</p>' % \
1023
            _('''If everything works, click the "%(finish)s" button, otherwise you can go
1024
back and check your settings.''') % { 'finish': _('Finish') }
1025

  
1026
        form.render()
1027

  
1028
    def auto_detect_configuration(self):
1029
        # Reset previous detected values
1030
        self.host.auth_form = None
1031
        self.host.auth_check_url = None
1032
        self.host.login_field_name = None
1033
        self.host.password_field_name = None
1034
        if not self.host.post_parameters:
1035
            self.host.post_parameters = {}
1036

  
1037
        self.parse_page(self.host.auth_form_url)
1038

  
1039
    def parse_page(self, page_url):
1040
        # Get the authentication page
1041
        try:
1042
            response, status, page, auth_header = http_get_page(page_url, use_proxy=self.host.use_proxy)
1043
        except Exception, msg:
1044
            print msg
1045
            return
1046

  
1047
        if page is None:
1048
            return
1049
            #raise FormError, ('auth_check_url', '%s : %s' % (_('Failed to get page'), self.host.auth_form_url))
1050

  
1051
        # Default authentication mode
1052
        self.host.auth_mode = 'form'
1053

  
1054
        if not self.host.site_authentication_plugin:
1055
            self.host.site_authentication_plugin = site_authentication_plugins.auto_detect(page)
1056
        self.parse_frames(page)
1057
        self.parse_forms(page)
1058
        if self.host.auth_form is not None:
1059
            self.parse_form_action()
1060
            input_fields = self.parse_input_fields()
1061
            self.parse_login_field(input_fields)
1062
            self.parse_password_field()
1063
            self.parse_select_fields()
1064
            self.parse_other_fields()
1065

  
1066
    def parse_frames(self, page):
1067
        '''If there are frames, parse them recursively'''
1068
        regexp = re.compile("""<frame.*?src=["'](.*?)["'][^>]*?>""", re.DOTALL | re.IGNORECASE)
1069
        found_frames = regexp.findall(page)
1070
        if found_frames:
1071
            for frame_url in found_frames:
1072
                if frame_url.startswith('http'):
1073
                    frame_full_url = frame_url
1074
                else:
1075
                    page_url_tokens = frame_url.split('/')
1076
                    page_url_tokens[-1] = frame_url
1077
                    frame_full_url = '/'.join(page_url_tokens)
1078
                self.parse_page(frame_full_url)
1079

  
1080
    def parse_forms(self, page):
1081
        '''Search for an authentication form'''
1082
        # Get all forms
1083
        regexp = re.compile("""<form.*?</form>""", re.DOTALL | re.IGNORECASE)
1084
        found_forms = regexp.findall(page)
1085
        if not found_forms:
1086
            return
1087
            #raise FormError, ('auth_check_url', '%s : %s' % (_('Failed to find any form'), self.host.auth_form_url))
1088

  
1089
        # Get the first form with a password field
1090
        for found_form in found_forms:
1091
            regexp = re.compile("""<input[^>]*?type=["']?password["']?[^>]*?>""", re.DOTALL | re.IGNORECASE)
1092
            if regexp.search(found_form) is not None:
1093
                self.host.auth_form = found_form
1094
                break
1095

  
1096
    def parse_form_action(self):
1097
        '''Get the action url of the form'''
1098
        regexp = re.compile("""<form.*?action=["']?(.*?)["']?[\s>].*?>""", re.DOTALL | re.IGNORECASE)
1099
        self.host.auth_form_action = regexp.findall(self.host.auth_form)[0]
1100
        # FIXME: Find a Python module which unescapes html entities
1101
        self.host.auth_check_url = self.host.auth_form_action.replace('&amp;', '&')
1102
        if not self.host.auth_check_url.startswith('http'):
1103
            if self.host.auth_check_url.startswith('/'):
1104
                if self.host.orig_site.startswith('https'):
1105
                    orig_site_root = 'https://%s' % urllib.splithost(self.host.orig_site[6:])[0]
1106
                else:
1107
                    orig_site_root = 'http://%s' % urllib.splithost(self.host.orig_site[5:])[0]
1108
                self.host.auth_check_url = orig_site_root + self.host.auth_check_url
1109
            else:
1110
                auth_form_url_tokens = self.host.auth_form_url.split('/')
1111
                auth_form_url_tokens[-1] = self.host.auth_check_url
1112
                self.host.auth_check_url = '/'.join(auth_form_url_tokens)
1113

  
1114
    def parse_input_fields(self):
1115
        '''Get all input fields'''
1116
        regexp = re.compile("""<input[^>]*?>""", re.DOTALL | re.IGNORECASE)
1117
        return regexp.findall(self.host.auth_form)
1118

  
1119
    def parse_login_field(self, input_fields):
1120
        '''Get login field name'''
1121
        try:
1122
            regexp = re.compile("""<input[^>]*?type=["']?text["']?[^>]*?>""", re.DOTALL | re.IGNORECASE)
1123
            text_fields = regexp.findall(self.host.auth_form)
1124
            login_field = ''
1125
            if text_fields:
1126
                login_field = text_fields[0]
1127
            else:
1128
                for field in input_fields:
1129
                    if re.search("""type=["']?""", field, re.DOTALL | re.IGNORECASE) is None:
1130
                        login_field = field
1131
                        break
1132
            regexp = re.compile("""name=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE)
1133
            self.host.login_field_name = regexp.findall(login_field)[0]
1134
            if not self.host.post_parameters.has_key(self.host.login_field_name):
1135
                self.host.post_parameters[self.host.login_field_name] = \
1136
                    { 'enabled': True, 'value': _('(filled by users)'), 'immutable': True }
1137
                self.host.store()
1138
        except IndexError, e:
1139
            self.host.login_field_name = None
1140
            print 'Error handling login field : %s' % e
1141

  
1142
    def parse_password_field(self):
1143
        '''Get password field name'''
1144
        try:
1145
            regexp = re.compile("""<input[^>]*?type=["']?password["']?[^>]*?>""", re.DOTALL | re.IGNORECASE)
1146
            password_field = regexp.findall(self.host.auth_form)[0]
1147
            regexp = re.compile("""name=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE)
1148
            self.host.password_field_name = regexp.findall(password_field)[0]
1149
            if not self.host.post_parameters.has_key(self.host.password_field_name):
1150
                self.host.post_parameters[self.host.password_field_name] = \
1151
                    { 'enabled': True, 'value': _('(filled by users)'), 'immutable': True }
1152
        except IndexError, e:
1153
            self.host.password_field_name = None
1154
            print 'Error handling password field : %s' % e
1155

  
1156
    def parse_select_fields(self):
1157
        '''Add select fields to host attributes'''
1158
        # First added for Imuse (Rennes)
1159
        regexp = re.compile("""<select.*?</select>""", re.DOTALL | re.IGNORECASE)
1160
        self.host.select_fields = {}
1161
        for field in regexp.findall(self.host.auth_form):
1162
            try:
1163
                regexp = re.compile("""name=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE)
1164
                name = regexp.findall(field)[0]
1165
                regexp = re.compile("""<option[^>]*?>.*?</option>""", re.DOTALL | re.IGNORECASE)
1166
                options = regexp.findall(field)
1167
                values = []
1168
                for option in options:
1169
                    regexp = re.compile("""<option[^>]*?>(.*?)</option>""", re.DOTALL | re.IGNORECASE)
1170
                    option_label = regexp.findall(option)
1171
                    regexp = re.compile("""value=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE)
1172
                    option_value = regexp.findall(option)
1173
                    if option_label:
1174
                        if not option_value:
1175
                            option_value = option_label
1176
                        values.append((option_value[0], option_label[0]))
1177
                    else:
1178
                        print >> sys.stderr, 'W: Could not parse select options'
1179
                self.host.select_fields[name] = values
1180
                if not self.host.post_parameters.has_key(name):
1181
                    self.host.post_parameters[name] = \
1182
                        { 'enabled': True, 'value': _('(filled by users)'), 'immutable': True }
1183
            except IndexError, e:
1184
                continue
1185

  
1186
    def parse_other_fields(self):
1187
        '''Get the default value of all other fields'''
1188
        self.host.other_fields = {}
1189

  
1190
        # Get hidden fields
1191
        regexp = re.compile("""<input[^>]*?type=["']?hidden["']?[^>]*?>""", re.DOTALL | re.IGNORECASE)
1192
        other_fields = regexp.findall(self.host.auth_form)
1193

  
1194
        # Only get first submit field
1195
        regexp = re.compile("""<input[^>]*?type=["']?submit["']?[^>]*?>""", re.DOTALL | re.IGNORECASE)
1196
        found = regexp.findall(self.host.auth_form)
1197
        if found:
1198
            if other_fields:
1199
                other_fields.append(found[0])
1200
            else:
1201
                other_fields = found[0]
1202

  
1203
        for field in other_fields:
1204
            try:
1205
                regexp = re.compile("""name=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE)
1206
                name = regexp.findall(field)[0]
1207
                regexp = re.compile("""value=["'](.*?)["'][\s/>]""", re.DOTALL | re.IGNORECASE)
1208
                value = regexp.findall(field)[0]
1209
                self.host.other_fields[name] = value
1210
                if not self.host.post_parameters.has_key(name):
1211
                    self.host.post_parameters[name] = { 'enabled': True, 'value': value, 'immutable': False }
1212
            except IndexError, e:
1213
                continue
1214

  
1215

  
1216
class HostPage(Directory):
1217
    _q_exports = ['', 'delete']
1218

  
1219
    def __init__(self, host_id):
1220
        self.host = Host.get(host_id)
1221
        get_response().breadcrumb.append((host_id + '/', self.host.label))
1222

  
1223
    def _q_lookup(self, component):
1224
        if component == 'configuration_assistant':
1225
            return ConfigurationAssistant(self.host)
1226
        elif component == 'forms_prefill':
1227
            return FormsDirectory(self.host)
1228

  
1229
    def _q_index [html] (self):
1230
        get_publisher().reload_cfg()
1231
        html_top('hosts', title = self.host.label)
1232

  
1233
        '<h2>%s</h2>' % _('Configuration assistant')
1234

  
1235
        '<dl>'
1236

  
1237
        '<dt><a href="configuration_assistant/start">%s</a></dt> <dd>%s</dd>' % (
1238
                _('Address of the original site'), _('Configure the root address of the site'))
1239

  
1240
        '<dt><a href="configuration_assistant/check_new_address">%s</a></dt> <dd>%s</dd>' % (
1241
                _('New address and name'), _('Configure the new address and name of this site'))
1242

  
1243
        '<dt><a href="configuration_assistant/authentication_and_logout_adresses">%s</a></dt> <dd>%s</dd>' % (
1244
                _('Authentication and logout addresses'), _('Configure the authentication and logout addresses of the original site'))
1245

  
1246
        '<dt><a href="configuration_assistant/check_auto_detected_configuration">%s</a></dt> <dd>%s</dd>' % (
1247
                _('Check auto detected configuration'), _('Check the automatically detected configuration is right'))
1248

  
1249
        '<dt><a href="configuration_assistant/credentials">%s</a></dt> <dd>%s</dd>' % (
1250
                _('Credentials'), _('Configure some valid credentials to authenticate on the original site'))
1251

  
1252
        '<dt><a href="configuration_assistant/send_authentication_request">%s</a></dt> <dd>%s</dd>' % (
1253
                _('Retry authentication'), _('Retry sending an authentication request to the site to check if your new parameters work well'))
1254

  
1255
        '<dt><a href="configuration_assistant/see_authentication_response">%s</a></dt> <dd>%s</dd>' % (
1256
                _('Check authentication response'), _('Check the response from the latest authentication request'))
1257

  
1258
        '<dt><a href="configuration_assistant/authentication_success_criteria">%s</a></dt> <dd>%s</dd>' % (
1259
                _('Configure authentication success criteria'), _('Specify how Larpe knows if the authentication has succeeded or not'))
1260

  
1261
        '<dt><a href="configuration_assistant/modify_authentication_request">%s</a></dt> <dd>%s</dd>' % (
1262
                _('Modify authentication request'), _('Modify POST fields or HTTP headers of the authentication request'))
1263

  
1264
        '<dt><a href="configuration_assistant/sso_init_link">%s</a></dt> <dd>%s</dd>' % (
1265
                _('Configure how a Single Sign On can be initiated'), _('Configure how a Single Sign On can be initiated'))
1266

  
1267
        '<dt><a href="configuration_assistant/metadatas">%s</a></dt> <dd>%s</dd>' % (
1268
                _('Metadatas and key'), _('Download SAML 2.0 or ID-FF metadatas and SSL public key'))
1269

  
1270
        '<dt><a href="configuration_assistant/advanced_options">%s</a></dt> <dd>%s</dd>' % (
1271
                _('Adavanced options'), _('Configure advanced options to setup the last details of your site'))
1272

  
1273
        '</dl>'
1274

  
1275
        '<h2>%s</h2>' % _('Form prefilling with ID-WSF')
1276

  
1277
        '<dl>'
1278
        '<dt><a href="forms_prefill/">%s</a></dt> <dd>%s</dd>' % (
1279
                _('Forms'), _('Configure the forms to prefill'))
1280
        '</dl>'
1281

  
1282
    def delete [html] (self):
1283
        form = Form(enctype='multipart/form-data')
1284
        form.widgets.append(HtmlWidget('<p>%s</p>' % _(
1285
                        'You are about to irrevocably delete this host.')))
1286
        form.add_submit('submit', _('Submit'))
1287
        form.add_submit('cancel', _('Cancel'))
1288
        if form.get_widget('cancel').parse():
1289
            return redirect('..')
1290
        if not form.is_submitted() or form.has_errors():
1291
            get_response().breadcrumb.append(('delete', _('Delete')))
1292
            html_top('hosts', title = _('Delete Host'))
1293
            '<h2>%s : %s</h2>' % (_('Delete Host'), self.host.label)
1294
            form.render()
1295
        else:
1296
            self.host.remove_self()
1297
            write_apache2_vhosts()
1298
            return redirect('..')
1299

  
1300

  
1301
class HostsDirectory(Directory):
1302
    _q_exports = ['', 'new']
1303

  
1304
    def _q_index [html] (self):
1305
        get_response().breadcrumb.append(('hosts/', _('Hosts')))
1306
        html_top('hosts', title = _('Hosts'))
1307
        """<ul id="nav-hosts-admin">
1308
          <li><a href="new">%s</a></li>
1309
        </ul>""" % _('New Host')
1310

  
1311
        '<ul class="biglist">'
1312

  
1313
        for host in Host.select(lambda x: x.name != 'larpe', order_by = 'label'):
1314
            if not host.name:
1315
                continue
1316
            if not hasattr(host, str('scheme')):
1317
                host.scheme = str('http')
1318
            '<li>'
1319
            '<strong class="label">%s</strong>' % host.label
1320
            if hasattr(host, str('new_url')) and host.new_url:
1321
                url = host.new_url
1322
            else:
1323
                # Compat with older Larpe versions
1324
                url = '%s://%s%s/' % (host.scheme, host.reversed_hostname, get_request().environ['SCRIPT_NAME'])
1325
                if host.reversed_directory is not None:
1326
                    url += '%s/' % host.reversed_directory
1327
            '<br /><a href="%s">%s</a>' % (url, url)
1328
            '<p class="commands">'
1329
            command_icon('%s/' % host.id, 'edit')
1330
            command_icon('%s/delete' % host.id, 'remove')
1331
            '</p></li>'
1332
        '</ul>'
1333

  
1334
    def new [html] (self):
1335
        if not os.path.isdir(os.path.join(get_publisher().app_dir, str('idp'))):
1336
            html_top('hosts', title = _('New Host'))
1337
            html = '<h2>%s</h2>' % _('New Host')
1338
            html += 'You must <a href="%s/admin/settings/liberty_idp/">' % misc.get_root_url()
1339
            html += 'configure an Identity Provider</a> first<br /><br />'
1340
            html += '<a href="."><input type="button" value="%s" /></a>' % _('Back')
1341
            return html
1342

  
1343
        get_response().breadcrumb.append(('hosts/', _('Hosts')))
1344
        get_response().breadcrumb.append(('new', _('New')) )
1345
        host = Host()
1346
        host.store()
1347
        return redirect('%s/configuration_assistant/start' % host.id)
1348

  
1349
    def _q_lookup(self, component):
1350
        get_response().breadcrumb.append(('hosts/', _('Hosts')))
1351
        return HostPage(component)
1352

  
larpe/tags/release-1.1.1/larpe/admin/liberty_utils.py
1
import os
2

  
3
def set_provider_keys(private_key_path, public_key_path):
4
    # use system calls for openssl since PyOpenSSL doesn't expose the
5
    # necessary functions.
6
    if os.system('openssl version > /dev/null 2>&1') == 0:
7
        os.system('openssl genrsa -out %s 2048' % private_key_path)
8
        os.system('openssl rsa -in %s -pubout -out %s' % (private_key_path, public_key_path))
9

  
10

  
11
def get_metadata(cfg):
12
    prologue = """\
13
<?xml version="1.0"?>
14
<EntityDescriptor
15
    providerID="%(provider_id)s"
16
    xmlns="urn:liberty:metadata:2003-08">""" % cfg
17

  
18
    sp_head = """
19
  <SPDescriptor protocolSupportEnumeration="urn:liberty:iff:2003-08">"""
20

  
21
    signing_public_key = ''
22
    if cfg.has_key('signing_public_key') and cfg['signing_public_key']:
23
        if 'CERTIF' in cfg['signing_public_key']:
24
            signing_public_key = """
25
        <KeyDescriptor use="signing">
26
          <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
27
            <ds:X509Data><ds:X509Certificate>%s</ds:X509Certificate></ds:X509Data>
28
          </ds:KeyInfo>
29
        </KeyDescriptor>""" % cfg['signing_public_key']
30
        elif 'KEY' in cfg['signing_public_key']:
31
            signing_public_key = """
32
        <KeyDescriptor use="signing">
33
          <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
34
            <ds:KeyValue>%s</ds:KeyValue>
35
          </ds:KeyInfo>
36
        </KeyDescriptor>""" % cfg['signing_public_key']
37

  
38
    sp_body = """
39
    <AssertionConsumerServiceURL id="AssertionConsumerServiceURL1" isDefault="true">%(base_url)s/assertionConsumer</AssertionConsumerServiceURL>
40

  
41
    <SoapEndpoint>%(base_url)s/soapEndpoint</SoapEndpoint>
42

  
43
    <SingleLogoutServiceURL>%(base_url)s/singleLogout</SingleLogoutServiceURL>
44
    <SingleLogoutServiceReturnURL>%(base_url)s/singleLogoutReturn</SingleLogoutServiceReturnURL>
45
    <SingleLogoutProtocolProfile>http://projectliberty.org/profiles/slo-idp-http</SingleLogoutProtocolProfile>
46
    <SingleLogoutProtocolProfile>http://projectliberty.org/profiles/slo-sp-soap</SingleLogoutProtocolProfile>
47
    <SingleLogoutProtocolProfile>http://projectliberty.org/profiles/slo-sp-http</SingleLogoutProtocolProfile>
48

  
49
    <FederationTerminationServiceURL>%(base_url)s/federationTermination</FederationTerminationServiceURL>
50
    <FederationTerminationServiceReturnURL>%(base_url)s/federationTerminationReturn</FederationTerminationServiceReturnURL>
51
    <FederationTerminationNotificationProtocolProfile>http://projectliberty.org/profiles/fedterm-idp-soap</FederationTerminationNotificationProtocolProfile>
52
    <FederationTerminationNotificationProtocolProfile>http://projectliberty.org/profiles/fedterm-idp-http</FederationTerminationNotificationProtocolProfile>
53
    <FederationTerminationNotificationProtocolProfile>http://projectliberty.org/profiles/fedterm-sp-soap</FederationTerminationNotificationProtocolProfile>
54
    <FederationTerminationNotificationProtocolProfile>http://projectliberty.org/profiles/fedterm-sp-http</FederationTerminationNotificationProtocolProfile>
55

  
56
    <AuthnRequestsSigned>true</AuthnRequestsSigned>
57

  
58
  </SPDescriptor>""" % cfg
59

  
60
    orga = ''
61
    if cfg.get('organization_name'):
62
        orga = """
63
  <Organization>
64
    <OrganizationName>%s</OrganizationName>
65
  </Organization>""" % unicode(cfg['organization_name'], 'iso-8859-1').encode('utf-8')
66

  
67
    epilogue = """
68
</EntityDescriptor>"""
69

  
70
    return '\n'.join([prologue, sp_head, signing_public_key, sp_body, orga, epilogue])
71

  
72

  
73

  
74
def get_saml2_metadata(cfg):
75
    prologue = """\
76
<?xml version="1.0"?>
77
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
78
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
79
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
80
    entityID="%(saml2_provider_id)s">""" % cfg
81

  
82
    sp_head = """
83
  <SPSSODescriptor
84
      AuthnRequestsSigned="true"
85
      protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">"""
86

  
87
    signing_public_key = ''
88
    if cfg.has_key('signing_public_key') and cfg['signing_public_key']:
89
        if 'CERTIF' in cfg['signing_public_key']:
90
            signing_public_key = """
91
        <KeyDescriptor use="signing">
92
          <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
93
            <ds:X509Data><ds:X509Certificate>%s</ds:X509Certificate></ds:X509Data>
94
          </ds:KeyInfo>
95
        </KeyDescriptor>""" % cfg['signing_public_key']
96
        elif 'KEY' in cfg['signing_public_key']:
97
            signing_public_key = """
98
        <KeyDescriptor use="signing">
99
          <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
100
            <ds:KeyValue>%s</ds:KeyValue>
101
          </ds:KeyInfo>
102
        </KeyDescriptor>""" % cfg['signing_public_key']
103

  
104
    sp_body = """
105
    <AssertionConsumerService isDefault="true" index="0"
106
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
107
      Location="%(saml2_base_url)s/singleSignOnArtifact" />
108
    <SingleLogoutService
109
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
110
      Location="%(saml2_base_url)s/singleLogoutSOAP" />
111
    <SingleLogoutService
112
      Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
113
      Location="%(saml2_base_url)s/singleLogout"
114
      ResponseLocation="%(saml2_base_url)s/singleLogoutReturn" />
115

  
116
  </SPSSODescriptor>""" % cfg
117

  
118
    orga = ''
119
    if cfg.get('organization_name'):
120
        orga = """
121
  <Organization>
122
    <OrganizationName>%s</OrganizationName>
123
  </Organization>""" % unicode(cfg['organization_name'], 'iso-8859-1').encode('utf-8')
124

  
125
    epilogue = """
126
</EntityDescriptor>"""
127

  
128
    return '\n'.join([prologue, sp_head, signing_public_key, sp_body, orga, epilogue])
129

  
larpe/tags/release-1.1.1/larpe/admin/root.ptl
1
import os
2

  
3
import lasso
4

  
5
from quixote import get_session, get_session_manager, get_publisher, get_request, get_response
6
from quixote.directory import Directory, AccessControlled
7

  
8
from qommon.admin.menu import html_top
9
from qommon.admin import logger
10

  
11
from larpe import errors
12
from larpe import misc
13

  
14
import hosts
15
import users
16
import settings
17

  
18
def gpl [html] ():
19
    """<p>This program is free software; you can redistribute it and/or modify it
20
    under the terms of the GNU General Public License as published by the Free
21
    Software Foundation; either version 2 of the License, or (at your option)
22
    any later version.</p>
23

  
24
    <p>This program is distributed in the hope that it will be useful, but
25
    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
26
    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
27
    for more details.</p>
28

  
29
    <p>You should have received a copy of the GNU General Public License along with
30
    this program; if not, write to the Free Software Foundation, Inc., 59 Temple
31
    Place - Suite 330, Boston, MA  02111-1307, USA.</p>
32
    """
33

  
34

  
35
class RootDirectory(AccessControlled, Directory):
36
    _q_exports = ['', 'hosts', 'users', 'settings', 'logger']
37

  
38
    hosts = hosts.HostsDirectory()
39
    users = users.UsersDirectory()
40
    settings = settings.SettingsDirectory()
41
    logger = logger.LoggerDirectory()
42

  
43
    menu_items = [
44
        ('hosts/', N_('Hosts')),
45
        ('users/', N_('Users')),
46
        ('settings/', N_('Settings')),
47
        ('logger/', N_('Logs')),
48
        ('/', N_('Liberty Alliance Reverse Proxy'))]
49

  
50
    def _q_access(self):
51
        # FIXME : this block should be moved somewhere else
52
        get_publisher().reload_cfg()
53
        if not get_publisher().cfg.has_key('proxy_hostname'):
54
            get_publisher().cfg['proxy_hostname'] = get_request().get_server().split(':')[0]
55
        get_publisher().write_cfg()
56

  
57
        response = get_response()
58
        if not hasattr(response, 'breadcrumb'):
59
            response.breadcrumb = [ ('../admin/', _('Administration')) ]
60

  
61
        # Cheater
62
        if os.path.exists(os.path.join(get_publisher().app_dir, 'ADMIN_FOR_ALL')):
63
            return
64

  
65
        # No admin user created yet, free access
66
        user_list = users.User.select(lambda x: x.is_admin)
67
        if not user_list:
68
            return
69

  
70
        host_list = hosts.Host.select(lambda x: x.name == 'larpe')
71
        if host_list:
72
            host = host_list[0]
73
        else:
74
            raise errors.AccessForbiddenError()
75

  
76
        if misc.get_current_protocol() == lasso.PROTOCOL_SAML_2_0:
77
            user = get_session().get_user(host.saml2_provider_id)
78
        else:
79
            user = get_session().get_user(host.provider_id)
80
        if user:
81
            if not user.name or not user.is_admin:
82
                raise errors.AccessForbiddenError()
83
        else:
84
            raise errors.AccessUnauthorizedError()
85

  
86

  
87
    def _q_index [html] (self):
88
        html_top('')
89
        gpl()
90

  
larpe/tags/release-1.1.1/larpe/admin/settings.ptl
1
import cStringIO
2
import cPickle
3
import re
4
import os
5
import lasso
6
import glob
7
import zipfile
8

  
9
from quixote import get_publisher, get_request, get_response, redirect
10
from quixote.directory import Directory, AccessControlled
11

  
12
from qommon.form import *
13
from qommon.misc import get_abs_path
14
from qommon.admin.cfg import cfg_submit
15
from qommon.admin.menu import html_top, error_page
16
from qommon.admin.emails import EmailsDirectory as QommonEmailsDirectory
17
from qommon.admin.settings import SettingsDirectory as QommonSettingsDirectory
18

  
19
from larpe import misc
20
from larpe.hosts import Host
21
from larpe.admin.liberty_utils import *
22

  
23
class LibertyIDPDir(Directory):
24
    _q_exports = ['', ('metadata.xml', 'metadata')]
25

  
26
    def _q_index [html] (self):
27
        form = Form(enctype="multipart/form-data")
28
        form.add(FileWidget, "metadata", title = _("Metadata"), required=True)
29
        form.add(FileWidget, "publickey", title = _("Public Key"), required=False)
30
        form.add(FileWidget, "cacertchain", title = _("CA Certificate Chain"), required=False)
31
        form.add_submit("submit", _("Submit"))
32

  
33
        if not form.is_submitted() or form.has_errors():
34
            html_top('settings', title = _('New Identity Provider'))
35
            "<h2>%s</h2>" % _('New Identity Provider')
36
            form.render()
37
        else:
38
            self.submit_new(form)
39

  
40
    def submit_new(self, form, key_provider_id = None):
41
        metadata, publickey, cacertchain = None, None, None
42
        if form.get_widget('metadata').parse():
43
            metadata = form.get_widget('metadata').parse().fp.read()
44
        if form.get_widget('publickey').parse():
45
            publickey = form.get_widget('publickey').parse().fp.read()
46
        if form.get_widget('cacertchain').parse():
47
            cacertchain = form.get_widget('cacertchain').parse().fp.read()
48

  
49
        if not key_provider_id:
50
            try:
51
                provider_id = re.findall(r'(provider|entity)ID="(.*?)"', metadata)[0][1]
52
            except IndexError:
53
                return error_page('settings', _('Bad metadata'))
54
            key_provider_id = provider_id.replace(str('://'), str('-')).replace(str('/'), str('-'))
55

  
56
        dir = get_abs_path(os.path.join('idp', key_provider_id))
57
        if not os.path.isdir(dir):
58
            os.makedirs(dir)
59

  
60
        if metadata:
61
            metadata_fn = os.path.join(dir, 'metadata.xml')
62
            open(metadata_fn, 'w').write(metadata)
63
        if publickey:
64
            publickey_fn = os.path.join(dir, 'public_key')
65
            open(publickey_fn, 'w').write(publickey)
66
        else:
67
            publickey_fn = None
68
        if cacertchain:
69
            cacertchain_fn = os.path.join(dir, 'ca_cert_chain.pem')
70
            open(cacertchain_fn, 'w').write(cacertchain)
71
        else:
72
            cacertchain_fn = None
73

  
74
        p = lasso.Provider(lasso.PROVIDER_ROLE_IDP, metadata_fn, publickey_fn, None)
75

  
76
        try:
77
            misc.get_provider_label(p)
78
            get_publisher().cfg['idp'] = key_provider_id
79
            get_publisher().write_cfg()
80
        except TypeError:
81
            if metadata:
82
                os.unlink(metadata_fn)
83
            if publickey:
84
                os.unlink(publickey_fn)
85
            if cacertchain:
86
                os.unlink(cacertchain_fn)
87
            return error_page('settings', _('Bad metadata'))
88

  
89
        redirect('..')
90

  
91
    def metadata(self):
92
        response = get_response()
93
        response.set_content_type('text/xml', 'utf-8')
94
        get_publisher().reload_cfg()
95
        if get_publisher().cfg['idp']:
96
            idp_metadata = os.path.join(get_abs_path('idp'), get_publisher().cfg['idp'], 'metadata.xml')
97
            return unicode(open(idp_metadata).read(), 'utf-8')
98
        return 'No IDP is configured'
99

  
100

  
101
class EmailsDirectory(QommonEmailsDirectory):
102
    def _q_index [html] (self):
103
        # Don't use custom emails
104
        html_top('settings', title = _('Emails'))
105
        '<h2>%s</h2>' % _('Emails')
106

  
107
        '<ul>'
108
        '<li><a href="options">%s</a></li>' % _('General Options')
109
        '</ul>'
110

  
111
        '<p>'
112
        '<a href="..">%s</a>' % _('Back')
113
        '</p>'
114

  
115

  
116
class SettingsDirectory(QommonSettingsDirectory):
117
    _q_exports = ['', 'liberty_sp', 'liberty_idp', 'domain_names', 'apache2_configuration_generation',
118
                  'proxy', 'language', 'emails', 'debug_options' ]
119

  
120
    liberty_idp = LibertyIDPDir()
121
    emails = EmailsDirectory()
122

  
123
    def _q_index [html] (self):
124
        get_publisher().reload_cfg()
125
        html_top('settings', title = _('Settings'))
126

  
127
        if lasso.SAML2_SUPPORT:
128
            '<h2>%s</h2>' % _('Liberty Alliance & SAML 2.0 Service Provider')
129
        else:
130
            '<h2>%s</h2>' % _('Liberty Alliance Service Provider')
131
        '<dl> <dt><a href="liberty_sp">%s</a></dt> <dd>%s</dd>' % (
132
                _('Service Provider'), _('Configure Larpe as a Service Provider'))
133

  
134
        hosts = Host.select(lambda x: x.name == 'larpe')
135
        if hosts:
136
            self.host = hosts[0]
137

  
138
            if lasso.SAML2_SUPPORT and self.host.saml2_metadata is not None:
139
                metadata_url = '%s/metadata.xml' % self.host.saml2_base_url
140
                '<dt><a href="%s">%s</a></dt> <dd>%s</dd>' % (
141
                        metadata_url,
142
                        _('SAML 2.0 Metadata'),
143
                        _('Download SAML 2.0 metadata file for Larpe'))
144

  
145
            if self.host.metadata is not None:
146
                metadata_url = '%s/metadata.xml' % self.host.base_url
147
                '<dt><a href="%s">%s</a></dt> <dd>%s</dd>' % (
148
                        metadata_url,
149
                        _('ID-FF 1.2 Metadata'),
150
                        _('Download ID-FF 1.2 metadata file for Larpe'))
151

  
152
            if self.host.public_key is not None:
153
                public_key_url = '%s/public_key' % self.host.base_url
154
                '<dt><a href="%s">%s</a></dt> <dd>%s</dd>' % (
155
                        public_key_url,
156
                        _('Public key'),
157
                        _('Download SSL Public Key file'))
158

  
159
        if lasso.SAML2_SUPPORT:
160
            '<h2>%s</h2>' % _('Liberty Alliance & SAML 2.0 Identity Provider')
161
        else:
162
            '<h2>%s</h2>' % _('Liberty Alliance Identity Provider')
163

  
164
        '<dl>'
165

  
166
        '<dt><a href="liberty_idp/">%s</a></dt> <dd>%s</dd>' % (
167
               _('Identity Provider'), _('Configure an identity provider'))
168

  
169
        if get_publisher().cfg.has_key('idp'):
170
            '<dt><a href="liberty_idp/metadata.xml">%s</a></dt> <dd>%s</dd>' % (
171
                    _('Identity Provider metadatas'), _('See current identity provider metadatas'))
172

  
173
        '</dl>'
174

  
175
        '<h2>%s</h2>' % _('Global parameters for the sites')
176

  
177
        '<dl>'
178
        '<dt><a href="domain_names">%s</a></dt> <dd>%s</dd>' % (
179
                _('Domain name'), _('Configure the base domain name for the sites'))
180
        '<dt><a href="apache2_configuration_generation">%s</a></dt> <dd>%s</dd>' % (
181
                _('Apache 2 configuration generation'), _('Customise Apache 2 configuration generation'))
182
        '<dt><a href="proxy">%s</a></dt> <dd>%s</dd>' % (
183
                _('Proxy'), _('Connect to the sites through a web proxy'))
184
        '</dl>'
185

  
186
        '<h2>%s</h2>' % _('Customisation')
187

  
188
        '<dl>'
189
        '<dt><a href="language">%s</a></dt> <dd>%s</dd>' % (
190
                _('Language'), _('Configure site language'))
191
        '<dt><a href="emails/">%s</a></dt> <dd>%s</dd>' % (
192
                _('Emails'), _('Configure email settings'))
193
        '</dl>'
194

  
195
        '<h2>%s</h2>' % _('Misc')
196

  
197
        '<dl>'
198
        '<dt><a href="debug_options">%s</a></dt> <dd>%s</dd>' % (
199
                _('Debug Options'), _('Configure options useful for debugging'))
200
        '</dl>'
201

  
202

  
203
    def liberty_sp [html] (self):
204
        get_publisher().reload_cfg()
205

  
206
        # Get the host object for the reverse proxy
207
        hosts = Host.select(lambda x: x.name == 'larpe')
208
        if hosts:
209
            self.host = hosts[0]
210
        else:
211
            self.host = Host()
212
            self.host.reversed_hostname = get_publisher().cfg[str('proxy_hostname')]
213

  
214
        form = Form(enctype='multipart/form-data')
215
        form.add(StringWidget, 'organization_name', title=_('Organisation Name'), size=50,
216
                required = True, value = self.host.organization_name)
217
        form.add_submit('submit', _('Submit'))
218
        form.add_submit('cancel', _('Cancel'))
219
        if form.get_widget('cancel').parse():
220
            return redirect('.')
221
        if not form.is_submitted() or form.has_errors():
222
            html_top('settings', title = _('Service Provider Configuration'))
223
            '<h2>%s</h2>' % _('Service Provider Configuration')
224
            form.render()
225
        else:
226
            self.liberty_sp_submit(form)
227
            redirect('.')
228

  
229
    def liberty_sp_submit(self, form):
230
        get_publisher().reload_cfg()
231
        metadata_cfg = {}
232

  
233
        f = 'organization_name'
234
        if form.get_widget(f):
235
            setattr(self.host, f, form.get_widget(f).parse())
236

  
237
        metadata_cfg['organization_name'] = self.host.organization_name
238

  
239
        self.host.name = 'larpe'
240

  
241
        # Liberty Alliance / SAML parameters
242
        base_url = '%s/liberty/%s/liberty' % (misc.get_root_url(), self.host.name)
243
        metadata_cfg['base_url'] = base_url
244
        self.host.base_url = base_url
245

  
246
        if lasso.SAML2_SUPPORT:
247
            saml2_base_url = '%s/liberty/%s/saml' % (misc.get_root_url(), self.host.name)
248
            metadata_cfg['saml2_base_url'] = saml2_base_url
249
            self.host.saml2_base_url = saml2_base_url
250

  
251
        provider_id = '%s/metadata' % base_url
252
        metadata_cfg['provider_id'] = provider_id
253
        self.host.provider_id = provider_id
254

  
255
        if lasso.SAML2_SUPPORT:
256
            saml2_provider_id = '%s/metadata' % saml2_base_url
257
            metadata_cfg['saml2_provider_id'] = saml2_provider_id
258
            self.host.saml2_provider_id = saml2_provider_id
259

  
260
        # Storage directories
261
        site_dir = os.path.join(get_publisher().app_dir, 'sp',
262
                    self.host.reversed_hostname, self.host.name)
263
        user_dir = os.path.join(site_dir, 'users')
264
        token_dir = os.path.join(site_dir, 'tokens')
265
        for dir in (site_dir, user_dir, token_dir):
266
            if not os.path.isdir(dir):
267
                os.makedirs(dir)
268
        metadata_cfg['site_dir'] = site_dir
269
        self.host.site_dir = site_dir
270

  
271
        # Generate SSL keys
272
        private_key_path = os.path.join(site_dir, 'private_key.pem')
273
        public_key_path = os.path.join(site_dir, 'public_key')
274
        if not os.path.isfile(private_key_path) or not os.path.isfile(public_key_path):
275
            set_provider_keys(private_key_path, public_key_path)
276
        self.host.private_key = private_key_path
277
        metadata_cfg['signing_public_key'] = open(public_key_path).read()
278
        self.host.public_key = public_key_path
279

  
280
        # Write metadatas
281
        metadata_path = os.path.join(site_dir, 'metadata.xml')
282
        open(metadata_path, 'w').write(get_metadata(metadata_cfg))
283
        self.host.metadata = metadata_path
284

  
285
        if hasattr(self.host, 'saml2_provider_id'):
286
            saml2_metadata_path = os.path.join(site_dir, 'saml2_metadata.xml')
287
            open(saml2_metadata_path, 'w').write(get_saml2_metadata(metadata_cfg))
288
            self.host.saml2_metadata = saml2_metadata_path
289

  
290
        self.host.root_url = '%s/' % misc.get_root_url()
291
        self.host.return_url = '%s/admin/' % misc.get_root_url()
292

  
293
        self.host.store()
294

  
295
    def domain_names [html] (self):
296
        form = self.form_domain_name()
297

  
298
        if form.get_widget('cancel').parse():
299
            return redirect('.')
300

  
301
        if not form.is_submitted() or form.has_errors():
302
            html_top('settings', title = _('Domain name'))
303
            '<h2>%s</h2>' % _('Domain name')
304
            form.render()
305
        else:
306
            self.submit_domain_name(form)
307
            redirect('.')
308

  
309
    def form_domain_name(self):
310
        get_publisher().reload_cfg()
311
        if get_cfg('domain_names'):
312
            domain_name = get_cfg('domain_names')[0]
313
        else:
314
            domain_name = None
315

  
316
        form = Form(enctype='multipart/form-data')
317
        form.add(StringWidget, 'domain_name',
318
            title=_('Domain name for the sites'),
319
            value = domain_name)
320
        # TODO: Add the option "Both" and handle it in hosts configuration
321
        form.add(SingleSelectWidget, 'sites_url_scheme', title = _('Use HTTP or HTTPS'),
322
                value = get_cfg('sites_url_scheme'),
323
                options = [ (None, _('Same as the site')),
324
                            ('http', 'HTTP'),
325
                            ('https', 'HTTPS') ] )
326
        form.add_submit('submit', _('Submit'))
327
        form.add_submit('cancel', _('Cancel'))
328
        return form
329

  
330
    def submit_domain_name(self, form):
331
        get_publisher().reload_cfg()
332
        get_publisher().cfg['domain_names'] = [ form.get_widget('domain_name').parse() ]
333
        get_publisher().cfg['sites_url_scheme'] = form.get_widget('sites_url_scheme').parse()
334
        get_publisher().write_cfg()
335

  
336
    def apache2_configuration_generation [html] (self):
337
        get_publisher().reload_cfg()
338

  
339
        form = Form(enctype='multipart/form-data')
340
        form.add(CheckboxWidget, 'allow_config_generation',
341
                title=_('Automatically generate Apache 2 configuration for new hosts and reload Apache 2 after changes'),
342
                value = get_publisher().cfg.get(str('allow_config_generation'), True))
343
        form.add_submit('submit', _('Submit'))
344
        form.add_submit('cancel', _('Cancel'))
345
        if form.get_widget('cancel').parse():
346
            return redirect('.')
347
        if not form.is_submitted() or form.has_errors():
348
            html_top('settings', title = _('Apache 2 configuration generation'))
349
            '<h2>%s</h2>' % _('Apache 2 configuration generation')
350
            form.render()
351
        else:
352
            self.apache2_configuration_generation_submit(form)
353
            redirect('.')
354

  
355
    def apache2_configuration_generation_submit(self, form):
356
        get_publisher().reload_cfg()
357

  
358
        f = 'allow_config_generation'
359
        get_publisher().cfg[f] = form.get_widget(f).parse()
360

  
361
        get_publisher().write_cfg()
larpe/tags/release-1.1.1/larpe/admin/users.ptl
1
import random
2

  
3
import lasso
4

  
5
from quixote import get_request, get_session, redirect, get_publisher
6
from quixote.directory import Directory
7

  
8
from qommon.admin.menu import html_top, error_page, command_icon
9
from qommon.errors import EmailError
10
from qommon.form import *
11
from qommon import emails
12

  
13
from larpe import errors
14
from larpe import misc
15
from larpe.users import User
16
from larpe.hosts import Host
17

  
18
class UserUI:
19
    def __init__(self, user):
20
        self.user = user
21

  
22
    def form_new(self):
23
        form = Form(enctype="multipart/form-data")
24
        form.add(StringWidget, "name", title = _('User Name'), required = True, size=30)
25
        form.add(StringWidget, "email", title = _('Email'), required = False, size=30)
26
        form.add_submit("submit", _("Submit"))
27
        form.add_submit("cancel", _("Cancel"))
28
        return form
29

  
30
    def form_edit(self):
31
        form = Form(enctype="multipart/form-data")
32
        form.add(StringWidget, "name", title = _('User Name'), required = True, size=30,
33
                value = self.user.name)
34
        form.add(StringWidget, "email", title = _('Email'), required = False, size=30,
35
                value = self.user.email)
36
        form.add_submit("submit", _("Submit"))
37
        form.add_submit("cancel", _("Cancel"))
38
        return form
39

  
40
    def submit_form(self, form):
41
        if not self.user:
42
            self.user = User()
43
        for f in ('name', 'email'):
44
            widget = form.get_widget(f)
45
            if widget:
46
                setattr(self.user, f, widget.parse())
47
        self.user.is_admin = True
48
        self.user.store()
49

  
50

  
51
class UserPage(Directory):
52
    _q_exports = ['', 'edit', 'delete', 'token']
53

  
54
    def __init__(self, component):
55
        self.user = User.get(component)
56
        self.user_ui = UserUI(self.user)
57
        get_response().breadcrumb.append((component + '/', self.user.name))
58

  
59
    def _q_index [html] (self):
60
        html_top('users', '%s - %s' % (_('User'), self.user.name))
61
        '<h2>%s - %s</h2>' % (_('User'), self.user.name)
62
        '<div class="form">'
63
        '<div class="title">%s</div>' % _('Name')
64
        '<div class="StringWidget content">%s</div>' % self.user.name
65
        if self.user.email:
66
            '<div class="title">%s</div>' % _('Email')
67
            '<div class="StringWidget content">%s</div>' % self.user.email
68
#         if self.user.lasso_dump:
69
#             identity = lasso.Identity.newFromDump(self.user.lasso_dump)
70
#             server = misc.get_lasso_server()
71
#             if len(identity.providerIds) and server:
72
#                 '<h3>%s</h3>' % _('Liberty Alliance Details')
73
#                 '<div class="StringWidget content"><ul>'
74
#                 for pid in identity.providerIds:
75
#                     provider = server.getProvider(pid)
76
#                     label = misc.get_provider_label(provider)
77
#                     if label:
78
#                         label = '%s (%s)' % (label, pid)
79
#                     else:
80
#                         label = pid
81
#                     federation = identity.getFederation(pid)
82
#                     '<li>'
83
#                     _('Account federated with %s') % label
84
#                     '<br />'
85
#                     if federation.localNameIdentifier:
86
#                         _("local: ") + federation.localNameIdentifier.content
87
#                     if federation.remoteNameIdentifier:
88
#                         _("remote: ") + federation.remoteNameIdentifier.content
89
#                     '</li>'
90
#                 '</ul></div>'
91

  
92
#                 # XXX: only display this in debug mode:
93
#                 '<h4>%s</h4>' % _('Lasso Identity Dump')
94
#                 '<pre>%s</pre>' % self.user.lasso_dump
95
        '</div>'
96

  
97
    def debug [html] (self):
98
        get_response().breadcrumb.append( ('debug', _('Debug')) )
99
        html_top('users', 'Debug')
100
        "<h2>Debug - %s</h2>" % self.user.name
101
        "<pre>"
102
        self.user.lasso_dump
103
        "</pre>"
104

  
105
    def edit [html] (self):
106
        form = self.user_ui.form_edit()
107
        if form.get_widget('cancel').parse():
108
            return redirect('..')
109
        if not form.is_submitted() or form.has_errors():
110
            get_response().breadcrumb.append( ('edit', _('Edit')) )
111
            html_top('users', title = _('Edit User'))
112
            '<h2>%s</h2>' % _('Edit User')
113
            form.render()
114
        else:
115
            self.user_ui.submit_form(form)
116
            return redirect('..')
117

  
118
    def delete [html] (self):
119
        form = Form(enctype="multipart/form-data")
120
        form.widgets.append(HtmlWidget('<p>%s</p>' % _(
121
                        "You are about to irrevocably delete this user.")))
122
        form.add_submit("submit", _("Submit"))
123
        form.add_submit("cancel", _("Cancel"))
124
        if form.get_widget('cancel').parse():
125
            return redirect('..')
126
        if not form.is_submitted() or form.has_errors():
127
            get_response().breadcrumb.append(('delete', _('Delete')))
128
            html_top('users', title = _('Delete User'))
129
            '<h2>%s %s</h2>' % (_('Deleting User :'), self.user.name)
130
            form.render()
131
        else:
132
            self.user.remove_self()
133
            return redirect('..')
134

  
135
    def token [html] (self):
136
        form = Form(enctype="multipart/form-data", use_tokens = False)
137
        form.add_submit("submit", _("Generate"))
138
        form.add_submit("cancel", _("Cancel"))
139
        request = get_request()
140
        if request.form.has_key('cancel') or request.form.has_key('done'):
141
            return redirect('..')
142

  
143
        get_response().breadcrumb.append(('token', _('Identification Token')))
144

  
145
        if not form.is_submitted() or form.has_errors():
146
            html_top('users', title = _('Identification Token'))
147
            '<h2>%s</h2>' % _('Identification Token')
148
            '<p>%s</p>' % _('You are about to generate a token than can be used to federate the account.')
149
            '<p>%s</p>' % _('After that, you will have the choice to send it to the user by email so that he can federate his accounts.')
150
            if self.user.identification_token:
151
                '<p>%s</p>' % _('Note that user has already been issued an identification token : %s') % self.user.identification_token
152
            form.render()
153
        else:
154
            if request.form.has_key('submit'):
155
                html_top('users', title = _('Identification Token'))
156
                token = '-'.join(['%04d' % random.randint(1, 9999) for x in range(4)])
157
                self.user.identification_token = str(token)
158
                self.user.store()
159

  
160
                '<p>'
161
                _('Identification Token for %s') % self.user.name
162
                ' : %s</p>' % self.user.identification_token
163

  
164
                form = Form(enctype="multipart/form-data", use_tokens = False)
165
                form.add_submit('done', _('Done'))
166
                if self.user.email:
167
                    form.add_submit("submit-email", _("Send by email"))
168
                form.render()
169
            else:
170
                site_url = '%s://%s%s/token?token=%s' \
171
                    % (request.get_scheme(), request.get_server(),
172
                       get_request().environ['SCRIPT_NAME'], self.user.identification_token)
173
                body = _("""You have been given an identification token.
174

  
175
Your token is %(token)s
176

  
177
Click on %(url)s to use it.
178
""") % {'token': self.user.identification_token, 'url': site_url}
179
                try:
180
                    emails.email(_('Identification Token'), body, self.user.email)
181
                except EmailError, e:
182
                    html_top('users', title = _('Identification Token'))
183
                    _('Failed sending email. Check your email configuration.')
184
                    '<div class="buttons"><a href=".."><input type="button" value="%s" /></a></div><br />' % _('Back')
185
                else:
186
                    return redirect('..')
187

  
188
class UsersDirectory(Directory):
189

  
190
    _q_exports = ['', 'new']
191

  
192
    def _q_index [html] (self):
193
        get_publisher().reload_cfg()
194
        get_response().breadcrumb.append( ('users/', _('Users')) )
195
        html_top('users', title = _('Users'))
196

  
197

  
198
        if not list(Host.select(lambda x: x.name == 'larpe')):
199
            '<p>%s</p>' % _('Liberty support must be setup before creating users.')
200
        else:
201
            """<ul id="nav-users-admin">
202
              <li><a href="new">%s</a></li>
203
            </ul>""" % _('New User')
204

  
205
        debug_cfg = get_publisher().cfg.get('debug', {})
206

  
207
        users = User.select(lambda x: x.name is not None, order_by = 'name')
208

  
209
        '<ul class="biglist">'
210
        for user in users:
211
            '<li>'
212
            '<strong class="label">%s</strong>' % user.name
213
            if user.email:
214
                '<p class="details">'
215
                user.email
216
                '</p>'
217

  
218
            '<p class="commands">'
219
            command_icon('%s/' % user.id, 'view')
220
            if not user.name_identifiers:
221
                if not user.identification_token:
222
                    command_icon('%s/token' % user.id, 'token',
223
                            label = _('Identification Token'), icon = 'stock_exec_16.png')
224
                else:
225
                    command_icon('%s/token' % user.id, 'token',
226
                            label = _('Identification Token (current: %s)') % \
227
                                user.identification_token,
228
                            icon = 'stock_exec_16.png')
229
            command_icon('%s/edit' % user.id, 'edit')
230
            command_icon('%s/delete' % user.id, 'remove')
231
            if debug_cfg.get('logger', False):
232
                command_icon('../logger/by_user/%s/' % user.id, 'logs',
233
                        label = _('Logs'), icon = 'stock_harddisk_16.png')
234
            '</p></li>'
235
        '</ul>'
236

  
237
    def new [html] (self):
238
        get_response().breadcrumb.append( ('users/', _('Users')) )
239
        get_response().breadcrumb.append( ('new', _('New')) )
240
        hosts = list(Host.select(lambda x: x.name == 'larpe'))
241
        if not hosts:
242
            return error_page('users', _('Liberty support must be setup before creating users.'))
243
        host = hosts[0]
244
        # XXX: user must be logged in to get here
245
        user_ui = UserUI(None)
246
        # FIXME : should be able to use User.count(). Track fake user creations.
247
        users = User.select(lambda x: x.name is not None)
248
        first_user = (len(users) == 0)
249
        form = user_ui.form_new()
250
        if form.get_widget('cancel').parse():
251
            return redirect('.')
252

  
253
        if not form.is_submitted() or form.has_errors():
254
            html_top('users', title = _('New User'))
255
            '<h2>%s</h2>' % _('New User')
256
            form.render()
257
        else:
258
            user_ui.submit_form(form)
259
            if first_user:
260
                session = get_session()
261
                if hasattr(session, str('lasso_dump')):
262
                    user_ui.user.name_identifiers = [ session.name_identifier ]
263
                    user_ui.user.lasso_dumps = [ session.lasso_anonymous_identity_dump ]
264
                    user_ui.user.store()
265
                if misc.get_current_protocol() == lasso.PROTOCOL_SAML_2_0:
266
                    get_session().set_user(user_ui.user.id, host.saml2_provider_id)
267
                else:
268
                    get_session().set_user(user_ui.user.id, host.provider_id)
269
            return redirect('.')
270

  
271
    def _q_lookup(self, component):
272
        get_response().breadcrumb.append( ('users/', _('Users')) )
273
        try:
274
            return UserPage(component)
275
        except KeyError:
276
            raise errors.TraversalError()
larpe/tags/release-1.1.1/larpe/ctl/__init__.py
1
from start import start
2

  
larpe/tags/release-1.1.1/larpe/ctl/start.py
1
import socket
2
import sys
3
import quixote.server.simple_server
4

  
5
from qommon.scgi_server import run
6

  
7
import publisher
8

  
9
def start(args):
10
    run_function = run
11
    run_kwargs = {
12
        'port': 3007,
13
        'script_name': ''
14
    }
15
    http = 0
16

  
17
    i = 0
18
    while i < len(args):
19
        if args[i] == '--port':
20
            run_kwargs['port'] = int(args[i+1])
21
            i += 1
22
        elif args[i] == '--silent':
23
            sys.stdout = open('/dev/null', 'w')
24
            sys.stderr = open('/dev/null', 'w')
25
        elif args[i] == '--script-name':
26
            run_kwargs['script_name'] = args[i+1]
27
            i += 1
28
        elif args[i] == '--app-dir':
29
            publisher.LarpePublisher.APP_DIR = args[i+1]
30
            i += 1
31
        elif args[i] == '--data-dir':
32
            publisher.LarpePublisher.DATA_DIR = args[i+1]
33
            i += 1
34
        elif args[i] == '--http':
35
            http = 1
36
        i += 1
37

  
38
    if http == 1:
39
        run_function = quixote.server.simple_server.run
40
        if run_kwargs['script_name']:
41
            print "--http option is incompatible with --script-name"
42
        del run_kwargs['script_name']
43
    try:
44
        run_function(publisher.LarpePublisher.create_publisher, **run_kwargs)
45
    except socket.error, err:
46
        if err[0] == 98:
47
            print >> sys.stderr, 'address already in use'
48
            sys.exit(1)
49
        raise
50
    except KeyboardInterrupt:
51
        sys.exit(1)
52

  
larpe/tags/release-1.1.1/larpe/errors.ptl
1
from quixote import get_session, get_request, redirect
2

  
3
from qommon.errors import *
4

  
5
class AccessUnauthorizedError(AccessError):
6
    def render [html] (self):
7
        session = get_session()
8
        request = get_request()
9
        query = request.get_query()
10
        session.after_url = request.get_url()
11
        if query:
12
            session.after_url += '?' + query
13
            session.after_url = str(session.after_url)
14
        login_url = '%s/liberty/larpe/login' % request.environ['SCRIPT_NAME']
15
        redirect(login_url)
larpe/tags/release-1.1.1/larpe/federations.py
1
'''Federation object. Configuration variables and utilities'''
2

  
3
from qommon.storage import StorableObject
4

  
5
class Federation(StorableObject):
6
    _names = 'federations'
7

  
8
    username = None
9
    password = None
10
    host_id = None
11
    name_identifiers = None
12
    cookies = None
13
    select_fields = {}
14

  
15
    def __init__(self, username, password, host_id, name_identifier, cookies=None, select=None):
16
        select = select or {}
17
        StorableObject.__init__(self)
18
        self.username = username
19
        self.password = password
20
        self.host_id = host_id
21
        self.name_identifiers = [ name_identifier ]
22
        self.cookies = cookies
23
        self.select_fields = select
24

  
25
    def remove_name_identifier(self, name_identifier):
26
        self.name_identifiers.remove(name_identifier)
27
        if not self.name_identifiers:
28
            self.remove_self()
29

  
30
    def set_cookies(self, cookies):
31
        self.cookies = cookies
32

  
33
    def __str__(self):
34
        return 'Federation username : %s, name identifiers : %s, cookies : %s' \
35
                % (self.username, self.name_identifiers, self.cookies)
larpe/tags/release-1.1.1/larpe/field_prefill.py
1
from qommon.storage import StorableObject
2

  
3
class FieldPrefill(StorableObject):
4
    _names = 'field_prefill'
5

  
6
    form_id = 0
7
    name = None
8
    xpath = None
9
    number = 1
10
    raw_xml = False
11
    regexp_match = None
12
    regexp_replacing = None
13
    select_options = {}
larpe/tags/release-1.1.1/larpe/form_prefill.py
1
from qommon.storage import StorableObject
2

  
3
class FormPrefill(StorableObject):
4
    _names = 'form_prefill'
5

  
6
    host_id = 0
7
    name = None
8
    url = None
9
    profile = None
10
    prefix = None
larpe/tags/release-1.1.1/larpe/hosts.py
1
'''Host object. Configuration variables and utilities'''
2

  
3
import os
4
from shutil import rmtree
5

  
6
from quixote import get_request
7

  
8
from qommon.storage import StorableObject
9

  
10
from Defaults import APP_DIR
11

  
12
def get_proxied_site_name():
13
    nb_subdirs = get_request().environ['SCRIPT_NAME'].count('/')
14
    return get_request().get_path().split('/')[nb_subdirs + 2]
15

  
16
class Host(StorableObject):
17
    '''Host object. Configuration variables and utilities'''
18
    _names = 'hosts'
19

  
20
    # Main settings
21
    label = None
22
    name = None
23
    orig_site = None
24
    new_url = None
25
    scheme = None
26
    auth_url = None
27
    auth_form_places = 'form_once'
28
    auth_form_page_url = None
29
    auth_form = None
30
    auth_form_url = None
31
    logout_url = None
32
    reversed_hostname = None
33
    reversed_directory = None
34
    organization_name = None
35
    use_ssl = False
36
    private_key = None
37
    public_key = None
38
    site_dir = None
39

  
40
    # Auto detected settings
41
    auth_mode = 'form'
42
    auth_form_action = None
43
    auth_check_url = None
44
    login_field_name = None
45
    password_field_name = None
46
    select_fields = {}
47
    post_parameters = {}
48
    http_headers = {}
49

  
50
    # Advanced settings
51
    return_url = '/'
52
    root_url = '/'
53
    auth_system = 'password'
54
    auth_match_text = ''
55
    send_hidden_fields = True
56
    initiate_sso_url = None
57
    redirect_root_to_login = False
58

  
59
    # Other attributes
60
    provider_id = None
61
    # Default value that indicates the proxy (if configured) is not disabled for this host yet
62
    use_proxy = True
63

  
64
    valid_username = None
65
    valid_password = None
66
    apache_output_filters = []
67
    apache_output_python_filters = []
68
    apache_python_paths = []
69

  
70
    # Plugins
71
    # If name is set to None, use the default site authentication class
72
    site_authentication_plugin = None
73

  
74
    def get_host_from_url(cls):
75
        try:
76
            host = list(Host.select(lambda x: x.name == get_proxied_site_name()))[0]
77
            if hasattr(host, 'site_authentication_instance'):
78
                del host.site_authentication_instance
79
            return list(Host.select(lambda x: x.name == get_proxied_site_name()))[0]
80
        except IndexError:
81
            return None
82
    get_host_from_url = classmethod(get_host_from_url)
83

  
84
    def get_host_with_provider_id(cls, provider_id):
85
        try:
86
            return list(Host.select(lambda x: x.provider_id == provider_id))[0]
87
        except IndexError:
88
            return None
89
    get_host_with_provider_id = classmethod(get_host_with_provider_id)
90

  
91
    def get_root_url(self):
92
        if self.root_url.startswith('/'):
93
            if self.reversed_directory:
94
                return '%s/%s%s' % (get_request().environ['SCRIPT_NAME'],
95
                                    self.reversed_directory,
96
                                    self.root_url)
97
            else:
98
                return '%s%s' % (get_request().environ['SCRIPT_NAME'], self.root_url)
99
        # In this case, must be a full url
100
        return self.root_url
101

  
102
    def get_return_url(self):
103
        if self.return_url.startswith('/'):
104
            if self.reversed_directory:
105
                return '%s/%s%s' % (get_request().environ['SCRIPT_NAME'],
106
                                    self.reversed_directory,
107
                                    self.return_url)
108
            else:
109
                return '%s%s' % (get_request().environ['SCRIPT_NAME'], self.return_url)
110
        # In this case, must be a full url
111
        return self.return_url
112

  
113
    def __cmp__(self, other):
114
        hostname_cmp = cmp(self.reversed_hostname, other.reversed_hostname)
115
        if hostname_cmp != 0:
116
            return hostname_cmp
117
        return cmp(self.reversed_directory, other.reversed_directory)
118

  
119
    def remove_self(self):
120
        # Main configuration file
121
        StorableObject.remove_self(self)
122
        # Other generated files
123
        if self.site_dir and os.path.exists(self.site_dir):
124
            rmtree(self.site_dir, ignore_errors=1)
125
            # Also remove hostname directory if empty (meaning there was no other subdirectory
126
            # for this hostname)
127
            try:
128
                os.rmdir('/'.join(self.site_dir.split('/')[:-1]))
129
            except OSError:
130
                pass
131
        # Virtual host directory
132
        if self.reversed_hostname:
133
            path = os.path.join(APP_DIR, self.reversed_hostname)
134
            if os.path.exists(path):
135
                rmtree(path, ignore_errors=1)
136

  
larpe/tags/release-1.1.1/larpe/idwsf2.ptl
1
import os
2
import sys
3
import re
4

  
5
try:
6
    import lasso
7
except ImportError:
8
    print >> sys.stderr, 'Missing Lasso module, IdWsf 2.0 support disabled'
9
else:
10
    if not lasso.WSF_SUPPORT:
11
        print >> sys.stderr, 'Found Lasso module, but IdWsf 2.0 support not enabled'
12

  
13
from quixote import get_publisher, get_session, get_request, get_response, redirect
14
from quixote.directory import Directory
15

  
16
from qommon.liberty import SOAPException, soap_call
17
from qommon import template
18
from qommon.misc import http_get_page
19

  
20
import misc
21
from form_prefill import FormPrefill
22
from field_prefill import FieldPrefill
23

  
24
def cleanup_html_value(value):
25
    # Ensure the field value can be properly integrated in HTML code
26
    value = value.replace('"', "'")
27
    # Conversion to iso-8859-1
28
    try:
29
        value = unicode(value, 'utf-8').encode('iso-8859-1')
30
    except UnicodeEncodeError:
31
        return None
32

  
33
class IdWsf2(Directory):
34
    _q_exports = []
35

  
36
    def _q_lookup(self, component):
37
        if not hasattr(get_session(), 'prefill_form'):
38
            get_session().prefill_form = component
39
            get_session().after_url = get_request().get_url()
40
            if get_request().get_query():
41
                get_session().after_url += '?' + get_request().get_query()
42
            return redirect('../saml/login')
43
        else:
44
            prefill_form = FormPrefill.get(get_session().prefill_form)
45
            del get_session().prefill_form
46
            if prefill_form:
47
                try:
48
                    response, status, page, auth_header = http_get_page(prefill_form.url)
49
                except:
50
                    return template.error_page(_('Failed connecting to the original site.'))
51
                try:
52
                    fields = self.do_prefill_form(prefill_form)
53
                    if not fields:
54
                        raise lasso.Error
55
                    for key, value in get_request().get_fields().iteritems():
56
                        value = cleanup_html_value(value)
57
                        if value:
58
                            fields[key] = value
59
                except lasso.Error:
60
                    return page + '<script type="text/javascript">alert("%s")</script>' % \
61
                         _('Failed getting attributes from the attribute provider.')
62
                except:
63
                    return page + '<script type="text/javascript">alert("%s")</script>' % \
64
                         _('Failed getting attributes for an unknown reason.')
65

  
66
                return self.send_prefilled_form(prefill_form, page, fields)
67

  
68
    def do_prefill_form(self, prefill_form):
69
        server = misc.get_lasso_server(protocol = 'saml2')
70
        disco = lasso.IdWsf2Discovery(server)
71
        if not get_session().lasso_session_dumps or not get_session().lasso_session_dumps[server.providerId]:
72
            return None
73
        disco.setSessionFromDump(get_session().lasso_session_dumps[server.providerId])
74

  
75
        disco.initQuery()
76
        disco.addRequestedServiceType(prefill_form.profile)
77
        disco.buildRequestMsg()
78

  
79
        try:
80
            soap_answer = soap_call(disco.msgUrl, disco.msgBody)
81
        except SOAPException:
82
            return None
83
        disco.processQueryResponseMsg(soap_answer)
84

  
85
        service = disco.getService()
86
        lasso.registerIdWsf2DstService(prefill_form.prefix, prefill_form.profile)
87

  
88
        service.initQuery()
89

  
90
        fields = FieldPrefill.select(lambda x: x.form_id == prefill_form.id)
91
        for field in fields:
92
            if field.xpath and field.name:
93
                service.addQueryItem(field.xpath, field.name)
94

  
95
        service.buildRequestMsg()
96

  
97
        try:
98
            soap_answer = soap_call(service.msgUrl, service.msgBody)
99
        except SOAPException:
100
            return None
101
        service.processQueryResponseMsg(soap_answer)
102

  
103
        fields_dict = {}
104
        for field in fields:
105
            if not field.xpath or not field.name:
106
                continue
107
            if field.number > 0:
108
                number = field.number -1
109
            try:
110
                if field.raw_xml:
111
                    value = service.getAttributeNodes(field.name)[number]
112
                else:
113
                    value = service.getAttributeStrings(field.name)[number]
114
            except (IndexError, TypeError):
115
                value = ''
116
                # Log
117
            if value:
118
                # Regexp transformation
119
                if field.regexp_match:
120
                    value = re.sub(field.regexp_match, field.regexp_replacing, value)
121
                value = cleanup_html_value(value)
122
                # Conversion of select field options
123
                if field.select_options:
124
                    try:
125
                        value = field.select_options[value]
126
                    except (IndexError, KeyError):
127
                        pass
128
                if not value:
129
                    continue
130
            fields_dict[field.name] = value
131

  
132
        return fields_dict
133

  
134
    def send_prefilled_form(self, prefill_form, page, fields):
135
        for field_name, new_value in fields.iteritems():
136
            # Input
137
            regex = re.compile('(.*)(<input[^>]*? id="%s".*?>)(.*)' % field_name,
138
                               re.DOTALL | re.IGNORECASE)
139
            match = regex.match(page)
140
            if not match:
141
                regex = re.compile('(.*)(<input[^>]*? name="%s".*?>)(.*)' % field_name,
142
                                   re.DOTALL | re.IGNORECASE)
143
                match = regex.match(page)
144
            if match:
145
                before, input_field, after = match.groups()
146
                if 'value="' in input_field.lower():
147
                    regex_sub = re.compile('value=".*?"', re.DOTALL | re.IGNORECASE)
148
                    input_field = regex_sub.sub('value="%s"' % new_value, input_field)
149
                else:
150
                    input_field = input_field.replace('<input', '<input value="%s"' % new_value)
151
                page = ''.join([before, input_field, after])
152
                continue
153

  
154
            # Textarea
155
            regex = re.compile('(.*<textarea[^>]*? id="%s".*?>)[^<]*(</textarea>.*)' % field_name,
156
                               re.DOTALL | re.IGNORECASE)
157
            match = regex.match(page)
158
            if not match:
159
                regex = re.compile('(.*<textarea[^>]*? name="%s".*?>)[^<]*(</textarea>.*)' % field_name,
160
                                   re.DOTALL | re.IGNORECASE)
161
                match = regex.match(page)
162
            if match:
163
                before, after = match.groups()
164
                page = ''.join([before, new_value, after])
165
                continue
166

  
167
            # Select
168
            regex = re.compile('(.*<select[^>]*? id="%s".*?>)(.*?)(</select>.*)' % field_name,
169
                               re.DOTALL | re.IGNORECASE)
170
            match = regex.match(page)
171
            if not match:
172
                regex = re.compile('(.*<select[^>]*? name="%s".*?>)(.*?)(</select>.*)' % field_name,
173
                                   re.DOTALL | re.IGNORECASE)
174
                match = regex.match(page)
175
            if match:
176
                before, options, after = match.groups()
177
                # If the option to select is found, first unselect the previoulsy selected one
178
                regex2 = re.compile('(.*<option[^>]*? value="%s".*?)(>[^<]*</option>.*)' % new_value,
179
                               re.DOTALL | re.IGNORECASE)
180
                match2 = regex2.match(options)
181
                if match2:
182
                    before2, after2 = match2.groups()
183
                    regex3 = re.compile('(.*<option[^>]*?)( selected(="selected")?)(.*?>[^<]*</option>.*)',
184
                               re.DOTALL | re.IGNORECASE)
185
                    match3 = regex3.match(options)
186
                    if match3:
187
                        before3, selected, selected_value, after3 = match3.groups()
188
                        options = ''.join([before3, after3])
189
                regex2 = re.compile('(.*<option[^>]*? value="%s".*?)(>[^<]*</option>.*)' % new_value,
190
                    re.DOTALL | re.IGNORECASE)
191
                match2 = regex2.match(options)
192
                if match2:
193
                    before2, after2 = match2.groups()
194
                    options = ''.join([before2, ' selected="selected"', after2])
195

  
196
                page = ''.join([before, options, after])
197

  
198
        return page
199

  
larpe/tags/release-1.1.1/larpe/liberty.ptl
1
import libxml2
2
import urllib
3
import urlparse
4
import httplib
5
import re
6
import os
7

  
8
from quixote import get_field, get_request, get_response, get_session, get_session_manager, redirect
9
from quixote.directory import Directory
10
from quixote.http_request import parse_header
11

  
12
import lasso
13

  
14
from qommon import get_logger
15
from qommon.form import *
16
from qommon.template import *
17
from qommon.liberty import soap_call, SOAPException
18

  
19
import misc
20
from users import User
21
from hosts import Host
22
from federations import Federation
23
import site_authentication
24

  
25
class Liberty(Directory):
26
    _q_exports = ['', 'login', 'assertionConsumer', 'soapEndpoint',
27
            'singleLogout', 'singleLogoutReturn',
28
            'federationTermination', 'federationTerminationReturn',
29
            ('metadata.xml', 'metadata'), 'public_key', 'local_auth']
30

  
31
    def perform_login(self, idp = None):
32
        server = misc.get_lasso_server()
33
        login = lasso.Login(server)
34
        login.initAuthnRequest(idp, lasso.HTTP_METHOD_REDIRECT)
35
        login.request.nameIdPolicy = 'federated'
36
        login.request.forceAuthn = False
37
        login.request.isPassive = False
38
        login.request.consent = 'urn:liberty:consent:obtained'
39
        login.buildAuthnRequestMsg()
40
        return redirect(login.msgUrl)
41

  
42
    def assertionConsumer(self):
43
        server = misc.get_lasso_server()
44
        if not server:
45
            return error_page(_('Liberty support is not yet configured'))
46
        login = lasso.Login(server)
47
        request = get_request()
48
        if request.get_method() == 'GET' or get_field('LAREQ'):
49
            if request.get_method() == 'GET':
50
                login.initRequest(request.get_query(), lasso.HTTP_METHOD_REDIRECT)
51
            else:
52
                login.initRequest(get_field('LAREQ'), lasso.HTTP_METHOD_POST)
53

  
54
            login.buildRequestMsg()
55
            try:
56
                soap_answer = soap_call(login.msgUrl, login.msgBody)
57
            except SOAPException:
58
                return error_page(_('Failure to communicate with identity provider'))
59
            try:
60
                login.processResponseMsg(soap_answer)
61
            except lasso.Error, error:
62
                if error[0] == lasso.LOGIN_ERROR_STATUS_NOT_SUCCESS:
63
                    return error_page(_('Unknown authentication failure'))
64
                if hasattr(lasso, 'LOGIN_ERROR_UNKNOWN_PRINCIPAL'):
65
                    if error[0] == lasso.LOGIN_ERROR_UNKNOWN_PRINCIPAL:
66
                        return error_page(_('Authentication failure; unknown principal'))
67
                return error_page(_("Identity Provider didn't accept artifact transaction."))
68
        else:
69
            login.processAuthnResponseMsg(get_field('LARES'))
70
        login.acceptSso()
71
        session = get_session()
72
        if login.isSessionDirty:
73
            if login.session:
74
                session.lasso_session_dumps[server.providerId] = login.session.dump()
75
            else:
76
                session.lasso_session_dumps[server.providerId] = None
77

  
78
        # Look for an existing user
79
        user = self.lookup_user(session, login)
80

  
81
        # Check if it is for Larpe administration or token
82
        host = Host.get_host_from_url()
83
        if host is None:
84
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
85
        if host.name == 'larpe':
86
            if user:
87
                session.set_user(user.id, server.providerId)
88
            else:
89
                session.name_identifier = login.nameIdentifier.content
90
                session.lasso_anonymous_identity_dump = login.identity.dump()
91
                session.provider_id = server.providerId
92

  
93
            if session.after_url:
94
                # Access to an admin page or token url with parameter
95
                after_url = session.after_url
96
                session.after_url = None
97
                return redirect(after_url)
98

  
99
            if user and user.is_admin:
100
                return redirect('%s/admin/' % get_request().environ['SCRIPT_NAME'])
101
            else:
102
                return redirect('%s/token' % get_request().environ['SCRIPT_NAME'])
103

  
104
        # Set session user
105
        if not user:
106
            user = User()
107
        user.name_identifiers = [ login.nameIdentifier.content ]
108
        user.lasso_dumps = [ login.identity.dump() ]
109
        user.store()
110
        session.set_user(user.id, server.providerId)
111

  
112
        federations = Federation.select(lambda x: host.id == x.host_id \
113
                                        and user.name_identifiers[0] in x.name_identifiers)
114

  
115
        if federations:
116
            return site_authentication.get_site_authentication(host).sso_local_login(federations[0])
117
        else:
118
            response = get_response()
119
            if session.after_url:
120
                after_url = session.after_url
121
                session.after_url = None
122
                return redirect(after_url)
123
            response.set_status(303)
124
            response.headers['location'] = urlparse.urljoin(request.get_url(), str('local_auth'))
125
            response.content_type = 'text/plain'
126
            return 'Your browser should redirect you'
127

  
128
    def lookup_user(self, session, login):
129
        found_users = list(User.select(lambda x: login.nameIdentifier.content in x.name_identifiers))
130
        if found_users:
131
            return found_users[0]
132
        return None
133

  
134
    def singleLogout(self):
135
        request = get_request()
136
        logout = lasso.Logout(misc.get_lasso_server())
137
        if lasso.isLibertyQuery(request.get_query()):
138
            try:
139
                logout.processRequestMsg(request.get_query())
140
            except lasso.Error, error:
141
                if error[0] == lasso.DS_ERROR_INVALID_SIGNATURE:
142
                    return error_page(_('Failed to check single logout request signature.'))
143
                raise
144
            session = get_session()
145
            if not session.id:
146
  	            # session has not been found, this may be because the user has
147
  	            # its browser configured so that cookies are not sent for
148
  	            # remote queries and IdP is using image-based SLO.
149
  	            # so we look up a session with the appropriate name identifier
150
                for session in get_session_manager().values():
151
                    # This block differs from qommon
152
                    user = session.get_user(logout.server.providerId)
153
                    if user and logout.nameIdentifier.content in user.name_identifiers:
154
                        break
155
                else:
156
                    session = get_session()
157
            return self.slo_idp(logout, session)
158
        else:
159
            return self.slo_sp(logout, get_session())
160

  
161
    def singleLogoutReturn(self):
162
        logout = lasso.Logout(misc.get_lasso_server())
163
        host = Host.get_host_from_url()
164
        if host is None:
165
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
166

  
167
        try:
168
            logout.processResponseMsg(get_request().get_query())
169
        except lasso.Error, error:
170
            if error[0] == lasso.PROFILE_ERROR_INVALID_QUERY:
171
                raise AccessError()
172
            if error[0] == lasso.DS_ERROR_INVALID_SIGNATURE:
173
                return error_page(_('Failed to check single logout request signature.'))
174
            if hasattr(lasso, 'LOGOUT_ERROR_REQUEST_DENIED') and \
175
                    error[0] == lasso.LOGOUT_ERROR_REQUEST_DENIED:
176
                return redirect(host.get_root_url()) # ignore silently
177
            elif error[0] == lasso.ERROR_UNDEFINED:
178
                # XXX: unknown status; ignoring for now.
179
                return redirect(host.get_root_url()) # ignore silently
180
            raise
181
        return redirect(host.get_root_url())
182

  
183
    def slo_idp(self, logout, session):
184
        '''Single Logout initiated by IdP'''
185
        # This block differs from qommon
186
        if session.lasso_session_dumps.has_key(logout.server.providerId):
187
            logout.setSessionFromDump(session.lasso_session_dumps[logout.server.providerId])
188
        user = session.get_user(logout.server.providerId)
189
        if user and user.lasso_dumps:
190
            logout.setIdentityFromDump(user.lasso_dumps[0])
191
        if user and logout.nameIdentifier.content not in user.name_identifiers:
192
            raise 'No appropriate name identifier in user (%s and %s)' % (
193
                    logout.nameIdentifier.content, user.name_identifiers)
194

  
195
        host = Host.get_host_with_provider_id(logout.server.providerId)
196
        if host is not None:
197
            site_authentication.get_site_authentication(host).local_logout(user=user)
198

  
199
        try:
200
            logout.validateRequest()
201
        except lasso.Error, error:
202
            if error[0] != lasso.PROFILE_ERROR_SESSION_NOT_FOUND:
203
                raise
204
        else:
205
            get_session_manager().expire_session(logout.server.providerId)
206

  
207
        logout.buildResponseMsg()
208
        if logout.msgBody: # soap answer
209
            return logout.msgBody
210
        else:
211
            return redirect(logout.msgUrl)
212

  
213
    def slo_sp(self, logout, session):
214
        host = Host.get_host_from_url()
215
        if host is None:
216
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
217

  
218
        if not session.id or not session.users.has_key(logout.server.providerId) \
219
                or not session.lasso_session_dumps.has_key(logout.server.providerId):
220
            get_session_manager().expire_session(logout.server.providerId)
221
            return redirect(host.get_root_url())
222

  
223
        logout.setSessionFromDump(session.lasso_session_dumps[logout.server.providerId])
224
        user = session.get_user(logout.server.providerId)
225

  
226
        if host.name != 'larpe' and user:
227
            site_authentication.get_site_authentication(host).local_logout(user=user)
228

  
229
        if user and user.lasso_dumps:
230
            logout.setIdentityFromDump(user.lasso_dumps[0])
231
        else:
232
            get_session_manager().expire_session(logout.server.providerId)
233
            return redirect(host.get_root_url())
234

  
235
        return self.slo_sp_redirect(logout, host)
236

  
237
    def slo_sp_redirect(self, logout, host):
238
        try:
239
            logout.initRequest(None, lasso.HTTP_METHOD_REDIRECT)
240
        except lasso.Error, error:
241
            if error[0] == lasso.PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND:
242
                get_session_manager().expire_session()
243
                return redirect(host.get_root_url())
244
            raise
245
        logout.buildRequestMsg()
246
        get_session_manager().expire_session(logout.server.providerId)
247
        return redirect(logout.msgUrl)
248

  
249
    def soapEndpoint(self):
250
        request = get_request()
251
        ctype = request.environ.get('CONTENT_TYPE')
252
        if not ctype:
253
            return
254

  
255
        ctype, ctype_params = parse_header(ctype)
256
        if ctype != 'text/xml':
257
            return
258

  
259
        response = get_response()
260
        response.set_content_type('text/xml')
261

  
262
        length = int(request.environ.get('CONTENT_LENGTH'))
263
        soap_message = request.stdin.read(length)
264

  
265
        request_type = lasso.getRequestTypeFromSoapMsg(soap_message)
266

  
267
        if request_type == lasso.REQUEST_TYPE_LOGOUT:
268
            logout = lasso.Logout(misc.get_lasso_server())
269
            logout.processRequestMsg(soap_message)
270
            name_identifier = logout.nameIdentifier.content
271
            for session in get_session_manager().values():
272
                user = session.get_user(logout.server.providerId)
273
                if user and logout.nameIdentifier.content in user.name_identifiers:
274
                    break
275
            else:
276
                session = None
277
            return self.slo_idp(logout, session)
278

  
279
        if request_type == lasso.REQUEST_TYPE_DEFEDERATION:
280
            defederation = lasso.Defederation(misc.get_lasso_server())
281
            defederation.processNotificationMsg(soap_message)
282
            for session in get_session_manager().values():
283
                user = session.get_user(defederation.server.providerId)
284
                if user and defederation.nameIdentifier.content in user.name_identifiers:
285
                    break
286
            else:
287
                session = None
288
            return self.fedterm(defederation, session)
289

  
290
    def federationTermination(self):
291
        request = get_request()
292
        if not lasso.isLibertyQuery(request.get_query()):
293
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
294

  
295
        defederation = lasso.Defederation(misc.get_lasso_server())
296
        defederation.processNotificationMsg(request.get_query())
297
        return self.fedterm(defederation, get_session())
298

  
299
    def fedterm(self, defederation, session):
300
        if session is not None:
301
            host = Host.get_host_with_provider_id(defederation.server.providerId)
302
            if host is not None:
303
                site_authentication.get_site_authentication(host).local_defederate(session, defederation.server.providerId)
304
            if session.lasso_session_dumps.has_key(defederation.server.providerId):
305
                defederation.setSessionFromDump(session.lasso_session_dumps[defederation.server.providerId])
306
            user = session.get_user(defederation.server.providerId)
307
            if user and user.lasso_dumps:
308
                defederation.setIdentityFromDump(user.lasso_dumps[0])
309
        else:
310
            user = None
311

  
312
        try:
313
            defederation.validateNotification()
314
        except lasso.Error, error:
315
            pass # ignore failure (?)
316
        else:
317
            if user:
318
                if not defederation.identity:
319
                    # if it was the last federation the whole identity dump collapsed
320
                    del user.lasso_dumps[0]
321
                else:
322
                    user.lasso_dumps[0] = defederation.identity.dump()
323
                user.store()
324

  
325
        if user and defederation.nameIdentifier.content:
326
            user.remove_name_identifier(defederation.nameIdentifier.content)
327
            user.store()
328

  
329
        if defederation.isSessionDirty and session is not None:
330
            if not defederation.session:
331
                del session.lasso_session_dumps[defederation.server.providerId]
332
            else:
333
                session.lasso_session_dumps[defederation.server.providerId] = defederation.session.dump()
334
            session.store()
335

  
336
        get_session_manager().expire_session(defederation.server.providerId)
337

  
338
        if defederation.msgUrl:
339
            return redirect(defederation.msgUrl)
340
        else:
341
            response = get_response()
342
            response.set_status(204)
343
            return ''
344

  
345
    def federationTerminationReturn(self):
346
        host = Host.get_host_from_url()
347
        if host is None:
348
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
349
        return redirect(host.get_return_url())
350

  
351
    def local_auth(self):
352
        host = Host.get_host_from_url()
353
        if host is None:
354
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
355
        return site_authentication.get_site_authentication(host).local_auth
356
    local_auth = property(local_auth)
357

  
358
    def metadata(self):
359
        host = Host.get_host_from_url()
360
        if host is None:
361
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
362
        get_response().set_content_type('text/xml', 'utf-8')
363
        metadata = unicode(open(host.metadata).read(), 'utf-8')
364
        return metadata
365

  
366
    def public_key(self):
367
        host = Host.get_host_from_url()
368
        if host is None:
369
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
370
        get_response().set_content_type('text/plain')
371
        public_key = open(host.public_key).read()
372
        return public_key
larpe/tags/release-1.1.1/larpe/liberty_root.ptl
1
from quixote.directory import Directory
2
from quixote import get_response
3

  
4
from liberty_site import LibertySite
5

  
6
class LibertyRootDirectory(Directory):
7

  
8
    def _q_lookup(self, component):
9
        return LibertySite(component)
larpe/tags/release-1.1.1/larpe/liberty_site.ptl
1
import sys
2
import random
3

  
4
from quixote import get_publisher, get_response, redirect, get_request
5
from quixote.directory import Directory
6
from quixote.errors import TraversalError
7

  
8
import lasso
9

  
10
import admin
11
import liberty
12
import saml2
13
import idwsf2
14
import httplib
15
import urllib
16

  
17
from qommon.form import *
18
from qommon.misc import get_abs_path, get_current_protocol
19
from qommon import template, get_logger
20

  
21
import errors
22
import misc
23

  
24
from users import User
25
from hosts import Host
26

  
27
class LibertySite(Directory):
28

  
29
    _q_exports = ['', 'login', 'logout', 'liberty', 'saml', 'idwsf2']
30

  
31
    liberty = liberty.Liberty()
32
    saml = saml2.Saml2()
33
    idwsf2 = idwsf2.IdWsf2()
34

  
35
    def __init__(self, component):
36
        self.name = component
37

  
38
    def _q_index (self):
39
        raise errors.TraversalError()
40

  
41
    def login [html] (self):
42
        get_logger().info('login')
43
        get_publisher().reload_cfg()
44

  
45
        if not get_publisher().cfg.has_key('idp'):
46
            return template.error_page(_('SSO support is not yet configured'))
47
        else:
48
            server = misc.get_lasso_server('liberty')
49
            if server is not None:
50
                return self.liberty.perform_login()
51

  
52
            server = misc.get_lasso_server('saml2')
53
            if server is not None:
54
                return self.saml.perform_login()
55

  
56
            return template.error_page(_('SSO support is not yet configured'))
57

  
58
    def logout(self):
59
        get_logger().info('logout')
60
        session = get_session()
61
        if not session:
62
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
63

  
64
        if misc.get_current_protocol() == lasso.PROTOCOL_SAML_2_0:
65
            return self.saml.slo_sp()
66
        else:
67
            return self.liberty.singleLogout()
68

  
larpe/tags/release-1.1.1/larpe/logger.py
1
import logging
2

  
3
from quixote import get_request, get_session
4

  
5
from qommon.logger import BotFilter
6

  
7
from hosts import Host
8

  
9
class Formatter(logging.Formatter):
10
    def format(self, record):
11
        request = get_request()
12

  
13
        record.address = request.get_environ('REMOTE_ADDR', '-')
14
        record.path = request.get_path()
15
        record.session_id = get_session().get_session_id() or '[nosession]'
16

  
17
        user = None
18
        host = Host.get_host_from_url()
19
        if not host:
20
            host = Host.select(lambda x: x.name == 'larpe')[0]
21
        if host:
22
            user = get_session().get_user(host.provider_id)
23
            if not user:
24
                user = get_session().get_user(host.saml2_provider_id)
25

  
26
        if user:
27
            user_id = user.id
28
        else:
29
            user_id = 'unlogged'
30
            if BotFilter.is_bot():
31
                user_id = 'bot'
32
        record.user_id = user_id
33

  
34
        return logging.Formatter.format(self, record)
larpe/tags/release-1.1.1/larpe/misc.py
1
import re
2
import os
3

  
4
import lasso
5

  
6
from quixote import get_publisher, get_request
7

  
8
from qommon.misc import get_abs_path
9

  
10
from hosts import Host
11

  
12
def get_root_url():
13
    req = get_request()
14
    return '%s://%s%s' % (req.get_scheme(), req.get_server(), req.environ['SCRIPT_NAME'])
15

  
16
def get_proxied_site_path():
17
    host = Host.get_host_from_url()
18
    if host is None:
19
        return None
20
    return host.site_dir
21

  
22
def get_proxied_site_domain():
23
    return get_request().get_server().split(':')[0]
24

  
25
def get_identity_provider_config():
26
    get_publisher().reload_cfg()
27
    idps_dir = get_abs_path('idp')
28
    if get_publisher().cfg.has_key('idp'):
29
        idp_dir = os.path.join(idps_dir, get_publisher().cfg['idp'])
30

  
31
        metadata_path = os.path.join(idp_dir, 'metadata.xml')
32

  
33
        public_key_path = os.path.join(idp_dir, 'public_key')
34
        if not os.path.isfile(public_key_path):
35
            public_key_path = None
36

  
37
        ca_cert_chain_path = os.path.join(idp_dir, 'ca_cert_chain.pem')
38
        if not os.path.isfile(ca_cert_chain_path):
39
            ca_cert_chain_path = None
40

  
41
        return metadata_path, public_key_path, ca_cert_chain_path
42
    return None, None, None
43

  
44
def get_lasso_server(protocol='liberty'):
45
    proxied_site_path = get_proxied_site_path()
46
    if proxied_site_path is None:
47
        return None
48
    if protocol == 'liberty':
49
        server = lasso.Server(
50
            os.path.join(proxied_site_path, 'metadata.xml'),
51
            os.path.join(proxied_site_path, 'private_key.pem'),
52
            None, None)
53
    elif protocol == 'saml2':
54
        server = lasso.Server(
55
            os.path.join(proxied_site_path, 'saml2_metadata.xml'),
56
            os.path.join(proxied_site_path, 'private_key.pem'),
57
            None, None)
58
    else:
59
        raise 'Unknown protocol'
60

  
61
    metadata_path, public_key_path, ca_cert_chain_path = get_identity_provider_config()
62
    if metadata_path:
63
        try:
64
            server.addProvider(
65
                    lasso.PROVIDER_ROLE_IDP,
66
                    metadata_path,
67
                    public_key_path,
68
                    ca_cert_chain_path)
69
        except lasso.Error, error:
70
            if error[0] == lasso.SERVER_ERROR_ADD_PROVIDER_PROTOCOL_MISMATCH:
71
                return None
72
            if error[0] == lasso.SERVER_ERROR_ADD_PROVIDER_FAILED:
73
                return None
74
            raise
75

  
76
    return server
77

  
78
def get_provider_label(provider):
79
    if not provider:
80
        return None
81
    if not hasattr(provider, str('getOrganization')):
82
        return provider.providerId
83

  
84
    organization = provider.getOrganization()
85
    if not organization:
86
        return provider.providerId
87

  
88
    name = re.findall("<OrganizationDisplayName.*>(.*?)</OrganizationDisplayName>", organization)
89
    if not name:
90
        name = re.findall("<OrganizationName.*>(.*?)</OrganizationName>", organization)
91
        if not name:
92
            return provider.providerId
93
    return name[0]
94

  
95
def get_current_protocol():
96
    metadata_path, public_key_path, ca_cert_chain_path = get_identity_provider_config()
97
    if not metadata_path:
98
        return None
99
    try:
100
        provider = lasso.Provider(lasso.PROVIDER_ROLE_IDP, metadata_path, public_key_path, None)
101
    except lasso.Error:
102
        return None
103
    else:
104
        return provider.getProtocolConformance()
105

  
larpe/tags/release-1.1.1/larpe/plugins/__init__.py
1
from larpe.plugins.site_authentication_plugins import SiteAuthenticationPlugins
2

  
3
site_authentication_plugins = SiteAuthenticationPlugins()
larpe/tags/release-1.1.1/larpe/plugins/site_authentication/agirhe.py
1
import re
2
import urllib
3

  
4
from quixote import get_request, get_response, get_session
5

  
6
from qommon.misc import http_post_request
7
from qommon.errors import ConnectionError
8
from qommon import get_logger
9

  
10
from larpe.qommon.misc import http_get_page
11
from larpe.plugins import site_authentication_plugins
12
from larpe.site_authentication import SiteAuthentication
13

  
14
class AgirheSiteAuthentication(SiteAuthentication):
15
    plugin_name = 'agirhe'
16

  
17
    def auto_detect_site(cls, html_doc):
18
        if re.search(
19
                """<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/""",
20
                html_doc):
21
            return True
22
        return False
23
    auto_detect_site = classmethod(auto_detect_site)
24

  
25
    def local_auth_check_post(self, username, password, select=None):
26
        select = select or {}
27
        url = self.host.auth_check_url
28

  
29
        # Build request body
30
        body = '%s=%s&%s=%s' % (
31
            self.host.login_field_name, username, self.host.password_field_name, password)
32
        # Add select fields to the body
33
        for name, value in select.iteritems():
34
            body += '&%s=%s' % (name, value)
35

  
36
        # Get the authentication page
37
        try:
38
            response, status, page, auth_headers = http_get_page(
39
                self.host.auth_form_url, use_proxy=self.host.use_proxy)
40
        except ConnectionError, err:
41
            get_logger().warn(err)
42
            return None, None
43

  
44
        # Get current hidden fields everytime
45
        self.parse_forms(page)
46
        if self.host.auth_form is not None:
47
            self.parse_other_fields()
48

  
49
        # Add hidden fields to the body
50
        for key, value in self.host.other_fields.iteritems():
51
            value = urllib.quote_plus(value)
52
            body += '&%s=%s' % (key, value)
53

  
54
        # Build request HTTP headers
55
        headers = {'Content-Type': 'application/x-www-form-urlencoded',
56
                   'X-Forwarded-For': get_request().get_environ('REMOTE_ADDR', '-'),
57
                   'X-Forwarded-Host': self.host.reversed_hostname}
58

  
59
        # Send request
60
        response, status, data, auth_headers = http_post_request(
61
            url, body, headers, self.host.use_proxy)
62

  
63
        cookies = response.getheader('Set-Cookie', None)
64
        self.host.cookies = []
65
        if cookies is not None:
66
            cookies_list = []
67
            cookies_set_list = []
68
            for cookie in cookies.split(', '):
69
                # Drop the path and other attributes
70
                cookie_only = cookie.split('; ')[0]
71
                regexp = re.compile('=')
72
                if regexp.search(cookie_only) is None:
73
                    continue
74
                # Split name and value
75
                cookie_split = cookie_only.split('=')
76
                cookie_name = cookie_split[0]
77
                cookie_value = cookie_split[1]
78
                cookies_list.append('%s=%s' % (cookie_name, cookie_value))
79
                set_cookie = '%s=%s; path=/' % (cookie_name, cookie_value)
80
                cookies_set_list.append(set_cookie)
81
                self.host.cookies.append(cookie_name)
82
            cookies_headers = '\r\nSet-Cookie: '.join(cookies_set_list)
83
            get_response().set_header('Set-Cookie', cookies_headers)
84
            self.host.store()
85
            get_session().cookies = '; '.join(cookies_list)
86
        else:
87
            get_logger().warn('No cookie from local authentication')
88

  
89
        return response.status, data
90

  
91
    # The 3 following functions have been copied from admin/hosts.ptl
92

  
93
    def parse_forms(self, page):
94
        '''Search for an authentication form'''
95
        # Get all forms
96
        regexp = re.compile("""<form.*?</form>""", re.DOTALL | re.IGNORECASE)
97
        found_forms = regexp.findall(page)
98
        if not found_forms:
99
            return
100

  
101
        # Get the first form with a password field
102
        for found_form in found_forms:
103
            regexp = re.compile(
104
                """<input[^>]*?type=["']?password["']?[^>]*?>""", re.DOTALL | re.IGNORECASE)
105
            if regexp.search(found_form) is not None:
106
                self.host.auth_form = found_form
107
                break
108

  
109
    def parse_other_fields(self):
110
        '''Get the default value of all other fields'''
111
        self.host.other_fields = {}
112

  
113
        # Get hidden fields
114
        regexp = re.compile(
115
            """<input[^>]*?type=["']?hidden["']?[^>]*?>""", re.DOTALL | re.IGNORECASE)
116
        other_fields = regexp.findall(self.host.auth_form)
117

  
118
        # Only get first submit field
119
        regexp = re.compile(
120
            """<input[^>]*?type=["']?submit["']?[^>]*?>""", re.DOTALL | re.IGNORECASE)
121
        found = regexp.findall(self.host.auth_form)
122
        if found:
123
            if other_fields:
124
                other_fields.append(found[0])
125
            else:
126
                other_fields = found[0]
127

  
128
        for field in other_fields:
129
            try:
130
                regexp = re.compile("""name=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE)
131
                name = regexp.findall(field)[0]
132
                regexp = re.compile("""value=["'](.*?)["'][\s/>]""", re.DOTALL | re.IGNORECASE)
133
                value = regexp.findall(field)[0]
134
                self.host.other_fields[name] = value
135
                if not self.host.post_parameters.has_key(name):
136
                    self.host.post_parameters[name] = { 'enabled': True,
137
                                                        'value': value,
138
                                                        'immutable': False }
139
            except IndexError:
140
                continue
141

  
142
site_authentication_plugins.register(AgirheSiteAuthentication)
larpe/tags/release-1.1.1/larpe/plugins/site_authentication/ciril_net_rh.py
1

  
2
import re
3

  
4
from quixote import redirect
5

  
6
from larpe.plugins import site_authentication_plugins
7
from larpe.site_authentication import SiteAuthentication
8

  
9
class CirilSiteAuthentication(SiteAuthentication):
10

  
11
    plugin_name = 'ciril'
12
    output_filters = ['output_ciril_net_rh']
13

  
14
    def auto_detect_site(cls, html_doc):
15
        if re.search(
16
                """<form name="myForm" id="myForm" method="post" target="choixAppli" action="/cgi-bin/acces.exe" """,
17
                html_doc):
18
            return True
19
        return False
20
    auto_detect_site = classmethod(auto_detect_site)
21

  
22
    def check_auth(self, status, data):
23
        success = False
24
        return_content = ''
25

  
26
        # If status is 500, fail without checking other criterias
27
        if status // 100 == 5:
28
            success = False
29
            return_content = redirect(self.host.get_return_url())
30

  
31
        regexp = re.compile(
32
            """javascript\:window\.open\('(/net_rh/accueil.php\?.*?)', '_blank'\)""",
33
            re.DOTALL | re.IGNORECASE)
34
        match = regexp.findall(data)
35
        if match:
36
            success = True
37
            return_content = redirect(match[0])
38

  
39
        return success, return_content
40

  
41

  
42

  
43
site_authentication_plugins.register(CirilSiteAuthentication)
44

  
larpe/tags/release-1.1.1/larpe/plugins/site_authentication/concerto.py
1
import re
2

  
3
from quixote import get_request, get_response, get_session
4

  
5
from qommon.misc import http_post_request
6
from qommon import get_logger
7

  
8
from larpe.plugins import site_authentication_plugins
9
from larpe.site_authentication import SiteAuthentication
10

  
11
class ConcertoSiteAuthentication(SiteAuthentication):
12
    plugin_name = 'concerto'
13

  
14
    def auto_detect_site(cls, html_doc):
15
        if re.search(
16
                """<meta name="description" content="Page d'accueil du site Espace-Famille" />""",
17
                html_doc):
18
            return True
19
        return False
20
    auto_detect_site = classmethod(auto_detect_site)
21

  
22
    def local_auth_check_post(self, username, password, select=None, session_cookies=False):
23
        select = select or {}
24
        url = self.host.auth_check_url
25

  
26
        # Build request body
27
        body = '%s=%s&%s=%s' % (
28
            self.host.login_field_name, username, self.host.password_field_name, password)
29
        # Add select fields to the body
30
        for name, value in select.iteritems():
31
            body += '&%s=%s' % (name, value)
32
        # Add hidden fields to the body
33
        if self.host.send_hidden_fields:
34
            for key, value in self.host.other_fields.iteritems():
35
                body += '&%s=%s' % (key, value)
36

  
37
        # Build request HTTP headers
38
        headers = {'Content-Type': 'application/x-www-form-urlencoded',
39
                   'X-Forwarded-For': get_request().get_environ('REMOTE_ADDR', '-'),
40
                   'X-Forwarded-Host': self.host.reversed_hostname}
41

  
42
        # Add session id cookie
43
        if session_cookies is True:
44
            for key, value in self.host.other_fields.iteritems():
45
                headers['Cookie'] = 'JSESSIONID=' + value
46

  
47
        # Send request
48
        response, status, data, auth_headers = http_post_request(
49
            url, body, headers, self.host.use_proxy)
50

  
51
        cookies = response.getheader('Set-Cookie', None)
52
        self.host.cookies = []
53
        new_session_id = None
54
        if cookies is not None:
55
            cookies_list = []
56
            cookies_set_list = []
57
            for cookie in cookies.split(', '):
58
                # Drop the path and other attributes
59
                cookie_only = cookie.split('; ')[0]
60
                regexp = re.compile('=')
61
                if regexp.search(cookie_only) is None:
62
                    continue
63
                # Split name and value
64
                cookie_split = cookie_only.split('=')
65
                cookie_name = cookie_split[0]
66
                cookie_value = cookie_split[1]
67
                if cookie_name == 'JSESSIONID':
68
                    new_session_id = cookie_value
69
                cookies_list.append('%s=%s' % (cookie_name, cookie_value))
70
                set_cookie = '%s=%s; path=/demo' % (cookie_name, cookie_value)
71
                cookies_set_list.append(set_cookie)
72
                self.host.cookies.append(cookie_name)
73
            cookies_headers = '\r\nSet-Cookie: '.join(cookies_set_list)
74
            get_response().set_header('Set-Cookie', cookies_headers)
75
            self.host.store()
76
            get_session().cookies = '; '.join(cookies_list)
77
        else:
78
            get_logger().warn('No cookie from local authentication')
79

  
80
        if session_cookies is False:
81
            # Change idSession hidden field with new session id
82
            self.host.other_fields['idSession'] = new_session_id
83
            # Retry the request with the new session id
84
            return self.local_auth_check_post(username, password, select, session_cookies=True)
85
        else:
86
            return response.status, data
87

  
88
site_authentication_plugins.register(ConcertoSiteAuthentication)
89

  
larpe/tags/release-1.1.1/larpe/plugins/site_authentication/egroupware.py
1
import re
2
import urlparse
3

  
4
from quixote import get_request, get_response, get_session
5

  
6
from qommon.misc import http_post_request, http_get_page
7
from qommon import get_logger
8

  
9
from larpe.plugins import site_authentication_plugins
10
from larpe.site_authentication import SiteAuthentication
11

  
12
class EgroupwareSiteAuthentication(SiteAuthentication):
13
    plugin_name = 'egroupware'
14

  
15
    def auto_detect_site(cls, html_doc):
16
        if re.search("""<meta name="description" content="eGroupWare" />""", html_doc):
17
            return True
18
        return False
19
    auto_detect_site = classmethod(auto_detect_site)
20

  
21
    def local_auth_check_post(self, username, password, select=None):
22
        select = select or {}
23
        url = self.host.auth_check_url
24

  
25
        # Build request body
26
        body = '%s=%s&%s=%s' % (
27
            self.host.login_field_name, username, self.host.password_field_name, password)
28
        # Add select fields to the body
29
        for name, value in select.iteritems():
30
            body += '&%s=%s' % (name, value)
31
        # Add hidden fields to the body
32
        if self.host.send_hidden_fields:
33
            for key, value in self.host.other_fields.iteritems():
34
                body += '&%s=%s' % (key, value)
35

  
36
        # Build request HTTP headers
37
        headers = {'Content-Type': 'application/x-www-form-urlencoded',
38
                   'X-Forwarded-For': get_request().get_environ('REMOTE_ADDR', '-'),
39
                   'X-Forwarded-Host': self.host.reversed_hostname}
40

  
41
        # Send request
42
        response, status, data, auth_headers = http_post_request(
43
            url, body, headers, self.host.use_proxy)
44

  
45
        # The specific code is these 2 lines and the called function
46
        if self.host.name.startswith('egroupware'):
47
            data = self.get_data_after_redirects(response, data)
48

  
49
        cookies = response.getheader('Set-Cookie', None)
50
        self.host.cookies = []
51
        if cookies is not None:
52
            cookies_list = []
53
            cookies_set_list = []
54
            for cookie in cookies.split(', '):
55
                # Drop the path and other attributes
56
                cookie_only = cookie.split('; ')[0]
57
                regexp = re.compile('=')
58
                if regexp.search(cookie_only) is None:
59
                    continue
60
                # Split name and value
61
                cookie_split = cookie_only.split('=')
62
                cookie_name = cookie_split[0]
63
                cookie_value = cookie_split[1]
64
                cookies_list.append('%s=%s' % (cookie_name, cookie_value))
65
                set_cookie = '%s=%s; path=/' % (cookie_name, cookie_value)
66
                cookies_set_list.append(set_cookie)
67
                self.host.cookies.append(cookie_name)
68
            cookies_headers = '\r\nSet-Cookie: '.join(cookies_set_list)
69
            get_response().set_header('Set-Cookie', cookies_headers)
70
            self.host.store()
71
            get_session().cookies = '; '.join(cookies_list)
72
        else:
73
            get_logger().warn('No cookie from local authentication')
74

  
75
        return response.status, data
76

  
77
    def get_data_after_redirects(self, response, data):
78
        status = response.status
79
        headers = {'X-Forwarded-For': get_request().get_environ('REMOTE_ADDR', '-'),
80
                   'X-Forwarded-Host': self.host.reversed_hostname}
81
        while status == 302:
82
            location = response.getheader('Location', None)
83
            if location is not None:
84
                url_tokens = urlparse.urlparse(self.host.auth_check_url)
85
                url = '%s://%s%s'% (url_tokens[0], url_tokens[1], location)
86
                response, status, data, auth_headers = http_get_page(
87
                    url, headers, self.host.use_proxy)
88
        return data
89

  
90
site_authentication_plugins.register(EgroupwareSiteAuthentication)
91

  
larpe/tags/release-1.1.1/larpe/plugins/site_authentication/sympa.py
1
import re
2

  
3
from quixote import get_response, redirect
4
from quixote.html import htmltext
5

  
6
from larpe.plugins import site_authentication_plugins
7
from larpe.site_authentication import SiteAuthentication
8

  
9
class SympaSiteAuthentication(SiteAuthentication):
10
    plugin_name = 'sympa'
11

  
12
    def auto_detect_site(cls, html_doc):
13
        if re.search("""<FORM ACTION="/wwsympa.fcgi" METHOD=POST>""", html_doc):
14
            return True
15
        return False
16
    auto_detect_site = classmethod(auto_detect_site)
17

  
18
    def check_auth(self, status, data):
19
        success = False
20
        return_content = ''
21

  
22
        if self.host.auth_system == 'password':
23
            # If there is a password field, authentication probably failed
24
            regexp = re.compile(
25
                """<input[^>]*?type=["']?password["']?[^>]*?>""", re.DOTALL | re.IGNORECASE)
26
            if not regexp.findall(data):
27
                success = True
28
                # The specific part is only these 2 lines
29
                get_response().filter.update({'no_template': True})
30
                return_content = htmltext(data)
31
        elif self.host.auth_system == 'status':
32
            match_status = int(self.host.auth_match_status)
33
            if match_status == status:
34
                success = True
35
                return_content = redirect(self.host.return_url)
36
        elif self.host.auth_system == 'match_text':
37
            # If the auth_match_text is not matched, it means the authentication is successful
38
            regexp = re.compile(self.host.auth_match_text, re.DOTALL)
39
            if not regexp.findall(data):
40
                success = True
41
                return_content = redirect(self.host.get_return_url())
42

  
43
        return success, return_content
44

  
45
site_authentication_plugins.register(SympaSiteAuthentication)
larpe/tags/release-1.1.1/larpe/plugins/site_authentication_plugins.py
1

  
2
class SiteAuthenticationPlugins:
3
    """ This class manages the plugins for site authentification """
4

  
5
    def __init__(self):
6
        self.site_authentication_classes = dict()
7

  
8
    def register(self, klass):
9
        """ Register a custom SiteAuthentification instance """
10
        self.site_authentication_classes[klass.plugin_name] = klass
11

  
12
    def get(self, plugin_name):
13
        """ Return a custom SiteAuthentification instance """
14
        if self.site_authentication_classes.has_key(plugin_name):
15
            return self.site_authentication_classes[plugin_name]
16
        else:
17
            return None
18

  
19
    def get_plugins_name(self):
20
        plugins_name = list()
21
        for plugin_name in self.site_authentication_classes.iterkeys():
22
            plugins_name.append(plugin_name)
23
        return plugins_name
24

  
25
    def auto_detect(self, html_doc):
26
        """
27
        Try to find automatically the right plugin name
28
        Return the plugin name or None
29
        """
30
        for name, klass in self.site_authentication_classes.iteritems():
31
            if klass.auto_detect_site(html_doc):
32
                return klass.plugin_name
33
        return None
34

  
larpe/tags/release-1.1.1/larpe/publisher.py
1
import os
2
import cPickle
3

  
4
from quixote import get_request
5

  
6
from Defaults import *
7

  
8
from qommon.publisher import set_publisher_class, QommonPublisher
9

  
10
from root import RootDirectory
11
from admin import RootDirectory as AdminRootDirectory
12

  
13
from sessions import StorageSessionManager
14
from users import User
15

  
16
class LarpePublisher(QommonPublisher):
17
    APP_NAME = 'larpe'
18
    APP_DIR = APP_DIR
19
    DATA_DIR = DATA_DIR
20
    ERROR_LOG = ERROR_LOG
21
    WEB_ROOT = WEB_ROOT
22

  
23
    supported_languages = ['fr']
24

  
25
    root_directory_class = RootDirectory
26
    admin_directory_class = AdminRootDirectory
27

  
28
    session_manager_class = StorageSessionManager
29
    user_class = User
30

  
31
    def get_application_static_files_root_url(self):
32
        return '%s/%s/' % (get_request().environ['SCRIPT_NAME'], WEB_ROOT)
33

  
34
    def set_app_dir(self, request):
35
        self.app_dir = os.path.join(self.APP_DIR, request.get_server().lower().split(':')[0])
36
        self.reload_cfg()
37
        if self.cfg.has_key('proxy_hostname'):
38
            self.app_dir = os.path.join(self.APP_DIR, self.cfg['proxy_hostname'])
39
        if self.app_dir is not None and not os.path.exists(self.app_dir):
40
            os.mkdir(self.app_dir)
41
        return True
42

  
43
    cfg = None
44
    def write_cfg(self, directory=None):
45
        dump = cPickle.dumps(self.cfg)
46
        if directory is None:
47
            directory = self.app_dir
48
        filename = os.path.join(directory, 'config.pck')
49
        open(filename, 'w').write(dump)
50

  
51
set_publisher_class(LarpePublisher)
52
extra_dir = os.path.join(os.path.dirname(__file__), 'plugins','site_authentication')
53
LarpePublisher.register_extra_dir(extra_dir)
larpe/tags/release-1.1.1/larpe/root.ptl
1
import os
2
import httplib
3

  
4
import lasso
5

  
6
from quixote import get_request, get_response, get_session, redirect
7
from quixote.directory import Directory
8

  
9
from qommon.form import *
10
from qommon import template
11

  
12
import admin
13
import liberty_root
14
import errors
15

  
16
from hosts import Host
17
from users import User
18
from Defaults import WEB_ROOT
19

  
20
class RootDirectory(Directory):
21
    _q_exports = ['', 'admin', 'liberty', 'logout', 'token']
22

  
23
    admin = admin.RootDirectory()
24
    liberty = liberty_root.LibertyRootDirectory()
25

  
26
    def _q_index [html] (self):
27
        template.html_top(_('Welcome to Larpe reverse proxy'))
28
        '<ul><li><a href="%s/admin/">%s</a></li></ul>' % (get_request().environ['SCRIPT_NAME'],
29
                                                         _('Configure Larpe'))
30

  
31
    def _q_traverse(self, path):
32
        response = get_response()
33
        response.filter = {}
34

  
35
        return Directory._q_traverse(self, path)
36

  
37
    def _q_lookup(self, component):
38
        return redirect(component + '/')
39

  
40
    def logout(self):
41
        return redirect(get_publisher().get_root_url() + 'liberty/larpe/logout')
42

  
43
    def token [html] (self):
44
        session = get_session()
45

  
46
        if not session.name_identifier or not session.lasso_anonymous_identity_dump:
47
            raise errors.AccessUnauthorizedError()
48

  
49
        # If the token is in the query string, use it
50
        query_string = get_request().get_query()
51
        if query_string:
52
            parameters = query_string.split(str('&'))
53
            for param in parameters:
54
                values = param.split(str('='))
55
                if len(values) < 2:
56
                    continue
57
                if values[0] == str('token'):
58
                    return self._federate_token(values[1])
59

  
60
        # Otherwise, display a form to ask for the token
61
        form = Form(enctype='multipart/form-data')
62
        form.add(StringWidget, 'token', title = _('Identification Token'),
63
                required = True, size = 30)
64
        form.add_submit('submit', _('Submit'))
65
        form.add_submit('cancel', _('Cancel'))
66

  
67
        if form.get_widget('cancel').parse():
68
            return redirect('.')
69

  
70
        if not form.is_submitted() or form.has_errors():
71
            template.html_top(_('Identification Token'))
72
            '<p>'
73
            _('Please enter your identification token. ')
74
            _('Your local account will be federated with your Liberty Alliance account.')
75
            '</p>'
76
            form.render()
77
        else:
78
            token = form.get_widget('token').parse()
79
            return self._federate_token(token)
80

  
81
    def _federate_token(self, token):
82
        session = get_session()
83

  
84
        # Get the user who owns this token
85
        users_with_token = list(User.select(lambda x: x.identification_token == token))
86
        if len(users_with_token) == 0:
87
            return template.error_page(_('Unknown Token'))
88

  
89
        # Fill user attributes
90
        user = users_with_token[0]
91
        user.name_identifiers = [ session.name_identifier ]
92
        user.lasso_dumps = [ session.lasso_anonymous_identity_dump ]
93
        user.identification_token = None
94
        user.is_admin = True
95
        user.store()
96

  
97
        # Set this user in the session
98
        session.set_user(user.id, session.provider_id)
99

  
100
        # Delete now useless session attributes
101
        session.name_identifier = None
102
        session.lasso_anonymous_identity_dump = None
103
        session.provider_id = None
104

  
105
        return redirect('%s/admin/' % get_request().environ['SCRIPT_NAME'])
106

  
larpe/tags/release-1.1.1/larpe/saml2.ptl
1
import os
2
import sys
3
import urlparse
4

  
5
try:
6
    import lasso
7
except ImportError:
8
    print >> sys.stderr, 'Missing Lasso module, SAMLv2 support disabled'
9

  
10
from quixote import get_publisher, get_request, get_response, get_session, get_session_manager, redirect
11

  
12
from qommon.liberty import SOAPException, soap_call
13
from qommon.saml2 import Saml2Directory
14
from qommon import template
15
from qommon import get_logger
16

  
17
import misc
18
from users import User
19
from hosts import Host
20
from federations import Federation
21
import site_authentication
22

  
23
class Saml2(Saml2Directory):
24
    _q_exports = Saml2Directory._q_exports + ['local_auth']
25

  
26
    def login(self):
27
        return self.perform_login()
28

  
29
    def perform_login(self, idp = None):
30
        server = misc.get_lasso_server(protocol = 'saml2')
31
        if not server:
32
            return template.error_page(_('SAML 2.0 support not yet configured.'))
33
        login = lasso.Login(server)
34
        login.initAuthnRequest(idp, lasso.HTTP_METHOD_REDIRECT)
35
        login.request.nameIDPolicy.format = lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT
36
        login.request.nameIDPolicy.allowCreate = True
37
        login.request.forceAuthn = False
38
        login.request.isPassive = False
39
        login.request.consent = 'urn:oasis:names:tc:SAML:2.0:consent:current-implicit'
40
        login.buildAuthnRequestMsg()
41
        return redirect(login.msgUrl)
42

  
43
    def singleSignOnArtifact(self):
44
        server = misc.get_lasso_server(protocol = 'saml2')
45
        if not server:
46
            return template.error_page(_('SAML 2.0 support not yet configured.'))
47
        login = lasso.Login(server)
48
        request = get_request()
49
        try:
50
            login.initRequest(request.get_query(), lasso.HTTP_METHOD_ARTIFACT_GET)
51
        except lasso.Error, error:
52
            if error[0] == lasso.PROFILE_ERROR_MISSING_ARTIFACT:
53
                return template.error_page(_('Missing SAML Artifact'))
54
            else:
55
                raise
56

  
57
        login.buildRequestMsg()
58
        #remote_provider_cfg = get_cfg('idp', {}).get(misc.get_provider_key(login.remoteProviderId))
59
        #client_cert = remote_provider_cfg.get('clientcertificate')
60

  
61
        try:
62
            soap_answer = soap_call(login.msgUrl, login.msgBody)
63
        except SOAPException:
64
            return template.error_page(_('Failure to communicate with identity provider'))
65

  
66
        try:
67
            login.processResponseMsg(soap_answer)
68
        except lasso.Error, error:
69
            if error[0] == lasso.LOGIN_ERROR_STATUS_NOT_SUCCESS:
70
                return template.error_page(_('Unknown authentication failure'))
71
            if error[0] == lasso.LOGIN_ERROR_UNKNOWN_PRINCIPAL:
72
                return template.error_page(_('Authentication failure; unknown principal'))
73
            if error[0] == lasso.LOGIN_ERROR_FEDERATION_NOT_FOUND:
74
                return template.error_page('there was no federation')
75
            raise
76

  
77
        return self.sso_after_response(login)
78

  
79
    def sso_after_response(self, login):
80
        providerId = login.server.providerId
81
        try:
82
            assertion = login.response.assertion[0]
83
            if assertion.subject.subjectConfirmation.subjectConfirmationData.recipient != \
84
                        get_request().get_url():
85
                return template.error_page('SubjectConfirmation Recipient Mismatch')
86
        except:
87
                return template.error_page('SubjectConfirmation Recipient Mismatch')
88

  
89
        assertions_dir = os.path.join(get_publisher().app_dir, 'assertions')
90
        if not os.path.exists(assertions_dir):
91
            os.mkdir(assertions_dir)
92

  
93
        assertion_fn = os.path.join(assertions_dir, assertion.iD)
94
        if os.path.exists(assertion_fn):
95
            return template.error_page('Assertion replay')
96

  
97
        try:
98
            if assertion.subject.subjectConfirmation.method != \
99
                        'urn:oasis:names:tc:SAML:2.0:cm:bearer':
100
                return template.error_page('Unknown SubjectConfirmation Method')
101
        except:
102
            return template.error_page('Unknown SubjectConfirmation Method')
103

  
104
        try:
105
            audience_ok = False
106
            for audience_restriction in assertion.conditions.audienceRestriction:
107
                if audience_restriction.audience != providerId:
108
                    return template.error_page('Incorrect AudienceRestriction')
109
                audience_ok = True
110
            if not audience_ok:
111
                return template.error_page('Incorrect AudienceRestriction')
112
        except:
113
            return template.error_page('Incorrect AudienceRestriction')
114

  
115
#        try:
116
#            current_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
117
#            not_before = assertion.subject.subjectConfirmation.subjectConfirmationData.notBefore
118
#            not_on_or_after = assertion.subject.subjectConfirmation.subjectConfirmationData.notOnOrAfter
119
#            if not_before and current_time < not_before:
120
#                return template.error_page('Assertion received too early')
121
#            if not_on_or_after and current_time > not_on_or_after:
122
#                return template.error_page('Assertion expired')
123
#        except:
124
#            return template.error_page('Error checking Assertion Time')
125

  
126
        # TODO: check for unknown conditions
127

  
128
        login.acceptSso()
129

  
130
        session = get_session()
131
        if login.isSessionDirty:
132
            if login.session:
133
                session.lasso_session_dumps[providerId] = login.session.dump()
134
                session.lasso_session_indexes[providerId] = assertion.authnStatement[0].sessionIndex
135
                session.lasso_session_name_identifiers[providerId] = login.nameIdentifier.content
136
            else:
137
                session.lasso_session_dumps[login.server.providerId] = None
138

  
139
        if assertion.authnStatement[0].sessionIndex:
140
            session.lasso_session_index = assertion.authnStatement[0].sessionIndex
141

  
142
        user = self.lookup_user(session, login)
143

  
144
        # Check if it is for Larpe administration or token
145
        host = Host.get_host_from_url()
146
        if host is None:
147
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
148
        if host.name == 'larpe':
149
            if user:
150
                session.set_user(user.id, login.server.providerId)
151
            else:
152
                session.name_identifier = login.nameIdentifier.content
153
                session.lasso_anonymous_identity_dump = login.identity.dump()
154
                session.provider_id = login.server.providerId
155

  
156
            if session.after_url:
157
                # Access to an admin page or token url with parameter
158
                after_url = session.after_url
159
                session.after_url = None
160
                return redirect(after_url)
161

  
162
            if user and user.is_admin:
163
                return redirect('%s/admin/' % get_request().environ['SCRIPT_NAME'])
164
            else:
165
                return redirect('%s/token' % get_request().environ['SCRIPT_NAME'])
166

  
167
        # Set session user
168
        if not user:
169
            user = User()
170
        user.name_identifiers = [ login.nameIdentifier.content ]
171
        user.lasso_dumps = [ login.identity.dump() ]
172
        user.store()
173
        session.set_user(user.id, login.server.providerId)
174

  
175
        # Check if a federation already exist
176
        federations = Federation.select(lambda x: host.id == x.host_id \
177
                                        and user.name_identifiers[0] in x.name_identifiers)
178

  
179
        if federations:
180
            return site_authentication.get_site_authentication(host).sso_local_login(federations[0])
181
        else:
182
            # Build response redirection
183
            response = get_response()
184
            if session.after_url:
185
                after_url = session.after_url
186
                session.after_url = None
187
                return redirect(after_url)
188
            response.set_status(303)
189
            response.headers['location'] = urlparse.urljoin(get_request().get_url(), str('local_auth'))
190
            response.content_type = 'text/plain'
191
            return 'Your browser should redirect you'
192

  
193
    def lookup_user(self, session, login):
194
        found_users = list(User.select(lambda x: login.nameIdentifier.content in x.name_identifiers, ignore_errors = True))
195
        if found_users:
196
            return found_users[0]
197
        return None
198

  
199
    def slo_sp(self, method = None):
200
        host = Host.get_host_from_url()
201
        if host is None:
202
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
203

  
204
        if method is None:
205
            method = lasso.HTTP_METHOD_REDIRECT
206

  
207
        logout = lasso.Logout(misc.get_lasso_server(protocol = 'saml2'))
208
        session = get_session()
209

  
210
        if not session.id or not session.users.has_key(logout.server.providerId) \
211
                or not session.lasso_session_dumps.has_key(logout.server.providerId):
212
            get_session_manager().expire_session(logout.server.providerId)
213
            return redirect(host.get_root_url())
214
        logout.setSessionFromDump(session.lasso_session_dumps[logout.server.providerId])
215
        user = session.get_user(logout.server.providerId)
216

  
217
        if host.name != 'larpe' and user:
218
            site_authentication.get_site_authentication(host).local_logout(user=user)
219

  
220
        if user and user.lasso_dumps:
221
            logout.setIdentityFromDump(user.lasso_dumps[0])
222
        else:
223
            get_session_manager().expire_session(logout.server.providerId)
224
            return redirect(host.get_root_url())
225

  
226
        if method == lasso.HTTP_METHOD_REDIRECT:
227
            return self.slo_sp_redirect(logout)
228

  
229
        # Not implemented yet
230
        if method == lasso.HTTP_METHOD_SOAP:
231
            return self.slo_sp_soap(logout)
232

  
233
    def slo_sp_redirect(self, logout):
234
        session = get_session()
235
        try:
236
            logout.initRequest(None, lasso.HTTP_METHOD_REDIRECT)
237
        except lasso.Error, error:
238
            if error[0] == lasso.PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND:
239
                get_session_manager().expire_session(logout.server.providerId)
240
                return redirect(host.get_root_url())
241
            if error[0] == lasso.PROFILE_ERROR_SESSION_NOT_FOUND:
242
                get_session_manager().expire_session(logout.server.providerId)
243
                return redirect(host.get_root_url())
244
            raise
245

  
246
        logout.buildRequestMsg()
247
        return redirect(logout.msgUrl)
248

  
249
    def singleLogoutReturn(self):
250
        host = Host.get_host_from_url()
251
        if host is None:
252
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
253

  
254
        logout = lasso.Logout(misc.get_lasso_server(protocol = 'saml2'))
255
        session = get_session()
256

  
257
        if not session.id or not session.users.has_key(logout.server.providerId) \
258
                or not session.lasso_session_dumps.has_key(logout.server.providerId):
259
            get_session_manager().expire_session(logout.server.providerId)
260
            return redirect(host.get_root_url())
261
        logout.setSessionFromDump(session.lasso_session_dumps[logout.server.providerId])
262

  
263
        message = get_request().get_query()
264
        return self.slo_return(logout, message)
265

  
266
    def slo_return(self, logout, message):
267
        host = Host.get_host_from_url()
268

  
269
        session = get_session()
270

  
271
        try:
272
            logout.processResponseMsg(message)
273
        except lasso.Error, error:
274
            if error[0] == lasso.PROFILE_ERROR_INVALID_QUERY:
275
                get_logger().warn('Invalid response')
276
            elif error[0] == lasso.DS_ERROR_INVALID_SIGNATURE:
277
                get_logger().warn('Failed to check single logout request signature')
278
            elif error[0] == lasso.LOGOUT_ERROR_REQUEST_DENIED:
279
                get_logger().warn('Request Denied')
280
            elif error[0] == lasso.LOGOUT_ERROR_UNKNOWN_PRINCIPAL:
281
                get_logger().warn('Unknown principal on logout, probably session stopped already on IdP')
282
            else:
283
                get_logger().error('Unknown Lasso exception on logout return: ' + repr(error))
284
        except Exception, exception:
285
            get_logger().error('Unknown exception on logout return: ' + repr(exception))
286

  
287
        get_session_manager().expire_session(logout.server.providerId)
288

  
289
        return redirect(host.get_root_url())
290

  
291
    def singleLogoutSOAP(self):
292
        try:
293
            soap_message = self.get_soap_message()
294
        except:
295
            return
296

  
297
        response = get_response()
298
        response.set_content_type('text/xml')
299

  
300
        request_type = lasso.getRequestTypeFromSoapMsg(soap_message)
301

  
302
        if request_type != lasso.REQUEST_TYPE_LOGOUT:
303
            get_logger().warn('SOAP message on single logout url not a slo message')
304
            return
305

  
306
        logout = lasso.Logout(misc.get_lasso_server(protocol = 'saml2'))
307
        providerId = logout.server.providerId
308
        logout.processRequestMsg(soap_message)
309
        name_identifier = logout.nameIdentifier.content
310
        # find one session matching the name identifier, and eventually the request
311
        for session in get_session_manager().values():
312
            session_index = session.lasso_session_indexes.get(providerId)
313
            name_identifier = session.lasso_session_name_identifiers.get(providerId)
314
            request_name_identifier = logout.nameIdentifier.content
315
            request_session_index = logout.request.sessionIndex
316
            if request_name_identifier == name_identifier and \
317
                    (not session_index or request_session_index == session_index) \
318
                        and session.lasso_session_dumps.get(providerId):
319
                get_logger().info('SLO/SOAP from %s' % logout.remoteProviderId)
320
                break
321
        else:
322
            # no session, build straight failure answer
323
            logout.buildResponseMsg()
324
            return logout.msgBody
325

  
326
        return self.slo_idp(logout, session)
327

  
328
    def singleLogout(self):
329
        logout = lasso.Logout(misc.get_lasso_server(protocol = 'saml2'))
330
        try:
331
            logout.processRequestMsg(get_request().get_query())
332
        except lasso.Error, error:
333
            if error[0] == lasso.DS_ERROR_INVALID_SIGNATURE:
334
                return template.error_page(_('Failed to check single logout request signature.'))
335
            raise
336
        session = get_session()
337
        if not session.id:
338
            # session has not been found, this may be because the user has
339
            # its browser configured so that cookies are not sent for
340
            # remote queries and IdP is using image-based SLO.
341
            # so we look up a session with the appropriate name identifier
342
            # find a matching 
343
            for session in get_session_manager().values():
344
                session_index = session.lasso_session_indexes.get(providerId)
345
                name_identifier = session.lasso_session_name_identifiers.get(providerId)
346
                request_name_identifier = logout.nameIdentifier.content
347
                request_session_index = logout.request.sessionIndex
348
                if request_name_identifier == name_identifier and \
349
                        (not session_index or request_session_index == session_index) \
350
                        and session.lasso_session_dump.get(providerId):
351
                    get_logger().info('SLO/SOAP from %s' % logout.remoteProviderId)
352
                    break
353
            else:
354
                # no session, build straight failure answer
355
                logout.buildResponseMsg()
356
                return logout.msgBody
357

  
358
        return self.slo_idp(logout, session)
359

  
360
    def slo_idp(self, logout, session):
361
        # This block differs from qommon
362
        if session.lasso_session_dumps.has_key(logout.server.providerId):
363
            logout.setSessionFromDump(session.lasso_session_dumps[logout.server.providerId])
364
        user = session.get_user(logout.server.providerId)
365
        if user and user.lasso_dumps:
366
            logout.setIdentityFromDump(user.lasso_dumps[0])
367

  
368
        if user and logout.nameIdentifier.content not in user.name_identifiers:
369
            raise 'no appropriate name identifier in session (%s and %s)' % (
370
                    logout.nameIdentifier.content, session.name_identifier)
371

  
372
        try:
373
            assertion = logout.session.getAssertions(logout.remoteProviderId)[0]
374
            if logout.request.sessionIndex and (
375
                    assertion.authnStatement[0].sessionIndex != logout.request.sessionIndex):
376
                logout.setSessionFromDump('<Session />')
377
        except:
378
            pass
379

  
380
        try:
381
            logout.validateRequest()
382
        except lasso.Error, error:
383
            if error[0] == lasso.PROFILE_ERROR_SESSION_NOT_FOUND:
384
                pass
385
            elif error[0] == lasso.PROFILE_ERROR_IDENTITY_NOT_FOUND:
386
                pass
387
            elif error[0] == lasso.PROFILE_ERROR_MISSING_ASSERTION:
388
                pass
389
            elif error[0] == lasso.SERVER_ERROR_PROVIDER_NOT_FOUND:
390
                pass
391
            elif error[0] == lasso.NAME_IDENTIFIER_NOT_FOUND:
392
                pass
393
            else:
394
                raise
395
        else:
396
            providerId = logout.server.providerId
397
            session_index = logout.request.sessionIndex
398
            name_identifier = logout.nameIdentifier.content
399
            # Remove reference to local authentication on this SP in the session
400
            # if a user is present, try a local logout
401
            for session2 in get_session_manager().values():
402
                if session2.lasso_session_name_identifiers.get(providerId) == name_identifier \
403
                        and ( not session_index
404
                                or session2.lasso_session_indexes.get(providerId) == session_index):
405
                    if session2.users.has_key(providerId):
406
                        # local logout
407
                        site_auth = site_authentication.get_site_authentication(Host.get_host_from_url())
408
                        site_auth.local_logout(user=session2.get_user(providerId),
409
                                cookies=getattr(session2,'cookies', None))
410
                        del session2.users[providerId]
411
                    if session2.lasso_session_dumps.has_key(providerId):
412
                        del session2.lasso_session_dumps[providerId]
413
                    if session2.lasso_session_indexes.has_key(providerId):
414
                        del session2.lasso_session_indexes[providerId]
415
                    if session2.lasso_session_name_identifiers.has_key(providerId):
416
                        del session2.lasso_session_name_identifiers[providerId]
417
                    session2.store()
418
            get_session_manager().expire_session(logout.server.providerId)
419

  
420
        logout.buildResponseMsg()
421
        if logout.msgBody: # soap answer
422
            return logout.msgBody
423
        else:
424
            return redirect(logout.msgUrl)
425

  
426
    def local_auth(self):
427
        host = Host.get_host_from_url()
428
        if host is None:
429
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
430
        return site_authentication.get_site_authentication(host).local_auth
431
    local_auth = property(local_auth)
432

  
433
    def metadata(self):
434
        host = Host.get_host_from_url()
435
        if host is None:
436
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
437
        get_response().set_content_type('text/xml', 'utf-8')
438
        metadata = unicode(open(host.saml2_metadata).read(), 'utf-8')
439
        return metadata
440

  
441
    def public_key(self):
442
        host = Host.get_host_from_url()
443
        if host is None:
444
            return redirect('%s/' % get_request().environ['SCRIPT_NAME'])
445
        get_response().set_content_type('text/plain')
446
        public_key = open(host.public_key).read()
447
        return public_key
448

  
larpe/tags/release-1.1.1/larpe/sessions.py
1
'''Session and SessionManager objects. Configuration variables and utilities'''
2

  
3
from quixote import get_request
4

  
5
import qommon.sessions
6
from qommon.sessions import Session
7
from qommon.sessions import StorageSessionManager as SessionManager
8

  
9
from users import User
10
from hosts import Host
11

  
12
class BasicSession(Session):
13
    '''Session object. Configuration variables and utilities'''
14
    _names = 'sessions'
15

  
16
    def __init__(self, id):
17
        self.users = {}
18
        self.lasso_session_dumps = {}
19
        self.lasso_session_indexes = {}
20
        self.lasso_session_name_identifiers = {}
21
        self.provider_id = None
22
        Session.__init__(self, id)
23

  
24
    # lasso_session_indexes newly introduced
25
    def __setstate__(self, dict):
26
        self.lasso_session_indexes = {}
27
        self.lasso_session_name_identifiers = {}
28
        self.__dict__.update(dict)
29

  
30
    def has_info(self):
31
        return self.users or self.lasso_session_dumps or self.provider_id or Session.has_info(self)
32
    is_dirty = has_info
33

  
34
    def get_user(self, provider_id=None):
35
        # Defaults to getting Larpe user.
36
        # It allows get_request().user to work in administration interface.
37
        if not provider_id:
38
            user_id = None
39
            host = Host.get_host_from_url()
40
            if not host:
41
                host_list = Host.select(lambda x: x.name == 'larpe')
42
                if host_list:
43
                    host = host_list[0]
44
            if host:
45
                user_id = self.users.get(host.provider_id)
46
                if not user_id:
47
                    user_id = self.users.get(host.saml2_provider_id)
48
        else:
49
            user_id = self.users.get(provider_id)
50

  
51
        if user_id:
52
            try:
53
                user = User.get(user_id)
54
            except KeyError:
55
                user = User()
56
#            if str(user_id).startswith('anonymous-'):
57
                user.id = user_id
58
#                user.anonymous = True
59
#                if self.name_identifiers.has_key(providerId):
60
#                    if not user.name_identifiers.has_key(providerId):
61
#                        user.name_identifiers[providerId] = [ self.name_identifiers[providerId] ]
62

  
63
#                if self.name_identifiers.has_key(providerId):
64
#                    user.name_identifiers[providerId] = [ self.name_identifiers[providerId] ]
65
#                else:
66
#                    user.name_identifiers[providerId] = []
67
#                user.lasso_dumps[providerId] = self.lasso_anonymous_identity_dump
68
            return user
69
        return None
70

  
71
    def set_user(self, user_id, provider_id):
72
        self.users[provider_id] = user_id
73

  
74
class StorageSessionManager(SessionManager):
75
    '''SessionManager object. Subclass with multi-hosts specific features.'''
76
    def expire_session(self, provider_id=None):
77
        session = get_request().session
78
        if session.id is not None:
79
            if provider_id:
80
                if session.users.has_key(provider_id):
81
                    del session.users[provider_id]
82
                if session.lasso_session_dumps.has_key(provider_id):
83
                    del session.lasso_session_dumps[provider_id]
84
                if session.lasso_session_indexes.has_key(provider_id):
85
                    del session.lasso_session_indexes[provider_id]
86
                if session.lasso_session_name_identifiers.has_key(provider_id):
87
                    del session.lasso_session_name_identifiers[provider_id]
88
                session.store()
89
            if not session.users:
90
                SessionManager.expire_session(self)
91

  
92
qommon.sessions.BasicSession = BasicSession
larpe/tags/release-1.1.1/larpe/site_authentication.ptl
1
import libxml2
2
import urllib
3
import urlparse
4
import httplib
5
import re
6
import os
7
import socket
8
import base64
9

  
10
from quixote import get_request, get_response, get_session, redirect, get_publisher
11
from quixote.directory import Directory
12
from quixote.http_request import parse_header
13

  
14
import lasso
15

  
16
from qommon import get_logger
17
from qommon.form import *
18
from qommon.errors import ConnectionError, ConfigurationError, LoginError
19
from qommon.misc import http_post_request, http_get_page
20
from qommon.template import *
21

  
22
from larpe.plugins import site_authentication_plugins
23

  
24
import misc
25
from users import User
26
from federations import Federation
27

  
28
class SiteAuthentication:
29

  
30
    output_filters = []
31

  
32
    def __init__(self, host):
33
        self.host = host
34

  
35
    def federate(self, username, password, provider_id, cookies, select):
36
        user = get_session().get_user(provider_id)
37
        if user is not None:
38
            Federation(username, password, self.host.id, user.name_identifiers[0], cookies, select).store()
39

  
40
    def sso_local_login(self, federation):
41
        status, data = self.local_auth_check_dispatch(
42
            federation.username, federation.password, federation.select_fields)
43
        success, return_content = self.check_auth(status, data)
44
        if success:
45
            session = get_session()
46
            if hasattr(session, 'cookies'):
47
                federation.set_cookies(session.cookies)
48
                federation.store()
49
            return return_content
50
        else:
51
            return redirect('local_auth')
52

  
53
    def local_auth [html] (self, first_time=True):
54
        response = get_response()
55
        response.set_content_type('text/html')
56

  
57
        if hasattr(get_response(), str('breadcrumb')):
58
            del get_response().breadcrumb
59

  
60
        get_response().filter['default_org'] = '%s - %s' % (self.host.label, _('Local authentication'))
61
        get_response().filter['body_class'] = 'login'
62

  
63
        form = self.form_local_auth()
64
        form.add_submit('submit', _('Submit'))
65
        #form.add_submit('cancel', _('Cancel'))
66

  
67
#        if form.get_widget('cancel').parse():
68
#            return redirect('.')
69
        authentication_failure = None
70
        if form.is_submitted() and not form.has_errors():
71
            try:
72
                return self.submit_local_auth_form(form)
73
            except LoginError:
74
                authentication_failure = _('Authentication failure')
75
                get_logger().info('local auth page : %s' % authentication_failure)
76
            except ConnectionError, err:
77
                authentication_failure = _('Connection failed : %s') % err
78
                get_logger().info('local auth page : %s' % authentication_failure)
79
            except ConfigurationError, err:
80
                authentication_failure = _('This service provider is not fully configured : %s') % err
81
                get_logger().info('local auth page : %s' % authentication_failure)
82
            except Exception, err:
83
                authentication_failure = _('Unknown error : %s' % err)
84
                get_logger().info('local auth page : %s' % authentication_failure)
85

  
86
        if authentication_failure:
87
            '<div class="errornotice">%s</div>' % authentication_failure
88
        '<p>'
89
        _('Please type your login and password for this Service Provider.')
90
        _('Your local account will be federated with your Liberty Alliance account.')
91
        '</p>'
92

  
93
        form.render()
94

  
95
    # Also used in admin/hosts.ptl
96
    def form_local_auth(self):
97
        form = Form(enctype='multipart/form-data')
98
        form.add(StringWidget, 'username', title = _('Username'), required = True,
99
                size = 30)
100
        form.add(PasswordWidget, 'password', title = _('Password'), required = True,
101
                size = 30)
102
        for name, values in self.host.select_fields.iteritems():
103
            options = []
104
            if values:
105
                for value in values:
106
                    options.append(value)
107
                form.add(SingleSelectWidget, name, title = name.capitalize(),
108
                    value = values[0], options = options)
109
        return form
110

  
111
    def submit_local_auth_form(self, form):
112
        username = form.get_widget('username').parse()
113
        password = form.get_widget('password').parse()
114
        select = {}
115
        for name, values in self.host.select_fields.iteritems():
116
            if form.get_widget(name):
117
                select[name] = form.get_widget(name).parse()
118
        return self.local_auth_check(username, password, select)
119

  
120
    def local_auth_check(self, username, password, select=None):
121
        select = select or {}
122
        status, data = self.local_auth_check_dispatch(username, password, select)
123
        if status == 0:
124
            raise
125
        success, return_content = self.check_auth(status, data)
126
        if success:
127
            if misc.get_current_protocol() == lasso.PROTOCOL_SAML_2_0:
128
                provider_id = self.host.saml2_provider_id
129
            else:
130
                provider_id = self.host.provider_id
131
            session = get_session()
132

  
133
            if hasattr(session, 'cookies'):
134
                self.federate(username, password, provider_id, session.cookies, select)
135
            else:
136
                self.federate(username, password, provider_id, None, select)
137
            return return_content
138
        raise LoginError()
139

  
140
    def local_auth_check_dispatch(self, username, password, select=None):
141
        select = select or {}
142
        if self.host.auth_mode == 'http_basic':
143
            return self.local_auth_check_http_basic(username, password)
144
        elif self.host.auth_mode == 'form' and hasattr(self.host, 'auth_check_url') \
145
                and self.host.auth_check_url is not None:
146
            return self.local_auth_check_post(username, password, select)
147
        else:
148
            raise ConfigurationError('No authentication form was found')
149

  
150
    def local_auth_check_post(self, username, password, select=None):
151
        select = select or {}
152
        url = self.host.auth_check_url
153

  
154
        # Build request body
155
        if self.host.post_parameters:
156
            body_params = {}
157
            # Login field
158
            if self.host.post_parameters[self.host.login_field_name]['enabled'] is True:
159
                body_params[self.host.login_field_name] = username
160
            # Password field
161
            if self.host.post_parameters[self.host.password_field_name]['enabled'] is True:
162
                body_params[self.host.password_field_name] = password
163
            # Select fields
164
            for name, value in select.iteritems():
165
                if self.host.post_parameters[name]['enabled'] is True:
166
                    body_params[name] = value
167
            # Other fields (hidden, submit and custom)
168
            for name, value in self.host.other_fields.iteritems():
169
                if self.host.post_parameters[name]['enabled'] is True:
170
                    body_params[name] = self.host.post_parameters[name]['value']
171
            body = urllib.urlencode(body_params)
172
        else:
173
            # XXX: Legacy (to be removed later) Send all parameters for sites configured with a previous version of Larpe
174
            body = '%s=%s&%s=%s' % (self.host.login_field_name, username, self.host.password_field_name, password)
175
            # Add select fields to the body
176
            for name, value in select.iteritems():
177
                body += '&%s=%s' % (name, value)
178
            # Add hidden fields to the body
179
            if self.host.send_hidden_fields:
180
                for name, value in self.host.other_fields.iteritems():
181
                    body += '&%s=%s' % (name, value)
182

  
183
        # Build request HTTP headers
184
        if self.host.http_headers:
185
            headers = {}
186
            if self.host.http_headers['X-Forwarded-For']['enabled'] is True:
187
                headers['X-Forwarded-For'] = get_request().get_environ('REMOTE_ADDR', '-')
188
            for name, value in self.host.http_headers.iteritems():
189
                if value['enabled'] is True and value['immutable'] is False:
190
                    headers[name] = value['value']
191
        else:
192
            # XXX: (to be removed later) Send default headers for sites configured with a previous version of Larpe
193
            headers = { 'Content-Type': 'application/x-www-form-urlencoded',
194
                        'X-Forwarded-For': get_request().get_environ('REMOTE_ADDR', '-'),
195
                        'X-Forwarded-Host': self.host.reversed_hostname }
196

  
197
        # Send request
198
        response, status, data, auth_headers = http_post_request(url, body, headers, self.host.use_proxy)
199

  
200
        cookies = response.getheader('Set-Cookie', None)
201
        self.host.cookies = []
202
        if cookies is not None:
203
            cookies_list = []
204
            cookies_set_list = []
205
            for cookie in cookies.split(', '):
206
                # Drop the path and other attributes
207
                cookie_only = cookie.split('; ')[0]
208
                regexp = re.compile('=')
209
                if regexp.search(cookie_only) is None:
210
                    continue
211
                # Split name and value
212
                cookie_split = cookie_only.split('=')
213
                cookie_name = cookie_split[0]
214
                cookie_value = cookie_split[1]
215
                cookies_list.append('%s=%s' % (cookie_name, cookie_value))
216
                set_cookie = '%s=%s; path=/' % (cookie_name, cookie_value)
217
                cookies_set_list.append(set_cookie)
218
                self.host.cookies.append(cookie_name)
219
            cookies_headers = '\r\nSet-Cookie: '.join(cookies_set_list)
220
            get_response().set_header('Set-Cookie', cookies_headers)
221
            self.host.store()
222
            get_session().cookies = '; '.join(cookies_list)
223
        else:
224
            get_logger().warn('No cookie from local authentication')
225

  
226
        return response.status, data
227

  
228
    def local_auth_check_http_basic(self, username, password):
229
        url = self.host.auth_form_url
230
        hostname, query = urllib.splithost(url[5:])
231
        conn = httplib.HTTPConnection(hostname)
232

  
233
        auth_header = 'Basic %s' % base64.encodestring('%s:%s' % (username, password))
234

  
235
        try:
236
            conn.request('GET', query, headers={'Authorization': auth_header})
237
        except socket.gaierror, err:
238
            print err
239
            conn.close()
240
            return 0, None
241
        else:
242
            response = conn.getresponse()
243
            conn.close()
244
            return response.status, response.read()
245

  
246
    def check_auth(self, status, data):
247
        success = False
248
        return_content = ''
249

  
250
        # If status is 500, fail without checking other criterias
251
        if status // 100 == 5:
252
            success = False
253
            return_content = redirect(self.host.get_return_url())
254

  
255

  
256
        # For http auth, only check status code
257
        elif self.host.auth_mode == 'http_basic':
258
            # If failed, status code should be 401
259
            if status // 100 == 2 or status // 100 == 3:
260
                success = True
261
                return_content = redirect(self.host.get_return_url())
262

  
263
        else:
264
            if self.host.auth_system == 'password':
265
                # If there is a password field, authentication probably failed
266
                regexp = re.compile("""<input[^>]*?type=["']?password["']?[^>]*?>""", re.DOTALL | re.IGNORECASE)
267
                if not regexp.findall(data):
268
                    success = True
269
                    return_content = redirect(self.host.get_return_url())
270
            elif self.host.auth_system == 'status':
271
                match_status = int(self.host.auth_match_status)
272
                if match_status == status:
273
                    success = True
274
                    return_content = redirect(self.host.get_return_url())
275
            elif self.host.auth_system == 'match_text':
276
                # If the auth_match_text is not matched, it means the authentication is successful
277
                regexp = re.compile(self.host.auth_match_text, re.DOTALL)
278
                if not regexp.findall(data):
279
                    success = True
280
                    return_content = redirect(self.host.get_return_url())
281

  
282
        return success, return_content
283

  
284
    def local_logout(self, federation=None, user=None, cookies=None):
285
        if cookies is None and federation is None and user is not None:
286
            federations = Federation.select(lambda x: user.name_identifiers[0] in x.name_identifiers)
287
            if federations:
288
                cookies = federations[0].cookies
289

  
290
        # Logout request to the site
291
        url = self.host.logout_url
292
        if url is not None and cookies is not None:
293
            try:
294
                http_get_page(url, {'Cookie': cookies})
295
            except ConnectionError, err:
296
                get_logger().warning(_("%s logout failed") % url)
297
                get_logger().debug(err)
298

  
299
        # Remove cookies from the browser
300
        # TODO: this should be removed because this only works
301
        # with a 'direct' logout
302
        if hasattr(self.host, 'cookies'):
303
            for cookie in self.host.cookies:
304
                get_response().expire_cookie(cookie, path='/')
305

  
306
    def local_defederate(self, session, provider_id):
307
        if session is None:
308
            return
309
        user = session.get_user(provider_id)
310
        if user is not None:
311
            federations = Federation.select(lambda x: user.name_identifiers[0] in x.name_identifiers)
312
            for federation in federations:
313
                self.local_logout(provider_id, federation)
314
                federation.remove_name_identifier(user.name_identifiers[0])
315
                federation.store()
316

  
317
def get_site_authentication(host):
318
    if host.site_authentication_plugin is None:
319
        return SiteAuthentication(host)
320
    return site_authentication_plugins.get(host.site_authentication_plugin)(host)
321

  
larpe/tags/release-1.1.1/larpe/users.py
1
'''User object. Configuration variables and utilities'''
2

  
3
from qommon.storage import StorableObject
4

  
5
class User(StorableObject):
6
    '''User object. Configuration variables and utilities'''
7
    _names = 'users'
8

  
9
    name = None
10
    email = None
11
    name_identifiers = None
12
    identification_token = None
13
    lasso_dumps = None
14
    is_admin = False
15
    anonymous = False
16

  
17
    def __init__(self, name=None):
18
        StorableObject.__init__(self)
19
        self.name = name
20
        self.name_identifiers = []
21
        self.lasso_dumps = []
22

  
23
    def migrate(self):
24
        pass
25

  
26
    def remove_name_identifier(self, name_identifier):
27
        self.name_identifiers.remove(name_identifier)
28
        if not self.name_identifiers:
29
            self.remove_self()
30
        else:
31
            self.store()
32

  
33
    def get_display_name(self):
34
        if self.name:
35
            return self.name
36
        if self.email:
37
            return self.email
38
        return _('Unknown User')
39
    display_name = property(get_display_name)
40

  
41
    def __str__(self):
42
        return 'User %s, name : %s, name identifiers : %s, lasso_dumps : %s, token : %s' \
43
                % (self.id, self.name, self.name_identifiers, self.lasso_dumps,
44
                   self.identification_token)
larpe/tags/release-1.1.1/larpectl
1
#!/usr/bin/python
2

  
3
import sys
4

  
5
from larpe import ctl
6

  
7
def print_usage():
8
    print 'Usage: larpectl command [...]'
9
    print ''
10
    print 'Commands:'
11
    print '  start                start server'
12
    print '  cache_modulesets     parse and cache jhbuild module sets'
13

  
14
if len(sys.argv) < 2:
15
    print_usage()
16
    sys.exit(1)
17
else:
18
    command = sys.argv[1]
19

  
20
    if command == 'start':
21
        ctl.start(sys.argv[2:])
22
    elif command == 'cache_modulesets':
23
        ctl.cache_modulesets()
24
    else:
25
        print_usage()
larpe/tags/release-1.1.1/po/Makefile
1
prefix = /usr
2

  
3
POFILES=$(wildcard *.po)
4
MOFILES=$(POFILES:.po=.mo)
5
PYFILES=$(shell find -L ../larpe -name '*.py' -or -name '*.ptl')
6
RM=rm -f
7

  
8
all: $(MOFILES)
9

  
10
install: all
11
	for file in $(MOFILES); do \
12
		lang=`echo $$file | sed 's/\.mo//'`; \
13
		install -d $(DESTDIR)$(prefix)/share/locale/$$lang/LC_MESSAGES/; \
14
		install -m 0644 $$file $(DESTDIR)$(prefix)/share/locale/$$lang/LC_MESSAGES/larpe.mo; \
15
	done
16

  
17
uninstall:
18
	@for file in $(MOFILES); do \
19
		lang=`echo $$file | sed 's/\.mo//'`; \
20
		$(RM) $(DESTDIR)$(prefix)/share/locale/$$lang/LC_MESSAGES/larpe.mo; \
21
	done
22

  
23
clean:
24
	-$(RM) messages.mo $(MOFILES)
25

  
26
larpe.pot: $(PYFILES)
27
	@echo "Rebuilding the pot file"
28
	$(RM) larpe.pot tmp.*.pot
29
	cnt=0;
30
	for file in $(PYFILES); do \
31
		cnt=$$(expr $$cnt + 1); \
32
		bn=$$cnt.`basename $$file`; \
33
		xgettext --keyword=N_ -c -L Python -o tmp.$$bn.pot $$file; \
34
	done
35
	msgcat tmp.*.pot > larpe.pot
36
	$(RM) tmp.*.pot
37

  
38
%.mo: %.po
39
	msgfmt -o $@ $<
40

  
41
%.po: larpe.pot
42
	@echo -n "Merging larpe.pot and $@"
43
	@msgmerge $@ larpe.pot -o $@.new
44
	@if [ "`diff $@ $@.new | grep '[<>]' | wc -l`" -ne 2 ]; then \
45
		mv -f $@.new $@; \
46
	else \
47
		$(RM) $@.new; \
48
	fi
49
	@msgfmt --statistics $@
larpe/tags/release-1.1.1/po/fr.po
1
msgid ""
2
msgstr ""
3
"Project-Id-Version: Larpe 0.2.0\n"
4
"Report-Msgid-Bugs-To: \n"
5
"POT-Creation-Date: 2010-07-19 13:53+0200\n"
6
"PO-Revision-Date: 2010-07-19 13:51+0100\n"
7
"Last-Translator: Jérôme Schneider <jerome.schneider@gmail.com>\n"
8
"Language-Team: French\n"
9
"Language: \n"
10
"MIME-Version: 1.0\n"
11
"Content-Type: text/plain; charset=utf-8\n"
12
"Content-Transfer-Encoding: 8bit\n"
13

  
14
#: ../larpe/idwsf2.ptl:50
15
msgid "Failed connecting to the original site."
16
msgstr "Échec de connexion au site d'origine"
17

  
18
#: ../larpe/idwsf2.ptl:61
19
msgid "Failed getting attributes from the attribute provider."
20
msgstr ""
21
"Échec lors de la récupération d'attributs depuis le fournisseur d'attributs."
22

  
23
#: ../larpe/idwsf2.ptl:64
24
msgid "Failed getting attributes for an unknown reason."
25
msgstr "Échec lors de la récupération d'attributs pour une raison inconnue"
26

  
27
#: ../larpe/liberty_site.ptl:46 ../larpe/liberty_site.ptl:56
28
msgid "SSO support is not yet configured"
29
msgstr "Le support SSO n'est pas encore configuré"
30

  
31
#: ../larpe/admin/users.ptl:24 ../larpe/admin/users.ptl:32
32
msgid "User Name"
33
msgstr "Nom de l'utilisateur"
34

  
35
#: ../larpe/admin/users.ptl:25 ../larpe/admin/users.ptl:34
36
#: ../larpe/admin/users.ptl:66
37
msgid "Email"
38
msgstr "Courriel"
39

  
40
#: ../larpe/admin/users.ptl:26 ../larpe/admin/users.ptl:36
41
#: ../larpe/admin/users.ptl:122 ../larpe/admin/forms_prefill.ptl:24
42
#: ../larpe/admin/forms_prefill.ptl:76 ../larpe/admin/settings.ptl:31
43
#: ../larpe/admin/settings.ptl:217 ../larpe/admin/settings.ptl:326
44
#: ../larpe/admin/settings.ptl:343 ../larpe/admin/fields_prefill.ptl:30
45
#: ../larpe/admin/fields_prefill.ptl:73 ../larpe/admin/hosts.ptl:384
46
#: ../larpe/admin/hosts.ptl:692 ../larpe/admin/hosts.ptl:740
47
#: ../larpe/admin/hosts.ptl:787 ../larpe/admin/hosts.ptl:1286
48
#: ../larpe/site_authentication.ptl:64 ../larpe/root.ptl:64
49
msgid "Submit"
50
msgstr "Valider"
51

  
52
#: ../larpe/admin/users.ptl:27 ../larpe/admin/users.ptl:37
53
#: ../larpe/admin/users.ptl:123 ../larpe/admin/users.ptl:138
54
#: ../larpe/admin/forms_prefill.ptl:25 ../larpe/admin/forms_prefill.ptl:77
55
#: ../larpe/admin/settings.ptl:218 ../larpe/admin/settings.ptl:327
56
#: ../larpe/admin/settings.ptl:344 ../larpe/admin/fields_prefill.ptl:31
57
#: ../larpe/admin/fields_prefill.ptl:74 ../larpe/admin/hosts.ptl:124
58
#: ../larpe/admin/hosts.ptl:385 ../larpe/admin/hosts.ptl:693
59
#: ../larpe/admin/hosts.ptl:741 ../larpe/admin/hosts.ptl:788
60
#: ../larpe/admin/hosts.ptl:1287 ../larpe/root.ptl:65
61
msgid "Cancel"
62
msgstr "Annuler"
63

  
64
#: ../larpe/admin/users.ptl:60 ../larpe/admin/users.ptl:61
65
msgid "User"
66
msgstr "Utilisateur"
67

  
68
#: ../larpe/admin/users.ptl:63 ../larpe/admin/hosts.ptl:382
69
msgid "Name"
70
msgstr "Nom"
71

  
72
#: ../larpe/admin/users.ptl:98
73
msgid "Debug"
74
msgstr "Debug"
75

  
76
#: ../larpe/admin/users.ptl:110 ../larpe/admin/forms_prefill.ptl:48
77
#: ../larpe/admin/forms_prefill.ptl:66 ../larpe/admin/forms_prefill.ptl:67
78
#: ../larpe/admin/forms_prefill.ptl:68 ../larpe/admin/fields_prefill.ptl:63
79
#: ../larpe/admin/fields_prefill.ptl:64 ../larpe/admin/fields_prefill.ptl:65
80
msgid "Edit"
81
msgstr "Modifier"
82

  
83
#: ../larpe/admin/users.ptl:111 ../larpe/admin/users.ptl:112
84
msgid "Edit User"
85
msgstr "Modifier l'utilisateur"
86

  
87
#: ../larpe/admin/users.ptl:121
88
msgid "You are about to irrevocably delete this user."
89
msgstr "Vous allez définitivement supprimer cet utilisateur."
90

  
91
#: ../larpe/admin/users.ptl:127 ../larpe/admin/forms_prefill.ptl:81
92
#: ../larpe/admin/fields_prefill.ptl:78 ../larpe/admin/hosts.ptl:1291
93
msgid "Delete"
94
msgstr "Supprimer"
95

  
96
#: ../larpe/admin/users.ptl:128
97
msgid "Delete User"
98
msgstr "Supprimer l'utilisateur"
99

  
100
#: ../larpe/admin/users.ptl:129
101
msgid "Deleting User :"
102
msgstr "Suppression de l'utilisateur :"
103

  
104
#: ../larpe/admin/users.ptl:137
105
msgid "Generate"
106
msgstr "Générer"
107

  
108
#: ../larpe/admin/users.ptl:143 ../larpe/admin/users.ptl:146
109
#: ../larpe/admin/users.ptl:147 ../larpe/admin/users.ptl:155
110
#: ../larpe/admin/users.ptl:180 ../larpe/admin/users.ptl:182
111
#: ../larpe/admin/users.ptl:223 ../larpe/root.ptl:62 ../larpe/root.ptl:71
112
msgid "Identification Token"
113
msgstr "Jeton d'identification"
114

  
115
#: ../larpe/admin/users.ptl:148
116
msgid ""
117
"You are about to generate a token than can be used to federate the account."
118
msgstr ""
119
"Vous allez générer un jeton qui pourra être utilisé pour fédérer le compte."
120

  
121
#: ../larpe/admin/users.ptl:149
122
msgid ""
123
"After that, you will have the choice to send it to the user by email so that "
124
"he can federate his accounts."
125
msgstr ""
126
"Ensuite, vous aurez la possibilité de l'envoyer à l'utilisateur par courriel "
127
"pour qu'il puisse fédérer ses comptes."
128

  
129
#: ../larpe/admin/users.ptl:151
130
#, python-format
131
msgid "Note that user has already been issued an identification token : %s"
132
msgstr "À noter que l'utilisateur a déjà un jeton d'identification : %s"
133

  
134
#: ../larpe/admin/users.ptl:161
135
#, python-format
136
msgid "Identification Token for %s"
137
msgstr "Jeton d'identification pour %s"
138

  
139
#: ../larpe/admin/users.ptl:165
140
msgid "Done"
141
msgstr "Fait"
142

  
143
#: ../larpe/admin/users.ptl:167
144
msgid "Send by email"
145
msgstr "Envoyer par courriel"
146

  
147
#: ../larpe/admin/users.ptl:173
148
#, python-format
149
msgid ""
150
"You have been given an identification token.\n"
151
"\n"
152
"Your token is %(token)s\n"
153
"\n"
154
"Click on %(url)s to use it.\n"
155
msgstr ""
156
"Un jeton d'identification vous a été attribué.\n"
157
"\n"
158
"Votre jeton est %(token)s\n"
159
"\n"
160
"Cliquez sur %(url)s pour l'utiliser.\n"
161

  
162
#: ../larpe/admin/users.ptl:183
163
msgid "Failed sending email. Check your email configuration."
164
msgstr ""
165
"Échec de l'envoi du courriel. Vérifiez votre configuration des courriels."
166

  
167
#: ../larpe/admin/users.ptl:184 ../larpe/admin/settings.ptl:112
168
#: ../larpe/admin/hosts.ptl:657 ../larpe/admin/hosts.ptl:713
169
#: ../larpe/admin/hosts.ptl:1340
170
msgid "Back"
171
msgstr "Retour"
172

  
173
#: ../larpe/admin/users.ptl:194 ../larpe/admin/users.ptl:195
174
#: ../larpe/admin/users.ptl:238 ../larpe/admin/users.ptl:272
175
#: ../larpe/admin/root.ptl:45
176
msgid "Users"
177
msgstr "Utilisateurs"
178

  
179
#: ../larpe/admin/users.ptl:199 ../larpe/admin/users.ptl:242
180
msgid "Liberty support must be setup before creating users."
181
msgstr ""
182
"Le support Liberty doit être configuré avant de créer des utilisateurs."
183

  
184
#: ../larpe/admin/users.ptl:203 ../larpe/admin/users.ptl:254
185
#: ../larpe/admin/users.ptl:255
186
msgid "New User"
187
msgstr "Nouvel utilisateur"
188

  
189
#: ../larpe/admin/users.ptl:226
190
#, python-format
191
msgid "Identification Token (current: %s)"
192
msgstr "Jeton d'identification (actuellement: %s)"
193

  
194
#: ../larpe/admin/users.ptl:233 ../larpe/admin/root.ptl:47
195
msgid "Logs"
196
msgstr "Journaux"
197

  
198
#: ../larpe/admin/users.ptl:239 ../larpe/admin/forms_prefill.ptl:122
199
#: ../larpe/admin/fields_prefill.ptl:125 ../larpe/admin/hosts.ptl:1344
200
msgid "New"
201
msgstr "Nouveau"
202

  
203
#: ../larpe/admin/forms_prefill.ptl:16
204
msgid "Form name"
205
msgstr "Nom du formulaire"
206

  
207
#: ../larpe/admin/forms_prefill.ptl:17
208
msgid "Only used for display"
209
msgstr "Utilisé uniquement pour l'affichage"
210

  
211
#: ../larpe/admin/forms_prefill.ptl:18
212
msgid "Form address"
213
msgstr "Addresse du formulaire"
214

  
215
#: ../larpe/admin/forms_prefill.ptl:20
216
msgid "ID-WSF data profile"
217
msgstr "Profile des données ID-WSF"
218

  
219
#: ../larpe/admin/forms_prefill.ptl:21
220
msgid "Example: urn:liberty:id-sis-pp:2005-05"
221
msgstr "Exemple : urn:liberty:id-sis-pp:2005-05"
222

  
223
#: ../larpe/admin/forms_prefill.ptl:22
224
msgid "ID-WSF data XML prefix"
225
msgstr "Préfixe XML des données ID-WSF"
226

  
227
#: ../larpe/admin/forms_prefill.ptl:23
228
msgid "Example: pp"
229
msgstr "Exemple : pp"
230

  
231
#: ../larpe/admin/forms_prefill.ptl:45
232
msgid "Form prefilling configuration"
233
msgstr "Configuration du pré-remplissage de formulaire"
234

  
235
#: ../larpe/admin/forms_prefill.ptl:48
236
msgid "Configure this form"
237
msgstr "Configurer ce formulaire"
238

  
239
#: ../larpe/admin/forms_prefill.ptl:50 ../larpe/admin/fields_prefill.ptl:91
240
#: ../larpe/admin/fields_prefill.ptl:98
241
msgid "Fields"
242
msgstr "Champs"
243

  
244
#: ../larpe/admin/forms_prefill.ptl:50
245
msgid "Configure the fields of this form"
246
msgstr "Configurer les champs de ce formulaire"
247

  
248
#: ../larpe/admin/forms_prefill.ptl:75
249
msgid "You are about to irrevocably delete this form."
250
msgstr "Vous allez définitivement supprimer ce fomulaire."
251

  
252
#: ../larpe/admin/forms_prefill.ptl:82 ../larpe/admin/forms_prefill.ptl:83
253
msgid "Delete Form"
254
msgstr "Supprimer le formulaire"
255

  
256
#: ../larpe/admin/forms_prefill.ptl:94 ../larpe/admin/forms_prefill.ptl:101
257
#: ../larpe/admin/hosts.ptl:1279
258
msgid "Forms"
259
msgstr "Formulaires"
260

  
261
#: ../larpe/admin/forms_prefill.ptl:104
262
msgid "New Form"
263
msgstr "Nouveau formulaire"
264

  
265
#: ../larpe/admin/settings.ptl:28
266
msgid "Metadata"
267
msgstr "Méta-données"
268

  
269
#: ../larpe/admin/settings.ptl:29
270
msgid "Public Key"
271
msgstr "Clé publique"
272

  
273
#: ../larpe/admin/settings.ptl:30
274
msgid "CA Certificate Chain"
275
msgstr "Chaîne de certification"
276

  
277
#: ../larpe/admin/settings.ptl:34 ../larpe/admin/settings.ptl:35
278
msgid "New Identity Provider"
279
msgstr "Nouveau fournisseur d'identité"
280

  
281
#: ../larpe/admin/settings.ptl:53 ../larpe/admin/settings.ptl:87
282
msgid "Bad metadata"
283
msgstr "Mauvaises méta-données"
284

  
285
#. Don't use custom emails
286
#: ../larpe/admin/settings.ptl:104 ../larpe/admin/settings.ptl:105
287
#: ../larpe/admin/settings.ptl:192
288
msgid "Emails"
289
msgstr "Courriels"
290

  
291
#: ../larpe/admin/settings.ptl:108
292
msgid "General Options"
293
msgstr "Options générales"
294

  
295
#: ../larpe/admin/settings.ptl:125 ../larpe/admin/hosts.ptl:84
296
#: ../larpe/admin/root.ptl:46
297
msgid "Settings"
298
msgstr "Paramètres"
299

  
300
#: ../larpe/admin/settings.ptl:128
301
msgid "Liberty Alliance & SAML 2.0 Service Provider"
302
msgstr "Fournisseur de service Liberty Alliance et SAML 2.0"
303

  
304
#: ../larpe/admin/settings.ptl:130
305
msgid "Liberty Alliance Service Provider"
306
msgstr "Fournisseur de service Liberty Alliance"
307

  
308
#: ../larpe/admin/settings.ptl:132
309
msgid "Service Provider"
310
msgstr "Fournisseur de service"
311

  
312
#: ../larpe/admin/settings.ptl:132
313
msgid "Configure Larpe as a Service Provider"
314
msgstr "Configurer Larpe en tant que fournisseur de service"
315

  
316
#: ../larpe/admin/settings.ptl:142 ../larpe/admin/hosts.ptl:913
317
msgid "SAML 2.0 Metadata"
318
msgstr "Méta-données SAML 2.0"
319

  
320
#: ../larpe/admin/settings.ptl:143
321
msgid "Download SAML 2.0 metadata file for Larpe"
322
msgstr "Télécharger le fichier des méta-données SAML 2.0 pour Larpe"
323

  
324
#: ../larpe/admin/settings.ptl:149 ../larpe/admin/hosts.ptl:918
325
msgid "ID-FF 1.2 Metadata"
326
msgstr "Méta-données ID-FF 1.2"
327

  
328
#: ../larpe/admin/settings.ptl:150
329
msgid "Download ID-FF 1.2 metadata file for Larpe"
330
msgstr "Télécharger le fichier des méta-données ID-FF 1.2 pour Larpe"
331

  
332
#: ../larpe/admin/settings.ptl:156 ../larpe/admin/hosts.ptl:927
333
msgid "Public key"
334
msgstr "Clé publique"
335

  
336
#: ../larpe/admin/settings.ptl:157 ../larpe/admin/hosts.ptl:928
337
msgid "Download SSL Public Key file"
338
msgstr "Télécharger le fichier de clé SSL publique"
339

  
340
#: ../larpe/admin/settings.ptl:160
341
msgid "Liberty Alliance & SAML 2.0 Identity Provider"
342
msgstr "Fournisseur d'identité Liberty Alliance et SAML 2.0"
343

  
344
#: ../larpe/admin/settings.ptl:162
345
msgid "Liberty Alliance Identity Provider"
346
msgstr "Fournisseur d'identité Liberty Alliance"
347

  
348
#: ../larpe/admin/settings.ptl:167
349
msgid "Identity Provider"
350
msgstr "Fournisseur d'identité"
351

  
352
#: ../larpe/admin/settings.ptl:167
353
msgid "Configure an identity provider"
354
msgstr "Configurer un fournisseur d'identité"
355

  
356
#: ../larpe/admin/settings.ptl:171
357
msgid "Identity Provider metadatas"
358
msgstr "Méta-données du fournisseur d'identité"
359

  
360
#: ../larpe/admin/settings.ptl:171
361
msgid "See current identity provider metadatas"
362
msgstr "Voir les méta-données du fournisseur d'identité actuel"
363

  
364
#: ../larpe/admin/settings.ptl:175
365
msgid "Global parameters for the sites"
366
msgstr "Paramètres globaux des sites"
367

  
368
#: ../larpe/admin/settings.ptl:179 ../larpe/admin/settings.ptl:302
369
#: ../larpe/admin/settings.ptl:303
370
msgid "Domain name"
371
msgstr "Nom de domaine"
372

  
373
#: ../larpe/admin/settings.ptl:179
374
msgid "Configure the base domain name for the sites"
375
msgstr "Configurer le nom de domaine de base pour les sites"
376

  
377
#: ../larpe/admin/settings.ptl:181 ../larpe/admin/settings.ptl:348
378
#: ../larpe/admin/settings.ptl:349
379
msgid "Apache 2 configuration generation"
380
msgstr "Génération de la configuration d'Apache 2"
381

  
382
#: ../larpe/admin/settings.ptl:181
383
msgid "Customise Apache 2 configuration generation"
384
msgstr "Personnaliser la génération de la configuration d'Apache 2"
385

  
386
#: ../larpe/admin/settings.ptl:183
387
msgid "Proxy"
388
msgstr "Mandataire (proxy)"
389

  
390
#: ../larpe/admin/settings.ptl:183
391
msgid "Connect to the sites through a web proxy"
392
msgstr "Se connecter aux sites en passant par un mandataire (proxy)"
393

  
394
#: ../larpe/admin/settings.ptl:186
395
msgid "Customisation"
396
msgstr "Personnalisation"
397

  
398
#: ../larpe/admin/settings.ptl:190
399
msgid "Language"
400
msgstr "Langue"
401

  
402
#: ../larpe/admin/settings.ptl:190
403
msgid "Configure site language"
404
msgstr "Configurer la langue du site"
405

  
406
#: ../larpe/admin/settings.ptl:192
407
msgid "Configure email settings"
408
msgstr "Configurer les paramètres des courriels"
409

  
410
#: ../larpe/admin/settings.ptl:195
411
msgid "Misc"
412
msgstr "Divers"
413

  
414
#: ../larpe/admin/settings.ptl:199
415
msgid "Debug Options"
416
msgstr "Options de débogage"
417

  
418
#: ../larpe/admin/settings.ptl:199
419
msgid "Configure options useful for debugging"
420
msgstr "Configurer les options utiles au debogage"
421

  
422
#: ../larpe/admin/settings.ptl:215
423
msgid "Organisation Name"
424
msgstr "Nom de l'organisation"
425

  
426
#: ../larpe/admin/settings.ptl:222 ../larpe/admin/settings.ptl:223
427
msgid "Service Provider Configuration"
428
msgstr "Configuration du fournisseur d'identité"
429

  
430
#: ../larpe/admin/settings.ptl:318
431
msgid "Domain name for the sites"
432
msgstr "Noms de domaine pour les sites"
433

  
434
#. TODO: Add the option "Both" and handle it in hosts configuration
435
#: ../larpe/admin/settings.ptl:321
436
msgid "Use HTTP or HTTPS"
437
msgstr "Utiliser HTTP ou HTTPS"
438

  
439
#: ../larpe/admin/settings.ptl:323
440
msgid "Same as the site"
441
msgstr "Identique au site d'origine"
442

  
443
#: ../larpe/admin/settings.ptl:341
444
msgid ""
445
"Automatically generate Apache 2 configuration for new hosts and reload "
446
"Apache 2 after changes"
447
msgstr ""
448
"Générer automatiquement la configuration Apache 2 pour les nouveaux hôtes et "
449
"recharger Apache 2 après les changements"
450

  
451
#: ../larpe/admin/fields_prefill.ptl:15
452
msgid "Field name"
453
msgstr "Nom du champ"
454

  
455
#: ../larpe/admin/fields_prefill.ptl:17
456
msgid "Xpath of the attribute"
457
msgstr "Xpath de l'attribut"
458

  
459
#: ../larpe/admin/fields_prefill.ptl:18
460
msgid "Example: /pp:PP/pp:InformalName"
461
msgstr "Exemple : /pp:PP/pp:InformalName"
462

  
463
#: ../larpe/admin/fields_prefill.ptl:19
464
msgid "Number of the field in the data"
465
msgstr "Numéro du champ dans les données"
466

  
467
#: ../larpe/admin/fields_prefill.ptl:21
468
msgid ""
469
"Change it if there are multiple fields corresponding to the same Xpath and "
470
"you want to get another than the first one"
471
msgstr ""
472
"À changer s'il existe plusieurs champs correspondants au même Xpath et que "
473
"vous voulez obtenir un autre élément que le premier"
474

  
475
#: ../larpe/admin/fields_prefill.ptl:22
476
msgid "Get raw XML value"
477
msgstr "Récupérer la valeur XML brute"
478

  
479
#: ../larpe/admin/fields_prefill.ptl:24
480
msgid "Python regexp of a string to match"
481
msgstr ""
482
"Expression régulière en Python correspondant à la chaîne de caractères à "
483
"chercher"
484

  
485
#: ../larpe/admin/fields_prefill.ptl:26
486
msgid "Python regexp of the replacing string"
487
msgstr ""
488
"Expression régulière en Python de la chaîne de caractères de remplacement"
489

  
490
#: ../larpe/admin/fields_prefill.ptl:28
491
msgid "Options mapping for a select field"
492
msgstr "Correspondance d'options pour un champ select"
493

  
494
#: ../larpe/admin/fields_prefill.ptl:29
495
msgid "Add item"
496
msgstr "Ajouter un élément"
497

  
498
#: ../larpe/admin/fields_prefill.ptl:72
499
msgid "You are about to irrevocably delete this field."
500
msgstr "Vous allez définitivement supprimer ce champ."
501

  
502
#: ../larpe/admin/fields_prefill.ptl:79 ../larpe/admin/fields_prefill.ptl:80
503
msgid "Delete Field"
504
msgstr "Supprimer le champ"
505

  
506
#: ../larpe/admin/fields_prefill.ptl:101
507
msgid "New Field"
508
msgstr "Nouveau champ"
509

  
510
#: ../larpe/admin/hosts.ptl:33
511
msgid ""
512
"You must either choose a different hostname from Larpe or specify a reversed "
513
"directory"
514
msgstr ""
515
"Vous devez soit choisir un nom d'hôte différent de celui de Larpe, soit "
516
"spécifier un répertoire inversé"
517

  
518
#: ../larpe/admin/hosts.ptl:80 ../larpe/admin/hosts.ptl:102
519
msgid "Basic configuration"
520
msgstr "Configuration de base"
521

  
522
#: ../larpe/admin/hosts.ptl:81
523
msgid "Need domain name configuration"
524
msgstr "Nécessite la configuration du nom de domaine"
525

  
526
#: ../larpe/admin/hosts.ptl:82
527
#, python-format
528
msgid ""
529
"Before configuring hosts, you must\n"
530
"<a href=\"../../../settings/domain_names\">setup a global domain name</a> "
531
"in\n"
532
"%(settings)s menu."
533
msgstr ""
534
"Avant des configurer les sites, vous devez <a href=\"../../../settings/"
535
"domain_names\">définir un nom de domaine global</a> dans le menu "
536
"%(settings)s."
537

  
538
#: ../larpe/admin/hosts.ptl:103
539
msgid "Step 1 - Basic configuration"
540
msgstr "Étape 1 - Configuration de base"
541

  
542
#: ../larpe/admin/hosts.ptl:112
543
msgid "Original site root address"
544
msgstr "Adresse racine du site d'origine"
545

  
546
#: ../larpe/admin/hosts.ptl:114
547
msgid ""
548
"If your site address is http://test.org/index.php, put http://test.org/ here"
549
msgstr ""
550
"Si l'adresse de votre site est http://test.org/index.php, mettez http://test."
551
"org/ ici"
552

  
553
#: ../larpe/admin/hosts.ptl:117
554
msgid "Use a proxy"
555
msgstr "Utiliser un mandataire (proxy)"
556

  
557
#: ../larpe/admin/hosts.ptl:118
558
msgid ""
559
"Uncheck it if Larpe doesn't need to use the proxy to connect to this site"
560
msgstr ""
561
"Décocher cette case si Larpe ne doit pas utiliser un mandataire (proxy) pour "
562
"se connecter à ce site"
563

  
564
#: ../larpe/admin/hosts.ptl:122
565
msgid ""
566
"If Larpe needs to use a proxy to connect to this site, you must first "
567
"configure\n"
568
" it in <a href=\"../../../settings/proxy\">global proxy parameters</a>."
569
msgstr ""
570
"Si Larpe doit utiliser un mandataire (proxy) pour se connecter à ce site, "
571
"vous devez d'abord le configurer dans les <a href=\"../../../settings/proxy"
572
"\">paramètres globaux du mandataire</a>."
573

  
574
#: ../larpe/admin/hosts.ptl:125 ../larpe/admin/hosts.ptl:315
575
#: ../larpe/admin/hosts.ptl:343 ../larpe/admin/hosts.ptl:433
576
#: ../larpe/admin/hosts.ptl:464 ../larpe/admin/hosts.ptl:547
577
#: ../larpe/admin/hosts.ptl:583 ../larpe/admin/hosts.ptl:873
578
#: ../larpe/admin/hosts.ptl:889 ../larpe/admin/hosts.ptl:947
579
#: ../larpe/admin/hosts.ptl:977
580
msgid "Next"
581
msgstr "Suivant"
582

  
583
#: ../larpe/admin/hosts.ptl:126 ../larpe/admin/hosts.ptl:316
584
#: ../larpe/admin/hosts.ptl:434 ../larpe/admin/hosts.ptl:465
585
#: ../larpe/admin/hosts.ptl:548 ../larpe/admin/hosts.ptl:584
586
#: ../larpe/admin/hosts.ptl:874 ../larpe/admin/hosts.ptl:890
587
#: ../larpe/admin/hosts.ptl:978
588
msgid "Terminate"
589
msgstr "Terminer"
590

  
591
#: ../larpe/admin/hosts.ptl:314 ../larpe/admin/hosts.ptl:343
592
#: ../larpe/admin/hosts.ptl:432 ../larpe/admin/hosts.ptl:463
593
#: ../larpe/admin/hosts.ptl:546 ../larpe/admin/hosts.ptl:582
594
#: ../larpe/admin/hosts.ptl:872 ../larpe/admin/hosts.ptl:888
595
#: ../larpe/admin/hosts.ptl:976 ../larpe/admin/hosts.ptl:1002
596
msgid "Previous"
597
msgstr "Précédent"
598

  
599
#: ../larpe/admin/hosts.ptl:332
600
msgid "Check site address and name"
601
msgstr "Vérifier l'adresse et le nom du site"
602

  
603
#: ../larpe/admin/hosts.ptl:333
604
msgid "Step 2 - Check the new site address works"
605
msgstr "Étape 2 - Vérifier que la nouvelle adresse du site fonctionne"
606

  
607
#: ../larpe/admin/hosts.ptl:335
608
msgid "DNS configuration"
609
msgstr "Configuration DNS"
610

  
611
#: ../larpe/admin/hosts.ptl:337
612
msgid ""
613
"Before opening the following link, ensure you have configured your DNS\n"
614
"for this address. If you don't have a DNS server and you just want to test "
615
"Larpe, add this\n"
616
"domain name in the file \"/etc/hosts\"."
617
msgstr ""
618
"Avant d'ouvrir le lien suivant, assurez vous d'avoir configuré votre DNS "
619
"pour cette adresse. Si vous n'avez pas de serveur DNS et que vous souhaitez "
620
"seulement tester Larpe, ajoutez ce nom de domaine dans le fichier \"/etc/"
621
"hosts\"."
622

  
623
#: ../larpe/admin/hosts.ptl:341
624
#, python-format
625
msgid ""
626
"Then you can open this link in a new window or tab and see if your site\n"
627
"is displayed. If it's ok, you can click the \"%(next)s\" button. Otherwise, "
628
"click the \"%(previous)s\"\n"
629
"button and check your settings."
630
msgstr ""
631
"Vous pouvez ensuite ouvrir ce lien dans une nouvelle fenêtre ou un nouvel "
632
"onglet et voir si votre site est affiché. Si cela fonctionne, vous pouvez "
633
"cliquer sur le bouton \"%(next)s\". Sinon, cliquez sur le bouton"
634
"\"%(previous)s\" et vérifiez vos paramètres."
635

  
636
#: ../larpe/admin/hosts.ptl:345
637
msgid "Site adress and name"
638
msgstr "Adresse et nom du site"
639

  
640
#: ../larpe/admin/hosts.ptl:347
641
msgid "The new address of this site is "
642
msgstr "La nouvelle adresse du site est "
643

  
644
#: ../larpe/admin/hosts.ptl:349
645
#, python-format
646
msgid "The name of this site is \"%s\"."
647
msgstr "Le nom du site est \"%s\"."
648

  
649
#: ../larpe/admin/hosts.ptl:350
650
msgid ""
651
"You can also <a href=\"modify_site_address_and_name\">\n"
652
"modify the address or the name of this site</a>"
653
msgstr ""
654
"Vous pouvez aussi <a href=\"modify_site_address_and_name\">modifier "
655
"l'adresse ou le nom du site</a>"
656

  
657
#: ../larpe/admin/hosts.ptl:366
658
msgid "An host with the same name already exists"
659
msgstr "Un hôte avec le même nom existe déjà"
660

  
661
#: ../larpe/admin/hosts.ptl:373 ../larpe/admin/hosts.ptl:374
662
msgid "Modify site address and name"
663
msgstr "Modifier l'adresse et le nom du site"
664

  
665
#: ../larpe/admin/hosts.ptl:380
666
msgid "Address"
667
msgstr "Adresse"
668

  
669
#: ../larpe/admin/hosts.ptl:419
670
msgid "Authentication and logout"
671
msgstr "Authentification et déconnexion"
672

  
673
#: ../larpe/admin/hosts.ptl:420
674
msgid "Step 3 - Configure authentication and logout pages"
675
msgstr "Étape 3 - Configurer les pages d'authentification et de déconnexion"
676

  
677
#: ../larpe/admin/hosts.ptl:426 ../larpe/admin/hosts.ptl:969
678
msgid "Authentication form page address"
679
msgstr "Adresse de la page du formulaire d'authentification"
680

  
681
#: ../larpe/admin/hosts.ptl:427
682
msgid "Address of a page on the site which contains the authentication form"
683
msgstr "Adresse d'une page du site contenant le formulaire d'authentification"
684

  
685
#: ../larpe/admin/hosts.ptl:429
686
msgid "Logout address"
687
msgstr "Adresse de déconnexion"
688

  
689
#: ../larpe/admin/hosts.ptl:430
690
msgid "Address of the logout link on the site"
691
msgstr "Adresse du lien de déconnexion du site"
692

  
693
#: ../larpe/admin/hosts.ptl:446
694
msgid "(computed automatically)"
695
msgstr "(calculé automatiquement)"
696

  
697
#: ../larpe/admin/hosts.ptl:459
698
msgid "Plugin"
699
msgstr "Extension"
700

  
701
#: ../larpe/admin/hosts.ptl:460
702
msgid "You can force a plugin"
703
msgstr "Vous pouvez forcer une extension"
704

  
705
#: ../larpe/admin/hosts.ptl:478
706
msgid "Auto detected configuration"
707
msgstr "Configuration détectée automatiquement"
708

  
709
#: ../larpe/admin/hosts.ptl:479
710
msgid ""
711
"Step 4 - Check automatically detected configuration for the authentication "
712
"form"
713
msgstr ""
714
"Étape 4 - Vérifier la configuration détectée automatiquement pour "
715
"l'authentification"
716

  
717
#: ../larpe/admin/hosts.ptl:482
718
msgid "Address where the authentication form must be sent"
719
msgstr "Adresse à laquelle le formulaire d'authentification doit être envoyé"
720

  
721
#: ../larpe/admin/hosts.ptl:483
722
msgid "Name of the login field"
723
msgstr "Nom du champ identifiant"
724

  
725
#: ../larpe/admin/hosts.ptl:484
726
msgid "Name of the password field"
727
msgstr "Nom du champ mot de passe"
728

  
729
#: ../larpe/admin/hosts.ptl:503
730
msgid ""
731
"The following authentication form parameters have been detected. If they "
732
"look right, you can go to the next step.\n"
733
"If you think they are wrong, go back and check your settings then try "
734
"again.\n"
735
msgstr ""
736
"Les paramètres d'authentification suivants ont été détectés. Si ils semblent "
737
"corrects, vous pouvez passer à l'étape suivante.\n"
738
"Si vous pensez qu'ils sont incorrects, retournez à l'étape précédente et "
739
"vérifiez vos paramètres, puis essayez à nouveau.\n"
740

  
741
#: ../larpe/admin/hosts.ptl:508
742
msgid ""
743
"The following authentication form parameters in red haven't been correctly "
744
"detected. Go back and check\n"
745
"your settings then try again.\n"
746
msgstr ""
747
"Les paramètres d'authentification suivants en rouge n'ont pas été détectés "
748
"correctement. Retournez à une étape précédente vérifiez vos paramètres, puis "
749
"essayez à nouveau.\n"
750

  
751
#: ../larpe/admin/hosts.ptl:529 ../larpe/admin/hosts.ptl:1250
752
msgid "Credentials"
753
msgstr "Identifiant et mot de passe"
754

  
755
#: ../larpe/admin/hosts.ptl:530
756
msgid "Step 5 - Fill in a valid username/password for this site"
757
msgstr "Étape 5 - Nom d'utilisateur et mot de passe pour ce site"
758

  
759
#: ../larpe/admin/hosts.ptl:535 ../larpe/site_authentication.ptl:98
760
msgid "Username"
761
msgstr "Identifiant"
762

  
763
#: ../larpe/admin/hosts.ptl:537 ../larpe/site_authentication.ptl:100
764
msgid "Password"
765
msgstr "Mot de passe"
766

  
767
#: ../larpe/admin/hosts.ptl:594
768
msgid "Check authentication"
769
msgstr "Vérifier l'authentification"
770

  
771
#: ../larpe/admin/hosts.ptl:595
772
msgid "Step 6 - Check the authentication process"
773
msgstr "Étape 6 - Vérifier la procédure d'authentification"
774

  
775
#: ../larpe/admin/hosts.ptl:614
776
msgid "Authentication succeeded ! You can go to the next step."
777
msgstr ""
778
"L'authentification a réussi ! Vous pouvez continuer à l'étape suivante."
779

  
780
#: ../larpe/admin/hosts.ptl:616
781
msgid "Authentication has failed. To resolve this problem, you can :"
782
msgstr "L'authentification a échoué. Pour résoudre ce problème, vous pouvez :"
783

  
784
#: ../larpe/admin/hosts.ptl:619
785
msgid "Try authentication again"
786
msgstr "Retenter une authentification"
787

  
788
#: ../larpe/admin/hosts.ptl:621
789
msgid "See the response of the authentication requests"
790
msgstr "Voir la réponse de la requête d'authentification"
791

  
792
#: ../larpe/admin/hosts.ptl:623 ../larpe/admin/hosts.ptl:705
793
msgid "Modify the parameters of the authentication requests"
794
msgstr "Modifier les paramètres des requêtes d'authentification"
795

  
796
#: ../larpe/admin/hosts.ptl:625
797
msgid "Change the way Larpe detects the authentication is successful or not"
798
msgstr ""
799
"Changer la façon donc Larpe détecte que l'authentification a réussi ou pas"
800

  
801
#: ../larpe/admin/hosts.ptl:626
802
msgid "Go back and change your username and/or password"
803
msgstr "Revenir en arrière et changer vos nom d'utilisateur et/ou mot de passe"
804

  
805
#: ../larpe/admin/hosts.ptl:632 ../larpe/admin/hosts.ptl:633
806
msgid "Authentication response"
807
msgstr "Réponse de l'authentification"
808

  
809
#: ../larpe/admin/hosts.ptl:635
810
msgid "Response of the request with good credentials"
811
msgstr "Réponse de la requête avec un bon couple identifiant/mot de passe"
812

  
813
#: ../larpe/admin/hosts.ptl:638 ../larpe/admin/hosts.ptl:649
814
msgid "HTTP status code"
815
msgstr "Code de status HTTP"
816

  
817
#: ../larpe/admin/hosts.ptl:643 ../larpe/admin/hosts.ptl:654
818
msgid "See HTML page"
819
msgstr "Voir la page HTML"
820

  
821
#: ../larpe/admin/hosts.ptl:646
822
msgid "Response of the request with bad credentials"
823
msgstr "Réponse de la requête avec un mauvais couple identifiant/mot de passe"
824

  
825
#: ../larpe/admin/hosts.ptl:675 ../larpe/admin/hosts.ptl:676
826
msgid "Authentication success criteria"
827
msgstr "Critères de succès de l'authentification"
828

  
829
#: ../larpe/admin/hosts.ptl:682
830
msgid "Authentication system of the original site"
831
msgstr "Système d'authentification du site d'origine"
832

  
833
#: ../larpe/admin/hosts.ptl:684
834
msgid "Check the existence of a password field"
835
msgstr "Vérifier l'existence d'un champ mot de passe"
836

  
837
#: ../larpe/admin/hosts.ptl:685
838
msgid "Match some text to detect an authentication failure"
839
msgstr "Trouver du texte pour détecter un échec d'authentification"
840

  
841
#: ../larpe/admin/hosts.ptl:690
842
msgid "Text to match in case of authentication failure"
843
msgstr "Texte à trouver dans le cas d'un échec d'authentification"
844

  
845
#: ../larpe/admin/hosts.ptl:704
846
msgid "Authentication request"
847
msgstr "Requête d'authentification"
848

  
849
#: ../larpe/admin/hosts.ptl:709
850
msgid "Modify POST parameters"
851
msgstr "Modifier les parameters du POST"
852

  
853
#: ../larpe/admin/hosts.ptl:709
854
msgid ""
855
"Configure the form attributes that will be sent within the authentication "
856
"POST requests"
857
msgstr ""
858
"Configurer les attributes du formulaire qui seront envoyés dans les requêtes "
859
"POST d'authentification"
860

  
861
#: ../larpe/admin/hosts.ptl:711
862
msgid "Modify HTTP headers"
863
msgstr "Modifier les entêtes HTTP"
864

  
865
#: ../larpe/admin/hosts.ptl:711
866
msgid "Configure the HTTP headers of the authentication requests made by Larpe"
867
msgstr ""
868
"Configurer les entêtes HTTP des requêtes d'authentification envoyées par "
869
"Larpe"
870

  
871
#: ../larpe/admin/hosts.ptl:725
872
msgid "POST parameters"
873
msgstr "Paramètres POST"
874

  
875
#: ../larpe/admin/hosts.ptl:726
876
msgid "Configure POST parameters"
877
msgstr "Configurer les paramètres POST"
878

  
879
#: ../larpe/admin/hosts.ptl:728
880
msgid ""
881
"Here are the detected form fields that will be sent as parameters of the\n"
882
"authentication POST request. You can desactivate some or all of them, or "
883
"change their value."
884
msgstr ""
885
"Voici les champs du formulaire détectés et qui seront envoyés en tant que "
886
"paramètres de la requête POST\n"
887
"d'authentification. Vous pouvez désactiver certains ou tous ces champs, ou "
888
"modifier leur valeur."
889

  
890
#: ../larpe/admin/hosts.ptl:766
891
msgid "HTTP headers"
892
msgstr "Entêtes HTTP"
893

  
894
#: ../larpe/admin/hosts.ptl:767
895
msgid "Configure HTTP headers"
896
msgstr "Configurer les entêtes HTTP"
897

  
898
#: ../larpe/admin/hosts.ptl:769
899
msgid ""
900
"Here are the HTTP headers that will be sent within the authentication\n"
901
"POST request. You can desactivate some or all of them, or change their value."
902
msgstr ""
903
"Voici les entêtes HTTP qui seront envoyés dans la requête POST\n"
904
"d'authentification. Vous pouvez désactiver certains ou tous ces champs, ou "
905
"modifier leur valeur."
906

  
907
#: ../larpe/admin/hosts.ptl:782
908
msgid ""
909
"The headers \"Host\", \"Accept-Encoding\" and \"Content-Length\" will also "
910
"automatically be sent."
911
msgstr ""
912
"Les entêtes \"Host\", \"Accept-Encoding\" et \"Content-Length\" seront "
913
"également envoyées automatiquement."
914

  
915
#: ../larpe/admin/hosts.ptl:785
916
msgid ""
917
"As Larpe uses a proxy for this site, the headers \"Proxy-Authorization\",\n"
918
"\"Proxy-Connection\" and \"Keep-Alive\" will be sent as well."
919
msgstr ""
920
"Comme Larpe utilise un mandataire (proxy) pour ce site, les entêtes\"Proxy-"
921
"Authorization\", \"Proxy-Connection\" et \"Keep-Alive\" seront aussienvoyées."
922

  
923
#: ../larpe/admin/hosts.ptl:846
924
msgid "SSO initiation"
925
msgstr "Initiation de l'authentification unique"
926

  
927
#: ../larpe/admin/hosts.ptl:847
928
msgid "Step 7 - Configure how a Single Sign On can be initiated"
929
msgstr ""
930
"Étape 7 - Configurer la façon dont l'authentification unique peut être "
931
"initiée"
932

  
933
#: ../larpe/admin/hosts.ptl:849
934
msgid ""
935
"Most sites use one of the following 2 ways to allow users to initialise an "
936
"authentication :"
937
msgstr ""
938
"La plupart des sites utilisent une des 2 méthodes suivantes pour permettre "
939
"aux utilisateursd'initier une authentification :"
940

  
941
#: ../larpe/admin/hosts.ptl:852
942
msgid ""
943
"The site has a single authentication page. It redirects users to this page "
944
"when\n"
945
"they click a \"Login\" button or try to access a page which require users to "
946
"be authenticated."
947
msgstr ""
948
"Le site a une page unique d'authentification. Il redirige les utilisateurs "
949
"vers cettepas lorsqu'ils cliquent sur un bouton \"Connexion\" ou essaient "
950
"d'accéder à une pagequi nécessitent que les utilisateurs soient authentifiés"
951

  
952
#: ../larpe/admin/hosts.ptl:855
953
msgid ""
954
"The site includes an authentication form in most or all of his pages. Users "
955
"can\n"
956
"authenticate on any of these pages, and don't need to be redirected to a "
957
"separate authentication page."
958
msgstr ""
959
"Le site inclut un formulaire d'authentification dans toutes ou la plupart de "
960
"ses pages.Les utilisateurs peuvent s'authentifier sur n'importe laquelle de "
961
"ces pages, et n'ont pasbesoin d'être redirigés vers une page "
962
"d'authentification séparée"
963

  
964
#: ../larpe/admin/hosts.ptl:860
965
msgid "Select the way your site works :"
966
msgstr "Sélectionner la façon dont votre site fonctionne :"
967

  
968
#: ../larpe/admin/hosts.ptl:868
969
msgid "The site has a single authentication page"
970
msgstr "Le site a une page d'authentification séparée"
971

  
972
#: ../larpe/admin/hosts.ptl:869
973
msgid "The site includes an authentication form in most or all pages"
974
msgstr ""
975
"Le site inclut un formulaire d'authentification imbriqué dans les pages"
976

  
977
#: ../larpe/admin/hosts.ptl:900
978
msgid "Metadatas"
979
msgstr "Méta-données"
980

  
981
#: ../larpe/admin/hosts.ptl:901
982
#, python-format
983
msgid "Step 8 - Metadatas of %(site_name)s"
984
msgstr "Étape 8- Méta-données de %(site_name)s"
985

  
986
#: ../larpe/admin/hosts.ptl:904
987
msgid ""
988
"Download the metadatas and the public key for this site and\n"
989
"upload them on your identity provider in order to use Liberty Alliance "
990
"features."
991
msgstr ""
992
"Téléchargez les méta-données et la clé publique de ce site et\n"
993
"fournissez-les au fournisseur d'identité afin d'utiliser les fonctionnalités "
994
"Liberty Alliance"
995

  
996
#: ../larpe/admin/hosts.ptl:914
997
msgid "Download SAML 2.0 metadata file"
998
msgstr "Télécharger le fichier des méta-données SAML 2.0"
999

  
1000
#: ../larpe/admin/hosts.ptl:919
1001
msgid "Download ID-FF 1.2 metadata file"
1002
msgstr "Télécharger le fichier des méta-données ID-FF 1.2"
1003

  
1004
#: ../larpe/admin/hosts.ptl:921
1005
msgid "No metadata has been generated for this host."
1006
msgstr "Les méta-données pour ce site n'ont pas été générées."
1007

  
1008
#: ../larpe/admin/hosts.ptl:930
1009
msgid "No public key has been generated for this host."
1010
msgstr "La clé publique pour ce site n'a pas été générée."
1011

  
1012
#: ../larpe/admin/hosts.ptl:942
1013
msgid "Advanced options"
1014
msgstr "Options avancées"
1015

  
1016
#: ../larpe/admin/hosts.ptl:943
1017
msgid "Step 9 - Advanced options"
1018
msgstr "Étape 9 - Options avancées"
1019

  
1020
#: ../larpe/admin/hosts.ptl:945
1021
msgid "Configure advanced options to setup the last details of your site."
1022
msgstr ""
1023
"Configurer les options avancées afin de paramétrer les derniers détails de "
1024
"votre site"
1025

  
1026
#: ../larpe/admin/hosts.ptl:946
1027
#, python-format
1028
msgid ""
1029
"If you don't know what to configure here, just click %(next)s and\n"
1030
"come here later if needed."
1031
msgstr ""
1032
"Si vous ne savez pas quoi configurer ici, cliquez simplement sur %(next)s "
1033
"etrevenez sur cette page plus tard si besoin"
1034

  
1035
#: ../larpe/admin/hosts.ptl:959
1036
msgid "Redirect the root URL of the site to the login page."
1037
msgstr "Rediriger la racine du site vers la page de d'authentification unique"
1038

  
1039
#: ../larpe/admin/hosts.ptl:961
1040
msgid "Return address"
1041
msgstr "Adresse de retour"
1042

  
1043
#: ../larpe/admin/hosts.ptl:962
1044
msgid "Where the user will be redirected after a successful authentication"
1045
msgstr ""
1046
"Adresse vers laquelle l'utilisateur sera redirigé après s'être authentifié"
1047

  
1048
#: ../larpe/admin/hosts.ptl:964
1049
msgid "Error address"
1050
msgstr "Addresse en cas d'erreur"
1051

  
1052
#: ../larpe/admin/hosts.ptl:965
1053
msgid "Where the user will be redirected after a disconnection or an error"
1054
msgstr "Où l'utilisateur sera redirigé après une déconnexion ou une erreur"
1055

  
1056
#: ../larpe/admin/hosts.ptl:967
1057
msgid "URL which must initiate the SSO"
1058
msgstr "URL qui doit initier l'authentification unique"
1059

  
1060
#: ../larpe/admin/hosts.ptl:968
1061
#, python-format
1062
msgid ""
1063
"Address which must initiate the SSO. If empty, defaults to the previously\n"
1064
"specified \"%s\""
1065
msgstr ""
1066
"Adresse qui doit initier l'authentification unique. Si ce champ est vide, "
1067
"l'adresse utilisée sera celle qui a été précédemment renseignée en tant que "
1068
"\"%s\""
1069

  
1070
#: ../larpe/admin/hosts.ptl:971
1071
msgid "Apache HTML proxy"
1072
msgstr "Mandataire (proxy) HTML d'Apache"
1073

  
1074
#: ../larpe/admin/hosts.ptl:972
1075
msgid ""
1076
"Converts urls in the HTML pages according to the host new domain name.\n"
1077
"Disabled by default because it makes some sites not work correctly."
1078
msgstr ""
1079
"Convertir les urls des pages HTML en fonction du nouveau nom de domaine du "
1080
"site. Cette option est désactivée par défaut car elle empêche certains sites "
1081
"de fonctionner correctement."
1082

  
1083
#: ../larpe/admin/hosts.ptl:1003 ../larpe/admin/hosts.ptl:1024
1084
msgid "Finish"
1085
msgstr "Terminer"
1086

  
1087
#: ../larpe/admin/hosts.ptl:1011
1088
msgid "Check everything works"
1089
msgstr "Vérifier que tout fonctionne"
1090

  
1091
#: ../larpe/admin/hosts.ptl:1012
1092
msgid "Step 10 - Check everything works"
1093
msgstr "Étape 10 - Vérifier que tout fonctionne"
1094

  
1095
#: ../larpe/admin/hosts.ptl:1015
1096
msgid ""
1097
"Now you can fully test your site, start from the home page, initiate a\n"
1098
"Single Sign On, federate your identities and do a Single Logout."
1099
msgstr ""
1100
"Vous pouvez maintenant tester vote nouveau site complètement.\n"
1101
"Commencez par la page d'accueil, initiez une authentification unique,\n"
1102
"fédérez vos identités puis faites une déconnexion unique."
1103

  
1104
#: ../larpe/admin/hosts.ptl:1018
1105
msgid "The address of your site is : "
1106
msgstr "L'adresse du site est : "
1107

  
1108
#: ../larpe/admin/hosts.ptl:1023
1109
#, python-format
1110
msgid ""
1111
"If everything works, click the \"%(finish)s\" button, otherwise you can go\n"
1112
"back and check your settings."
1113
msgstr ""
1114
"Si tout fonctionne, cliquez sur le bouton \"%(finish)s\", sinon vous pouvez "
1115
"revenir en arrière et vérifier votre configuration"
1116

  
1117
#: ../larpe/admin/hosts.ptl:1136 ../larpe/admin/hosts.ptl:1151
1118
#: ../larpe/admin/hosts.ptl:1182
1119
msgid "(filled by users)"
1120
msgstr "(rempli par les utilisateurs)"
1121

  
1122
#: ../larpe/admin/hosts.ptl:1233
1123
msgid "Configuration assistant"
1124
msgstr "Assistant de configuration"
1125

  
1126
#: ../larpe/admin/hosts.ptl:1238
1127
msgid "Address of the original site"
1128
msgstr "Adresse du site d'origine"
1129

  
1130
#: ../larpe/admin/hosts.ptl:1238
1131
msgid "Configure the root address of the site"
1132
msgstr "Configurer l'adresse racine de ce site"
1133

  
1134
#: ../larpe/admin/hosts.ptl:1241
1135
msgid "New address and name"
1136
msgstr "Nouvelle adresse et nouveau nom du site"
1137

  
1138
#: ../larpe/admin/hosts.ptl:1241
1139
msgid "Configure the new address and name of this site"
1140
msgstr "Configurer la nouvelle adresse et le nouveau nom du site"
1141

  
1142
#: ../larpe/admin/hosts.ptl:1244
1143
msgid "Authentication and logout addresses"
1144
msgstr "Adresses des pages d'authentification et de déconnexion"
1145

  
1146
#: ../larpe/admin/hosts.ptl:1244
1147
msgid "Configure the authentication and logout addresses of the original site"
1148
msgstr ""
1149
"Configurer les adresses des pages d'authentification et de déconnexion du "
1150
"site d'origine"
1151

  
1152
#: ../larpe/admin/hosts.ptl:1247
1153
msgid "Check auto detected configuration"
1154
msgstr "Vérifier la configuration détectée automatiquement"
1155

  
1156
#: ../larpe/admin/hosts.ptl:1247
1157
msgid "Check the automatically detected configuration is right"
1158
msgstr "Vérifier que la configuration détectée automatiquement est correcte"
1159

  
1160
#: ../larpe/admin/hosts.ptl:1250
1161
msgid "Configure some valid credentials to authenticate on the original site"
1162
msgstr ""
1163
"Configurer un couple identifiant / mot de passe pour s'authentifier sur le "
1164
"site d'origine"
1165

  
1166
#: ../larpe/admin/hosts.ptl:1253
1167
msgid "Retry authentication"
1168
msgstr "Retenter l'authentification"
1169

  
1170
#: ../larpe/admin/hosts.ptl:1253
1171
msgid ""
1172
"Retry sending an authentication request to the site to check if your new "
1173
"parameters work well"
1174
msgstr ""
1175
"Retenter d'envoyer une requête d'authentification au site pour vérifier si "
1176
"vos nouveaux paramètres fonctionnent bien"
1177

  
1178
#: ../larpe/admin/hosts.ptl:1256
1179
msgid "Check authentication response"
1180
msgstr "Vérifier la réponse de l'authentification"
1181

  
1182
#: ../larpe/admin/hosts.ptl:1256
1183
msgid "Check the response from the latest authentication request"
1184
msgstr "Vérifier la réponse de la dernière requête d'authentification"
1185

  
1186
#: ../larpe/admin/hosts.ptl:1259
1187
msgid "Configure authentication success criteria"
1188
msgstr "Configurer les critères de succès de l'authentification"
1189

  
1190
#: ../larpe/admin/hosts.ptl:1259
1191
msgid "Specify how Larpe knows if the authentication has succeeded or not"
1192
msgstr ""
1193
"Spécifier comment Larpe détermine si l'authentification a réussi ou pas"
1194

  
1195
#: ../larpe/admin/hosts.ptl:1262
1196
msgid "Modify authentication request"
1197
msgstr "Modifier la requête d'authentification"
1198

  
1199
#: ../larpe/admin/hosts.ptl:1262
1200
msgid "Modify POST fields or HTTP headers of the authentication request"
1201
msgstr ""
1202
"Modifier les champs POST ou les entêtes HTTP de la requête d'authentification"
1203

  
1204
#: ../larpe/admin/hosts.ptl:1265
1205
msgid "Configure how a Single Sign On can be initiated"
1206
msgstr "Configurer la façon dont l'authentification unique peut être initiée"
1207

  
1208
#: ../larpe/admin/hosts.ptl:1268
1209
msgid "Metadatas and key"
1210
msgstr "Méta-données et clé"
1211

  
1212
#: ../larpe/admin/hosts.ptl:1268
1213
msgid "Download SAML 2.0 or ID-FF metadatas and SSL public key"
1214
msgstr "Télécharger les méta-données SAML 2.0 ou ID-FF et la clé SSL publique"
1215

  
1216
#: ../larpe/admin/hosts.ptl:1271
1217
msgid "Adavanced options"
1218
msgstr "Options avancées"
1219

  
1220
#: ../larpe/admin/hosts.ptl:1271
1221
msgid "Configure advanced options to setup the last details of your site"
1222
msgstr ""
1223
"Configurer les options avancées afin de paramétrer les derniers détails de "
1224
"votre site"
1225

  
1226
#: ../larpe/admin/hosts.ptl:1275
1227
msgid "Form prefilling with ID-WSF"
1228
msgstr "Pré-remplissage de formulaire avec ID-WSF"
1229

  
1230
#: ../larpe/admin/hosts.ptl:1279
1231
msgid "Configure the forms to prefill"
1232
msgstr "Configurer les formulaires à pré-remplir"
1233

  
1234
#: ../larpe/admin/hosts.ptl:1285
1235
msgid "You are about to irrevocably delete this host."
1236
msgstr "Vous allez définitivement supprimer cet hôte."
1237

  
1238
#: ../larpe/admin/hosts.ptl:1292 ../larpe/admin/hosts.ptl:1293
1239
msgid "Delete Host"
1240
msgstr "Supprimer l'hôte"
1241

  
1242
#: ../larpe/admin/hosts.ptl:1305 ../larpe/admin/hosts.ptl:1306
1243
#: ../larpe/admin/hosts.ptl:1343 ../larpe/admin/hosts.ptl:1350
1244
#: ../larpe/admin/root.ptl:44
1245
msgid "Hosts"
1246
msgstr "Hôtes"
1247

  
1248
#: ../larpe/admin/hosts.ptl:1309 ../larpe/admin/hosts.ptl:1336
1249
#: ../larpe/admin/hosts.ptl:1337
1250
msgid "New Host"
1251
msgstr "Nouvel hôte"
1252

  
1253
#: ../larpe/admin/root.ptl:48
1254
msgid "Liberty Alliance Reverse Proxy"
1255
msgstr "Relais inverse Liberty Alliance"
1256

  
1257
#: ../larpe/admin/root.ptl:59
1258
msgid "Administration"
1259
msgstr "Administration"
1260

  
1261
#: ../larpe/saml2.ptl:32 ../larpe/saml2.ptl:46
1262
msgid "SAML 2.0 support not yet configured."
1263
msgstr "Le support SAML 2.0 n'est pas encore configuré"
1264

  
1265
#: ../larpe/saml2.ptl:53
1266
msgid "Missing SAML Artifact"
1267
msgstr "Artifact SAML manquant"
1268

  
1269
#: ../larpe/saml2.ptl:64 ../larpe/liberty.ptl:58
1270
msgid "Failure to communicate with identity provider"
1271
msgstr "Impossible de communiquer avec le fournisseur d'identités."
1272

  
1273
#: ../larpe/saml2.ptl:70 ../larpe/liberty.ptl:63
1274
msgid "Unknown authentication failure"
1275
msgstr "Erreur d'authentification inconnue"
1276

  
1277
#: ../larpe/saml2.ptl:72 ../larpe/liberty.ptl:66
1278
msgid "Authentication failure; unknown principal"
1279
msgstr "Erreur d'authentification: utilisateur inconnu"
1280

  
1281
#: ../larpe/saml2.ptl:334 ../larpe/liberty.ptl:142 ../larpe/liberty.ptl:173
1282
msgid "Failed to check single logout request signature."
1283
msgstr "Erreur à la vérification de la signature de la demande de déconnexion"
1284

  
1285
#: ../larpe/site_authentication.ptl:60
1286
msgid "Local authentication"
1287
msgstr "Authentification locale"
1288

  
1289
#: ../larpe/site_authentication.ptl:74
1290
msgid "Authentication failure"
1291
msgstr "Erreur d'authentification"
1292

  
1293
#: ../larpe/site_authentication.ptl:77
1294
#, python-format
1295
msgid "Connection failed : %s"
1296
msgstr "Échec de la connexion : %s"
1297

  
1298
#: ../larpe/site_authentication.ptl:80
1299
#, python-format
1300
msgid "This service provider is not fully configured : %s"
1301
msgstr "Ce fournisseur de service n'est pas complètement configuré : %s"
1302

  
1303
#: ../larpe/site_authentication.ptl:83
1304
#, python-format
1305
msgid "Unknown error : %s"
1306
msgstr "Erreur inconnue : %s"
1307

  
1308
#: ../larpe/site_authentication.ptl:89
1309
msgid "Please type your login and password for this Service Provider."
1310
msgstr ""
1311
"Entrez votre identifiant et votre mot de passe pour ce fournisseur de "
1312
"service."
1313

  
1314
#: ../larpe/site_authentication.ptl:90 ../larpe/root.ptl:74
1315
msgid ""
1316
"Your local account will be federated with your Liberty Alliance account."
1317
msgstr "Votre compte local sera fédéré avec votre compte Liberty Alliance."
1318

  
1319
#: ../larpe/site_authentication.ptl:296
1320
#, python-format
1321
msgid "%s logout failed"
1322
msgstr "%s échec de la déconnexion"
1323

  
1324
#: ../larpe/root.ptl:27
1325
msgid "Welcome to Larpe reverse proxy"
1326
msgstr "Bienvenue sur le reverse proxy Larpe"
1327

  
1328
#: ../larpe/root.ptl:29
1329
msgid "Configure Larpe"
1330
msgstr "Configurer Larpe"
1331

  
1332
#: ../larpe/root.ptl:73
1333
msgid "Please enter your identification token. "
1334
msgstr "Veuillez saisir votre jeton d'identification. "
1335

  
1336
#: ../larpe/root.ptl:87
1337
msgid "Unknown Token"
1338
msgstr "Jeton inconnu"
1339

  
1340
#: ../larpe/liberty.ptl:45
1341
msgid "Liberty support is not yet configured"
1342
msgstr "Le support Liberty n'est pas encore configuré"
1343

  
1344
#: ../larpe/liberty.ptl:67
1345
msgid "Identity Provider didn't accept artifact transaction."
1346
msgstr "Le fournisseur d'identité n'a pas accepté l'artifact."
1347

  
1348
#: ../larpe/users.py:38
1349
msgid "Unknown User"
1350
msgstr "Utilisateur inconnu"
1351

  
1352
#~ msgid "My Space"
1353
#~ msgstr "Mon espace"
1354

  
1355
#~ msgid "back office"
1356
#~ msgstr "backoffice"
1357

  
1358
#~ msgid "admin"
1359
#~ msgstr "admin"
1360

  
1361
#~ msgid "My Profile"
1362
#~ msgstr "Mon profil"
1363

  
1364
#~ msgid "Empty profile"
1365
#~ msgstr "Profile vide"
1366

  
1367
#~ msgid "Edit My Profile"
1368
#~ msgstr "Editer mon profil"
1369

  
1370
#~ msgid "Change My Password"
1371
#~ msgstr "Changement de mot de passe"
1372

  
1373
#~ msgid "Remove My Account"
1374
#~ msgstr "Supprimer un compte"
1375

  
1376
#~ msgid "Apply Changes"
1377
#~ msgstr "Appliquer les changements"
1378

  
1379
#~ msgid "Edit Profile"
1380
#~ msgstr "Editer le profile"
1381

  
1382
#~ msgid "New Password"
1383
#~ msgstr "Nouveau mot de passe"
1384

  
1385
#~ msgid "New Password (confirm)"
1386
#~ msgstr "Nouveau mot de passe (confirmation)"
1387

  
1388
#~ msgid "Change Password"
1389
#~ msgstr "Changement de mot de passe"
1390

  
1391
#~ msgid "Passwords do not match"
1392
#~ msgstr "Les mots de passe sont différents"
1393

  
1394
#~ msgid "Are you really sure you want to remove your account?"
1395
#~ msgstr "Etes vous vraiment sûr de vouloir supprimer votre compte ?"
1396

  
1397
#~ msgid "Remove my account"
1398
#~ msgstr "Supprimer mon compte"
1399

  
1400
#~ msgid "Removing Account"
1401
#~ msgstr "Supression du compte"
1402

  
1403
#~ msgid "Text on top of the profile page"
1404
#~ msgstr "Texte en haut de la page de profil"
1405

  
1406
#~ msgid "day"
1407
#~ msgstr "Moi"
1408

  
1409
#, fuzzy
1410
#~ msgid "minute"
1411
#~ msgstr "moins"
1412

  
1413
#, fuzzy
1414
#~ msgid "minutes"
1415
#~ msgstr "moins"
1416

  
1417
#, fuzzy
1418
#~ msgid "%s minutes"
1419
#~ msgstr "moins"
1420

  
1421
#~ msgid "registered"
1422
#~ msgstr "enregistré"
1423

  
1424
#~ msgid "running"
1425
#~ msgstr "en fonctionnement"
1426

  
1427
#~ msgid "completed"
1428
#~ msgstr "terminé"
1429

  
1430
#~ msgid "Access Forbidden"
1431
#~ msgstr "Accès interdit"
1432

  
1433
#~ msgid "the homepage"
1434
#~ msgstr "la page d'accueil"
1435

  
1436
#~ msgid "Oops, the server borked severely"
1437
#~ msgstr "Oups, le serveur s'est méchamment planté"
1438

  
1439
#~ msgid ""
1440
#~ "This is bad bad bad; perhaps you will have more luck if you retry in a "
1441
#~ "few minutes ? "
1442
#~ msgstr ""
1443
#~ "C'est mal mal mal; peut-être aurez-vous plus de chance en réessayant dans "
1444
#~ "quelques minutes ? "
1445

  
1446
#~ msgid ""
1447
#~ "Alternatively you could harass the webmaster (who may have been emailed "
1448
#~ "automatically with this incident but you can't be sure about this."
1449
#~ msgstr ""
1450
#~ "Autrement vous pouvez harceler le webmestre (qui devrait avoir été "
1451
#~ "prévenu automatiquement de cet incident par un courriel, mais en êtes "
1452
#~ "vous sûr ?)."
1453

  
1454
#~ msgid "Page not found"
1455
#~ msgstr "Page non trouvée"
1456

  
1457
#~ msgid ""
1458
#~ "The requested link does not exist on this site.  If you arrived here by "
1459
#~ "following a link from an external page, please inform that page's "
1460
#~ "maintainer."
1461
#~ msgstr ""
1462
#~ "La page demandée n'existe pas sur ce site.  Si vous êtes arrivé ici en "
1463
#~ "suivant un lien depuis un autre site, veuillez informer le propriétaire "
1464
#~ "de cette autre page."
1465

  
1466
#~ msgid "Password is too short.  It must be at least %d characters."
1467
#~ msgstr ""
1468
#~ "Le mot de passe est trop court. Il doit contenir au moins %d caractères."
1469

  
1470
#~ msgid "Password is too long.  It must be at most %d characters."
1471
#~ msgstr ""
1472
#~ "Le mot de passe est trop long. Il doit contenir au plus %d caractères."
1473

  
1474
#, fuzzy
1475
#~ msgid "Invalid Token"
1476
#~ msgstr "date invalide"
1477

  
1478
#~ msgid "Account Creation Confirmed"
1479
#~ msgstr "Création du compte confirmée"
1480

  
1481
#~ msgid "Log in"
1482
#~ msgstr "S'identifier"
1483

  
1484
#~ msgid "Login"
1485
#~ msgstr "S'identifier"
1486

  
1487
#~ msgid "Invalid credentials"
1488
#~ msgstr "Identifiant ou mot de passe invalide"
1489

  
1490
#~ msgid "This account is waiting for moderation"
1491
#~ msgstr "Ce compte est en attente de modération"
1492

  
1493
#~ msgid "This account is waiting for confirmation"
1494
#~ msgstr "Ce compte est en attente de confirmation"
1495

  
1496
#~ msgid "This account has been disabled"
1497
#~ msgstr "Ce compte a été désactivé"
1498

  
1499
#~ msgid "Submit Request"
1500
#~ msgstr "Valider la requête"
1501

  
1502
#~ msgid "Forgotten password"
1503
#~ msgstr "Mot de passe oublié"
1504

  
1505
#~ msgid "There is no user with that name or it has no email contact."
1506
#~ msgstr ""
1507
#~ "Il n'y a pas d'utilisateur avec ce nom ou cet utilisateur n'a pas "
1508
#~ "d'adresse de courriel de contact"
1509

  
1510
#~ msgid "Failed to send email (server error)"
1511
#~ msgstr "Échec lors de l'envoi du courriel (erreur du serveur)"
1512

  
1513
#~ msgid "Forgotten Password"
1514
#~ msgstr "Mot de passe oublié"
1515

  
1516
#~ msgid ""
1517
#~ "The token you submitted does not exist, has expired, or has been "
1518
#~ "cancelled."
1519
#~ msgstr ""
1520
#~ "Le jeton que vous avez entré n'existe pas, a expiré, ou a été annulé"
1521

  
1522
#~ msgid "home page"
1523
#~ msgstr "page d'accueil"
1524

  
1525
#~ msgid "The token you submitted is not appropriate for the requested task."
1526
#~ msgstr ""
1527
#~ "Le jeton que vous avez entré n'est pas approprié pour la tâche demandée"
1528

  
1529
#~ msgid "Request Cancelled"
1530
#~ msgstr "Requête annulée"
1531

  
1532
#~ msgid "Your request has been cancelled"
1533
#~ msgstr "Votre requête a été annulée"
1534

  
1535
#~ msgid "Continue to <a href=\"/\">home page</a></p>"
1536
#~ msgstr "Continuez vers <a href=\"/\">page d'accueil</a></p>"
1537

  
1538
#~ msgid "New password sent by email"
1539
#~ msgstr "Un nouveau mot de passe a été envoyé par courriel"
1540

  
1541
#, fuzzy
1542
#~ msgid "Password (confirm)"
1543
#~ msgstr "Nouveau mot de passe (confirmation)"
1544

  
1545
#~ msgid "Create Account"
1546
#~ msgstr "Création un compte"
1547

  
1548
#~ msgid "New Account"
1549
#~ msgstr "Nouveau compte"
1550

  
1551
#~ msgid "There is already a user with that username"
1552
#~ msgstr "Il y a déjà un utilisateur avec ce nom"
1553

  
1554
#~ msgid "There is already a user with that email address"
1555
#~ msgstr "Il y a déjà un utilisateur avec cette adresse de courriel"
1556

  
1557
#~ msgid ""
1558
#~ "Accounts are configured to require confirmation but accounts can be "
1559
#~ "created without emails"
1560
#~ msgstr ""
1561
#~ "Les comptes sont configurés pour nécessiter une confirmation mais les "
1562
#~ "comptes peuvent être crées sans courriel"
1563

  
1564
#, fuzzy
1565
#~ msgid ""
1566
#~ "Accounts are configured to have a generated password but accounts can be "
1567
#~ "created without emails"
1568
#~ msgstr ""
1569
#~ "Les comptes sont configurés pour nécessiter une confirmation mais les "
1570
#~ "comptes peuvent être crées sans courriel"
1571

  
1572
#~ msgid "Account created, waiting for moderation"
1573
#~ msgstr "Compte créé, en attente de modération"
1574

  
1575
#~ msgid "A site administrator will now review then activate your account."
1576
#~ msgstr ""
1577
#~ "Un administrateur du site va maintenant vérifier puis activer votre compte"
1578

  
1579
#~ msgid "You will then get your password by email."
1580
#~ msgstr "Votre mot de passe vous sera ensuite envoyé par courriel"
1581

  
1582
#~ msgid "Back to home page"
1583
#~ msgstr "Retour à la page d'accueil"
1584

  
1585
#~ msgid "Email sent"
1586
#~ msgstr "Courriel envoyé"
1587

  
1588
#~ msgid "Username / Password"
1589
#~ msgstr "Identifiant / Mot de passe"
1590

  
1591
#~ msgid "Configure username/password identification method"
1592
#~ msgstr "Configurer la méthode d'identification par identifiant/mot de passe"
1593

  
1594
#~ msgid "Identities"
1595
#~ msgstr "Identités"
1596

  
1597
#~ msgid "Configure identities creation"
1598
#~ msgstr "Configurer la création des identités"
1599

  
1600
#~ msgid "Passwords"
1601
#~ msgstr "Mots de passe"
1602

  
1603
#~ msgid "Configure all password things"
1604
#~ msgstr "Configurer les paramètres relatifs aux mots de passe"
1605

  
1606
#~ msgid "Bulk Import"
1607
#~ msgstr "Import de masse"
1608

  
1609
#~ msgid "Import accounts from a CSV file"
1610
#~ msgstr "Comptes importer depuis un fichier CSV"
1611

  
1612
#~ msgid "Users can change their password"
1613
#~ msgstr "Les utilisateurs peuvent changer leur mot de passe"
1614

  
1615
#~ msgid "Generate initial password"
1616
#~ msgstr "Générer le mot de passe initial"
1617

  
1618
#~ msgid "Lost Password Behaviour"
1619
#~ msgstr "Comportement en cas de perte de mot de passe"
1620

  
1621
#~ msgid "Nothing (contact admin)"
1622
#~ msgstr "Rien (contactez l'administrateur)"
1623

  
1624
#~ msgid "Email reminder"
1625
#~ msgstr "Rappel par courriel"
1626

  
1627
#~ msgid "Question selected by user"
1628
#~ msgstr "Question selectionnée par l'utilisateur"
1629

  
1630
#~ msgid "Minimum password length"
1631
#~ msgstr "Taille minimum des mots de passe"
1632

  
1633
#~ msgid "Maximum password length"
1634
#~ msgstr "Taille maximum des mots de passe"
1635

  
1636
#~ msgid "0 for unlimited length"
1637
#~ msgstr "0 pour une taille illimitée"
1638

  
1639
#~ msgid "Email address (for questions...)"
1640
#~ msgstr "Addresse de courriel (pour des questions ...)"
1641

  
1642
#~ msgid "None"
1643
#~ msgstr "Aucun"
1644

  
1645
#~ msgid "Password Hashing Algorithm"
1646
#~ msgstr "Algorithm de hachage de mots de passe"
1647

  
1648
#~ msgid "Identity Creation"
1649
#~ msgstr "Création d'identité"
1650

  
1651
#~ msgid "Site Administrator"
1652
#~ msgstr "Administrateur du site"
1653

  
1654
#~ msgid "Self-registration"
1655
#~ msgstr "Inscription par l'utilisateur"
1656

  
1657
#~ msgid "Moderated user registration"
1658
#~ msgstr "Inscription par l'utilisateur avec modération"
1659

  
1660
#~ msgid "Require email confirmation for new accounts"
1661
#~ msgstr "Demander une confirmation par courriel pour les nouveaux comptes"
1662

  
1663
#~ msgid "Notify Administrators on Registration"
1664
#~ msgstr "Notifier les administrateurs lors d'inscriptions"
1665

  
1666
#~ msgid "Use email as username"
1667
#~ msgstr "Utiliser le courriel comme identifiant"
1668

  
1669
#~ msgid "Warn about unused account after so many days"
1670
#~ msgstr "Avertir lorsque des comptes sont inutilisés depuis plusieurs jours"
1671

  
1672
#~ msgid "0 for no warning"
1673
#~ msgstr "0 pour aucun avertissement"
1674

  
1675
#~ msgid "Removed unused account after so many days"
1676
#~ msgstr "Compte inutilisés qui ont été supprimés après plusieurs jours"
1677

  
1678
#~ msgid "0 for no automatic removal"
1679
#~ msgstr "0 pour désactiver la suppression automatique"
1680

  
1681
#~ msgid "Identities Interface"
1682
#~ msgstr "Interface des identités"
1683

  
1684
#~ msgid "File"
1685
#~ msgstr "Fichier"
1686

  
1687
#, fuzzy
1688
#~ msgid "Send notifications to users"
1689
#~ msgstr "Jeton d'identification"
1690

  
1691
#, fuzzy
1692
#~ msgid "Add Role"
1693
#~ msgstr "Ajouter un élément"
1694

  
1695
#~ msgid "The CSV file must strictly adhere to the following structure:"
1696
#~ msgstr "Le fichier CSV doit correspondre à la structure suivante :"
1697

  
1698
#~ msgid "Charset: %s"
1699
#~ msgstr "Encodage: %s"
1700

  
1701
#~ msgid "Column Separator: ;"
1702
#~ msgstr "Séparateur de colonne: ;"
1703

  
1704
#~ msgid "Columns:"
1705
#~ msgstr "Colonnes :"
1706

  
1707
#, fuzzy
1708
#~ msgid "(empty to get an automatically generated password)"
1709
#~ msgstr "Nouveau mot de passe généré"
1710

  
1711
#~ msgid "Incorrect number of columns (line: %s)"
1712
#~ msgstr "Numéro de colonne incorrect (ligne : %s)"
1713

  
1714
#~ msgid "Duplicate username (line: %s)"
1715
#~ msgstr "Nom d'utilisateur dupliqué (ligne: %s)"
1716

  
1717
#~ msgid "Number of accounts created: %s"
1718
#~ msgstr "Nombre de compte créé : %s"
1719

  
1720
#, fuzzy
1721
#~ msgid "Sending subscription emails"
1722
#~ msgstr "Configuration de souscription"
1723

  
1724
#, fuzzy
1725
#~ msgid "Notifications"
1726
#~ msgstr "Jeton d'identification"
1727

  
1728
#~ msgid "Awaiting Confirmation"
1729
#~ msgstr "En attente de confirmation"
1730

  
1731
#~ msgid "Awaiting Moderation"
1732
#~ msgstr "En attente de modération"
1733

  
1734
#~ msgid "Disabled Account"
1735
#~ msgstr "Nouvel hôte"
1736

  
1737
#~ msgid "Username / password"
1738
#~ msgstr "Identifiant / mot de passe"
1739

  
1740
#~ msgid "Duplicate user name"
1741
#~ msgstr "Nom d'utilisateur en double"
1742

  
1743
#~ msgid "Accounts"
1744
#~ msgstr "Comptes"
1745

  
1746
#~ msgid "Account - %s"
1747
#~ msgstr "Compte - %s"
1748

  
1749
#~ msgid "Moderation of account"
1750
#~ msgstr "Modération de compte"
1751

  
1752
#~ msgid "Reply by email"
1753
#~ msgstr "Répondre par courriel"
1754

  
1755
#~ msgid "Accept"
1756
#~ msgstr "Accepter"
1757

  
1758
#~ msgid "Reject"
1759
#~ msgstr "Rejeter"
1760

  
1761
#~ msgid "To"
1762
#~ msgstr "À"
1763

  
1764
#~ msgid "Subject"
1765
#~ msgstr "Sujet"
1766

  
1767
#~ msgid "Message"
1768
#~ msgstr "Message"
1769

  
1770
#~ msgid "Submit and don't send email"
1771
#~ msgstr "Valider et ne pas envoyer de courriel"
1772

  
1773
#~ msgid "Rejection"
1774
#~ msgstr "Rejet"
1775

  
1776
#~ msgid "About your account request"
1777
#~ msgstr "À propos de votre demande de compte"
1778

  
1779
#~ msgid "You are not allowed to access Accounts Management"
1780
#~ msgstr "Vous n'êtes pas autorisé à accéder à la gestion des comptes"
1781

  
1782
#~ msgid "Accounts Management"
1783
#~ msgstr "Gestion des comptes"
1784

  
1785
#~ msgid "New accounts waiting for moderation"
1786
#~ msgstr "De nouveaux comptes sont en attente de modération"
1787

  
1788
#~ msgid "Username:"
1789
#~ msgstr "Identifiant :"
1790

  
1791
#~ msgid "Subscription notification for password account"
1792
#~ msgstr "Notification d'inscription pour un compte à mot de passe"
1793

  
1794
#~ msgid ""
1795
#~ "Available variables: email, website, token_url, admin_email, username, "
1796
#~ "password"
1797
#~ msgstr ""
1798
#~ "Variables disponibles : email, website, token_url, admin_email, username, "
1799
#~ "password"
1800

  
1801
#, fuzzy
1802
#~ msgid "Identification"
1803
#~ msgstr "Jeton d'identification"
1804

  
1805
#~ msgid "Subscription Confirmation"
1806
#~ msgstr "Configuration de souscription"
1807

  
1808
#~ msgid ""
1809
#~ "We have received a request for subscription of your email address,\n"
1810
#~ "\"[email]\", to the [website] web site.\n"
1811
#~ "\n"
1812
#~ "To confirm that you want to be subscribed to the web site, simply\n"
1813
#~ "visit this web page:\n"
1814
#~ "\n"
1815
#~ "[token_url]\n"
1816
#~ "\n"
1817
#~ "If you do not wish to be subscribed to the web site, pleasy simply\n"
1818
#~ "disregard this message.  If you think you are being maliciously\n"
1819
#~ "subscribed to the web site, or have any other questions, send them\n"
1820
#~ "to [admin_email].\n"
1821
#~ msgstr ""
1822
#~ "Nous avons reçu une demande d'inscription provenant de votre adresse\n"
1823
#~ "de courriel,\"[email]\", pour le site internet [website].\n"
1824
#~ "\n"
1825
#~ "Pour confirmer votre inscription à ce site, visitez simplement cette\n"
1826
#~ "page :\n"
1827
#~ "\n"
1828
#~ "[token_url]\n"
1829
#~ "\n"
1830
#~ "Si vous ne souhaitez pas être inscrit au site internet, ignorez ce\n"
1831
#~ "message. Si vous pensez que vous avez été inscrit à votre insu, ou\n"
1832
#~ "avez toute autre question à nous poser, envoyer nous un courriel\n"
1833
#~ "à [admin_email].\n"
1834

  
1835
#~ msgid "Request for password change"
1836
#~ msgstr "Demande de changement de mot de passe"
1837

  
1838
#~ msgid "Available variables: change_url, cancel_url, time"
1839
#~ msgstr "Variables disponibles : change_url, cancel_url, time"
1840

  
1841
#~ msgid "Change Password Request"
1842
#~ msgstr "Requête de changement de mot de passe"
1843

  
1844
#~ msgid ""
1845
#~ "You have (or someone impersonating you has) requested to change your\n"
1846
#~ "password. To complete the change, visit the following link:\n"
1847
#~ "\n"
1848
#~ "[change_url]\n"
1849
#~ "\n"
1850
#~ "If you are not the person who made this request, or you wish to cancel\n"
1851
#~ "this request, visit the following link:\n"
1852
#~ "\n"
1853
#~ "[cancel_url]\n"
1854
#~ "\n"
1855
#~ "If you do nothing, the request will lapse after 3 days (precisely on\n"
1856
#~ "[time]).\n"
1857
#~ msgstr ""
1858
#~ "Vous avez (ou quelqu'un se faisant passer pour vous) demandé à changer "
1859
#~ "de\n"
1860
#~ "mot de passe. Pour accomplir ce changement, visitez cette page :\n"
1861
#~ "\n"
1862
#~ "[change_url]\n"
1863
#~ "\n"
1864
#~ "Si vous n'êtes pas la personne qui a fait cette requête, ou si vous "
1865
#~ "voulez\n"
1866
#~ "l'annuler, allez sur la page suivante :\n"
1867
#~ "\n"
1868
#~ "[cancel_url]\n"
1869
#~ "\n"
1870
#~ "Si vous ne faites rien, la demande expirera automatiquement dans 3 "
1871
#~ "jours,\n"
1872
#~ "précisement le [time]).\n"
1873

  
1874
#~ msgid "New generated password"
1875
#~ msgstr "Nouveau mot de passe généré"
1876

  
1877
#~ msgid "Available variable: password"
1878
#~ msgstr "Variables disponibles : password"
1879

  
1880
#~ msgid "Your new password"
1881
#~ msgstr "Votre nouveau mot de passe"
1882

  
1883
#~ msgid "Your new password: [password]\n"
1884
#~ msgstr "Votre nouveau mot de passe : [password]\n"
1885

  
1886
#~ msgid "Approval of new account"
1887
#~ msgstr "Acceptation du nouveau compte"
1888

  
1889
#~ msgid "Available variables: username, password"
1890
#~ msgstr "Variables disponibles : username, password"
1891

  
1892
#~ msgid "Your account has been approved"
1893
#~ msgstr "Votre compte a été validé"
1894

  
1895
#~ msgid ""
1896
#~ "Your account has been approved.\n"
1897
#~ "\n"
1898
#~ "Account details:\n"
1899
#~ "\n"
1900
#~ "- username: [username]\n"
1901
#~ "[if-any password]- password: [password][end]\n"
1902
#~ msgstr ""
1903
#~ "Votre compte a été validé.\n"
1904
#~ "\n"
1905
#~ "Détails du compte :\n"
1906
#~ "\n"
1907
#~ "- identifiant: [username]\n"
1908
#~ "[if-any password]- mot de passe: [password][end]\n"
1909

  
1910
#~ msgid "Warning about unusued account"
1911
#~ msgstr "Avertissement pour les comptes inutilisés"
1912

  
1913
#~ msgid "Available variables: username"
1914
#~ msgstr "Variables disponibles : username"
1915

  
1916
#~ msgid "Your account is unused"
1917
#~ msgstr "Votre compte est inutilisé"
1918

  
1919
#~ msgid "Your account ([username]) is not being used.\n"
1920
#~ msgstr "Votre compte ([username]) n'est pas utilisé.\n"
1921

  
1922
#~ msgid "Notification of removal of unused account"
1923
#~ msgstr "Notification de suppression de compte inutilisé"
1924

  
1925
#~ msgid "Your account has been removed"
1926
#~ msgstr "Votre compte a été supprimé"
1927

  
1928
#~ msgid ""
1929
#~ "Your account ([username]) was not being used, it has therefore been "
1930
#~ "removed.\n"
1931
#~ msgstr ""
1932
#~ "Votre compte ([username]) n'était plus utilisé et a donc été supprimé.\n"
1933

  
1934
#~ msgid "Notification of new registration to administrators"
1935
#~ msgstr "Notification des nouvelles inscriptions aux administrateurs"
1936

  
1937
#~ msgid "Available variables: hostname, email_as_username, username"
1938
#~ msgstr "Variables disponibles : hostname, email_as_username, username"
1939

  
1940
#~ msgid "New Registration"
1941
#~ msgstr "Nouvelle inscription"
1942

  
1943
#~ msgid ""
1944
#~ "Hello,\n"
1945
#~ "\n"
1946
#~ "A new account has been created on [hostname].\n"
1947
#~ "\n"
1948
#~ " - name: [name]\n"
1949
#~ " - username: [username]\n"
1950
#~ msgstr ""
1951
#~ "Bonjour,\n"
1952
#~ "\n"
1953
#~ "Un nouveau compte a été créé sur [hostname].\n"
1954
#~ "\n"
1955
#~ " - nom : [name]\n"
1956
#~ " - identifiant : [username]\n"
1957

  
1958
#, fuzzy
1959
#~ msgid "Welcome email, with generated password"
1960
#~ msgstr "Nouveau mot de passe généré"
1961

  
1962
#, fuzzy
1963
#~ msgid "Available variables: hostname, username, password, email_as_username"
1964
#~ msgstr "Variables disponibles : hostname, email_as_username, username"
1965

  
1966
#, fuzzy
1967
#~ msgid ""
1968
#~ "Welcome to [hostname],\n"
1969
#~ "\n"
1970
#~ "Your password is: [password]\n"
1971
#~ msgstr "Votre nouveau mot de passe : [password]\n"
1972

  
1973
#~ msgid "Text when account confirmed by user but waiting moderator approval"
1974
#~ msgstr ""
1975
#~ "Texte quand le compte a été confirmé par l'utilisateur mais en attente de "
1976
#~ "validation d'un modérateur"
1977

  
1978
#~ msgid ""
1979
#~ "<p>\n"
1980
#~ "Your account has been created.  In order to be effective\n"
1981
#~ "it must be activated by a moderator.  You will receive an\n"
1982
#~ "email when this is done.\n"
1983
#~ "</p>"
1984
#~ msgstr ""
1985
#~ "<p>\n"
1986
#~ "Votre compte a été créé. Afin d'être utilisable,\n"
1987
#~ "il doit être activé par un modérateur. Vous recevrez un\n"
1988
#~ "courriel quand ce sera fait.\n"
1989
#~ "</p>"
1990

  
1991
#~ msgid "Text when account confirmed by user"
1992
#~ msgstr "Texte quand le compte a été confirmé par l'utilisateur"
1993

  
1994
#~ msgid ""
1995
#~ "<p>\n"
1996
#~ "Your account has been created.\n"
1997
#~ "</p>"
1998
#~ msgstr ""
1999
#~ "<p>\n"
2000
#~ "Votre compte a été créé.\n"
2001
#~ "</p>"
2002

  
2003
#~ msgid "Text when an email with a change password token has been sent"
2004
#~ msgstr ""
2005
#~ "Texte quand un courriel avec un jeton de changement de mot de passe a été "
2006
#~ "envoyé"
2007

  
2008
#~ msgid ""
2009
#~ "<p>\n"
2010
#~ "A token for changing your password has been emailed to you. Follow the "
2011
#~ "instructions in that email to change your password.\n"
2012
#~ "</p>\n"
2013
#~ "<p>\n"
2014
#~ " <a href=\"login\">Log In</a>\n"
2015
#~ "</p>"
2016
#~ msgstr ""
2017
#~ "<p>\n"
2018
#~ "Un jeton de changement de mot de passe vous a été envoyé par courriel.  "
2019
#~ "Suivez les instructions dans celui-ci pour changer votre mot de passe.\n"
2020
#~ "</p>\n"
2021
#~ "<p>\n"
2022
#~ " <a href=\"login\">S'identifier</a>\n"
2023
#~ "</p>"
2024

  
2025
#~ msgid "Text when new password has been sent"
2026
#~ msgstr "Texte quand un nouveau mot de passe a été envoyé"
2027

  
2028
#~ msgid ""
2029
#~ "<p>\n"
2030
#~ "Your new password has been sent to you by email.\n"
2031
#~ "</p>\n"
2032
#~ "<p>\n"
2033
#~ " <a href=\"login\">Login</a>\n"
2034
#~ "</p>"
2035
#~ msgstr ""
2036
#~ "<p>\n"
2037
#~ "Votre nouveau mot de passe vous a été envoyé par courriel.\n"
2038
#~ "</p>\n"
2039
#~ "<p>\n"
2040
#~ " <a href=\"login\">S'identifier</a>\n"
2041
#~ "</p>"
2042

  
2043
#~ msgid "Text on top of registration form"
2044
#~ msgstr "Texte en haut du formulaire d'enregistrement"
2045

  
2046
#~ msgid "Text on forgotten password request page"
2047
#~ msgstr "Texte sur la page de demande de mot de passe oublié"
2048

  
2049
#~ msgid ""
2050
#~ "<p>\n"
2051
#~ "If you have an account, but have forgotten your password, enter your user "
2052
#~ "name\n"
2053
#~ "below and submit a request to change your password.\n"
2054
#~ "</p>"
2055
#~ msgstr ""
2056
#~ "<p>\n"
2057
#~ "Si vous avez un compte, mais avez oublié votre mot de passe, entrez votre "
2058
#~ "nom d'utilisateur\n"
2059
#~ "ci-dessous et validez la requête de changement de mot de passe.\n"
2060
#~ "</p>"
2061

  
2062
#~ msgid "Text linking the login page to the account creation page"
2063
#~ msgstr "Texte liant la page de connexion à la page de création de compte"
2064

  
2065
#~ msgid "Available variable: register_url"
2066
#~ msgstr "Variables disponibles: register_url"
2067

  
2068
#~ msgid ""
2069
#~ "<p>\n"
2070
#~ "If you do not have an account, you should go to the <a href="
2071
#~ "\"[register_url]\">\n"
2072
#~ "New Account page</a>.\n"
2073
#~ "</p>"
2074
#~ msgstr ""
2075
#~ "<p>\n"
2076
#~ "Si vous n'avez pas de compte, vous devez aller à la page de <a href="
2077
#~ "\"[register_url]\">\n"
2078
#~ "Nouveau Compte</a>.\n"
2079
#~ "</p>"
2080

  
2081
#, fuzzy
2082
#~ msgid "Text when an invalid password token is used"
2083
#~ msgstr ""
2084
#~ "Texte quand un courriel avec un jeton de changement de mot de passe a été "
2085
#~ "envoyé"
2086

  
2087
#, fuzzy
2088
#~ msgid "Text on top of the login page"
2089
#~ msgstr "Texte en haut de la page de profil"
2090

  
2091
#, fuzzy
2092
#~ msgid ""
2093
#~ "Text when a mail for confirmation of an account creation has been sent"
2094
#~ msgstr ""
2095
#~ "Texte quand un courriel avec un jeton de changement de mot de passe a été "
2096
#~ "envoyé"
2097

  
2098
#~ msgid ""
2099
#~ "An email has been sent to you so you can confirm your account creation."
2100
#~ msgstr ""
2101
#~ "Un courriel vous a été envoyé afin que vous confirmiez la création de "
2102
#~ "votre compte."
2103

  
2104
#~ msgid "Liberty/SAML2"
2105
#~ msgstr "Liberty/SAML2"
2106

  
2107
#~ msgid "Select the identity provider you want to use."
2108
#~ msgstr "Choisissez le fournisseur d'identités que vous voulez utiliser."
2109

  
2110
#~ msgid "Identity Providers"
2111
#~ msgstr "Fournisseurs d'identité"
2112

  
2113
#~ msgid "Create new from remote URL"
2114
#~ msgstr "Nouveau créé à partir d'une URL distante"
2115

  
2116
#~ msgid "Broken"
2117
#~ msgstr "Cassé"
2118

  
2119
#~ msgid "Client Key and Certificate"
2120
#~ msgstr "Clé et certificat du client"
2121

  
2122
#~ msgid "Hide this provider from user lists"
2123
#~ msgstr "Cacher ce fournisseur de la liste présentée à l'utilisateur"
2124

  
2125
#~ msgid "URL to metadata"
2126
#~ msgstr "URL vers les méta-données"
2127

  
2128
#~ msgid "Resource not found"
2129
#~ msgstr "Ressource non trouvée"
2130

  
2131
#~ msgid "HTTP error on retrieval: %s"
2132
#~ msgstr "Erreur HTTP à la récupération : %s"
2133

  
2134
#~ msgid "Failed to retrieve file"
2135
#~ msgstr "Échec à la récupération du fichier"
2136

  
2137
#~ msgid "URL to public key"
2138
#~ msgstr "URL de la clé publique"
2139

  
2140
#~ msgid "Error in this metadata file"
2141
#~ msgstr "Fichier de méta-données erroné"
2142

  
2143
#~ msgid "File looks like a bad metadata file"
2144
#~ msgstr "Le fichier de méta-données semble invalide"
2145

  
2146
#~ msgid ""
2147
#~ "The metadata file does not embed a public key, please provide it here."
2148
#~ msgstr ""
2149
#~ "Ce fichier de meta-données ne contient pas de clé publique, vous devez "
2150
#~ "donc en fournir une ici."
2151

  
2152
#~ msgid "Update from remote URL"
2153
#~ msgstr "Mettre à jour à partir de l'URL distante"
2154

  
2155
#~ msgid "Edit Identity Provider"
2156
#~ msgstr "Modifier le fournisseur d'identités"
2157

  
2158
#~ msgid "You are about to irrevocably remove this identity provider."
2159
#~ msgstr "Vous allez définitivement supprimer ce fournisseur d'identités."
2160

  
2161
#~ msgid "Deleting"
2162
#~ msgstr "Suppression"
2163

  
2164
#~ msgid "Deleting Identity Provider"
2165
#~ msgstr "Suppression du fournisseur d'identité"
2166

  
2167
#~ msgid "Bad metadata or missing public key"
2168
#~ msgstr "Mauvaises méta-données ou clé publique manquante"
2169

  
2170
#~ msgid "Configure Liberty/SAML identification method"
2171
#~ msgstr "Configurer la méthode d'identification Liberty/SAML"
2172

  
2173
#~ msgid "Configure Liberty / SAML 2.0 parameters"
2174
#~ msgstr "Configurer les paramètres Liberty / SAML 2.0"
2175

  
2176
#~ msgid "Configure Liberty parameters"
2177
#~ msgstr "Configurer les paramètres Liberty"
2178

  
2179
#~ msgid "ID-FF 1.2 Service Provider Metadata"
2180
#~ msgstr "Méta-données ID-FF 1.2 du fournisseur de service"
2181

  
2182
#~ msgid "Download Service Provider ID-FF 1.2 Metadata file"
2183
#~ msgstr ""
2184
#~ "Télécharger le fichier des méta-données ID-FF 1.2 du fournisseur de "
2185
#~ "service"
2186

  
2187
#~ msgid "SAML 2.0 Service Provider Metadata"
2188
#~ msgstr "Méta-données du fournisseur de service SAML 2.0"
2189

  
2190
#~ msgid "Download Service Provider SAML 2.0 Metadata file"
2191
#~ msgstr ""
2192
#~ "Télécharger le fichier des méta-données SAML 2.0 du fournisseur de service"
2193

  
2194
#~ msgid "Add and remove identity providers"
2195
#~ msgstr "Ajouter et supprimer des fournisseurs d'identités"
2196

  
2197
#~ msgid "Liberty Provider ID"
2198
#~ msgstr "Identifiant du fournisseur Liberty (Provider ID)"
2199

  
2200
#~ msgid "Liberty Base URL"
2201
#~ msgstr "URL de la racine Liberty"
2202

  
2203
#~ msgid "SAML 2.0 Provider ID"
2204
#~ msgstr "Identifiant du fournisseur SAML 2.0 (Provider ID)"
2205

  
2206
#~ msgid "SAML 2.0 Base URL"
2207
#~ msgstr "URL de la racine SAML 2.0"
2208

  
2209
#~ msgid "Provider ID"
2210
#~ msgstr "Identifiant du fournisseur (Provider ID)"
2211

  
2212
#~ msgid "Base URL"
2213
#~ msgstr "URL de la racine"
2214

  
2215
#~ msgid "Signing Private Key"
2216
#~ msgstr "Clé privée de signature"
2217

  
2218
#~ msgid "Signing Public Key"
2219
#~ msgstr "Clé publique de signature"
2220

  
2221
#~ msgid "Encryption Private Key"
2222
#~ msgstr "Clé privée de chiffrement"
2223

  
2224
#~ msgid "Encryption Public Key"
2225
#~ msgstr "Clé publique de chiffrement"
2226

  
2227
#~ msgid "Identity Provider Introduction, Common Domain"
2228
#~ msgstr "Domaine commun, pour 'Identity Provider Introduction'"
2229

  
2230
#~ msgid "Disabled if empty"
2231
#~ msgstr "Désactivé si vide"
2232

  
2233
#~ msgid "Identity Provider Introduction, URL of Cookie Getter"
2234
#~ msgstr "Identity Provider Introduction, URL de récupération"
2235

  
2236
#, fuzzy
2237
#~ msgid "Sign authentication request"
2238
#~ msgstr "Modifier la requête d'authentification"
2239

  
2240
#~ msgid "Grab user details with ID-WSF on first logon"
2241
#~ msgstr ""
2242
#~ "Récupérer les détails de l'utilisateur avec ID-WSF à la première connexion"
2243

  
2244
#~ msgid "Lasso version is too old for this support."
2245
#~ msgstr "La version de Lasso est trop vieille pour ce support"
2246

  
2247
#~ msgid "Liberty/SAML2 identity provider"
2248
#~ msgstr "Fournisseur d'identité Liberty Alliance/SAML2"
2249

  
2250
#~ msgid "This feature is not yet implemented."
2251
#~ msgstr "Cette fonctionnalité n'a pas encore été implémentée."
2252

  
2253
#~ msgid "Sorry"
2254
#~ msgstr "Désolé"
2255

  
2256
#~ msgid ""
2257
#~ "The server encountered an internal error and was unable to complete your "
2258
#~ "request."
2259
#~ msgstr ""
2260
#~ "Une erreur s'est produite sur le serveur; votre requête n'a ainsi pas pu "
2261
#~ "complètement être traîtée."
2262

  
2263
#~ msgid "Internal Server Error"
2264
#~ msgstr "Erreur interne du serveur"
2265

  
2266
#~ msgid "Bad log file: %s"
2267
#~ msgstr "Mauvais fichier journal : %s"
2268

  
2269
#~ msgid "Nothing to show"
2270
#~ msgstr "Rien à afficher"
2271

  
2272
#~ msgid "Download Raw Log File"
2273
#~ msgstr "Télécharger le fichier journal"
2274

  
2275
#~ msgid "Time"
2276
#~ msgstr "Horodatage"
2277

  
2278
#~ msgid "Anonymous"
2279
#~ msgstr "Anonyme"
2280

  
2281
#~ msgid "Unlogged"
2282
#~ msgstr "Non authentifié"
2283

  
2284
#~ msgid "Unknown"
2285
#~ msgstr "Inconnu"
2286

  
2287
#~ msgid "Select another logfile:"
2288
#~ msgstr "Choisir un autre fichier journal :"
2289

  
2290
#~ msgid "Since: %s"
2291
#~ msgstr "Depuis: %s"
2292

  
2293
#~ msgid "Texts"
2294
#~ msgstr "Textes"
2295

  
2296
#, fuzzy
2297
#~ msgid "Custom Texts"
2298
#~ msgstr "Texte personnalisé :"
2299

  
2300
#~ msgid "Restore default text"
2301
#~ msgstr "Restaurer le texte par défaut"
2302

  
2303
#~ msgid "Invalid template"
2304
#~ msgstr "Squelette invalide"
2305

  
2306
#~ msgid "Text"
2307
#~ msgstr "Texte"
2308

  
2309
#~ msgid "System Default"
2310
#~ msgstr "Valeur du système"
2311

  
2312
#~ msgid "English"
2313
#~ msgstr "Anglais"
2314

  
2315
#~ msgid "French"
2316
#~ msgstr "Français"
2317

  
2318
#~ msgid "Use a web proxy"
2319
#~ msgstr "Utiliser un mandataire (proxy) web"
2320

  
2321
#~ msgid "Proxy IP address or domain name"
2322
#~ msgstr "Adresse IP or nom de domaine du mandataire"
2323

  
2324
#~ msgid "Proxy port"
2325
#~ msgstr "Port du mandataire (proxy)"
2326

  
2327
#~ msgid "User name"
2328
#~ msgstr "Identifiant"
2329

  
2330
#~ msgid "User password"
2331
#~ msgstr "Mot de passe"
2332

  
2333
#~ msgid "Email for Tracebacks"
2334
#~ msgstr "Courriel pour les exceptions"
2335

  
2336
#~ msgid "Display Exceptions"
2337
#~ msgstr "Afficher les exceptions"
2338

  
2339
#~ msgid "No display"
2340
#~ msgstr "Aucun affichage"
2341

  
2342
#~ msgid "Display as Text"
2343
#~ msgstr "Afficher sous forme de texte"
2344

  
2345
#~ msgid "Display as Text in an HTML error page"
2346
#~ msgstr "Afficher sous forme de texte dans une page d'erreur HTML"
2347

  
2348
#~ msgid "Display as HTML"
2349
#~ msgstr "Afficher sous de forme de HTML"
2350

  
2351
#~ msgid "Logger"
2352
#~ msgstr "Journalisation"
2353

  
2354
#~ msgid "Enable debug mode"
2355
#~ msgstr "Activer le mode de débogage"
2356

  
2357
#, fuzzy
2358
#~ msgid "Certificate %s"
2359
#~ msgstr "Certificats"
2360

  
2361
#~ msgid "You are about to delete this certificate."
2362
#~ msgstr "Vous allez définitivement supprimer ce certificat."
2363

  
2364
#~ msgid "certificates"
2365
#~ msgstr "certificats"
2366

  
2367
#~ msgid "Certificates"
2368
#~ msgstr "Certificats"
2369

  
2370
#~ msgid "Certificate Authorities"
2371
#~ msgstr "Autorités de certification"
2372

  
2373
#~ msgid "Add Certificate Authority"
2374
#~ msgstr "Ajoutez une autorité de certification"
2375

  
2376
#~ msgid "You need to install M2Crypto to use this feature"
2377
#~ msgstr "Vous devez installer M2Crypto pour utiliser cette fonctionnalité"
2378

  
2379
#~ msgid "Add"
2380
#~ msgstr "Ajouter"
2381

  
2382
#~ msgid "Certificate"
2383
#~ msgstr "Certificat"
2384

  
2385
#~ msgid "Bad certificate"
2386
#~ msgstr "Mauvais certificat"
2387

  
2388
#~ msgid "backoffice"
2389
#~ msgstr "backoffice"
2390

  
2391
#~ msgid "logout"
2392
#~ msgstr "déconnexion"
2393

  
2394
#~ msgid "help"
2395
#~ msgstr "aide"
2396

  
2397
#~ msgid "Administration of %s"
2398
#~ msgstr "Administration de %s"
2399

  
2400
#~ msgid "Remove"
2401
#~ msgstr "Supprimer"
2402

  
2403
#~ msgid "Duplicate"
2404
#~ msgstr "Dupliquer"
2405

  
2406
#~ msgid "View"
2407
#~ msgstr "Voir"
2408

  
2409
#~ msgid "Export"
2410
#~ msgstr "Exporter"
2411

  
2412
#~ msgid "Error"
2413
#~ msgstr "Erreur"
2414

  
2415
#~ msgid "SMTP Server"
2416
#~ msgstr "Serveur SMTP"
2417

  
2418
#~ msgid "Email Sender"
2419
#~ msgstr "Émetteur des courriels"
2420

  
2421
#~ msgid "Reply-To Address"
2422
#~ msgstr "Adresse de réponse (Reply-To)"
2423

  
2424
#~ msgid "Handle Bounces"
2425
#~ msgstr "Gérer les rebonds"
2426

  
2427
#~ msgid "Check DNS for domain name"
2428
#~ msgstr "Vérifier le nom de domaine à l'aide d'une requête DNS"
2429

  
2430
#~ msgid "Use a DNS request to check domain names used in email fields"
2431
#~ msgstr ""
2432
#~ "Utiliser une requête DNS pour vérifier les noms de domaine utilisés dans "
2433
#~ "les champs courriel"
2434

  
2435
#~ msgid "Enabled Email"
2436
#~ msgstr "Courriel activé"
2437

  
2438
#~ msgid "Restore default email"
2439
#~ msgstr "Restaurer le courriel par défaut"
2440

  
2441
#~ msgid "required field"
2442
#~ msgstr "champ obligatoire"
2443

  
2444
#~ msgid ""
2445
#~ "The form you have submitted is invalid.  Most likely it has been "
2446
#~ "successfully submitted once already.  Please review the form data and "
2447
#~ "submit the form again."
2448
#~ msgstr ""
2449
#~ "Le formulaire que vous avez transmis n'est pas valide.  Une raison "
2450
#~ "probable est qu'il ait déjà été transmis une fois.  Vérifiez les données "
2451
#~ "du formulaire avant de le soumettre à nouveau."
2452

  
2453
#~ msgid "There were errors processing your form.  See below for details."
2454
#~ msgstr ""
2455
#~ "Il y a eu un problème à la soumission du formulaire. Regardez ci-dessous "
2456
#~ "pour le détail."
2457

  
2458
#~ msgid "must be a valid email address"
2459
#~ msgstr "doit être une adresse électronique valide"
2460

  
2461
#~ msgid "invalid address domain"
2462
#~ msgstr "adresse du domaine invalide"
2463

  
2464
#~ msgid "Prefill"
2465
#~ msgstr "Préremplir"
2466

  
2467
#~ msgid "wrong format"
2468
#~ msgstr "format invalide"
2469

  
2470
#~ msgid "invalid date"
2471
#~ msgstr "date invalide"
2472

  
2473
#~ msgid "invalid date: date must be on or after %s"
2474
#~ msgstr "date invalide ; la date doit être antérieure à %s"
2475

  
2476
#~ msgid "invalid date; date must be on or before %s"
2477
#~ msgstr "date invalide ; la date doit être postérieure à %s"
2478

  
2479
#~ msgid "Previous Year"
2480
#~ msgstr "Année précédente"
2481

  
2482
#~ msgid "Previous Month"
2483
#~ msgstr "Mois précédent"
2484

  
2485
#~ msgid "Next Year"
2486
#~ msgstr "Année Suivante"
2487

  
2488
#~ msgid "Next Month"
2489
#~ msgstr "Mois suivant"
2490

  
2491
#~ msgid "Close"
2492
#~ msgstr "Fermer"
2493

  
2494
#~ msgid "Choose Date"
2495
#~ msgstr "Choisir la date"
2496

  
2497
#~ msgid "invalid regular expression"
2498
#~ msgstr "expression rationnelle invalide"
2499

  
2500
#~ msgid "You must select at most %d answers."
2501
#~ msgstr "Vous devez sélectionner au maximum %d réponses."
2502

  
2503
#~ msgid "must start with http:// or https:// and have a domain name"
2504
#~ msgstr "doit commencer par http:// ou https:// et avoir un nom de domaine"
2505

  
2506
#~ msgid "client error: access forbidden (error 403)"
2507
#~ msgstr "erreur du client : accès interdit (erreur 403)"
2508

  
2509
#~ msgid "client error: page not found (error 404)"
2510
#~ msgstr "erreur du client : page non trouvée (erreur 404)"
2511

  
2512
#~ msgid "client error: %(reason)s (error %(code)s)"
2513
#~ msgstr "erreur du client : %(reason)s (erreur %(code)s)"
2514

  
2515
#~ msgid "server error: %(reason)s (error %(code)s)"
2516
#~ msgstr "erreur du serveur : %(reason)s (erreur %(code)s)"
2517

  
2518
#~ msgid ""
2519
#~ "must start with http:// or https:// and have a domain name or start with /"
2520
#~ msgstr ""
2521
#~ "doit commencer par http:// ou https:// et avoir un nom de domaine ou "
2522
#~ "commencer par /"
2523

  
2524
#~ msgid "times"
2525
#~ msgstr "fois"
2526

  
2527
#~ msgid "plus"
2528
#~ msgstr "plus"
2529

  
2530
#~ msgid "minus"
2531
#~ msgstr "moins"
2532

  
2533
#~ msgid "What is the result of %(a)d %(op)s %(b)d?"
2534
#~ msgstr "Quel est le résultat de %(a)d %(op)s %(b)d ?"
2535

  
2536
#~ msgid ""
2537
#~ "Please answer this simple mathematical question as proof you are not a "
2538
#~ "bot."
2539
#~ msgstr ""
2540
#~ "Répondez à cette simple question mathématique comme preuve que vous "
2541
#~ "n'êtes pas un robot'"
2542

  
2543
#~ msgid "wrong answer"
2544
#~ msgstr "mauvaise réponse"
2545

  
2546
#~ msgid "January"
2547
#~ msgstr "Janvier"
2548

  
2549
#~ msgid "February"
2550
#~ msgstr "Février"
2551

  
2552
#~ msgid "March"
2553
#~ msgstr "Mars"
2554

  
2555
#~ msgid "April"
2556
#~ msgstr "Avril"
2557

  
2558
#~ msgid "May"
2559
#~ msgstr "Mai"
2560

  
2561
#~ msgid "June"
2562
#~ msgstr "Juin"
2563

  
2564
#~ msgid "July"
2565
#~ msgstr "Juillet"
2566

  
2567
#~ msgid "August"
2568
#~ msgstr "Août"
2569

  
2570
#~ msgid "September"
2571
#~ msgstr "Septembre"
2572

  
2573
#~ msgid "October"
2574
#~ msgstr "Octobre"
2575

  
2576
#~ msgid "November"
2577
#~ msgstr "Novembre"
2578

  
2579
#~ msgid "December"
2580
#~ msgstr "Décembre"
2581

  
2582
#~ msgid "Monday"
2583
#~ msgstr "Lundi"
2584

  
2585
#~ msgid "Tuesday"
2586
#~ msgstr "Mardi"
2587

  
2588
#~ msgid "Wednesday"
2589
#~ msgstr "Mercredi"
2590

  
2591
#~ msgid "Thursday"
2592
#~ msgstr "Jeudi"
2593

  
2594
#~ msgid "Friday"
2595
#~ msgstr "Vendredi"
2596

  
2597
#~ msgid "Saturday"
2598
#~ msgstr "Samedi"
2599

  
2600
#~ msgid "Sunday"
2601
#~ msgstr "Dimanche"
2602

  
2603
#~ msgid "Back Office of %s"
2604
#~ msgstr "Back Office de %s"
2605

  
2606
#, fuzzy
2607
#~ msgid "Invalid authentication response"
2608
#~ msgstr "Réponse de l'authentification"
2609

  
2610
#~ msgid "Authentication failure; federation not found"
2611
#~ msgstr "Erreur d'authentification: pas de fédération"
2612

  
2613
#~ msgid "Authentication failure; failed to get response"
2614
#~ msgstr "Erreur d'authentification: pas de réponse reçue"
2615

  
2616
#, fuzzy
2617
#~ msgid "Unknown error"
2618
#~ msgstr "Erreur inconnue : %s"
2619

  
2620
#~ msgid "No SAML Response"
2621
#~ msgstr "Pas de réponse SAML"
2622

  
2623
#~ msgid "No SAML Response in query string"
2624
#~ msgstr "Pas de réponse SAML dans la 'query string'"
2625

  
2626
#~ msgid "Request from unknown provider ID"
2627
#~ msgstr "Requête d'un fournisseur inconnu"
2628

  
2629
#~ msgid "Error checking signature"
2630
#~ msgstr "Erreur à la vérification de signature"
2631

  
2632
#, fuzzy
2633
#~ msgid "Could not send logout request to the identity provider"
2634
#~ msgstr "Ajouter et supprimer des fournisseurs d'identités"
2635

  
2636
#~ msgid "It has been sent to the site administrator for analyse."
2637
#~ msgstr "Elle a été envoyée à l'administrateur du site pour analyse."
2638

  
2639
#~ msgid "Continue to %s"
2640
#~ msgstr "Continuer vers %s"
2641

  
2642
#~ msgid "View Error Details"
2643
#~ msgstr "Afficher le détail de l'erreur"
2644

  
2645
#~ msgid "Logged in as %s."
2646
#~ msgstr "Identifié en tant que %s."
2647

  
2648
#~ msgid "Passwords will be automatically generated."
2649
#~ msgstr "Les mots de passe vont être générés automatiquement."
2650

  
2651
#~ msgid "description"
2652
#~ msgstr "description"
2653

  
2654
#~ msgid "hint"
2655
#~ msgstr "astuce"
2656

  
2657
#~ msgid "Authentication request initiated by an unaffiliated provider."
2658
#~ msgstr "Requête d'authentification initié par un fournisseur non-affilié"
2659

  
2660
#~ msgid "Custom Email:"
2661
#~ msgstr "Courriel personnalisé :"
larpe/tags/release-1.1.1/po/larpe.pot
1
# SOME DESCRIPTIVE TITLE.
2
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3
# This file is distributed under the same license as the PACKAGE package.
4
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5
#
6
#, fuzzy
7
msgid ""
8
msgstr ""
9
"Project-Id-Version: PACKAGE VERSION\n"
10
"Report-Msgid-Bugs-To: \n"
11
"POT-Creation-Date: 2010-07-19 13:53+0200\n"
12
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
"Language-Team: LANGUAGE <LL@li.org>\n"
15
"Language: \n"
16
"MIME-Version: 1.0\n"
17
"Content-Type: text/plain; charset=CHARSET\n"
18
"Content-Transfer-Encoding: 8bit\n"
19

  
20
#: ../larpe/idwsf2.ptl:50
21
msgid "Failed connecting to the original site."
22
msgstr ""
23

  
24
#: ../larpe/idwsf2.ptl:61
25
msgid "Failed getting attributes from the attribute provider."
26
msgstr ""
27

  
28
#: ../larpe/idwsf2.ptl:64
29
msgid "Failed getting attributes for an unknown reason."
30
msgstr ""
31

  
32
#: ../larpe/liberty_site.ptl:46 ../larpe/liberty_site.ptl:56
33
msgid "SSO support is not yet configured"
34
msgstr ""
35

  
36
#: ../larpe/admin/users.ptl:24 ../larpe/admin/users.ptl:32
37
msgid "User Name"
38
msgstr ""
39

  
40
#: ../larpe/admin/users.ptl:25 ../larpe/admin/users.ptl:34
41
#: ../larpe/admin/users.ptl:66
42
msgid "Email"
43
msgstr ""
44

  
45
#: ../larpe/admin/users.ptl:26 ../larpe/admin/users.ptl:36
46
#: ../larpe/admin/users.ptl:122 ../larpe/admin/forms_prefill.ptl:24
47
#: ../larpe/admin/forms_prefill.ptl:76 ../larpe/admin/settings.ptl:31
48
#: ../larpe/admin/settings.ptl:217 ../larpe/admin/settings.ptl:326
49
#: ../larpe/admin/settings.ptl:343 ../larpe/admin/fields_prefill.ptl:30
50
#: ../larpe/admin/fields_prefill.ptl:73 ../larpe/admin/hosts.ptl:384
51
#: ../larpe/admin/hosts.ptl:692 ../larpe/admin/hosts.ptl:740
52
#: ../larpe/admin/hosts.ptl:787 ../larpe/admin/hosts.ptl:1286
53
#: ../larpe/site_authentication.ptl:64 ../larpe/root.ptl:64
54
msgid "Submit"
55
msgstr ""
56

  
57
#: ../larpe/admin/users.ptl:27 ../larpe/admin/users.ptl:37
58
#: ../larpe/admin/users.ptl:123 ../larpe/admin/users.ptl:138
59
#: ../larpe/admin/forms_prefill.ptl:25 ../larpe/admin/forms_prefill.ptl:77
60
#: ../larpe/admin/settings.ptl:218 ../larpe/admin/settings.ptl:327
61
#: ../larpe/admin/settings.ptl:344 ../larpe/admin/fields_prefill.ptl:31
62
#: ../larpe/admin/fields_prefill.ptl:74 ../larpe/admin/hosts.ptl:124
63
#: ../larpe/admin/hosts.ptl:385 ../larpe/admin/hosts.ptl:693
64
#: ../larpe/admin/hosts.ptl:741 ../larpe/admin/hosts.ptl:788
65
#: ../larpe/admin/hosts.ptl:1287 ../larpe/root.ptl:65
66
msgid "Cancel"
67
msgstr ""
68

  
69
#: ../larpe/admin/users.ptl:60 ../larpe/admin/users.ptl:61
70
msgid "User"
71
msgstr ""
72

  
73
#: ../larpe/admin/users.ptl:63 ../larpe/admin/hosts.ptl:382
74
msgid "Name"
75
msgstr ""
76

  
77
#: ../larpe/admin/users.ptl:98
78
msgid "Debug"
79
msgstr ""
80

  
81
#: ../larpe/admin/users.ptl:110 ../larpe/admin/forms_prefill.ptl:48
82
#: ../larpe/admin/forms_prefill.ptl:66 ../larpe/admin/forms_prefill.ptl:67
83
#: ../larpe/admin/forms_prefill.ptl:68 ../larpe/admin/fields_prefill.ptl:63
84
#: ../larpe/admin/fields_prefill.ptl:64 ../larpe/admin/fields_prefill.ptl:65
85
msgid "Edit"
86
msgstr ""
87

  
88
#: ../larpe/admin/users.ptl:111 ../larpe/admin/users.ptl:112
89
msgid "Edit User"
90
msgstr ""
91

  
92
#: ../larpe/admin/users.ptl:121
93
msgid "You are about to irrevocably delete this user."
94
msgstr ""
95

  
96
#: ../larpe/admin/users.ptl:127 ../larpe/admin/forms_prefill.ptl:81
97
#: ../larpe/admin/fields_prefill.ptl:78 ../larpe/admin/hosts.ptl:1291
98
msgid "Delete"
99
msgstr ""
100

  
101
#: ../larpe/admin/users.ptl:128
102
msgid "Delete User"
103
msgstr ""
104

  
105
#: ../larpe/admin/users.ptl:129
106
msgid "Deleting User :"
107
msgstr ""
108

  
109
#: ../larpe/admin/users.ptl:137
110
msgid "Generate"
111
msgstr ""
112

  
113
#: ../larpe/admin/users.ptl:143 ../larpe/admin/users.ptl:146
114
#: ../larpe/admin/users.ptl:147 ../larpe/admin/users.ptl:155
115
#: ../larpe/admin/users.ptl:180 ../larpe/admin/users.ptl:182
116
#: ../larpe/admin/users.ptl:223 ../larpe/root.ptl:62 ../larpe/root.ptl:71
117
msgid "Identification Token"
118
msgstr ""
119

  
120
#: ../larpe/admin/users.ptl:148
121
msgid ""
122
"You are about to generate a token than can be used to federate the account."
123
msgstr ""
124

  
125
#: ../larpe/admin/users.ptl:149
126
msgid ""
127
"After that, you will have the choice to send it to the user by email so that "
128
"he can federate his accounts."
129
msgstr ""
130

  
131
#: ../larpe/admin/users.ptl:151
132
#, python-format
133
msgid "Note that user has already been issued an identification token : %s"
134
msgstr ""
135

  
136
#: ../larpe/admin/users.ptl:161
137
#, python-format
138
msgid "Identification Token for %s"
139
msgstr ""
140

  
141
#: ../larpe/admin/users.ptl:165
142
msgid "Done"
143
msgstr ""
144

  
145
#: ../larpe/admin/users.ptl:167
146
msgid "Send by email"
147
msgstr ""
148

  
149
#: ../larpe/admin/users.ptl:173
150
#, python-format
151
msgid ""
152
"You have been given an identification token.\n"
153
"\n"
154
"Your token is %(token)s\n"
155
"\n"
156
"Click on %(url)s to use it.\n"
157
msgstr ""
158

  
159
#: ../larpe/admin/users.ptl:183
160
msgid "Failed sending email. Check your email configuration."
161
msgstr ""
162

  
163
#: ../larpe/admin/users.ptl:184 ../larpe/admin/settings.ptl:112
164
#: ../larpe/admin/hosts.ptl:657 ../larpe/admin/hosts.ptl:713
165
#: ../larpe/admin/hosts.ptl:1340
166
msgid "Back"
167
msgstr ""
168

  
169
#: ../larpe/admin/users.ptl:194 ../larpe/admin/users.ptl:195
170
#: ../larpe/admin/users.ptl:238 ../larpe/admin/users.ptl:272
171
#: ../larpe/admin/root.ptl:45
172
msgid "Users"
173
msgstr ""
174

  
175
#: ../larpe/admin/users.ptl:199 ../larpe/admin/users.ptl:242
176
msgid "Liberty support must be setup before creating users."
177
msgstr ""
178

  
179
#: ../larpe/admin/users.ptl:203 ../larpe/admin/users.ptl:254
180
#: ../larpe/admin/users.ptl:255
181
msgid "New User"
182
msgstr ""
183

  
184
#: ../larpe/admin/users.ptl:226
185
#, python-format
186
msgid "Identification Token (current: %s)"
187
msgstr ""
188

  
189
#: ../larpe/admin/users.ptl:233 ../larpe/admin/root.ptl:47
190
msgid "Logs"
191
msgstr ""
192

  
193
#: ../larpe/admin/users.ptl:239 ../larpe/admin/forms_prefill.ptl:122
194
#: ../larpe/admin/fields_prefill.ptl:125 ../larpe/admin/hosts.ptl:1344
195
msgid "New"
196
msgstr ""
197

  
198
#: ../larpe/admin/forms_prefill.ptl:16
199
msgid "Form name"
200
msgstr ""
201

  
202
#: ../larpe/admin/forms_prefill.ptl:17
203
msgid "Only used for display"
204
msgstr ""
205

  
206
#: ../larpe/admin/forms_prefill.ptl:18
207
msgid "Form address"
208
msgstr ""
209

  
210
#: ../larpe/admin/forms_prefill.ptl:20
211
msgid "ID-WSF data profile"
212
msgstr ""
213

  
214
#: ../larpe/admin/forms_prefill.ptl:21
215
msgid "Example: urn:liberty:id-sis-pp:2005-05"
216
msgstr ""
217

  
218
#: ../larpe/admin/forms_prefill.ptl:22
219
msgid "ID-WSF data XML prefix"
220
msgstr ""
221

  
222
#: ../larpe/admin/forms_prefill.ptl:23
223
msgid "Example: pp"
224
msgstr ""
225

  
226
#: ../larpe/admin/forms_prefill.ptl:45
227
msgid "Form prefilling configuration"
228
msgstr ""
229

  
230
#: ../larpe/admin/forms_prefill.ptl:48
231
msgid "Configure this form"
232
msgstr ""
233

  
234
#: ../larpe/admin/forms_prefill.ptl:50 ../larpe/admin/fields_prefill.ptl:91
235
#: ../larpe/admin/fields_prefill.ptl:98
236
msgid "Fields"
237
msgstr ""
238

  
239
#: ../larpe/admin/forms_prefill.ptl:50
240
msgid "Configure the fields of this form"
241
msgstr ""
242

  
243
#: ../larpe/admin/forms_prefill.ptl:75
244
msgid "You are about to irrevocably delete this form."
245
msgstr ""
246

  
247
#: ../larpe/admin/forms_prefill.ptl:82 ../larpe/admin/forms_prefill.ptl:83
248
msgid "Delete Form"
249
msgstr ""
250

  
251
#: ../larpe/admin/forms_prefill.ptl:94 ../larpe/admin/forms_prefill.ptl:101
252
#: ../larpe/admin/hosts.ptl:1279
253
msgid "Forms"
254
msgstr ""
255

  
256
#: ../larpe/admin/forms_prefill.ptl:104
257
msgid "New Form"
258
msgstr ""
259

  
260
#: ../larpe/admin/settings.ptl:28
261
msgid "Metadata"
262
msgstr ""
263

  
264
#: ../larpe/admin/settings.ptl:29
265
msgid "Public Key"
266
msgstr ""
267

  
268
#: ../larpe/admin/settings.ptl:30
269
msgid "CA Certificate Chain"
270
msgstr ""
271

  
272
#: ../larpe/admin/settings.ptl:34 ../larpe/admin/settings.ptl:35
273
msgid "New Identity Provider"
274
msgstr ""
275

  
276
#: ../larpe/admin/settings.ptl:53 ../larpe/admin/settings.ptl:87
277
msgid "Bad metadata"
278
msgstr ""
279

  
280
#. Don't use custom emails
281
#: ../larpe/admin/settings.ptl:104 ../larpe/admin/settings.ptl:105
282
#: ../larpe/admin/settings.ptl:192
283
msgid "Emails"
284
msgstr ""
285

  
286
#: ../larpe/admin/settings.ptl:108
287
msgid "General Options"
288
msgstr ""
289

  
290
#: ../larpe/admin/settings.ptl:125 ../larpe/admin/hosts.ptl:84
291
#: ../larpe/admin/root.ptl:46
292
msgid "Settings"
293
msgstr ""
294

  
295
#: ../larpe/admin/settings.ptl:128
296
msgid "Liberty Alliance & SAML 2.0 Service Provider"
297
msgstr ""
298

  
299
#: ../larpe/admin/settings.ptl:130
300
msgid "Liberty Alliance Service Provider"
301
msgstr ""
302

  
303
#: ../larpe/admin/settings.ptl:132
304
msgid "Service Provider"
305
msgstr ""
306

  
307
#: ../larpe/admin/settings.ptl:132
308
msgid "Configure Larpe as a Service Provider"
309
msgstr ""
310

  
311
#: ../larpe/admin/settings.ptl:142 ../larpe/admin/hosts.ptl:913
312
msgid "SAML 2.0 Metadata"
313
msgstr ""
314

  
315
#: ../larpe/admin/settings.ptl:143
316
msgid "Download SAML 2.0 metadata file for Larpe"
317
msgstr ""
318

  
319
#: ../larpe/admin/settings.ptl:149 ../larpe/admin/hosts.ptl:918
320
msgid "ID-FF 1.2 Metadata"
321
msgstr ""
322

  
323
#: ../larpe/admin/settings.ptl:150
324
msgid "Download ID-FF 1.2 metadata file for Larpe"
325
msgstr ""
326

  
327
#: ../larpe/admin/settings.ptl:156 ../larpe/admin/hosts.ptl:927
328
msgid "Public key"
329
msgstr ""
330

  
331
#: ../larpe/admin/settings.ptl:157 ../larpe/admin/hosts.ptl:928
332
msgid "Download SSL Public Key file"
333
msgstr ""
334

  
335
#: ../larpe/admin/settings.ptl:160
336
msgid "Liberty Alliance & SAML 2.0 Identity Provider"
337
msgstr ""
338

  
339
#: ../larpe/admin/settings.ptl:162
340
msgid "Liberty Alliance Identity Provider"
341
msgstr ""
342

  
343
#: ../larpe/admin/settings.ptl:167
344
msgid "Identity Provider"
345
msgstr ""
346

  
347
#: ../larpe/admin/settings.ptl:167
348
msgid "Configure an identity provider"
349
msgstr ""
350

  
351
#: ../larpe/admin/settings.ptl:171
352
msgid "Identity Provider metadatas"
353
msgstr ""
354

  
355
#: ../larpe/admin/settings.ptl:171
356
msgid "See current identity provider metadatas"
357
msgstr ""
358

  
359
#: ../larpe/admin/settings.ptl:175
360
msgid "Global parameters for the sites"
361
msgstr ""
362

  
363
#: ../larpe/admin/settings.ptl:179 ../larpe/admin/settings.ptl:302
364
#: ../larpe/admin/settings.ptl:303
365
msgid "Domain name"
366
msgstr ""
367

  
368
#: ../larpe/admin/settings.ptl:179
369
msgid "Configure the base domain name for the sites"
370
msgstr ""
371

  
372
#: ../larpe/admin/settings.ptl:181 ../larpe/admin/settings.ptl:348
373
#: ../larpe/admin/settings.ptl:349
374
msgid "Apache 2 configuration generation"
375
msgstr ""
376

  
377
#: ../larpe/admin/settings.ptl:181
378
msgid "Customise Apache 2 configuration generation"
379
msgstr ""
380

  
381
#: ../larpe/admin/settings.ptl:183
382
msgid "Proxy"
383
msgstr ""
384

  
385
#: ../larpe/admin/settings.ptl:183
386
msgid "Connect to the sites through a web proxy"
387
msgstr ""
388

  
389
#: ../larpe/admin/settings.ptl:186
390
msgid "Customisation"
391
msgstr ""
392

  
393
#: ../larpe/admin/settings.ptl:190
394
msgid "Language"
395
msgstr ""
396

  
397
#: ../larpe/admin/settings.ptl:190
398
msgid "Configure site language"
399
msgstr ""
400

  
401
#: ../larpe/admin/settings.ptl:192
402
msgid "Configure email settings"
403
msgstr ""
404

  
405
#: ../larpe/admin/settings.ptl:195
406
msgid "Misc"
407
msgstr ""
408

  
409
#: ../larpe/admin/settings.ptl:199
410
msgid "Debug Options"
411
msgstr ""
412

  
413
#: ../larpe/admin/settings.ptl:199
414
msgid "Configure options useful for debugging"
415
msgstr ""
416

  
417
#: ../larpe/admin/settings.ptl:215
418
msgid "Organisation Name"
419
msgstr ""
420

  
421
#: ../larpe/admin/settings.ptl:222 ../larpe/admin/settings.ptl:223
422
msgid "Service Provider Configuration"
423
msgstr ""
424

  
425
#: ../larpe/admin/settings.ptl:318
426
msgid "Domain name for the sites"
427
msgstr ""
428

  
429
#. TODO: Add the option "Both" and handle it in hosts configuration
430
#: ../larpe/admin/settings.ptl:321
431
msgid "Use HTTP or HTTPS"
432
msgstr ""
433

  
434
#: ../larpe/admin/settings.ptl:323
435
msgid "Same as the site"
436
msgstr ""
437

  
438
#: ../larpe/admin/settings.ptl:341
439
msgid ""
440
"Automatically generate Apache 2 configuration for new hosts and reload "
441
"Apache 2 after changes"
442
msgstr ""
443

  
444
#: ../larpe/admin/fields_prefill.ptl:15
445
msgid "Field name"
446
msgstr ""
447

  
448
#: ../larpe/admin/fields_prefill.ptl:17
449
msgid "Xpath of the attribute"
450
msgstr ""
451

  
452
#: ../larpe/admin/fields_prefill.ptl:18
453
msgid "Example: /pp:PP/pp:InformalName"
454
msgstr ""
455

  
456
#: ../larpe/admin/fields_prefill.ptl:19
457
msgid "Number of the field in the data"
458
msgstr ""
459

  
460
#: ../larpe/admin/fields_prefill.ptl:21
461
msgid ""
462
"Change it if there are multiple fields corresponding to the same Xpath and "
463
"you want to get another than the first one"
464
msgstr ""
465

  
466
#: ../larpe/admin/fields_prefill.ptl:22
467
msgid "Get raw XML value"
468
msgstr ""
469

  
470
#: ../larpe/admin/fields_prefill.ptl:24
471
msgid "Python regexp of a string to match"
472
msgstr ""
473

  
474
#: ../larpe/admin/fields_prefill.ptl:26
475
msgid "Python regexp of the replacing string"
476
msgstr ""
477

  
478
#: ../larpe/admin/fields_prefill.ptl:28
479
msgid "Options mapping for a select field"
480
msgstr ""
481

  
482
#: ../larpe/admin/fields_prefill.ptl:29
483
msgid "Add item"
484
msgstr ""
485

  
486
#: ../larpe/admin/fields_prefill.ptl:72
487
msgid "You are about to irrevocably delete this field."
488
msgstr ""
489

  
490
#: ../larpe/admin/fields_prefill.ptl:79 ../larpe/admin/fields_prefill.ptl:80
491
msgid "Delete Field"
492
msgstr ""
493

  
494
#: ../larpe/admin/fields_prefill.ptl:101
495
msgid "New Field"
496
msgstr ""
497

  
498
#: ../larpe/admin/hosts.ptl:33
499
msgid ""
500
"You must either choose a different hostname from Larpe or specify a reversed "
501
"directory"
502
msgstr ""
503

  
504
#: ../larpe/admin/hosts.ptl:80 ../larpe/admin/hosts.ptl:102
505
msgid "Basic configuration"
506
msgstr ""
507

  
508
#: ../larpe/admin/hosts.ptl:81
509
msgid "Need domain name configuration"
510
msgstr ""
511

  
512
#: ../larpe/admin/hosts.ptl:82
513
#, python-format
514
msgid ""
515
"Before configuring hosts, you must\n"
516
"<a href=\"../../../settings/domain_names\">setup a global domain name</a> "
517
"in\n"
518
"%(settings)s menu."
519
msgstr ""
520

  
521
#: ../larpe/admin/hosts.ptl:103
522
msgid "Step 1 - Basic configuration"
523
msgstr ""
524

  
525
#: ../larpe/admin/hosts.ptl:112
526
msgid "Original site root address"
527
msgstr ""
528

  
529
#: ../larpe/admin/hosts.ptl:114
530
msgid ""
531
"If your site address is http://test.org/index.php, put http://test.org/ here"
532
msgstr ""
533

  
534
#: ../larpe/admin/hosts.ptl:117
535
msgid "Use a proxy"
536
msgstr ""
537

  
538
#: ../larpe/admin/hosts.ptl:118
539
msgid ""
540
"Uncheck it if Larpe doesn't need to use the proxy to connect to this site"
541
msgstr ""
542

  
543
#: ../larpe/admin/hosts.ptl:122
544
msgid ""
545
"If Larpe needs to use a proxy to connect to this site, you must first "
546
"configure\n"
547
" it in <a href=\"../../../settings/proxy\">global proxy parameters</a>."
548
msgstr ""
549

  
550
#: ../larpe/admin/hosts.ptl:125 ../larpe/admin/hosts.ptl:315
551
#: ../larpe/admin/hosts.ptl:343 ../larpe/admin/hosts.ptl:433
552
#: ../larpe/admin/hosts.ptl:464 ../larpe/admin/hosts.ptl:547
553
#: ../larpe/admin/hosts.ptl:583 ../larpe/admin/hosts.ptl:873
554
#: ../larpe/admin/hosts.ptl:889 ../larpe/admin/hosts.ptl:947
555
#: ../larpe/admin/hosts.ptl:977
556
msgid "Next"
557
msgstr ""
558

  
559
#: ../larpe/admin/hosts.ptl:126 ../larpe/admin/hosts.ptl:316
560
#: ../larpe/admin/hosts.ptl:434 ../larpe/admin/hosts.ptl:465
561
#: ../larpe/admin/hosts.ptl:548 ../larpe/admin/hosts.ptl:584
562
#: ../larpe/admin/hosts.ptl:874 ../larpe/admin/hosts.ptl:890
563
#: ../larpe/admin/hosts.ptl:978
564
msgid "Terminate"
565
msgstr ""
566

  
567
#: ../larpe/admin/hosts.ptl:314 ../larpe/admin/hosts.ptl:343
568
#: ../larpe/admin/hosts.ptl:432 ../larpe/admin/hosts.ptl:463
569
#: ../larpe/admin/hosts.ptl:546 ../larpe/admin/hosts.ptl:582
570
#: ../larpe/admin/hosts.ptl:872 ../larpe/admin/hosts.ptl:888
571
#: ../larpe/admin/hosts.ptl:976 ../larpe/admin/hosts.ptl:1002
572
msgid "Previous"
573
msgstr ""
574

  
575
#: ../larpe/admin/hosts.ptl:332
576
msgid "Check site address and name"
577
msgstr ""
578

  
579
#: ../larpe/admin/hosts.ptl:333
580
msgid "Step 2 - Check the new site address works"
581
msgstr ""
582

  
583
#: ../larpe/admin/hosts.ptl:335
584
msgid "DNS configuration"
585
msgstr ""
586

  
587
#: ../larpe/admin/hosts.ptl:337
588
msgid ""
589
"Before opening the following link, ensure you have configured your DNS\n"
590
"for this address. If you don't have a DNS server and you just want to test "
591
"Larpe, add this\n"
592
"domain name in the file \"/etc/hosts\"."
593
msgstr ""
594

  
595
#: ../larpe/admin/hosts.ptl:341
596
#, python-format
597
msgid ""
598
"Then you can open this link in a new window or tab and see if your site\n"
599
"is displayed. If it's ok, you can click the \"%(next)s\" button. Otherwise, "
600
"click the \"%(previous)s\"\n"
601
"button and check your settings."
602
msgstr ""
603

  
604
#: ../larpe/admin/hosts.ptl:345
605
msgid "Site adress and name"
606
msgstr ""
607

  
608
#: ../larpe/admin/hosts.ptl:347
609
msgid "The new address of this site is "
610
msgstr ""
611

  
612
#: ../larpe/admin/hosts.ptl:349
613
#, python-format
614
msgid "The name of this site is \"%s\"."
615
msgstr ""
616

  
617
#: ../larpe/admin/hosts.ptl:350
618
msgid ""
619
"You can also <a href=\"modify_site_address_and_name\">\n"
620
"modify the address or the name of this site</a>"
621
msgstr ""
622

  
623
#: ../larpe/admin/hosts.ptl:366
624
msgid "An host with the same name already exists"
625
msgstr ""
626

  
627
#: ../larpe/admin/hosts.ptl:373 ../larpe/admin/hosts.ptl:374
628
msgid "Modify site address and name"
629
msgstr ""
630

  
631
#: ../larpe/admin/hosts.ptl:380
632
msgid "Address"
633
msgstr ""
634

  
635
#: ../larpe/admin/hosts.ptl:419
636
msgid "Authentication and logout"
637
msgstr ""
638

  
639
#: ../larpe/admin/hosts.ptl:420
640
msgid "Step 3 - Configure authentication and logout pages"
641
msgstr ""
642

  
643
#: ../larpe/admin/hosts.ptl:426 ../larpe/admin/hosts.ptl:969
644
msgid "Authentication form page address"
645
msgstr ""
646

  
647
#: ../larpe/admin/hosts.ptl:427
648
msgid "Address of a page on the site which contains the authentication form"
649
msgstr ""
650

  
651
#: ../larpe/admin/hosts.ptl:429
652
msgid "Logout address"
653
msgstr ""
654

  
655
#: ../larpe/admin/hosts.ptl:430
656
msgid "Address of the logout link on the site"
657
msgstr ""
658

  
659
#: ../larpe/admin/hosts.ptl:446
660
msgid "(computed automatically)"
661
msgstr ""
662

  
663
#: ../larpe/admin/hosts.ptl:459
664
msgid "Plugin"
665
msgstr ""
666

  
667
#: ../larpe/admin/hosts.ptl:460
668
msgid "You can force a plugin"
669
msgstr ""
670

  
671
#: ../larpe/admin/hosts.ptl:478
672
msgid "Auto detected configuration"
673
msgstr ""
674

  
675
#: ../larpe/admin/hosts.ptl:479
676
msgid ""
677
"Step 4 - Check automatically detected configuration for the authentication "
678
"form"
679
msgstr ""
680

  
681
#: ../larpe/admin/hosts.ptl:482
682
msgid "Address where the authentication form must be sent"
683
msgstr ""
684

  
685
#: ../larpe/admin/hosts.ptl:483
686
msgid "Name of the login field"
687
msgstr ""
688

  
689
#: ../larpe/admin/hosts.ptl:484
690
msgid "Name of the password field"
691
msgstr ""
692

  
693
#: ../larpe/admin/hosts.ptl:503
694
msgid ""
695
"The following authentication form parameters have been detected. If they "
696
"look right, you can go to the next step.\n"
697
"If you think they are wrong, go back and check your settings then try "
698
"again.\n"
699
msgstr ""
700

  
701
#: ../larpe/admin/hosts.ptl:508
702
msgid ""
703
"The following authentication form parameters in red haven't been correctly "
704
"detected. Go back and check\n"
705
"your settings then try again.\n"
706
msgstr ""
707

  
708
#: ../larpe/admin/hosts.ptl:529 ../larpe/admin/hosts.ptl:1250
709
msgid "Credentials"
710
msgstr ""
711

  
712
#: ../larpe/admin/hosts.ptl:530
713
msgid "Step 5 - Fill in a valid username/password for this site"
714
msgstr ""
715

  
716
#: ../larpe/admin/hosts.ptl:535 ../larpe/site_authentication.ptl:98
717
msgid "Username"
718
msgstr ""
719

  
720
#: ../larpe/admin/hosts.ptl:537 ../larpe/site_authentication.ptl:100
721
msgid "Password"
722
msgstr ""
723

  
724
#: ../larpe/admin/hosts.ptl:594
725
msgid "Check authentication"
726
msgstr ""
727

  
728
#: ../larpe/admin/hosts.ptl:595
729
msgid "Step 6 - Check the authentication process"
730
msgstr ""
731

  
732
#: ../larpe/admin/hosts.ptl:614
733
msgid "Authentication succeeded ! You can go to the next step."
734
msgstr ""
735

  
736
#: ../larpe/admin/hosts.ptl:616
737
msgid "Authentication has failed. To resolve this problem, you can :"
738
msgstr ""
739

  
740
#: ../larpe/admin/hosts.ptl:619
741
msgid "Try authentication again"
742
msgstr ""
743

  
744
#: ../larpe/admin/hosts.ptl:621
745
msgid "See the response of the authentication requests"
746
msgstr ""
747

  
748
#: ../larpe/admin/hosts.ptl:623 ../larpe/admin/hosts.ptl:705
749
msgid "Modify the parameters of the authentication requests"
750
msgstr ""
751

  
752
#: ../larpe/admin/hosts.ptl:625
753
msgid "Change the way Larpe detects the authentication is successful or not"
754
msgstr ""
755

  
756
#: ../larpe/admin/hosts.ptl:626
757
msgid "Go back and change your username and/or password"
758
msgstr ""
759

  
760
#: ../larpe/admin/hosts.ptl:632 ../larpe/admin/hosts.ptl:633
761
msgid "Authentication response"
762
msgstr ""
763

  
764
#: ../larpe/admin/hosts.ptl:635
765
msgid "Response of the request with good credentials"
766
msgstr ""
767

  
768
#: ../larpe/admin/hosts.ptl:638 ../larpe/admin/hosts.ptl:649
769
msgid "HTTP status code"
770
msgstr ""
771

  
772
#: ../larpe/admin/hosts.ptl:643 ../larpe/admin/hosts.ptl:654
773
msgid "See HTML page"
774
msgstr ""
775

  
776
#: ../larpe/admin/hosts.ptl:646
777
msgid "Response of the request with bad credentials"
778
msgstr ""
779

  
780
#: ../larpe/admin/hosts.ptl:675 ../larpe/admin/hosts.ptl:676
781
msgid "Authentication success criteria"
782
msgstr ""
783

  
784
#: ../larpe/admin/hosts.ptl:682
785
msgid "Authentication system of the original site"
786
msgstr ""
787

  
788
#: ../larpe/admin/hosts.ptl:684
789
msgid "Check the existence of a password field"
790
msgstr ""
791

  
792
#: ../larpe/admin/hosts.ptl:685
793
msgid "Match some text to detect an authentication failure"
794
msgstr ""
795

  
796
#: ../larpe/admin/hosts.ptl:690
797
msgid "Text to match in case of authentication failure"
798
msgstr ""
799

  
800
#: ../larpe/admin/hosts.ptl:704
801
msgid "Authentication request"
802
msgstr ""
803

  
804
#: ../larpe/admin/hosts.ptl:709
805
msgid "Modify POST parameters"
806
msgstr ""
807

  
808
#: ../larpe/admin/hosts.ptl:709
809
msgid ""
810
"Configure the form attributes that will be sent within the authentication "
811
"POST requests"
812
msgstr ""
813

  
814
#: ../larpe/admin/hosts.ptl:711
815
msgid "Modify HTTP headers"
816
msgstr ""
817

  
818
#: ../larpe/admin/hosts.ptl:711
819
msgid "Configure the HTTP headers of the authentication requests made by Larpe"
820
msgstr ""
821

  
822
#: ../larpe/admin/hosts.ptl:725
823
msgid "POST parameters"
824
msgstr ""
825

  
826
#: ../larpe/admin/hosts.ptl:726
827
msgid "Configure POST parameters"
828
msgstr ""
829

  
830
#: ../larpe/admin/hosts.ptl:728
831
msgid ""
832
"Here are the detected form fields that will be sent as parameters of the\n"
833
"authentication POST request. You can desactivate some or all of them, or "
834
"change their value."
835
msgstr ""
836

  
837
#: ../larpe/admin/hosts.ptl:766
838
msgid "HTTP headers"
839
msgstr ""
840

  
841
#: ../larpe/admin/hosts.ptl:767
842
msgid "Configure HTTP headers"
843
msgstr ""
844

  
845
#: ../larpe/admin/hosts.ptl:769
846
msgid ""
847
"Here are the HTTP headers that will be sent within the authentication\n"
848
"POST request. You can desactivate some or all of them, or change their value."
849
msgstr ""
850

  
851
#: ../larpe/admin/hosts.ptl:782
852
msgid ""
853
"The headers \"Host\", \"Accept-Encoding\" and \"Content-Length\" will also "
854
"automatically be sent."
855
msgstr ""
856

  
857
#: ../larpe/admin/hosts.ptl:785
858
msgid ""
859
"As Larpe uses a proxy for this site, the headers \"Proxy-Authorization\",\n"
860
"\"Proxy-Connection\" and \"Keep-Alive\" will be sent as well."
861
msgstr ""
862

  
863
#: ../larpe/admin/hosts.ptl:846
864
msgid "SSO initiation"
865
msgstr ""
866

  
867
#: ../larpe/admin/hosts.ptl:847
868
msgid "Step 7 - Configure how a Single Sign On can be initiated"
869
msgstr ""
870

  
871
#: ../larpe/admin/hosts.ptl:849
872
msgid ""
873
"Most sites use one of the following 2 ways to allow users to initialise an "
874
"authentication :"
875
msgstr ""
876

  
877
#: ../larpe/admin/hosts.ptl:852
878
msgid ""
879
"The site has a single authentication page. It redirects users to this page "
880
"when\n"
881
"they click a \"Login\" button or try to access a page which require users to "
882
"be authenticated."
883
msgstr ""
884

  
885
#: ../larpe/admin/hosts.ptl:855
886
msgid ""
887
"The site includes an authentication form in most or all of his pages. Users "
888
"can\n"
889
"authenticate on any of these pages, and don't need to be redirected to a "
890
"separate authentication page."
891
msgstr ""
892

  
893
#: ../larpe/admin/hosts.ptl:860
894
msgid "Select the way your site works :"
895
msgstr ""
896

  
897
#: ../larpe/admin/hosts.ptl:868
898
msgid "The site has a single authentication page"
899
msgstr ""
900

  
901
#: ../larpe/admin/hosts.ptl:869
902
msgid "The site includes an authentication form in most or all pages"
903
msgstr ""
904

  
905
#: ../larpe/admin/hosts.ptl:900
906
msgid "Metadatas"
907
msgstr ""
908

  
909
#: ../larpe/admin/hosts.ptl:901
910
#, python-format
911
msgid "Step 8 - Metadatas of %(site_name)s"
912
msgstr ""
913

  
914
#: ../larpe/admin/hosts.ptl:904
915
msgid ""
916
"Download the metadatas and the public key for this site and\n"
917
"upload them on your identity provider in order to use Liberty Alliance "
918
"features."
919
msgstr ""
920

  
921
#: ../larpe/admin/hosts.ptl:914
922
msgid "Download SAML 2.0 metadata file"
923
msgstr ""
924

  
925
#: ../larpe/admin/hosts.ptl:919
926
msgid "Download ID-FF 1.2 metadata file"
927
msgstr ""
928

  
929
#: ../larpe/admin/hosts.ptl:921
930
msgid "No metadata has been generated for this host."
931
msgstr ""
932

  
933
#: ../larpe/admin/hosts.ptl:930
934
msgid "No public key has been generated for this host."
935
msgstr ""
936

  
937
#: ../larpe/admin/hosts.ptl:942
938
msgid "Advanced options"
939
msgstr ""
940

  
941
#: ../larpe/admin/hosts.ptl:943
942
msgid "Step 9 - Advanced options"
943
msgstr ""
944

  
945
#: ../larpe/admin/hosts.ptl:945
946
msgid "Configure advanced options to setup the last details of your site."
947
msgstr ""
948

  
949
#: ../larpe/admin/hosts.ptl:946
950
#, python-format
951
msgid ""
952
"If you don't know what to configure here, just click %(next)s and\n"
953
"come here later if needed."
954
msgstr ""
955

  
956
#: ../larpe/admin/hosts.ptl:959
957
msgid "Redirect the root URL of the site to the login page."
958
msgstr ""
959

  
960
#: ../larpe/admin/hosts.ptl:961
961
msgid "Return address"
962
msgstr ""
963

  
964
#: ../larpe/admin/hosts.ptl:962
965
msgid "Where the user will be redirected after a successful authentication"
966
msgstr ""
967

  
968
#: ../larpe/admin/hosts.ptl:964
969
msgid "Error address"
970
msgstr ""
971

  
972
#: ../larpe/admin/hosts.ptl:965
973
msgid "Where the user will be redirected after a disconnection or an error"
974
msgstr ""
975

  
976
#: ../larpe/admin/hosts.ptl:967
977
msgid "URL which must initiate the SSO"
978
msgstr ""
979

  
980
#: ../larpe/admin/hosts.ptl:968
981
#, python-format
982
msgid ""
983
"Address which must initiate the SSO. If empty, defaults to the previously\n"
984
"specified \"%s\""
985
msgstr ""
986

  
987
#: ../larpe/admin/hosts.ptl:971
988
msgid "Apache HTML proxy"
989
msgstr ""
990

  
991
#: ../larpe/admin/hosts.ptl:972
992
msgid ""
993
"Converts urls in the HTML pages according to the host new domain name.\n"
994
"Disabled by default because it makes some sites not work correctly."
995
msgstr ""
996

  
997
#: ../larpe/admin/hosts.ptl:1003 ../larpe/admin/hosts.ptl:1024
998
msgid "Finish"
999
msgstr ""
1000

  
1001
#: ../larpe/admin/hosts.ptl:1011
1002
msgid "Check everything works"
1003
msgstr ""
1004

  
1005
#: ../larpe/admin/hosts.ptl:1012
1006
msgid "Step 10 - Check everything works"
1007
msgstr ""
1008

  
1009
#: ../larpe/admin/hosts.ptl:1015
1010
msgid ""
1011
"Now you can fully test your site, start from the home page, initiate a\n"
1012
"Single Sign On, federate your identities and do a Single Logout."
1013
msgstr ""
1014

  
1015
#: ../larpe/admin/hosts.ptl:1018
1016
msgid "The address of your site is : "
1017
msgstr ""
1018

  
1019
#: ../larpe/admin/hosts.ptl:1023
1020
#, python-format
1021
msgid ""
1022
"If everything works, click the \"%(finish)s\" button, otherwise you can go\n"
1023
"back and check your settings."
1024
msgstr ""
1025

  
1026
#: ../larpe/admin/hosts.ptl:1136 ../larpe/admin/hosts.ptl:1151
1027
#: ../larpe/admin/hosts.ptl:1182
1028
msgid "(filled by users)"
1029
msgstr ""
1030

  
1031
#: ../larpe/admin/hosts.ptl:1233
1032
msgid "Configuration assistant"
1033
msgstr ""
1034

  
1035
#: ../larpe/admin/hosts.ptl:1238
1036
msgid "Address of the original site"
1037
msgstr ""
1038

  
1039
#: ../larpe/admin/hosts.ptl:1238
1040
msgid "Configure the root address of the site"
1041
msgstr ""
1042

  
1043
#: ../larpe/admin/hosts.ptl:1241
1044
msgid "New address and name"
1045
msgstr ""
1046

  
1047
#: ../larpe/admin/hosts.ptl:1241
1048
msgid "Configure the new address and name of this site"
1049
msgstr ""
1050

  
1051
#: ../larpe/admin/hosts.ptl:1244
1052
msgid "Authentication and logout addresses"
1053
msgstr ""
1054

  
1055
#: ../larpe/admin/hosts.ptl:1244
1056
msgid "Configure the authentication and logout addresses of the original site"
1057
msgstr ""
1058

  
1059
#: ../larpe/admin/hosts.ptl:1247
1060
msgid "Check auto detected configuration"
1061
msgstr ""
1062

  
1063
#: ../larpe/admin/hosts.ptl:1247
1064
msgid "Check the automatically detected configuration is right"
1065
msgstr ""
1066

  
1067
#: ../larpe/admin/hosts.ptl:1250
1068
msgid "Configure some valid credentials to authenticate on the original site"
1069
msgstr ""
1070

  
1071
#: ../larpe/admin/hosts.ptl:1253
1072
msgid "Retry authentication"
1073
msgstr ""
1074

  
1075
#: ../larpe/admin/hosts.ptl:1253
1076
msgid ""
1077
"Retry sending an authentication request to the site to check if your new "
1078
"parameters work well"
1079
msgstr ""
1080

  
1081
#: ../larpe/admin/hosts.ptl:1256
1082
msgid "Check authentication response"
1083
msgstr ""
1084

  
1085
#: ../larpe/admin/hosts.ptl:1256
1086
msgid "Check the response from the latest authentication request"
1087
msgstr ""
1088

  
1089
#: ../larpe/admin/hosts.ptl:1259
1090
msgid "Configure authentication success criteria"
1091
msgstr ""
1092

  
1093
#: ../larpe/admin/hosts.ptl:1259
1094
msgid "Specify how Larpe knows if the authentication has succeeded or not"
1095
msgstr ""
1096

  
1097
#: ../larpe/admin/hosts.ptl:1262
1098
msgid "Modify authentication request"
1099
msgstr ""
1100

  
1101
#: ../larpe/admin/hosts.ptl:1262
1102
msgid "Modify POST fields or HTTP headers of the authentication request"
1103
msgstr ""
1104

  
1105
#: ../larpe/admin/hosts.ptl:1265
1106
msgid "Configure how a Single Sign On can be initiated"
1107
msgstr ""
1108

  
1109
#: ../larpe/admin/hosts.ptl:1268
1110
msgid "Metadatas and key"
1111
msgstr ""
1112

  
1113
#: ../larpe/admin/hosts.ptl:1268
1114
msgid "Download SAML 2.0 or ID-FF metadatas and SSL public key"
1115
msgstr ""
1116

  
1117
#: ../larpe/admin/hosts.ptl:1271
1118
msgid "Adavanced options"
1119
msgstr ""
1120

  
1121
#: ../larpe/admin/hosts.ptl:1271
1122
msgid "Configure advanced options to setup the last details of your site"
1123
msgstr ""
1124

  
1125
#: ../larpe/admin/hosts.ptl:1275
1126
msgid "Form prefilling with ID-WSF"
1127
msgstr ""
1128

  
1129
#: ../larpe/admin/hosts.ptl:1279
1130
msgid "Configure the forms to prefill"
1131
msgstr ""
1132

  
1133
#: ../larpe/admin/hosts.ptl:1285
1134
msgid "You are about to irrevocably delete this host."
1135
msgstr ""
1136

  
1137
#: ../larpe/admin/hosts.ptl:1292 ../larpe/admin/hosts.ptl:1293
1138
msgid "Delete Host"
1139
msgstr ""
1140

  
1141
#: ../larpe/admin/hosts.ptl:1305 ../larpe/admin/hosts.ptl:1306
1142
#: ../larpe/admin/hosts.ptl:1343 ../larpe/admin/hosts.ptl:1350
1143
#: ../larpe/admin/root.ptl:44
1144
msgid "Hosts"
1145
msgstr ""
1146

  
1147
#: ../larpe/admin/hosts.ptl:1309 ../larpe/admin/hosts.ptl:1336
1148
#: ../larpe/admin/hosts.ptl:1337
1149
msgid "New Host"
1150
msgstr ""
1151

  
1152
#: ../larpe/admin/root.ptl:48
1153
msgid "Liberty Alliance Reverse Proxy"
1154
msgstr ""
1155

  
1156
#: ../larpe/admin/root.ptl:59
1157
msgid "Administration"
1158
msgstr ""
1159

  
1160
#: ../larpe/saml2.ptl:32 ../larpe/saml2.ptl:46
1161
msgid "SAML 2.0 support not yet configured."
1162
msgstr ""
1163

  
1164
#: ../larpe/saml2.ptl:53
1165
msgid "Missing SAML Artifact"
1166
msgstr ""
1167

  
1168
#: ../larpe/saml2.ptl:64 ../larpe/liberty.ptl:58
1169
msgid "Failure to communicate with identity provider"
1170
msgstr ""
1171

  
1172
#: ../larpe/saml2.ptl:70 ../larpe/liberty.ptl:63
1173
msgid "Unknown authentication failure"
1174
msgstr ""
1175

  
1176
#: ../larpe/saml2.ptl:72 ../larpe/liberty.ptl:66
1177
msgid "Authentication failure; unknown principal"
1178
msgstr ""
1179

  
1180
#: ../larpe/saml2.ptl:334 ../larpe/liberty.ptl:142 ../larpe/liberty.ptl:173
1181
msgid "Failed to check single logout request signature."
1182
msgstr ""
1183

  
1184
#: ../larpe/site_authentication.ptl:60
1185
msgid "Local authentication"
1186
msgstr ""
1187

  
1188
#: ../larpe/site_authentication.ptl:74
1189
msgid "Authentication failure"
1190
msgstr ""
1191

  
1192
#: ../larpe/site_authentication.ptl:77
1193
#, python-format
1194
msgid "Connection failed : %s"
1195
msgstr ""
1196

  
1197
#: ../larpe/site_authentication.ptl:80
1198
#, python-format
1199
msgid "This service provider is not fully configured : %s"
1200
msgstr ""
1201

  
1202
#: ../larpe/site_authentication.ptl:83
1203
#, python-format
1204
msgid "Unknown error : %s"
1205
msgstr ""
1206

  
1207
#: ../larpe/site_authentication.ptl:89
1208
msgid "Please type your login and password for this Service Provider."
1209
msgstr ""
1210

  
1211
#: ../larpe/site_authentication.ptl:90 ../larpe/root.ptl:74
1212
msgid ""
1213
"Your local account will be federated with your Liberty Alliance account."
1214
msgstr ""
1215

  
1216
#: ../larpe/site_authentication.ptl:296
1217
#, python-format
1218
msgid "%s logout failed"
1219
msgstr ""
1220

  
1221
#: ../larpe/root.ptl:27
1222
msgid "Welcome to Larpe reverse proxy"
1223
msgstr ""
1224

  
1225
#: ../larpe/root.ptl:29
1226
msgid "Configure Larpe"
1227
msgstr ""
1228

  
1229
#: ../larpe/root.ptl:73
1230
msgid "Please enter your identification token. "
1231
msgstr ""
1232

  
1233
#: ../larpe/root.ptl:87
1234
msgid "Unknown Token"
1235
msgstr ""
1236

  
1237
#: ../larpe/liberty.ptl:45
1238
msgid "Liberty support is not yet configured"
1239
msgstr ""
1240

  
1241
#: ../larpe/liberty.ptl:67
1242
msgid "Identity Provider didn't accept artifact transaction."
1243
msgstr ""
1244

  
1245
#: ../larpe/users.py:38
1246
msgid "Unknown User"
1247
msgstr ""
larpe/tags/release-1.1.1/pylintrc
1
# lint Python modules using external checkers.
2
# 
3
# This is the main checker controlling the other ones and the reports
4
# generation. It is itself both a raw checker and an astng checker in order
5
# to:
6
# * handle message activation / deactivation at the module level
7
# * handle some basic but necessary stats'data (number of classes, methods...)
8
# 
9
[MASTER]
10

  
11
# Specify a configuration file.
12
#rcfile=
13

  
14
# Python code to execute, usually for sys.path manipulation such as
15
# pygtk.require().
16
#init-hook=
17

  
18
# Profiled execution.
19
profile=no
20

  
21
# Add <file or directory> to the black list. It should be a base name, not a
22
# path. You may set this option multiple times.
23
ignore=.svn,qommon
24

  
25
# Pickle collected data for later comparisons.
26
persistent=yes
27

  
28
# Set the cache size for astng objects.
29
cache-size=500
30

  
31
# List of plugins (as comma separated values of python modules names) to load,
32
# usually to register additional checkers.
33
load-plugins=
34

  
35

  
36
[MESSAGES CONTROL]
37

  
38
# Enable only checker(s) with the given id(s). This option conflicts with the
39
# disable-checker option
40
#enable-checker=
41

  
42
# Enable all checker(s) except those with the given id(s). This option
43
# conflicts with the enable-checker option
44
#disable-checker=
45

  
46
# Enable all messages in the listed categories.
47
#enable-msg-cat=
48

  
49
# Disable all messages in the listed categories.
50
#disable-msg-cat=
51

  
52
# Enable the message(s) with the given id(s).
53
#enable-msg=
54

  
55
# Disable the message(s) with the given id(s).
56
disable-msg=C0111,R0904,W0403
57

  
58

  
59
[REPORTS]
60

  
61
# Set the output format. Available formats are text, parseable, colorized, msvs
62
# (visual studio) and html
63
output-format=text
64

  
65
# Include message's id in output
66
include-ids=yes
67

  
68
# Put messages in a separate file for each module / package specified on the
69
# command line instead of printing them on stdout. Reports (if any) will be
70
# written in a file name "pylint_global.[txt|html]".
71
files-output=no
72

  
73
# Tells wether to display a full report or only the messages
74
reports=no
75

  
76
# Python expression which should return a note less than 10 (10 is the highest
77
# note). You have access to the variables errors warning, statement which
78
# respectivly contain the number of errors / warnings messages and the total
79
# number of statements analyzed. This is used by the global evaluation report
80
# (R0004).
81
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
82

  
83
# Add a comment according to your evaluation note. This is used by the global
84
# evaluation report (R0004).
85
comment=no
86

  
87
# Enable the report(s) with the given id(s).
88
#enable-report=
89

  
90
# Disable the report(s) with the given id(s).
91
#disable-report=
92

  
93

  
94
# try to find bugs in the code using type inference
95
# 
96
[TYPECHECK]
97

  
98
# Tells wether missing members accessed in mixin class should be ignored. A
99
# mixin class is detected if its name ends with "mixin" (case insensitive).
100
ignore-mixin-members=yes
101

  
102
# List of classes names for which member attributes should not be checked
103
# (useful for classes with attributes dynamicaly set).
104
ignored-classes=SQLObject
105

  
106
# When zope mode is activated, add a predefined set of Zope acquired attributes
107
# to generated-members.
108
zope=no
109

  
110
# List of members which are set dynamically and missed by pylint inference
111
# system, and so shouldn't trigger E0201 when accessed.
112
generated-members=REQUEST,acl_users,aq_parent
113

  
114

  
115
# checks for
116
# * unused variables / imports
117
# * undefined variables
118
# * redefinition of variable from builtins or from an outer scope
119
# * use of variable before assigment
120
# 
121
[VARIABLES]
122

  
123
# Tells wether we should check for unused import in __init__ files.
124
init-import=no
125

  
126
# A regular expression matching names used for dummy variables (i.e. not used).
127
dummy-variables-rgx=_|dummy
128

  
129
# List of additional names supposed to be defined in builtins. Remember that
130
# you should avoid to define new builtins when possible.
131
additional-builtins=
132

  
133

  
134
# checks for :
135
# * doc strings
136
# * modules / classes / functions / methods / arguments / variables name
137
# * number of arguments, local variables, branchs, returns and statements in
138
# functions, methods
139
# * required module attributes
140
# * dangerous default values as arguments
141
# * redefinition of function / method / class
142
# * uses of the global statement
143
# 
144
[BASIC]
145

  
146
# Required attributes for module, separated by a comma
147
required-attributes=
148

  
149
# Regular expression which should only match functions or classes name which do
150
# not require a docstring
151
no-docstring-rgx=__.*__
152

  
153
# Regular expression which should only match correct module names
154
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
155

  
156
# Regular expression which should only match correct module level names
157
#const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
158
const-rgx=[a-z\_][a-z0-9\_]{2,30}$
159

  
160
# Regular expression which should only match correct class names
161
class-rgx=[A-Z_][a-zA-Z0-9]+$
162

  
163
# Regular expression which should only match correct function names
164
function-rgx=[a-z_][a-z0-9_]{2,30}$
165

  
166
# Regular expression which should only match correct method names
167
method-rgx=[a-z_][a-z0-9_]{2,30}$
168

  
169
# Regular expression which should only match correct instance attribute names
170
attr-rgx=[a-z_][a-z0-9_]{2,30}$
171

  
172
# Regular expression which should only match correct argument names
173
argument-rgx=[a-z_][a-z0-9_]{2,30}$
174

  
175
# Regular expression which should only match correct variable names
176
variable-rgx=[a-z_][a-z0-9_]{2,30}$
177

  
178
# Regular expression which should only match correct list comprehension /
179
# generator expression variable names
180
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
181

  
182
# Good variable names which should always be accepted, separated by a comma
183
good-names=i,j,k,ex,Run,_
184

  
185
# Bad variable names which should always be refused, separated by a comma
186
bad-names=foo,bar,baz,toto,tutu,tata
187

  
188
# List of builtins function names that should not be used, separated by a comma
189
bad-functions=map,filter,apply,input
190

  
191

  
192
# checks for sign of poor/misdesign:
193
# * number of methods, attributes, local variables...
194
# * size, complexity of functions, methods
195
# 
196
[DESIGN]
197

  
198
# Maximum number of arguments for function / method
199
max-args=5
200

  
201
# Maximum number of locals for function / method body
202
max-locals=15
203

  
204
# Maximum number of return / yield for function / method body
205
max-returns=6
206

  
207
# Maximum number of branch for function / method body
208
max-branchs=12
209

  
210
# Maximum number of statements in function / method body
211
max-statements=50
212

  
213
# Maximum number of parents for a class (see R0901).
214
max-parents=7
215

  
216
# Maximum number of attributes for a class (see R0902).
217
max-attributes=7
218

  
219
# Minimum number of public methods for a class (see R0903).
220
min-public-methods=2
221

  
222
# Maximum number of public methods for a class (see R0904).
223
max-public-methods=20
224

  
225

  
226
# checks for :
227
# * methods without self as first argument
228
# * overridden methods signature
229
# * access only to existant members via self
230
# * attributes not defined in the __init__ method
231
# * supported interfaces implementation
232
# * unreachable code
233
# 
234
[CLASSES]
235

  
236
# List of interface methods to ignore, separated by a comma. This is used for
237
# instance to not check methods defines in Zope's Interface base class.
238
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
239

  
240
# List of method names used to declare (i.e. assign) instance attributes.
241
defining-attr-methods=__init__,__new__,setUp
242

  
243

  
244
# checks for
245
# * external modules dependencies
246
# * relative / wildcard imports
247
# * cyclic imports
248
# * uses of deprecated modules
249
# 
250
[IMPORTS]
251

  
252
# Deprecated modules which should not be used, separated by a comma
253
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
254

  
255
# Create a graph of every (i.e. internal and external) dependencies in the
256
# given file (report R0402 must not be disabled)
257
import-graph=
258

  
259
# Create a graph of external dependencies in the given file (report R0402 must
260
# not be disabled)
261
ext-import-graph=
262

  
263
# Create a graph of internal dependencies in the given file (report R0402 must
264
# not be disabled)
265
int-import-graph=
266

  
267

  
268
# checks for :
269
# * unauthorized constructions
270
# * strict indentation
271
# * line length
272
# * use of <> instead of !=
273
# 
274
[FORMAT]
275

  
276
# Maximum number of characters on a single line.
277
max-line-length=100
278

  
279
# Maximum number of lines in a module
280
max-module-lines=1000
281

  
282
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
283
# tab).
284
indent-string='    '
285

  
286

  
287
# checks for similarities and duplicated code. This computation may be
288
# memory / CPU intensive, so you should disable it if you experiments some
289
# problems.
290
# 
291
[SIMILARITIES]
292

  
293
# Minimum lines number of a similarity.
294
min-similarity-lines=4
295

  
296
# Ignore comments when computing similarities.
297
ignore-comments=yes
298

  
299
# Ignore docstrings when computing similarities.
300
ignore-docstrings=yes
301

  
302

  
303
# checks for:
304
# * warning notes in the code like FIXME, XXX
305
# * PEP 263: source code with non ascii character but no encoding declaration
306
# 
307
[MISCELLANEOUS]
308

  
309
# List of note tags to take in consideration, separated by a comma.
310
notes=FIXME,XXX,TODO
larpe/tags/release-1.1.1/root/index.html
1
<html xmlns="http://www.w3.org/1999/xhtml">
2
  <head>
3
    <title>Larpe</title>
4
    <link rel="stylesheet" type="text/css" href="/css/larpe.css"/>
5
    <style type="text/css">
6
p#larpe {
7
	margin-top: 30%;
8
	text-align: center;
9
	font-weight: bold;
10
}
11
</style>
12
  </head>
13
  <body>
14
   <p id="larpe">
15
     Larpe
16
   </p>
17
  </body>
18
</html>
larpe/tags/release-1.1.1/root/larpe/css/dc2/admin.css
1
@import url(../larpe-common.css);
2

  
3
html, body {
4
	margin: 0;
5
	background: white url(page-bg.png) repeat-y;
6
}
7

  
8
div#main-content {
9
	margin-left: 160px;
10
	margin-top: -10px;
11
	margin-right: 20px;
12
}
13

  
14
div#main-content h1 {
15
	color: #006699;
16
	font-size: 120%;
17
}
18

  
19
div#main-content h2 {
20
	color: #006699;
21
	font-size: 115%;
22
}
23

  
24
div#main-content h3 {
25
	color: #006699;
26
	font-size: 108%
27
}
28

  
29

  
30

  
31
div#header {
32
	margin: 0;
33
	background: white url(head-bg.png) repeat-x;
34
	height: 58px;
35
}
36

  
37
ul#menu {
38
	background: transparent url(head-logo.png) no-repeat;
39
	width: 177px;
40
	margin: 0;
41
	padding: 80px 0 0 5px;
42
}
43

  
44
a {
45
	color: #0066cc;
46
	text-decoration: none;
47
	border-bottom: 1px dotted #ff9900;
48
}
49

  
50
p.commands a {
51
	border: 0;
52
}
53

  
54
ul#menu a {
55
	font-weight: bold;
56
}
57

  
58
ul#menu li.active a {
59
	border-bottom: 1px solid #ff9900;
60
}
61

  
62
ul#menu li {
63
	font-size: 90%;
64
	margin-bottom: 1em;
65
	max-width: 130px;
66
}
67

  
68
div#footer {
69
	display: none;
70
}
71

  
72
ul.user-info {
73
	position: absolute;
74
	margin: 0;
75
	padding: 0;
76
	right: 25px;
77
	top: 13px;
78
	font-size: 70%;
79
	font-weight: bold;
80
}
81

  
82
ul.user-info li {
83
	display: inline;
84
	padding-left: 10px;
85
}
86

  
87
/** end of dc2 changes **/
88

  
89

  
90

  
91
ul.biglist {
92
	margin: 0;
93
	padding: 0;
94
}
95

  
96
ul.biglist li {
97
	list-style-type: none;
98
	margin: 4px 0;
99
	padding: 0 2px;
100
	border: 1px solid #888;
101
	background: #ffe;
102
	clear: both;
103
}
104

  
105
ul.biglist li p.details {
106
	display: block;
107
	margin: 0;
108
	color: #555;
109
	font-size: 80%;
110
}
111

  
112

  
113
ul.biglist li p.commands {
114
	float: right;
115
	margin-top: -17px;
116
}
117

  
118
ul.biglist li p.commands img {
119
	padding-right: 5px;
120
}
121

  
122
a img {
123
	border: 0;
124
}
125

  
126
td.time {
127
	text-align: right;
128
}
129

  
130
ul.biglist li.disabled, ul.biglist li.disabled p.details {
131
	color: #999;
132
	background: #ddd;
133
}
134

  
135

  
136
dl dt {
137
	margin : 0;
138
	padding : 0 0 0 0;
139
}
140

  
141
dl dd {
142
        margin : 0.3em 0 1.5em 10px;
143
}
144

  
145

  
146
img.theme-icon {
147
	float: right;
148
	margin: -16px 4px 0px 3px;
149
	border: 1px solid #999;
150
}
151

  
152
div#new-field table {
153
	margin: 0;
154
	padding: 0;
155
}
156

  
157
div#new-field div.widget {
158
	margin: 0;
159
	padding: 0;
160
}
161

  
162
div#new-field div.buttons {
163
	margin: 0;
164
	padding: 0;
165
}
166

  
167
div#new-field div.buttons input {
168
	margin: 0;
169
	padding: 0;
170
}
171

  
172
div#new-field {
173
	border: 1px solid #888;
174
	background: #ffe;
175
	margin: 2em 0 4px 0;
176
	padding: 0 2px;
177
}
178

  
179
div#new-field div.widget {
180
}
181

  
182
div#new-field h3 {
183
	margin: 0;
184
	font-size: 100%;
185
}
186

  
187
div#new-field br {
188
	display: none;
189
}
190

  
191
div#new-field p.commands {
192
	float: right;
193
	margin-top: -17px;
194
	margin-right: 3px;
195
}
196

  
197
div.WorkflowStatusWidget {
198
	border-left: 1px solid black;
199
}
200

  
201
p#breadcrumb {
202
	background: #e6e6e6;
203
	-moz-border-radius: 6px;
204
	padding: 3px 8px;
205
	font-size: 80%;
206
	border: 1px solid #bfbfbf;
207
}
208

  
209
/** steps **/
210
#steps {
211
	height: 32px;
212
	margin-bottom: 1em;
213
	background: #f0f0f0;
214
	color: #aaa;
215
}
216

  
217
#steps ol {
218
	list-style: none;
219
	padding: 0 20px;
220
}
221

  
222
#steps li {
223
	display: inline;
224
	padding-right: 1em;
225
	display: block;
226
	float: left;
227
	width: 30%;
228
	list-style: none;
229
}
230

  
231
#steps ol ul {
232
	display: none;
233
}
234

  
235
#steps span.marker {
236
	font-size: 26px;
237
	padding: 2px 9px;
238
	font-weight: bold;
239
	color: white;
240
	text-align: center;
241
	background: #ddd;
242
	border: 1px solid #ddd;
243
	-moz-border-radius: 0.7ex;
244
}
245

  
246
#steps li.current span.marker {
247
	background: #ffa500;
248
	border: 1px solid #ffc400;
249
}
250

  
251
#steps span.label {
252
	font-size: 90%;
253
}
254

  
255
#steps li.current span.label {
256
	color: black;
257
}
258

  
259
#steps ol ul {
260
	display: none;
261
}
262

  
263

  
264
/** logs **/
265
form#other-log-select {
266
	margin-top: 2em;
267
	padding-top: 1em;
268
	border-top: 1px solid #999;
269
}
270

  
271
form#other-log-select select {
272
	margin: 0 1em;
273
}
274

  
275
tr.level-error td {
276
	border: 1px solid #800;
277
	background: red;
278
}
279

  
280
tr.level-error td.message {
281
	font-weight: bold;
282
}
283

  
larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/theme.css
1
/* Distributed as part of The Coolest DHTML Calendar
2
   Author: Mihai Bazon, www.bazon.net/mishoo
3
   Copyright Dynarch.com 2005, www.dynarch.com
4
*/
5

  
6
/* The main calendar widget.  DIV containing a table. */
7

  
8
div.calendar { position: relative; }
9

  
10
.calendar, .calendar table {
11
  border: 1px solid #bdb2bf;
12
  font-size: 11px;
13
  color: #000;
14
  cursor: default;
15
  background: url("/css/jscalendar/aqua/normal-bg.gif");
16
  font-family: "trebuchet ms",verdana,tahoma,sans-serif;
17
}
18

  
19
.calendar {
20
  border-color: #797979;
21
}
22

  
23
/* Header part -- contains navigation buttons and day names. */
24

  
25
.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */
26
  text-align: center;    /* They are the navigation buttons */
27
  padding: 2px;          /* Make the buttons seem like they're pressing */
28
  background: url("/css/jscalendar/aqua/title-bg.gif") repeat-x 0 100%; color: #000;
29
  font-weight: bold;
30
}
31

  
32
.calendar .nav {
33
  font-family: verdana,tahoma,sans-serif;
34
}
35

  
36
.calendar .nav div {
37
  background: transparent url("/css/jscalendar/aqua/menuarrow.gif") no-repeat 100% 100%;
38
}
39

  
40
.calendar thead tr { background: url("/css/jscalendar/aqua/title-bg.gif") repeat-x 0 100%; color: #000; }
41

  
42
.calendar thead .title { /* This holds the current "month, year" */
43
  font-weight: bold;      /* Pressing it will take you to the current date */
44
  text-align: center;
45
  padding: 2px;
46
  background: url("/css/jscalendar/aqua/title-bg.gif") repeat-x 0 100%; color: #000;
47
}
48

  
49
.calendar thead .headrow { /* Row <TR> containing navigation buttons */
50
}
51

  
52
.calendar thead .name { /* Cells <TD> containing the day names */
53
  border-bottom: 1px solid #797979;
54
  padding: 2px;
55
  text-align: center;
56
  color: #000;
57
}
58

  
59
.calendar thead .weekend { /* How a weekend day name shows in header */
60
  color: #c44;
61
}
62

  
63
.calendar thead .hilite { /* How do the buttons in header appear when hover */
64
  background: url("/css/jscalendar/aqua/hover-bg.gif");
65
  border-bottom: 1px solid #797979;
66
  padding: 2px 2px 1px 2px;
67
}
68

  
69
.calendar thead .active { /* Active (pressed) buttons in header */
70
  background: url("/css/jscalendar/aqua/active-bg.gif"); color: #fff;
71
  padding: 3px 1px 0px 3px;
72
  border-bottom: 1px solid #797979;
73
}
74

  
75
.calendar thead .daynames { /* Row <TR> containing the day names */
76
  background: url("/css/jscalendar/aqua/dark-bg.gif");
77
}
78

  
79
/* The body part -- contains all the days in month. */
80

  
81
.calendar tbody .day { /* Cells <TD> containing month days dates */
82
  font-family: verdana,tahoma,sans-serif;
83
  width: 2em;
84
  color: #000;
85
  text-align: right;
86
  padding: 2px 4px 2px 2px;
87
}
88
.calendar tbody .day.othermonth {
89
  font-size: 80%;
90
  color: #999;
91
}
92
.calendar tbody .day.othermonth.oweekend {
93
  color: #f99;
94
}
95

  
96
.calendar table .wn {
97
  padding: 2px 3px 2px 2px;
98
  border-right: 1px solid #797979;
99
  background: url("/css/jscalendar/aqua/dark-bg.gif");
100
}
101

  
102
.calendar tbody .rowhilite td,
103
.calendar tbody .rowhilite td.wn {
104
  background: url("/css/jscalendar/aqua/rowhover-bg.gif");
105
}
106

  
107
.calendar tbody td.today { font-weight: bold; /* background: url("/css/jscalendar/aqua/today-bg.gif") no-repeat 70% 50%; */ }
108

  
109
.calendar tbody td.hilite { /* Hovered cells <TD> */
110
  background: url("/css/jscalendar/aqua/hover-bg.gif");
111
  padding: 1px 3px 1px 1px;
112
  border: 1px solid #bbb;
113
}
114

  
115
.calendar tbody td.active { /* Active (pressed) cells <TD> */
116
  padding: 2px 2px 0px 2px;
117
}
118

  
119
.calendar tbody td.weekend { /* Cells showing weekend days */
120
  color: #c44;
121
}
122

  
123
.calendar tbody td.selected { /* Cell showing selected date */
124
  font-weight: bold;
125
  border: 1px solid #797979;
126
  padding: 1px 3px 1px 1px;
127
  background: url("/css/jscalendar/aqua/active-bg.gif"); color: #fff;
128
}
129

  
130
.calendar tbody .disabled { color: #999; }
131

  
132
.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */
133
  visibility: hidden;
134
}
135

  
136
.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */
137
  display: none;
138
}
139

  
140
/* The footer part -- status bar and "Close" button */
141

  
142
.calendar tfoot .footrow { /* The <TR> in footer (only one right now) */
143
  text-align: center;
144
  background: #565;
145
  color: #fff;
146
}
147

  
148
.calendar tfoot .ttip { /* Tooltip (status bar) cell <TD> */
149
  padding: 2px;
150
  background: url("/css/jscalendar/aqua/status-bg.gif") repeat-x 0 0; color: #000;
151
}
152

  
153
.calendar tfoot .hilite { /* Hover style for buttons in footer */
154
  background: #afa;
155
  border: 1px solid #084;
156
  color: #000;
157
  padding: 1px;
158
}
159

  
160
.calendar tfoot .active { /* Active (pressed) style for buttons in footer */
161
  background: #7c7;
162
  padding: 2px 0px 0px 2px;
163
}
164

  
165
/* Combo boxes (menus that display months/years for direct selection) */
166

  
167
.calendar .combo {
168
  position: absolute;
169
  display: none;
170
  top: 0px;
171
  left: 0px;
172
  width: 4em;
173
  cursor: default;
174
  border-width: 0 1px 1px 1px;
175
  border-style: solid;
176
  border-color: #797979;
177
  background: url("/css/jscalendar/aqua/normal-bg.gif"); color: #000;
178
  z-index: 100;
179
  font-size: 90%;
180
}
181

  
182
.calendar .combo .label,
183
.calendar .combo .label-IEfix {
184
  text-align: center;
185
  padding: 1px;
186
}
187

  
188
.calendar .combo .label-IEfix {
189
  width: 4em;
190
}
191

  
192
.calendar .combo .hilite {
193
  background: url("/css/jscalendar/aqua/hover-bg.gif"); color: #000;
194
}
195

  
196
.calendar .combo .active {
197
  background: url("/css/jscalendar/aqua/active-bg.gif"); color: #fff;
198
  font-weight: bold;
199
}
200

  
201
.calendar td.time {
202
  border-top: 1px solid #797979;
203
  padding: 1px 0px;
204
  text-align: center;
205
  background: url("/css/jscalendar/aqua/dark-bg.gif");
206
}
207

  
208
.calendar td.time .hour,
209
.calendar td.time .minute,
210
.calendar td.time .ampm {
211
  padding: 0px 5px 0px 6px;
212
  font-weight: bold;
213
  background: url("/css/jscalendar/aqua/normal-bg.gif"); color: #000;
214
}
215

  
216
.calendar td.time .hour,
217
.calendar td.time .minute {
218
  font-family: monospace;
219
}
220

  
221
.calendar td.time .ampm {
222
  text-align: center;
223
}
224

  
225
.calendar td.time .colon {
226
  padding: 0px 2px 0px 3px;
227
  font-weight: bold;
228
}
229

  
230
.calendar td.time span.hilite {
231
  background: url("/css/jscalendar/aqua/hover-bg.gif"); color: #000;
232
}
233

  
234
.calendar td.time span.active {
235
  background: url("/css/jscalendar/aqua/active-bg.gif"); color: #fff;
236
}
larpe/tags/release-1.1.1/root/larpe/css/larpe-admin.css
1
@import url(larpe-common.css);
2

  
3
body {
4
	font-family: sans-serif;
5
	background : white url(fond.jpg) repeat;
6
}
7

  
8
div#main-content {
9
	clear: both;
10
	max-width: 800px;
11
	margin: 0 4em;
12
	background: white url(deg-top.png) top left repeat-x;
13
	border: 1px solid #999;
14
	padding: 1em;
15
}
16

  
17
div#main-content h1 {
18
	margin: 0 140px 1em 0;
19
	border: 1px solid #666;
20
	padding: 0 0.5ex;
21
	background: white url(bg-footer.png) top right repeat-y;
22
	font-size: 150%;
23
}
24

  
25
#header {
26
	max-width: 800px;
27
	margin: 0 4em;
28
	padding: 0 1em;
29
	background-image : url(dot999.png);
30
	background-repeat : repeat-x;
31
	background-position : 0 100%;
32
	position: relative;
33
	top: 1px;
34
}
35

  
36
#header ul {
37
	margin : 0;
38
	padding : 0;
39
	list-style : none;
40
}
41

  
42
#header li {
43
	float : left;
44
	margin : 0 -1px 0 0;
45
	padding : 0 0 0 8px;
46
	background-repeat : no-repeat;
47
	background-position : 0 -110px;
48
	background-image: url(onglet_left.png);
49
	border-bottom: 1px solid #999;
50
}
51
#header a {
52
	float : left;
53
	display : block;
54
	background-image : url(onglet_right.png);
55
	background-repeat : no-repeat;
56
	background-position : 100% -110px;
57
	padding : 10px 10px 4px 3px;
58
	font-weight : bold;
59
	text-decoration : none;
60
	color : #000;
61
}
62

  
63
/* Commented Backslash Hack
64
Cache des règles à IE5-Mac \*/
65
#header a {float:none;}
66
/* Fin du hack IE5-Mac */
67

  
68
#header li.active, #header li.active:hover {
69
	background-position : 0 0;
70
}
71
#header li.active a, #header li.active:hover a {
72
	background-position : 100% 0;
73
}
74
#header li:hover {
75
	background-position : 0 -220px;
76
}
77
#header li:hover a {
78
	background-position : 100% -220px;
79
}
80

  
81
#header li.active {
82
	border-bottom: 1px solid #eceade;
83
}
84

  
85
/*
86
#header li.inactive,
87
#header li.inactive:hover {
88
	background-position: 0 0;
89
}
90

  
91
#header li.inactive a,
92
#header li.inactive:hover a {
93
	background-position: 100% 0;
94
	color: gray;
95
}
96
*/
97

  
98
div#footer {
99
	max-width: 800px;
100
	margin: 0 4em;
101
	border: 1px solid #999;
102
	border-top: 0;
103
	background: #eceade;
104
	padding: 0 1em;
105
}
106

  
107
div#footer p {
108
	margin: 0;
109
	text-align: right;
110
	font-size: 80%;
111
	font-weight: bold;
112
}
113

  
114

  
115
div#login-top,
116
div#logout-top,
117
div#identity-top {
118
	margin: 6em auto 1em auto;
119
	border: 1px solid #999;
120
	background: white;
121
	padding: 0.5ex 1em;
122
}
123

  
124
div#login-top,
125
div#login-form {
126
	width: 20em;
127
	max-width: 200px;
128
}
129

  
130
div#logout-top,
131
div#logout-sps,
132
div#identity-top,
133
div#identity-content {
134
	width: 40em;
135
	max-width: 400px;
136
}
137

  
138
div#login-top h1,
139
div#logout-top h1,
140
div#identity-top h1 {
141
	margin: 0;
142
	text-align: center;
143
}
144

  
145
div#login-form,
146
div#logout-sps,
147
div#identity-content {
148
	margin: 0 auto;
149
	background: white url(deg-top.png) top left repeat-x;
150
	border: 1px solid #999;
151
	padding: 1em;
152
}
153

  
154
div#login-form br {
155
	display: none;
156
}
157

  
158
div#login-form div.StringWidget {
159
	margin-bottom: 1ex;
160
}
161

  
162
p#cookies {
163
	margin: 0 1em;
164
	text-align: center;
165
	font-size: 90%;
166
}
167

  
168
form#login span.required {
169
	display: none
170
}
171

  
172
div#logout-sps ul li {
173
	list-style: circle;
174
}
175

  
176
div#logout-sps ul {
177
	padding-left: 2em;
178
}
179

  
180
div#logout-sps ul li img {
181
	padding-left: 1em;
182
}
183

  
184
ul.user-info {
185
	float : right;
186
	width : 102px;
187
	position : relative;
188
	margin : 0 0 1em 1em;
189
	padding : 5px 0 0 30px;
190
	background : transparent url(user_info_top.png) no-repeat top left;
191
	list-style : none;
192
}
193
li.ui-name {
194
}
195
li.ui-logout {
196
	display : block;
197
	background : transparent url(user_info_bottom.png) no-repeat bottom left;
198
	padding : 8px 0 10px 10px;
199
	margin : 0 0 0 -30px;
200
}
201

  
202
li.ui-logout a {
203
	padding-left: 20px;
204
}
205

  
206
table {
207
	clear: both;
208
}
209

  
210
table th {
211
	text-align: left;
212
	border-bottom: 1px solid #999;
213
}
214

  
215
table td {
216
	padding-right: 1ex;
217
}
218

  
219
dl dt {
220
	margin : 0;
221
	padding : 0 0 0 0;
222
}
223

  
224
dl dd {
225
        margin : 0.3em 0 1.5em 10px;
226
}
227

  
228
div#identity-content hr {
229
	margin: 1em 2em;
230
	height: 1px;
231
	background: #999;
232
	border: 0;
233

  
234
}
235

  
236
div.FieldWidget div.StringWidget {
237
	float: left;
238
	width: 30%;
239
}
240

  
241
br.FieldWidget,
242
div.FieldWidget br {
243
	display: none;
244
}
245

  
246
pre {
247
	overflow: scroll;
248
}
249

  
250
div.explanation {
251
	margin: 0 140px 1em 0;
252
	background: white url(bg-footer.png) top right repeat-y;
253
	border: 1px solid #ccc;
254
	padding: 3px;
255
}
256

  
257
div.explanation ol,
258
div.explanation p {
259
	margin: 0;
260
}
261

  
262
div#error-page {
263
	border: 1px solid #a00;
264
}
265

  
266
div#error-page h2 {
267
	margin: 0;
268
	border-bottom: 1px solid #a00;
269
	background: #f52;
270
	padding: 0 3px;
271
}
272

  
273
div#error-page p {
274
	padding: 0 3px;
275
}
276

  
277
img.theme-icon {
278
	float: right;
279
	margin: -16px 4px 0px 3px;
280
	border: 1px solid #999;
281
}
282

  
283
a.arrow {
284
	text-decoration: none;
285
}
286

  
287
ul.biglist {
288
	margin: 0;
289
	padding: 0;
290
}
291

  
292
#fields-list li {
293
	cursor: move;
294
}
295

  
296
ul.biglist li {
297
	list-style-type: none;
298
	margin: 4px 0;
299
	padding: 0 2px;
300
	border: 1px solid #888;
301
	background: #ffe;
302
	clear: both;
303
}
304

  
305
ul.biglist li p.details {
306
	display: block;
307
	margin: 0;
308
	color: #555;
309
	font-size: 80%;
310
}
311

  
312

  
313
ul.biglist li p.commands {
314
	float: right;
315
	margin-top: -17px;
316
}
317

  
318
ul.biglist li p.commands img {
319
	padding-right: 5px;
320
}
321

  
322
a img {
323
	border: 0;
324
}
325

  
326
td.time {
327
	text-align: right;
328
}
329

  
330
ul.biglist li.disabled, ul.biglist li.disabled p.details {
331
	color: #999;
332
	background: #ddd;
333
}
334

  
335
form#other-log-select {
336
	margin-top: 2em;
337
	padding-top: 1em;
338
	border-top: 1px solid #999;
339
}
340

  
341
form#other-log-select select {
342
	margin: 0 1em;
343
}
344

  
345
tr.level-error td {
346
	border: 1px solid #800;
347
	background: red;
348
}
349

  
350
tr.level-error td.message {
351
	font-weight: bold;
352
}
353

  
354
div#new-field table {
355
	margin: 0;
356
	padding: 0;
357
}
358

  
359
div#new-field div.widget {
360
	margin: 0;
361
	padding: 0;
362
}
363

  
364
div#new-field div.buttons {
365
	margin: 0;
366
	padding: 0;
367
}
368

  
369
div#new-field div.buttons input {
370
	margin: 0;
371
	padding: 0;
372
}
373

  
374
div#new-field {
375
	border: 1px solid #888;
376
	background: #ffe;
377
	margin: 2em 0 4px 0;
378
	padding: 0 2px;
379
}
380

  
381
div#new-field div.widget {
382
}
383

  
384
div#new-field h3 {
385
	margin: 0;
386
	font-size: 100%;
387
}
388

  
389
div#new-field br {
390
	display: none;
391
}
392

  
393
div#new-field p.commands {
394
	float: right;
395
	margin-top: -17px;
396
	margin-right: 3px;
397
}
398

  
399
div.WorkflowStatusWidget {
400
	border-left: 1px solid black;
401
}
402

  
403
hr {
404
	border: none;
405
	border-top: 1px solid #666;
406
	height: 1px;
407
	width: 80%;
408
}
409

  
410

  
larpe/tags/release-1.1.1/root/larpe/css/larpe-common.css
1
a {
2
	color: #028;
3
}
4

  
5
div.content {
6
	margin-left: 5px;
7
}
8

  
9
div.TextWidget textarea,
10
div.StringWidget input,
11
div.DateWidget input,
12
div.WcsExtraStringWidget input,
13
div.RegexStringWidget input,
14
div.EmailWidget input,
15
div.PasswordWidget input,
16
div.UrlWidget input,
17
div.ValidUrlWidget input {
18
	border: 1px inset #ccc;
19
	margin: 1px;
20
	padding: 2px 3px;
21
}
22

  
23
div.SingleSelectWidget select {
24
	margin: 1px;
25
}
26

  
27
div.widget input.prefill-button {
28
	border: 1px outset #ccc;
29
	margin: 0 0 0 1em;
30
	padding: 0px 0px;
31
}
32

  
33
div.widget input.prefill-button:focus {
34
	border: 1px outset #ccc;
35
	margin: 0 0 0 1em;
36
	padding: 0;
37
}
38

  
39

  
40
div.widget textarea.readonly,
41
div.widget input.readonly {
42
	border: 1px solid #ccc;
43
	background: #eee;
44
	margin: 0 0 0 1em;
45
}
46

  
47
div.TextWidget textarea:focus,
48
div.DateWidget input:focus,
49
div.StringWidget input:focus,
50
div.WcsExtraStringWidget input:focus,
51
div.RegexStringWidget input:focus,
52
div.EmailWidget input:focus,
53
div.PasswordWidget input:focus,
54
div.UrlWidget input:focus,
55
div.ValidUrlWidget input:focus {
56
	border: 2px solid #ccf;
57
	/*margin: 0px; */
58
	padding: 1px 2px;
59
}
60

  
61
div.AccountSettingWidget label {
62
	padding-right: 2em;
63
}
64

  
65
div.SubmitWidget input, input[type=submit] {
66
	margin-top: 1em;
67
	border: 1px outset #ccc;
68
}
69

  
70
div.form .title, form.quixote .title {
71
	font-weight: bold;
72
}
73

  
74
div.errornotice {
75
	background: #fd6;
76
	border: 1px solid #ffae15;
77
	margin: 0em 1em 1em 1em;
78
	padding: 5px;
79
}
80

  
81
div.infonotice {
82
	background: #7b95a6;
83
	border: 1px solid #153eaf;
84
	margin: 0em 1em 1em 1em;
85
	padding: 5px;
86
}
87

  
88
div.error {
89
	color: black;
90
	font-weight: bold;
91
	background: transparent url(warning.png) top left no-repeat;
92
	padding-left: 20px;
93
}
94

  
95
div.buttons div.SubmitWidget,
96
div.buttons div.SubmitWidget div.content {
97
	display: inline;
98
}
99

  
100
div.buttons br { display: none; }
101

  
102
div.widget {
103
	margin-bottom: 0.5em;
104
	clear: both;
105
}
106

  
107
input[type="submit"][name="submit"] {
108
	font-weight: bold;
109
}
110

  
111
div.form pre {
112
	overflow: scroll;
113
}
114

  
115

  
116
div#error h1 {
117
	margin: 0;
118
}
119

  
120
div#error {
121
	width: 40em;
122
	max-width: 500px;
123
	margin: 15% auto;
124
	background: white;
125
	border: 1px solid #999;
126
	padding: 1em;
127
}
128

  
129
div.hint {
130
	font-size: 80%;
131
}
132

  
133
span.required {
134
	background: transparent url(required.png) 0px 0.5ex no-repeat;
135
	padding: 0 0 0 24px;
136
	margin-left: 1ex;
137
	overflow: hidden;
138
	color: white;
139
}
140

  
141
div.buttons {
142
	margin-top: 1em;
143
}
144

  
145
div.RadiobuttonsWidget div.content {
146
	display: block;
147
}
148

  
149
div.error-page {
150
	margin: 1em;
151
}
152

  
153
pre#exception {
154
	overflow: scroll;
155
	padding: 1em;
156
	border: 1px solid #bbb;
157
	background: #f0f0f0;
158
	font-size: 90%;
159
}
160

  
161
div.StringWidget ul {
162
	margin: 0;
163
	padding-left: 2em;
164
	list-style: circle;
165
}
166

  
167
div.inline-first div.title,
168
div.inline div.title {
169
	display: inline;
170
	float: left;
171
	max-width: 20em;
172
	text-align: left;
173
	padding-top: 6px;
174
}
175

  
176
div.inline-first div.title span.required,
177
div.inline div.title span.required {
178
	margin-left: 1ex;
179
	padding-left: 12px;
180
}
181

  
182
div.inline-first div.content,
183
div.inline div.content {
184
	margin-left: 1ex;
185
}
186

  
187
div.inline-first div.hint,
188
div.inline div.hint {
189
	display: none;
190
}
191

  
192
div.inline-first {
193
	float: left;
194
	clear: both;
195
}
196

  
197
div.inline {
198
	float: left;
199
	clear: none;
200
}
201

  
202
div.inline-first div.content,
203
div.inline div.content {
204
	margin-right: 1.5em;
205
}
206

  
207
	
208

  
209
div.inline-first div.content,
210
div.inline div.content {
211
	display: inline;
212
}
213

  
214
.clear-both {
215
	clear: both;
216
}
217

  
218
div.CheckboxesWidget div.content ul {
219
	list-style: none;
220
	padding: 0;
221
	margin: 0;
222
}
223

  
224
div.CheckboxesWidget div.content ul li {
225
	display: inline;
226
	margin-right: 2em;
227
}
228

  
229
div#receipt {
230
	clear: both;
231
}
232

  
233
div#receipt span.label {
234
	font-weight: bold;
235
	display: block;
236
}
237

  
238
div#receipt span.value {
239
	display: block;
240
	margin-left: 1em;
241
}
242

  
243
form div.page,
244
div#receipt div.page {
245
	border: 1px solid #aaa;
246
	padding: 1ex;
247
	margin-bottom: 1em;
248
}
249

  
250
form div.page p,
251
div#receipt div.page p {
252
	margin-top: 0;
253
}
254

  
255
form div.page h3,
256
div#receipt div.page h3 {
257
	margin: 0;
258
	margin-bottom: 1ex;
259
}
260

  
larpe/tags/release-1.1.1/root/larpe/css/larpe.css
1
@import url(larpe-common.css);
2
@import url(jscalendar/aqua/theme.css);
3
/* derived from soFresh, a DotClear theme by Maurice Svay (GPL)
4
 * http://www.svay.com/files/soFresh/theme-sofresh-1.2.zip */
5

  
6
html, body {
7
	font-family: sans-serif;
8
	text-align: center;
9
	background: #eee;
10
	color: black;
11
}
12

  
13
div#page {
14
	width: 800px;
15
	margin: 2em auto;
16
	text-align: justify;
17
	background: white url(img/page.png) repeat-y;
18
	color: black;
19
}
20

  
21
body.login div#page {
22
        width: 500px;
23
        background: white url(img/page-500.png) repeat-y;
24
}
25
#top {
26
	color: #09F;
27
	background: #FFF url(img/top.jpg) no-repeat;
28
	height: 100px;
29
	margin: 0;
30
}
31

  
32
body.login #top {
33
        background: white url(img/top-500.png) no-repeat;
34
}
35

  
36
#top h1 {
37
	margin: 0;
38
	padding-left: 30px;
39
	padding-right: 30px;
40
	line-height: 100px;
41
	height: 100px;
42
	overflow: hidden;
43
}
44

  
45
#footer {
46
	background: #FFF url(img/footer.jpg) no-repeat;
47
	color: #999;
48
	text-align: center;
49
	min-height: 30px;
50
}
51

  
52
body.login #footer {
53
        background: white url(img/footer-500.png) no-repeat;
54
}
55

  
56
div#main-content {
57
	margin: 0 2em;
58
}
59

  
60
div#main-content h1 {
61
	color: #09F;
62
}
63

  
64
#steps {
65
	height: 32px;
66
	margin-bottom: 1em;
67
}
68

  
69
#steps ol {
70
	list-style: none;
71
	padding: 0 20px;
72
}
73

  
74
#steps li {
75
	display: inline;
76
	padding-right: 1em;
77
	display: block;
78
	float: left;
79
	width: 30%;
80
	list-style: none;
81
}
82

  
83
#steps ol ul {
84
	border: 1px solid #ffa500;
85
	margin-left: 2em;
86
	background: #ffdb94;
87
	margin-bottom: 1em;
88
	padding: 0;
89
	width: auto;
90
}
91

  
92
#steps li li {
93
	display: block;
94
	width: auto;
95
	float: none;
96
	text-align: left;
97
	margin-left: 1em;
98
	font-size: 90%;
99
}
100

  
101
#steps li li.current {
102
	color: black;
103
}
104

  
105

  
106
#steps span.marker {
107
	font-size: 26px;
108
	padding: 2px 9px;
109
	font-weight: bold;
110
	color: white;
111
	text-align: center;
112
	background: #ddd;
113
	border: 1px solid #ddd;
114
	-moz-border-radius: 0.7ex;
115
}
116

  
117
#steps li.current span.marker {
118
	background: #ffa500;
119
	border: 1px solid #ffc400;
120
}
121

  
122
#steps span.label {
123
	font-size: 90%;
124
}
125

  
126
#steps li.current span.label {
127
	color: black;
128
}
129

  
130
#steps {
131
	background: #f0f0f0;
132
	color: #aaa;
133
}
134

  
135
#steps ol ul {
136
	display: none;
137
}
138

  
139
#steps ol li.current ul {
140
	display: block;
141
}
142

  
143
form {
144
	clear: both;
145
}
146

  
147
p#receiver {
148
	margin: 0;
149
	margin-left: 2em;
150
	margin-top: -0.7em;
151
	margin-bottom: 1em;
152
	padding: 2px 5px;
153
	border: 1px solid #ccc;
154
	float: left;
155
	background: #ffe;
156
}
157

  
158
p#login,
159
p#logout {
160
	margin-top: 2em;
161
	text-align: right;
162
}
163

  
164
p#login a, p#logout a {
165
	text-decoration: underline;
166
	/*
167
	text-decoration: none;
168
	-moz-border-radius: 2em !important;
169
	padding: 1px 6px !important;
170
	border: 1px solid #ccc !important;
171
	border-bottom: 2px solid #999 !important;*/
172
}
173

  
174
p#login a:hover {
175
	background-color: #ddeeff;
176
}
177

  
178
h2#submitted, h2#done {
179
	margin-top: 2em;
180
	color: #09F;
181
	font-size: 130%;
182
}
183

  
184
h2#done {
185
	margin-top: 1em;
186
}
187

  
188
ul li {
189
	list-style-image: url(img/li.png);
190
}
191

  
192
h2, h3 {
193
	color: #09F;
194
	margin-left: 0.5em;
195
	margin-bottom: 0;
196
}
197

  
198
h3 {
199
	margin-left: 1em;
200
}
201

  
202
table#listing {
203
	margin: 1em 0;
204
}
205

  
206
table#listing th {
207
	text-align: left;
208
	border-bottom: 1px solid #999;
209
	background: #eee;
210
}
211

  
212
table#listing td {
213
	padding-right: 1ex;
214
}
215

  
216
table#listing th a {
217
	text-decoration: none;
218
	color: #666;
219
}
220

  
221
table.sortable span.sortarrow {
222
	color: black;
223
	text-decoration: none;
224
}
225

  
226
table#listing tr.status-new {
227
	background: #aea;
228
}
229

  
230
table#listing tr.status-finished,
231
table#listing tr.status-rejected {
232
	color: #444;
233
}
234

  
235
table#listing tr.status-rejected td {
236
	text-decoration: line-through;
237
}
238

  
239
div.question p.label {
240
	font-weight: bold;
241
}
242

  
243
img.bar {
244
	border: 1px solid black;
245
}
246

  
247
div.question table {
248
	margin-left: 10px;
249
}
250

  
251
div.question table td {
252
}
253

  
254
div.question table td.percent {
255
	text-align: right;
256
	padding: 0 1em;
257
	width: 6em;
258
}
259

  
260
div.question table td.label {
261
	width: 6em;
262
}
263

  
264
span.user {
265
	margin-left: 1em;
266
	font-style: italic;
267
}
268

  
269
a.listing {
270
	font-size: 80%;
271
	padding-left: 1em;
272
}
273

  
274
a {
275
	text-decoration: none;
276
	color: #113;
277
}
278

  
279
a:hover {
280
	color: #06C;
281
	text-decoration: underline;
282
}
283

  
284

  
285
#prelude {
286
	color: #aaa;
287
	background: transparent;
288
	text-align: right;
289
	position: relative;
290
	top: -85px;
291
	margin: 0;
292
}
293

  
294
p#breadcrumb {
295
	margin-top: 0;
296
}
297

  
298
div.error-page {
299
	margin-bottom: 2em;
300
}
301

  
302
div.hint {
303
	display: inline;
304
	padding-left: 1ex;
305
	font-style: italic;
306
}
307

  
308
a.standalone {
309
	background: white url(img/h2.png) top left no-repeat;
310
	padding-left: 20px;
311
}
312

  
313
div#welcome-message a {
314
	text-decoration: underline;
315
}
316

  
317
input.cancel {
318
	margin-left: 5em;
319
}
320

  
321
hr {
322
	border: none;
323
	border-top: 1px solid #666;
324
	height: 1px;
325
	width: 80%;
326
}
327

  
328
div.buttons {
329
	clear: both;
330
}
331

  
larpe/tags/release-1.1.1/setup.py
1
#!/usr/bin/env python
2

  
3
import os
4
import distutils.core
5
from quixote.ptl.qx_distutils import qx_build_py
6

  
7
local_cfg = None
8
if os.path.exists('larpe/larpe_cfg.py'):
9
    local_cfg = open('larpe/larpe_cfg.py').read()
10
    os.unlink('larpe/larpe_cfg.py')
11

  
12
def data_tree(destdir, sourcedir):
13
    extensions = ['.css', '.png', '.jpeg', '.jpg', '.xml', '.html', '.js', '.py']
14
    r = []
15
    for root, dirs, files in os.walk(sourcedir):
16
        l = [os.path.join(root, x) for x in files if os.path.splitext(x)[1] in extensions]
17
        r.append( (root.replace(sourcedir, destdir, 1), l) )
18
        if '.svn' in dirs:
19
            dirs.remove('.svn')
20
    return r
21

  
22
distutils.core.setup(
23
        name = 'larpe',
24
        version = '1.1.1',
25
        maintainer = 'Jerome Schneider',
26
        maintainer_email = 'jschneider@entrouvert.com',
27
        url = 'http://larpe.labs.libre-entreprise.org',
28
        package_dir = { 'larpe': 'larpe' },
29
        packages = ['larpe', 'larpe.admin', 'larpe.ctl', 'larpe.plugins', 'larpe.plugins.site_authentication', 'larpe.qommon',
30
                    'larpe.qommon.admin', 'larpe.qommon.ident', 'larpe.qommon.backoffice', 'larpe.qommon.vendor'],
31
        cmdclass = {'build_py': qx_build_py},
32
        data_files = data_tree('share/larpe/web/', 'root/') + \
33
                     data_tree('share/larpe/web/larpe/qo/', 'larpe/qommon/static/') + \
34
                     data_tree('share/larpe/', 'conf/')
35
    )
36

  
37
if local_cfg:
38
    open('larpe/larpe_cfg.py', 'w').write(local_cfg)
39

  
larpe/tags/release-1.1.1/tests/all4dev/slo_check
1
url http://all4dev.test.org/index.php/Main_Page
2
find "Create an account or log in"
larpe/tags/release-1.1.1/tests/all4dev/sso_check
1
url http://all4dev.test.org/index.php/Main_Page
2
find $find_username
3
find logout
larpe/tags/release-1.1.1/tests/blueprint/slo_check
1
find "<frameset"
larpe/tags/release-1.1.1/tests/blueprint/sso_check
1
find logout.gif
larpe/tags/release-1.1.1/tests/check.sh
1
#!/bin/sh
2
#
3
# Usage : check.sh                : Test all sites in current directory
4
#         check.sh list_of_sites  : Test the sites whose name is given on the command line
5

  
6
exclude_sites="linuxfr listes_libre_entreprise egroupware"
7

  
8
if [ $# -eq 0 ];
9
then
10
    # Test all sites
11
    for site in *;
12
    do
13
        test_site=1
14
        for exclude_site in $exclude_sites;
15
        do
16
            if [ $site = $exclude_site ];
17
            then
18
                test_site=0
19
            fi
20
        done
21
        if [ $test_site -eq 1 ];
22
        then
23
            sites="$sites $site"
24
        fi
25
    done
26
else
27
    # Test the sites whose name is given on the command line
28
    while [ $# -ne 0 ];
29
    do
30
        sites="$sites $1"
31
        shift
32
    done
33
fi
34

  
35
function check() {
36
    site="$1"
37
    files=""
38

  
39
    # Combine as many functionnalities as given, at the same time
40
    shift
41
    echo -n "  "
42
    while [ $# -ne 0 ];
43
    do
44
        functionnality="$1"
45
        echo -n "$functionnality "
46
        case "$functionnality" in
47
            "Federation")
48
                add_files="sso idp_login federation $site/sso_check";;
49
            "SSO")
50
                add_files="sso idp_login $site/sso_check";;
51
            "SLO")
52
                add_files="slo $site/slo_check";;
53
        esac
54
        files="$files $add_files"
55
        shift
56
    done
57
    echo -n "..."
58

  
59
    cat $site/config $files | twill-sh > twill_output
60
    grep "ERROR" twill_output &> /dev/null
61
    if [ $? -eq 0 ];
62
    then
63
        echo "	[FAILED]"
64
        cat twill_output
65
        exit 1
66
    else
67
        echo "	[OK]"
68
    fi
69
}
70

  
71
echo
72
# Check loop
73
for site in $sites;
74
do
75
    if [ ! -d $site ];
76
    then
77
        continue
78
    fi
79

  
80
    echo "Testing $site :"
81

  
82
    echo -n "  Defederation ..."
83
    cat $site/config defederation idp_login | twill-sh &> /dev/null
84
    echo "	[OK]"
85
    check $site "Federation"
86
    check $site "SSO"
87
    check $site "SLO"
88
    check $site "SSO" "SLO"
89
    check $site "SLO" "SSO" "SLO" "SLO" "SSO" "SLO"
90

  
91
    rm -f twill_output
92
    echo
93
done
larpe/tags/release-1.1.1/tests/defederation
1
go $defederation_url
larpe/tags/release-1.1.1/tests/dotclear/slo_check
1
#url http://dotclear.test.org/
2
url https://dotclear.test.org/
larpe/tags/release-1.1.1/tests/dotclear/sso_check
1
#url http://dotclear.test.org/ecrire/
2
url https://dotclear.test.org/ecrire/
3
find $find_username
4
find déconnexion
larpe/tags/release-1.1.1/tests/dotclear_subdir/slo_check
1
url http://listes.test.org/dotclear/
larpe/tags/release-1.1.1/tests/dotclear_subdir/sso_check
1
url http://listes.test.org/dotclear/ecrire/
2
find $find_username
3
find déconnexion
larpe/tags/release-1.1.1/tests/federation
1
formvalue 1 username $sp_username
2
formvalue 1 password $sp_password
3
submit
larpe/tags/release-1.1.1/tests/gen_config.sh
1
#!/bin/sh
2

  
3
if [ $# -eq 0 ];
4
then
5
    echo "Usage : $0 site_name"
6
    exit 1
7
fi
8

  
9
while [ $# -ne 0 ];
10
do
11
    if [ -d $1 ];
12
    then
13
        config_file="$1/config"
14
        echo -n "Generating config template for $1 ... "
15
        echo "setlocal sp_login_url " >> $config_file
16
        echo "setlocal sp_logout_url " >> $config_file
17
        echo "setlocal defederation_url " >> $config_file
18
        echo "setlocal idp_username " >> $config_file
19
        echo "setlocal idp_password " >> $config_file
20
        echo "setlocal sp_username " >> $config_file
21
        echo "setlocal sp_password " >> $config_file
22
        echo "setlocal find_username " >> $config_file
23
        echo "[OK]"
24
    fi
25
    shift
26
done
larpe/tags/release-1.1.1/tests/idp_login
1
formvalue 1 username $idp_username
2
formvalue 1 password $idp_password
3
submit
larpe/tags/release-1.1.1/tests/libre-entreprise/slo_check
1
#url http://libre-entreprise.reverse-proxy.entrouvert.org/index.php/Accueil
2
url http://le.test.org/index.php/Accueil
3
find "Créer un compte ou se connecter"
larpe/tags/release-1.1.1/tests/libre-entreprise/sso_check
1
#url http://libre-entreprise.reverse-proxy.entrouvert.org/index.php/Accueil
2
url http://le.test.org/index.php/Accueil
3
find $find_username
4
find déconnexion
larpe/tags/release-1.1.1/tests/listes_entrouvert/slo_check
1
find Login
larpe/tags/release-1.1.1/tests/listes_entrouvert/sso_check
1
find $find_username
2
find "You have logged in"
larpe/tags/release-1.1.1/tests/listes_libre_entreprise/slo_check
1
find Login
larpe/tags/release-1.1.1/tests/listes_libre_entreprise/sso_check
1
find $find_username
2
find "Vous êtes identifié"
larpe/tags/release-1.1.1/tests/slo
1
go $sp_logout_url
larpe/tags/release-1.1.1/tests/sso
1
go $sp_login_url

Formats disponibles : Unified diff