diff --git a/larpe/tags/release-1.1.1/AUTHORS b/larpe/tags/release-1.1.1/AUTHORS new file mode 100644 index 0000000..b0adfde --- /dev/null +++ b/larpe/tags/release-1.1.1/AUTHORS @@ -0,0 +1,5 @@ +Damien Laniel + +Artwork and administrave interface design taken from DotClear, version 1.2 and +2.0, released under the GNU General Public License; and GTK+, version 2.8, +released under the GNU Lesser General Public License. diff --git a/larpe/tags/release-1.1.1/COPYING b/larpe/tags/release-1.1.1/COPYING new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/larpe/tags/release-1.1.1/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/larpe/tags/release-1.1.1/MANIFEST.in b/larpe/tags/release-1.1.1/MANIFEST.in new file mode 100644 index 0000000..06c2ffc --- /dev/null +++ b/larpe/tags/release-1.1.1/MANIFEST.in @@ -0,0 +1,13 @@ +include Makefile +include setup.py +include larpectl +include apache2-vhost-larpe +include apache2.conf +include larpe-reload-apache2-script +include larpe-reload-apache2.c +include README COPYING MANIFEST.in MANIFEST NEWS AUTHORS +recursive-include larpe *.py *.ptl +recursive-include data * +recursive-include root * +recursive-include po *.po *.pot Makefile +recursive-include doc *.rst Makefile *.png *.sty custom.tex *.py *.sh *.css diff --git a/larpe/tags/release-1.1.1/Makefile b/larpe/tags/release-1.1.1/Makefile new file mode 100644 index 0000000..b0be307 --- /dev/null +++ b/larpe/tags/release-1.1.1/Makefile @@ -0,0 +1,45 @@ +prefix = /usr +config_prefix = /var +config_dir = $(config_prefix)/lib/larpe + +INSTALL = /usr/bin/install -c +PYTHON = /usr/bin/python + +LARPE_VERSION = 0.2.9 + +larpe-reload-apache2: larpe-reload-apache2.c + +install: larpe-reload-apache2 + rm -rf build + $(MAKE) -C po install + $(PYTHON) setup.py install --root "$(DESTDIR)/" --prefix "$(prefix)" --no-compile + $(INSTALL) -d $(DESTDIR)$(prefix)/sbin/ + $(INSTALL) larpectl $(DESTDIR)$(prefix)/sbin/ + $(INSTALL) -m 4550 larpe-reload-apache2 $(DESTDIR)$(prefix)/sbin/ + $(INSTALL) -d $(DESTDIR)/etc/larpe + $(INSTALL) -m 644 conf/apache2-vhost-larpe-common $(DESTDIR)/etc/larpe + $(INSTALL) -d $(DESTDIR)$(config_dir) + $(INSTALL) -d $(DESTDIR)$(config_dir)/vhosts.d + $(INSTALL) -d $(DESTDIR)$(config_dir)/vhost-locations.d + $(INSTALL) -d $(DESTDIR)$(config_dir)/vhosts.d.disabled + $(INSTALL) -d $(DESTDIR)$(config_dir)/vhost-locations.d.disabled + +uninstall: + $(MAKE) -C po uninstall + -rm -f $(DESTDIR)$(prefix)/sbin/larpe-reload-apache2 + -rm -f $(DESTDIR)$(prefix)/sbin/larpe-reload-apache2-script + -rm -f $(DESTDIR)$(prefix)/sbin/larpectl + -rm -rf $(DESTDIR)$(prefix)/share/larpe/ + @echo + @echo "Depending on your Python version, you will have to remove manually the files in /usr/lib/python(version)/site-packages/larpe/" + +clean: + $(MAKE) -C po clean + $(MAKE) -C doc clean + -$(PYTHON) setup.py clean + -rm -f larpe-reload-apache2 + +dist: clean + tar czf dist/larpe-$(LARPE_VERSION).tar.gz -C .. --transform s/trunk/larpe-$(LARPE_VERSION)/ --exclude-from=exclude_from_dist trunk + +.PHONY: clean dist diff --git a/larpe/tags/release-1.1.1/NEWS b/larpe/tags/release-1.1.1/NEWS new file mode 100644 index 0000000..5e08d64 --- /dev/null +++ b/larpe/tags/release-1.1.1/NEWS @@ -0,0 +1,17 @@ +NEWS +==== + +Version 1.0 +----------- + +- Adds Liberty Alliance to some sites without modying sites code +- SAML 2.0 and ID-FF 1.2 support (authentication and logout) +- Form prefilling with ID-WSF 2.0 +- Configuration assistant (wizard-like) for configuring new sites +- Fully tested for several sites with very different behaviours +- Plugin system to handle specific behaviour of some sites +- Automatic Apache 2 configuration +- Automatic creation of Apache python filters to transform authentication boxes on the sites +- Support for proxies +- Logging and debug options +- Packages for Debian and Fedora (and children of both) distributions diff --git a/larpe/tags/release-1.1.1/README b/larpe/tags/release-1.1.1/README new file mode 100644 index 0000000..f135f76 --- /dev/null +++ b/larpe/tags/release-1.1.1/README @@ -0,0 +1,32 @@ +Larpe - Liberty Alliance Reverse Proxy +====================================== + +Description +----------- + +Larpe is a Liberty Alliance Reverse Proxy. It allows any service provider (that +is a website) to use Liberty Alliance features (Identity federation, Single +Sign On and Single Sign Logout) without changing the code of the service +provider itself. It uses the Lasso library which is certified by the Liberty +Alliance consortium. + + +Documentation +------------- + +* README, as you are doing; + +* doc/en/ for English documentation, published as HTML on + http://larpe.labs.libre-entreprise.org/doc/en/larpe-admin.html + + +Copyright +--------- + +Larpe is copyrighted by Entr'ouvert and is licensed under the GNU General +Public Licence. Artwork and administrative design are from DotClear and +released under the GNU General Public License by Olivier Meunier and others. +Some artwork comes from GTK+ (LGPL). + +Read the COPYING file for the complete license text. Read the AUTHORS file for +additional credits. diff --git a/larpe/tags/release-1.1.1/TODO b/larpe/tags/release-1.1.1/TODO new file mode 100644 index 0000000..5564cc8 --- /dev/null +++ b/larpe/tags/release-1.1.1/TODO @@ -0,0 +1,101 @@ +- Tests + - egroupware + - http://labs.libre-entreprise.org/ + - logs.entrouvert.org + +====== Roadmap de Larpe ====== + +===== 0.2 ===== + + * Vérifier la compatibilité avec egroupware + * 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 + * Supprimer debconf + * Vérification des formulaires de configuration d'hôtes + * Tests de valeurs erronés diverses + * Erreur si on donne un label qui existe deja + * Ne plus inclure le binaire larpe-reload-apache2 dans les sources + * Corriger les avertissements debian + * Ne pas demander la clé publique de l'idp + * Compléter les traductions + * Ajouter la possibilité de changer la langue dans l'interface d'administration + * Mettre à jour la documentation + * Ajouter un chapitre sur les sites testés et leurs options de configuration particulières + * Traduire la documentation en français + +===== 0.3 ===== + + * Implémenter le SLO en SOAP + * Supprimer un /liberty/ des urls + * Voir comment activer le SSLProxyEngine quand on utilise un sous répertoire + * Faire un site web pour présenter Larpe + * Ajouter la possibilité d'envoyer les exceptions par courriel à l'administrateur + * Améliorer la journalisation des accès et des erreurs + +===== 1.0 ===== + + * Support de SAML 2.0 + * Implémenter l'accès à un site nécessitant une authentification préalable avant tout accès + * Choix de cette fonctionnalité par une option de configuration par site + * 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 + * Documentation technique pour les développeurs ? + +===== Non classés ===== + + * Support des sites qui ont une authentification HTTP (à priori, nécessite de charger toute la configuration de larpe dans le filtre python d'apache) + * Création de nouveaux comptes pour les sites, avec des jetons (déjà implémenté en partie ; est-ce utile ?) + +Fait +==== + +- Serveur python principal + - Fonctionnalités liberty + - SSO (depuis le sp et depuis l'idp) + - Fédération + - SLO (depuis le sp et depuis l'idp) + - Défédération (depuis l'idp) en SOAP et redirect + - Support https + - Possibilité d'utiliser toutes les combinaisons de sous domaines et de sous répertoires + - RP par vhost (appli1.example.com, rp de appli1.interne) + - RP par repertoire (www.example.com/appli1, rp de appl1.interne) + - Récupère la configuration de l'IP des vhosts + +- Administration + - Authentification liberty sur l'admin + - Créer de nouveaux sites (+ modifier, supprimer) + - Écrire les vhosts correspondants + - Rechargement de la configuration d'apache + - Script + wrapper en C suid root + - Gestion d'utilisateurs pour administrer le RP (Authentification http) + - Gestion des traductions + +- Filtre Python branché en sortie sur Apache à la suite du filtre de réécriture html (proxy_html) + - Générique + - Personalisable par site pour une meilleure intégration dans les pages + +- Sites testés + - Dotclear + - Dacode + - linuxfr.org + - Sympa + - listes.entrouvert.com + - listes.libre-entreprise.org + - Mediawiki + - all4dev.libre-entreprise.org + - www.libre-entreprise.org + - www.besancon.com + - Egroupware + - quintine.entrouvert.org/egroupware/ + - squirrelmail + - Concerto Espace-famille + - Ciril Net RH + - Agirhe + +- Documentation + +- Paquets Debian + - Debconf pour demander le nom de domaine et le courriel de l'admin, ainsi que le compte administrateur + +- Installation sur lupin + +- Batterie de tests de non-regression + diff --git a/larpe/tags/release-1.1.1/conf/apache2-vhost-larpe b/larpe/tags/release-1.1.1/conf/apache2-vhost-larpe new file mode 100644 index 0000000..d5ff56b --- /dev/null +++ b/larpe/tags/release-1.1.1/conf/apache2-vhost-larpe @@ -0,0 +1,12 @@ + + ServerName localhost + ServerAdmin root@localhost + + include /etc/larpe/apache2-vhost-larpe-common + include /var/lib/larpe/vhost-locations.d + + CustomLog /var/log/apache2/larpe-access.log combined + ErrorLog /var/log/apache2/larpe-error.log + + +include /var/lib/larpe/vhosts.d diff --git a/larpe/tags/release-1.1.1/conf/apache2-vhost-larpe-common b/larpe/tags/release-1.1.1/conf/apache2-vhost-larpe-common new file mode 100644 index 0000000..3e3d86d --- /dev/null +++ b/larpe/tags/release-1.1.1/conf/apache2-vhost-larpe-common @@ -0,0 +1,19 @@ +# Static files +DocumentRoot /usr/share/larpe/web/ + +# Python application +SCGIMount / 127.0.0.1:3007 + +# Static files for larpe + + ProxyPass ! + SCGIHandler off + + +# Larpe python application + + ProxyPass ! + + +# No gzip compression +RequestHeader unset Accept-Encoding diff --git a/larpe/tags/release-1.1.1/conf/filters/output_ciril_net_rh.py b/larpe/tags/release-1.1.1/conf/filters/output_ciril_net_rh.py new file mode 100644 index 0000000..e61fe32 --- /dev/null +++ b/larpe/tags/release-1.1.1/conf/filters/output_ciril_net_rh.py @@ -0,0 +1,63 @@ +import re +import os +import pickle + +from larpe import sessions +from mod_python import Cookie + +def is_auth_ok(req): + """ Test if you are authenticate on the Larpe server """ + cookies = Cookie.get_cookies(req, Cookie.MarshalCookie, secret='secret007') + sessions_dir = os.path.join("%(larpe_dir)s", "sessions") + for name, cookie in cookies.iteritems(): + value = cookie.value.replace('"', '') + if "larpe-" in name and value in os.listdir(sessions_dir): + try: + file = open(os.path.join(sessions_dir, value), "rb") + session = pickle.load(file) + if not session.users or not session.id: + return False + return True + except Exception, err: + return False + return False + + +def filter_page(filter, page): + r = re.compile(r"""(D.*?connexion)""") + page = r.sub(r"""\1%(logout_url)s\2""", page) + return page + +def outputfilter(filter): + """ Apache called this function by default """ + if not re.search("^/liberty/.*", filter.req.uri) and not is_auth_ok(filter.req): + filter.write('') + filter.close() + return + + if filter.req.content_type is not None: + is_html = re.search('text/html', filter.req.content_type) + if filter.req.content_type is None or not is_html: + filter.pass_on() + else: + if not hasattr(filter.req, 'temp_doc'): + # Create a new attribute to hold the document + filter.req.temp_doc = [] + # If content-length ended up wrong, Gecko browsers truncated data + if 'Content-Length' in filter.req.headers_out: + del filter.req.headers_out['Content-Length'] + + temp_doc = filter.req.temp_doc + s = filter.read() + # Could get '' at any point, but only get None at end + while s: + temp_doc.append(s) + s = filter.read() + + # The end + if s is None: + page = ''.join(temp_doc) + page = filter_page(filter, page) + filter.write(page) + filter.close() + diff --git a/larpe/tags/release-1.1.1/conf/filters/output_replace_form.py b/larpe/tags/release-1.1.1/conf/filters/output_replace_form.py new file mode 100644 index 0000000..d8964a5 --- /dev/null +++ b/larpe/tags/release-1.1.1/conf/filters/output_replace_form.py @@ -0,0 +1,35 @@ +import re + +def filter_page(filter, page): + current_form = re.compile('
]*?action="%(auth_form_action)s".*?>.*?
', re.DOTALL) + page = current_form.sub('
', page) + return page + +def outputfilter(filter): + # Only filter html code + if filter.req.content_type is not None: + is_html = re.search('text/html', filter.req.content_type) + if filter.req.content_type is None or not is_html: + filter.pass_on() + else: + if not hasattr(filter.req, 'temp_doc'): + # Create a new attribute to hold the document + filter.req.temp_doc = [] + # If content-length ended up wrong, Gecko browsers truncated data + if 'Content-Length' in filter.req.headers_out: + del filter.req.headers_out['Content-Length'] + + temp_doc = filter.req.temp_doc + s = filter.read() + # Could get '' at any point, but only get None at end + while s: + temp_doc.append(s) + s = filter.read() + + # The end + if s is None: + page = ''.join(temp_doc) + page = filter_page(filter, page) + filter.write(page) + filter.close() + diff --git a/larpe/tags/release-1.1.1/debian/changelog b/larpe/tags/release-1.1.1/debian/changelog new file mode 100644 index 0000000..74aab13 --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/changelog @@ -0,0 +1,89 @@ +larpe (1.1.1-1) unstable; urgency=low + + * Removing a useless import + * Change Debian maintainer + * Change architecture from any to all + * Using pysupport instead of pycentral + * Update Debian package dependencies + + -- Jerome Schneider Mon, 19 Jul 2010 16:18:28 +0200 + +larpe (1.1-1) unstable; urgency=low + + * New release + - Rewrite filter management + - Filters are now customisable + - Improve Ciril module + - Improve plugins management + - Support multi filters + - Fix SAML 2 logout + - Fix site authentification plugins management + - Fix sessions management + - Code cleaning + + -- Jerome Schneider Mon, 19 Jul 2010 11:52:47 +0200 + +larpe (1.0-1) unstable; urgency=low + + * New release + - SAML 2.0 and ID-FF 1.2 support (authentication and logout) + - Form prefilling with ID-WSF 2.0 + - Configuration assistant (wizard-like) for configuring new sites + - Fully tested for several sites with very different behaviours + - Plugin system to handle specific behaviour of some sites + - Automatic Apache 2 configuration + - Automatic creation of Apache python filters to transform authentication + boxes on the sites + - Support for proxies + - Logging and debug options + + -- Damien Laniel Mon, 09 Mar 2009 11:19:49 +0100 + +larpe (0.2.1-1) unstable; urgency=low + + * New release + + -- Damien Laniel Wed, 20 Jun 2007 15:43:16 +0200 + +larpe (0.2.0-1) unstable; urgency=low + + * New release + + -- Damien Laniel Tue, 30 Jan 2007 18:07:04 +0100 + +larpe (0.1.1-2) unstable; urgency=low + + * Use python2.4 + + -- Damien Laniel Tue, 19 Dec 2006 17:21:05 +0100 + +larpe (0.1.1-1) unstable; urgency=low + + * New release + + -- Damien Laniel Thu, 5 Oct 2006 11:47:53 +0200 + +larpe (0.1.0-1) unstable; urgency=low + + * New release + + -- Damien Laniel Wed, 4 Oct 2006 10:19:26 +0200 + +larpe (0.0.4-1) unstable; urgency=low + + * New version, many improvements, more compatible sites, some bug fixes + + -- Damien Laniel Tue, 3 Oct 2006 20:44:06 +0200 + +larpe (0.0.3-1) unstable; urgency=low + + * New version, many improvements, more compatible sites, some bug fixes + + -- Damien Laniel Mon, 25 Sep 2006 11:11:36 +0200 + +larpe (0.0.2-1) unstable; urgency=low + + * Initial package. + + -- Damien Laniel Fri, 08 Sep 2006 16:00:00 +0200 + diff --git a/larpe/tags/release-1.1.1/debian/compat b/larpe/tags/release-1.1.1/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/compat @@ -0,0 +1 @@ +5 diff --git a/larpe/tags/release-1.1.1/debian/config b/larpe/tags/release-1.1.1/debian/config new file mode 100755 index 0000000..9543f2d --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/config @@ -0,0 +1,24 @@ +#!/bin/sh -e + +# Source debconf library. +. /usr/share/debconf/confmodule + +# Hostname +#db_input high larpe/hostname || true +#db_go + +# Administrator email address +#db_input medium larpe/admin_email || true +#db_go + +# Enable this vhost +#db_input high larpe/enable_vhost || true +#db_go + +# Administrator login +#db_input high larpe/admin_username || true +#db_go + +# Administrator password +#db_input high larpe/admin_password || true +#db_go diff --git a/larpe/tags/release-1.1.1/debian/control b/larpe/tags/release-1.1.1/debian/control new file mode 100644 index 0000000..812ff5d --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/control @@ -0,0 +1,16 @@ +Source: larpe +Section: web +Priority: optional +Maintainer: Jérôme Schneider +Build-Depends: debhelper (>= 5.0.37.2), python, python-support (>= 0.4), gettext, python-quixote (>= 2.5) +Standards-Version: 3.8.0 + +Package: larpe +Architecture: all +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 +XB-Python-Version: ${python:Versions} +Description: Liberty Alliance Reverse Proxy + Larpe allows any service provider (that is a website) to use Liberty Alliance + identity management and Single Sign On features without changing the code of + the service provider itself. + . diff --git a/larpe/tags/release-1.1.1/debian/copyright b/larpe/tags/release-1.1.1/debian/copyright new file mode 100644 index 0000000..c81e494 --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/copyright @@ -0,0 +1,27 @@ +This package was debianized by Damien Laniel on +Fri, 08 Sep 2006 16:00:00 +0200. + +Upstream Author: Damien Laniel + +Copyright (c) 2005 Entr'ouvert; +copyright (c) 2003-2005 dotclear for some graphics. + +License is GNU GPL v2 or later plus OpenSSL exception clause. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +On Debian GNU/Linux systems, the complete text of the GNU General Public +License can be found in `/usr/share/common-licenses/GPL'. + diff --git a/larpe/tags/release-1.1.1/debian/dirs b/larpe/tags/release-1.1.1/debian/dirs new file mode 100644 index 0000000..cc80198 --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/dirs @@ -0,0 +1,4 @@ +etc/apache2/sites-available +etc/larpe +usr/sbin +var/lib/larpe diff --git a/larpe/tags/release-1.1.1/debian/docs b/larpe/tags/release-1.1.1/debian/docs new file mode 100644 index 0000000..55bc0a6 --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/docs @@ -0,0 +1,2 @@ +README +AUTHORS diff --git a/larpe/tags/release-1.1.1/debian/init b/larpe/tags/release-1.1.1/debian/init new file mode 100644 index 0000000..edca4da --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/init @@ -0,0 +1,82 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: larpe +# Required-Start: $local_fs $network +# Required-Stop: $local_fs $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start Larpe Liberty Alliance reverse proxy +# Description: Start Larpe Liberty Alliance reverse proxy +### END INIT INFO + +set -e + +# Gracefully exit if the package has been removed. +test -x $DAEMON || exit 0 + +# Source function library +. /lib/lsb/init-functions + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DESC="larpe" +NAME=larpe +DAEMON=/usr/sbin/larpectl +PIDFILE=/var/run/$NAME.pid +SCRIPTNAME=/etc/init.d/$NAME + + +# Read config file if it is present. +if [ -r /etc/default/$NAME ] +then + . /etc/default/$NAME +fi + +# +# Function that starts the daemon/service. +# +d_start() { + start-stop-daemon --start --quiet --pidfile $PIDFILE --oknodo \ + --chuid www-data:www-data --make-pidfile --background --exec $DAEMON -- start $OPTIONS +} + +# +# Function that stops the daemon/service. +# +d_stop() { + start-stop-daemon --stop --quiet --pidfile $PIDFILE --oknodo + rm -f $PIDFILE +} + +case "$1" in + start) + log_begin_msg "Starting $DESC: $NAME" + d_start + log_end_msg $? + ;; + + stop) + log_begin_msg "Stopping $DESC: $NAME" + d_stop + log_end_msg $? + ;; + + restart|force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + log_begin_msg "Restarting $DESC: $NAME" + d_stop + sleep 1 + d_start + log_end_msg $? + ;; + + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/larpe/tags/release-1.1.1/debian/larpe-reload-apache2-script b/larpe/tags/release-1.1.1/debian/larpe-reload-apache2-script new file mode 100755 index 0000000..5431d0d --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/larpe-reload-apache2-script @@ -0,0 +1,3 @@ +#!/bin/sh + +/etc/init.d/apache2 reload diff --git a/larpe/tags/release-1.1.1/debian/postinst b/larpe/tags/release-1.1.1/debian/postinst new file mode 100644 index 0000000..6aa61f2 --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/postinst @@ -0,0 +1,66 @@ +#! /bin/sh +# postinst script for larpe +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package +# +# quoting from the policy: +# Any necessary prompting should almost always be confined to the +# post-installation script, and should be protected with a conditional +# so that unnecessary prompting doesn't happen if a package's +# installation fails and the `postinst' is called with `abort-upgrade', +# `abort-remove' or `abort-deconfigure'. + +PACKAGE=larpe +VERSION=2.4 +LIB="/usr/lib/python$VERSION" +DIRLIST="/usr/share/pycentral/larpe/site-packages/larpe/" + +case "$1" in + configure|abort-upgrade|abort-remove|abort-deconfigure) + for i in $DIRLIST ; do + /usr/bin/python$VERSION -O $LIB/compileall.py -q $i + /usr/bin/python$VERSION $LIB/compileall.py -q $i + done + + # Load Apache 2 modules + for module in "proxy" "rewrite" "headers" "proxy_http"; do + a2enmod ${module} > /dev/null || true + done + + # Restart Apache 2 + set +e + if [ -x /usr/sbin/invoke-rc.d ]; then + invoke-rc.d apache2 restart || true + else + /etc/init.d/apache2 restart || true + fi + set -e + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + + + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/larpe/tags/release-1.1.1/debian/prerm b/larpe/tags/release-1.1.1/debian/prerm new file mode 100644 index 0000000..525d726 --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/prerm @@ -0,0 +1,41 @@ +#! /bin/sh +# prerm script for larpe +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +PACKAGE=larpe + +case "$1" in + remove|upgrade|deconfigure) + dpkg --listfiles $PACKAGE | + awk '$0~/\.py$/ {print $0"c\n" $0"o"}' | + xargs rm -f >&2 + ;; + failed-upgrade) + ;; + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/larpe/tags/release-1.1.1/debian/pycompat b/larpe/tags/release-1.1.1/debian/pycompat new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/pycompat @@ -0,0 +1 @@ +2 diff --git a/larpe/tags/release-1.1.1/debian/rules b/larpe/tags/release-1.1.1/debian/rules new file mode 100755 index 0000000..f898b01 --- /dev/null +++ b/larpe/tags/release-1.1.1/debian/rules @@ -0,0 +1,74 @@ +#!/usr/bin/make -f +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +PYTHON=/usr/bin/python + +LARPE_USER = www-data +LARPE_GROUP = www-data + +ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) + CFLAGS += -g +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +build: build-stamp + +build-stamp: + dh_testdir + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + + make clean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + make install prefix=/usr DESTDIR=$(CURDIR)/debian/larpe + # Apache Vhost + dh_install conf/apache2-vhost-larpe etc/apache2/sites-available + # Apache reload script + dh_install debian/larpe-reload-apache2-script usr/sbin + + # Give files ownership to Larpe user and group + chown -R $(LARPE_USER):$(LARPE_GROUP) $(CURDIR)/debian/larpe/usr/share/larpe/ + chown -R $(LARPE_USER):$(LARPE_GROUP) $(CURDIR)/debian/larpe/var/lib/larpe/ + chgrp $(LARPE_GROUP) $(CURDIR)/debian/larpe/usr/sbin/larpe-reload-apache2 + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installdocs + dh_installinit + dh_installchangelogs + dh_link + dh_strip + dh_compress + dh_fixperms -X /var/lib/larpe -X /usr/sbin/larpe-reload-apache2 + dh_pysupport + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/larpe/tags/release-1.1.1/doc/Makefile b/larpe/tags/release-1.1.1/doc/Makefile new file mode 100644 index 0000000..9a27348 --- /dev/null +++ b/larpe/tags/release-1.1.1/doc/Makefile @@ -0,0 +1,8 @@ +all: + $(MAKE) -C en + +clean: + $(MAKE) -C en clean + +.PHONY: clean + diff --git a/larpe/tags/release-1.1.1/doc/en/Makefile b/larpe/tags/release-1.1.1/doc/en/Makefile new file mode 100644 index 0000000..295ee43 --- /dev/null +++ b/larpe/tags/release-1.1.1/doc/en/Makefile @@ -0,0 +1,35 @@ +RST2HTML = rst2html +RST2LATEX = ../scripts/rst2latex.py +PDFLATEX = pdflatex +RM = rm -f + +all: larpe-admin.pdf larpe-admin.html + +%.html: %.rst + $(RST2HTML) --stylesheet=default.css --link-stylesheet --language=en $? > $@ + +figures-no-alpha-stamp: + -$(RM) -r figures-no-alpha/ + mkdir figures-no-alpha/ + for F in figures/*.png; do \ + ../scripts/removealpha.sh $$F figures-no-alpha/`basename $$F`; \ + done + touch figures-no-alpha-stamp + +%.tex: %.rst #figures-no-alpha-stamp + cat $? | sed -e 's/figures\//figures-no-alpha\//' \ + -e 's/ ::$$/ : ::/g' \ + -e 's/.. section-numbering:://' | $(RST2LATEX) --language=en > $@ + +%.pdf: %.tex custom.tex + $(PDFLATEX) $? + logfile=`echo "$@" |sed -r "s/(.*)....$$/\\1/"`.log; while [ -f "$$logfile" -a -n "`grep "Rerun to get cross-references right" $$logfile`" ]; do $(PDFLATEX) $< ; done + +clean: + -$(RM) *.aux *.toc *.log *.out + -$(RM) larpe-admin.pdf + -$(RM) larpe-admin.tex + -$(RM) larpe-admin.html + -$(RM) -r figures-no-alpha figures-no-alpha-stamp + +.PHONY: all clean diff --git a/larpe/tags/release-1.1.1/doc/en/custom.tex b/larpe/tags/release-1.1.1/doc/en/custom.tex new file mode 100644 index 0000000..cf42eb7 --- /dev/null +++ b/larpe/tags/release-1.1.1/doc/en/custom.tex @@ -0,0 +1,45 @@ +\usepackage{float,fancyhdr,lscape,sectsty,colortbl,color,lastpage,setspace} +\usepackage[perpage,bottom]{footmisc} +\usepackage[hang]{caption2} +\usepackage{marvosym} + +\usepackage{float,url,listings,tocbibind,fancyhdr,calc,placeins} + +\usepackage{palatino} +\usepackage[Glenn]{fncychap} + +\pagestyle{fancy} +\fancyhead{} +\fancyfoot{} +\fancyhead[L]{Authentic} +\fancyhead[R]{Administrator Guide} +\fancyfoot[C]{Page \thepage} +\addtolength{\headheight}{1.6pt} + +\setlength\parindent{0pt} +\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex} +\setlength\abovecaptionskip{0.1ex} + +\makeatletter +\renewcommand{\maketitle}{\begin{titlepage}% + \let\footnotesize\small + \let\footnoterule\relax + \parindent \z@ + \reset@font + \null\vfil + \begin{flushleft} + \huge \@title + \end{flushleft} + \par + \hrule height 1pt + \par + \begin{flushright} + \LARGE \@author \par + \end{flushright} + \vskip 60\p@ + \vfil\null + \end{titlepage}% + \setcounter{footnote}{0}% +} +\makeatother + diff --git a/larpe/tags/release-1.1.1/doc/en/default.css b/larpe/tags/release-1.1.1/doc/en/default.css new file mode 100644 index 0000000..d198a16 --- /dev/null +++ b/larpe/tags/release-1.1.1/doc/en/default.css @@ -0,0 +1,143 @@ +body { + font-family: sans-serif; +} + + +h1 a, h2 a, h3 a, h4 a { + text-decoration: inherit; + color: inherit; +} + +pre.literal-block { + background: #eee; + border: 1px inset black; + padding: 2px; + margin: auto 10px; + overflow: auto; +} + +h1.title { + text-align: center; + background: #eef; + border: 1px solid #aaf; + letter-spacing: 1px; +} + +div.section { + margin-bottom: 2em; +} + +div.section h1 { + padding: 0 15px; + background: #eef; + border: 1px solid #aaf; +} + +div.section h2 { + padding: 0 15px; + background: #eef; + border: 1px solid #aaf; +} + +div.document { + margin-top: 1em; + border-top: 1px solid #aaf; + border-bottom: 1px solid #aaf; +} + +div.section p, +div.section ul { + text-align: justify; +} + +div.contents { + float: right; + border: 1px solid black; + margin: 1em; + background: #eef; + max-width: 33%; +} + +div#building-liberty-services-with-lasso div#table-of-contents { + max-width: inherit; + float: none; + background: white url(lasso.png) bottom right no-repeat; +} + +div.contents ul { + padding-left: 1em; + list-style: none; +} + +div.contents li { + padding-bottom: 2px; +} + +div.contents p { + background: #ddf; + text-align: center; + border-bottom: 1px solid black; + margin: 0; +} + +th.docinfo-name { + text-align: right; + padding-right: 0.5em; +} + +dd { + margin-bottom: 1ex; +} + +table.table { + margin: 1ex 0; + border-spacing: 0px; +} + + +table.table th { + padding: 0px 1ex; + background: #eef; + font-weight: normal; +} + + +table.table td { + padding: 0 0.5ex; +} + +div.note, div.warning { + padding: 0.3ex; + padding-left: 60px; + min-height: 50px; + margin: 1ex 1em; +} + +div.note { + background: #ffa url(note.png) top left no-repeat; + border: 1px solid #fd8; +} + +div.warning { + background: #ffd url(warning.png) top left no-repeat; +} + +p.admonition-title { + font-weight: bold; + display: inline; + display: none; + padding-right: 1em; +} + +div.figure { + margin: 0 auto; + width: 70%; + min-width: 800px; + text-align: center; +} + +div.figure p.caption { + font-style: italic; + margin: 1ex 0 2em 0; + text-align: center; +} diff --git a/larpe/tags/release-1.1.1/doc/en/fncychap.sty b/larpe/tags/release-1.1.1/doc/en/fncychap.sty new file mode 100644 index 0000000..9c4ed8d --- /dev/null +++ b/larpe/tags/release-1.1.1/doc/en/fncychap.sty @@ -0,0 +1,490 @@ +%%% Copyright Ulf A. Lindgren +%%% +%%% Note Premission is granted to modify this file under +%%% the condition that it is saved using another +%%% file and package name. +%%% +%%% Revision 1.1 (1997) +%%% +%%% Jan. 8th Modified package name base date option +%%% Jan. 22th Modified FmN and FmTi for error in book.cls +%%% \MakeUppercase{#}->{\MakeUppercase#} +%%% Apr. 6th Modified Lenny option to prevent undesired +%%% skip of line. +%%% Nov. 8th Fixed \@chapapp for AMS +%%% +%%% Revision 1.2 (1998) +%%% +%%% Feb. 11th Fixed appendix problem related to Bjarne +%%% Aug. 11th Fixed problem related to 11pt and 12pt +%%% suggested by Tomas Lundberg. THANKS! +%%% +%%% Revision 1.3 (2004) +%%% Sep. 20th problem with frontmatter, mainmatter and +%%% backmatter, pointed out by Lapo Mori +%%% +%%% Revision 1.31 (2004) +%%% Sep. 21th problem with the Rejne definition streched text +%%% caused ugly gaps in the vrule aligned with the title +%%% text. Kindly pointed out to me by Hendri Adriaens +%%% +%%% Revision 1.32 (2005) +%%% Jun. 23th compatibility problem with the KOMA class 'scrbook.cls' +%%% a remedy is a redefinition of '\@schapter' in +%%% line with that used in KOMA. The problem was pointed +%%% out to me by Mikkel Holm Olsen +%%% +%%% Revision 1.33 (2005) +%%% Aug. 9th misspelled ``TWELV'' corrected, the error was pointed +%%% out to me by George Pearson +%%% + + +%%% Last modified Aug. 9th 2005 + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesPackage{fncychap} + [2004/09/21 v1.33 + LaTeX package (Revised chapters)] + +%%%% DEFINITION OF Chapapp variables +\newcommand{\CNV}{\huge\bfseries} +\newcommand{\ChNameVar}[1]{\renewcommand{\CNV}{#1}} + + +%%%% DEFINITION OF TheChapter variables +\newcommand{\CNoV}{\huge\bfseries} +\newcommand{\ChNumVar}[1]{\renewcommand{\CNoV}{#1}} + +\newif\ifUCN +\UCNfalse +\newif\ifLCN +\LCNfalse +\def\ChNameLowerCase{\LCNtrue\UCNfalse} +\def\ChNameUpperCase{\UCNtrue\LCNfalse} +\def\ChNameAsIs{\UCNfalse\LCNfalse} + +%%%%% Fix for AMSBook 971008 + +\@ifundefined{@chapapp}{\let\@chapapp\chaptername}{} + + +%%%%% Fix for Bjarne and appendix 980211 + +\newif\ifinapp +\inappfalse +\renewcommand\appendix{\par + \setcounter{chapter}{0}% + \setcounter{section}{0}% + \inapptrue% + \renewcommand\@chapapp{\appendixname}% + \renewcommand\thechapter{\@Alph\c@chapter}} + +%%%%% Fix for frontmatter, mainmatter, and backmatter 040920 + +\@ifundefined{@mainmatter}{\newif\if@mainmatter \@mainmattertrue}{} + +%%%%% + + + +\newcommand{\FmN}[1]{% +\ifUCN + {\MakeUppercase#1}\LCNfalse +\else + \ifLCN + {\MakeLowercase#1}\UCNfalse + \else #1 + \fi +\fi} + + +%%%% DEFINITION OF Title variables +\newcommand{\CTV}{\Huge\bfseries} +\newcommand{\ChTitleVar}[1]{\renewcommand{\CTV}{#1}} + +%%%% DEFINITION OF the basic rule width +\newlength{\RW} +\setlength{\RW}{1pt} +\newcommand{\ChRuleWidth}[1]{\setlength{\RW}{#1}} + +\newif\ifUCT +\UCTfalse +\newif\ifLCT +\LCTfalse +\def\ChTitleLowerCase{\LCTtrue\UCTfalse} +\def\ChTitleUpperCase{\UCTtrue\LCTfalse} +\def\ChTitleAsIs{\UCTfalse\LCTfalse} +\newcommand{\FmTi}[1]{% +\ifUCT + {\MakeUppercase#1}\LCTfalse +\else + \ifLCT + {\MakeLowercase#1}\UCTfalse + \else {#1} + \fi +\fi} + + + +\newlength{\mylen} +\newlength{\myhi} +\newlength{\px} +\newlength{\py} +\newlength{\pyy} +\newlength{\pxx} + + +\def\mghrulefill#1{\leavevmode\leaders\hrule\@height #1\hfill\kern\z@} + +\newcommand{\DOCH}{% + \CNV\FmN{\@chapapp}\space \CNoV\thechapter + \par\nobreak + \vskip 20\p@ + } +\newcommand{\DOTI}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } +\newcommand{\DOTIS}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } + +%%%%%% SONNY DEF + +\DeclareOption{Sonny}{% + \ChNameVar{\Large\sf} + \ChNumVar{\Huge} + \ChTitleVar{\Large\sf} + \ChRuleWidth{0.5pt} + \ChNameUpperCase + \renewcommand{\DOCH}{% + \raggedleft + \CNV\FmN{\@chapapp}\space \CNoV\thechapter + \par\nobreak + \vskip 40\p@} + \renewcommand{\DOTI}[1]{% + \CTV\raggedleft\mghrulefill{\RW}\par\nobreak + \vskip 5\p@ + \CTV\FmTi{#1}\par\nobreak + \mghrulefill{\RW}\par\nobreak + \vskip 40\p@} + \renewcommand{\DOTIS}[1]{% + \CTV\raggedleft\mghrulefill{\RW}\par\nobreak + \vskip 5\p@ + \CTV\FmTi{#1}\par\nobreak + \mghrulefill{\RW}\par\nobreak + \vskip 40\p@} +} + +%%%%%% LENNY DEF + +\DeclareOption{Lenny}{% + + \ChNameVar{\fontsize{14}{16}\usefont{OT1}{phv}{m}{n}\selectfont} + \ChNumVar{\fontsize{60}{62}\usefont{OT1}{ptm}{m}{n}\selectfont} + \ChTitleVar{\Huge\bfseries\rm} + \ChRuleWidth{1pt} + \renewcommand{\DOCH}{% + \settowidth{\px}{\CNV\FmN{\@chapapp}} + \addtolength{\px}{2pt} + \settoheight{\py}{\CNV\FmN{\@chapapp}} + \addtolength{\py}{1pt} + + \settowidth{\mylen}{\CNV\FmN{\@chapapp}\space\CNoV\thechapter} + \addtolength{\mylen}{1pt} + \settowidth{\pxx}{\CNoV\thechapter} + \addtolength{\pxx}{-1pt} + + \settoheight{\pyy}{\CNoV\thechapter} + \addtolength{\pyy}{-2pt} + \setlength{\myhi}{\pyy} + \addtolength{\myhi}{-1\py} + \par + \parbox[b]{\textwidth}{% + \rule[\py]{\RW}{\myhi}% + \hskip -\RW% + \rule[\pyy]{\px}{\RW}% + \hskip -\px% + \raggedright% + \CNV\FmN{\@chapapp}\space\CNoV\thechapter% + \hskip1pt% + \mghrulefill{\RW}% + \rule{\RW}{\pyy}\par\nobreak% + \vskip -\baselineskip% + \vskip -\pyy% + \hskip \mylen% + \mghrulefill{\RW}\par\nobreak% + \vskip \pyy}% + \vskip 20\p@} + + + \renewcommand{\DOTI}[1]{% + \raggedright + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@} + + \renewcommand{\DOTIS}[1]{% + \raggedright + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@} + } + + +%%%%%%% GLENN DEF + + +\DeclareOption{Glenn}{% + \ChNameVar{\bfseries\Large\sf} + \ChNumVar{\Huge} + \ChTitleVar{\bfseries\Large\rm} + \ChRuleWidth{1pt} + \ChNameUpperCase + \ChTitleUpperCase + \renewcommand{\DOCH}{% + \settoheight{\myhi}{\CTV\FmTi{Test}} + \setlength{\py}{\baselineskip} + \addtolength{\py}{\RW} + \addtolength{\py}{\myhi} + \setlength{\pyy}{\py} + \addtolength{\pyy}{-1\RW} + + \raggedright + \CNV\FmN{\@chapapp}\space\CNoV\thechapter + \hskip 3pt\mghrulefill{\RW}\rule[-1\pyy]{2\RW}{\py}\par\nobreak} + + \renewcommand{\DOTI}[1]{% + \addtolength{\pyy}{-4pt} + \settoheight{\myhi}{\CTV\FmTi{#1}} + \addtolength{\myhi}{\py} + \addtolength{\myhi}{-1\RW} + \vskip -1\pyy + \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt + \raggedleft\CTV\FmTi{#1}\par\nobreak + \vskip 80\p@} + +\newlength{\backskip} + \renewcommand{\DOTIS}[1]{% +% \setlength{\py}{10pt} +% \setlength{\pyy}{\py} +% \addtolength{\pyy}{\RW} +% \setlength{\myhi}{\baselineskip} +% \addtolength{\myhi}{\pyy} +% \mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak +% \addtolength{}{} +%\vskip -1\baselineskip +% \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt +% \raggedleft\CTV\FmTi{#1}\par\nobreak +% \vskip 60\p@} +%% Fix suggested by Tomas Lundberg + \setlength{\py}{25pt} % eller vad man vill + \setlength{\pyy}{\py} + \setlength{\backskip}{\py} + \addtolength{\backskip}{2pt} + \addtolength{\pyy}{\RW} + \setlength{\myhi}{\baselineskip} + \addtolength{\myhi}{\pyy} + \mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak + \vskip -1\backskip + \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 3pt % + \raggedleft\CTV\FmTi{#1}\par\nobreak + \vskip 40\p@} + } + +%%%%%%% CONNY DEF + +\DeclareOption{Conny}{% + \ChNameUpperCase + \ChTitleUpperCase + \ChNameVar{\centering\Huge\rm\bfseries} + \ChNumVar{\Huge} + \ChTitleVar{\centering\Huge\rm} + \ChRuleWidth{2pt} + + \renewcommand{\DOCH}{% + \mghrulefill{3\RW}\par\nobreak + \vskip -0.5\baselineskip + \mghrulefill{\RW}\par\nobreak + \CNV\FmN{\@chapapp}\space \CNoV\thechapter + \par\nobreak + \vskip -0.5\baselineskip + } + \renewcommand{\DOTI}[1]{% + \mghrulefill{\RW}\par\nobreak + \CTV\FmTi{#1}\par\nobreak + \vskip 60\p@ + } + \renewcommand{\DOTIS}[1]{% + \mghrulefill{\RW}\par\nobreak + \CTV\FmTi{#1}\par\nobreak + \vskip 60\p@ + } + } + +%%%%%%% REJNE DEF + +\DeclareOption{Rejne}{% + + \ChNameUpperCase + \ChTitleUpperCase + \ChNameVar{\centering\Large\rm} + \ChNumVar{\Huge} + \ChTitleVar{\centering\Huge\rm} + \ChRuleWidth{1pt} + \renewcommand{\DOCH}{% + \settoheight{\py}{\CNoV\thechapter} + \parskip=0pt plus 1pt % Set parskip to default, just in case v1.31 + \addtolength{\py}{-1pt} + \CNV\FmN{\@chapapp}\par\nobreak + \vskip 20\p@ + \setlength{\myhi}{2\baselineskip} + \setlength{\px}{\myhi} + \addtolength{\px}{-1\RW} + \rule[-1\px]{\RW}{\myhi}\mghrulefill{\RW}\hskip + 10pt\raisebox{-0.5\py}{\CNoV\thechapter}\hskip 10pt\mghrulefill{\RW}\rule[-1\px]{\RW}{\myhi}\par\nobreak + \vskip -3\p@% Added -2pt vskip to correct for streched text v1.31 + } + \renewcommand{\DOTI}[1]{% + \setlength{\mylen}{\textwidth} + \parskip=0pt plus 1pt % Set parskip to default, just in case v1.31 + \addtolength{\mylen}{-2\RW} + {\vrule width\RW}\parbox{\mylen}{\CTV\FmTi{#1}}{\vrule width\RW}\par\nobreak% + \vskip -3pt\rule{\RW}{2\baselineskip}\mghrulefill{\RW}\rule{\RW}{2\baselineskip}% + \vskip 60\p@% Added -2pt in vskip to correct for streched text v1.31 + } + \renewcommand{\DOTIS}[1]{% + \setlength{\py}{\fboxrule} + \setlength{\fboxrule}{\RW} + \setlength{\mylen}{\textwidth} + \addtolength{\mylen}{-2\RW} + \fbox{\parbox{\mylen}{\vskip 2\baselineskip\CTV\FmTi{#1}\par\nobreak\vskip \baselineskip}} + \setlength{\fboxrule}{\py} + \vskip 60\p@ + } + } + + +%%%%%%% BJARNE DEF + +\DeclareOption{Bjarne}{% + \ChNameUpperCase + \ChTitleUpperCase + \ChNameVar{\raggedleft\normalsize\rm} + \ChNumVar{\raggedleft \bfseries\Large} + \ChTitleVar{\raggedleft \Large\rm} + \ChRuleWidth{1pt} + + +%% Note thechapter -> c@chapter fix appendix bug +%% Fixed misspelled 12 + + \newcounter{AlphaCnt} + \newcounter{AlphaDecCnt} + \newcommand{\AlphaNo}{% + \ifcase\number\theAlphaCnt + \ifnum\c@chapter=0 + ZERO\else{}\fi + \or ONE\or TWO\or THREE\or FOUR\or FIVE + \or SIX\or SEVEN\or EIGHT\or NINE\or TEN + \or ELEVEN\or TWELVE\or THIRTEEN\or FOURTEEN\or FIFTEEN + \or SIXTEEN\or SEVENTEEN\or EIGHTEEN\or NINETEEN\fi +} + + \newcommand{\AlphaDecNo}{% + \setcounter{AlphaDecCnt}{0} + \@whilenum\number\theAlphaCnt>0\do + {\addtocounter{AlphaCnt}{-10} + \addtocounter{AlphaDecCnt}{1}} + \ifnum\number\theAlphaCnt=0 + \else + \addtocounter{AlphaDecCnt}{-1} + \addtocounter{AlphaCnt}{10} + \fi + + + \ifcase\number\theAlphaDecCnt\or TEN\or TWENTY\or THIRTY\or + FORTY\or FIFTY\or SIXTY\or SEVENTY\or EIGHTY\or NINETY\fi + } + \newcommand{\TheAlphaChapter}{% + + \ifinapp + \thechapter + \else + \setcounter{AlphaCnt}{\c@chapter} + \ifnum\c@chapter<20 + \AlphaNo + \else + \AlphaDecNo\AlphaNo + \fi + \fi + } + \renewcommand{\DOCH}{% + \mghrulefill{\RW}\par\nobreak + \CNV\FmN{\@chapapp}\par\nobreak + \CNoV\TheAlphaChapter\par\nobreak + \vskip -1\baselineskip\vskip 5pt\mghrulefill{\RW}\par\nobreak + \vskip 20\p@ + } + \renewcommand{\DOTI}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } + \renewcommand{\DOTIS}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } +} + +\DeclareOption*{% + \PackageWarning{fancychapter}{unknown style option} + } + +\ProcessOptions* \relax + +\def\@makechapterhead#1{% + \vspace*{50\p@}% + {\parindent \z@ \raggedright \normalfont + \ifnum \c@secnumdepth >\m@ne + \if@mainmatter%%%%% Fix for frontmatter, mainmatter, and backmatter 040920 + \DOCH + \fi + \fi + \interlinepenalty\@M + \DOTI{#1} + }} + + +%%% Begin: To avoid problem with scrbook.cls (fncychap version 1.32) + +%%OUT: +%\def\@schapter#1{\if@twocolumn +% \@topnewpage[\@makeschapterhead{#1}]% +% \else +% \@makeschapterhead{#1}% +% \@afterheading +% \fi} + +%%IN: +\def\@schapter#1{% +\if@twocolumn% + \@makeschapterhead{#1}% +\else% + \@makeschapterhead{#1}% + \@afterheading% +\fi} + +%%% End: To avoid problem with scrbook.cls (fncychap version 1.32) + +\def\@makeschapterhead#1{% + \vspace*{50\p@}% + {\parindent \z@ \raggedright + \normalfont + \interlinepenalty\@M + \DOTIS{#1} + \vskip 40\p@ + }} + +\endinput + + diff --git a/larpe/tags/release-1.1.1/doc/en/larpe-admin.rst b/larpe/tags/release-1.1.1/doc/en/larpe-admin.rst new file mode 100644 index 0000000..32ac1c9 --- /dev/null +++ b/larpe/tags/release-1.1.1/doc/en/larpe-admin.rst @@ -0,0 +1,202 @@ +===================================== +Larpe - Administrator Guide +===================================== + +:author: Damien Laniel +:contact: dlaniel@entrouvert.com +:copyright: Copyright © 2006 Entr'ouvert + +.. contents:: Table of contents + +Overview +======== + +Larpe is a Liberty Alliance Reverse Proxy. It allows any service provider +(that is a website) to use Liberty Alliance features (Identity federation, +Single Sign On and Single Logout) without changing the code of +the service provider itself. It uses the Lasso_ library +which is certified by the `Liberty Alliance`_ consortium. Lasso_ and Larpe +are released under the terms of the `GNU GPL license`_. + + +How to get and install Larpe +============================ + +Installation under Debian_ Sarge +++++++++++++++++++++++++++++++++ + +To work correctly Larpe relies on : + +* Apache2_ ; + +* Lasso_ (0.6.3) ; + +* Quixote_ (2.0) ; + +* SCGI_ ; + +* mod_python_ ; + +* libxml2 ; + +* mod_proxy_html. + +You will also need a Liberty Alliance Identity Provider, be it on the same server or not. +We recommend Authentic_ for that need. + +Package Installation +-------------------- + +You need to add the following line to your /etc/apt/sources.list; this will +give you access to the repository where Larpe is stored:: + + deb http://deb.entrouvert.org/ sarge main + +As root type:: + + apt-get update + apt-get install larpe + +And follow the debconf wizard to set it up. + +All the required packages are now installed and configured. + +You might need to change the "" in your apache2 configuration +(/etc/apache2/sites-available/apache2-vhost-larpe) depending on how you +previously configured apache. + +Don't forget to modify your /etc/hosts file if necessary. Larpe now works, the +administration interface is reachable at http://your_domain_name/admin. The username +and password are the ones you entered during the installation wizard. + +If you don't want to modify your sources.list file, you can manually dowload and +install the required packages with the dpkg -i command : + +* Larpe, Authentic and Lasso on http://deb.entrouvert.org/ ; + +* Quixote 2.0 on http://authentic.labs.libre-entreprise.org/. + +Installation with another Linux distribution +++++++++++++++++++++++++++++++++++++++++++++ + +We suppose Apache2_, SCGI_, mod_python_, libxml2 and mod_proxy_html are already installed. You need then to +download and install the following sources : + +* Lasso http://lasso.entrouvert.org ; + +* Quixote http://www.mems-exchange.org/software/Quixote/ ; + +* Authentic http://authentic.labs.libre-entreprise.org/ ; + +* Larpe http://labs.libre-entreprise.org/frs/?group_id=108. + +To install Larpe, uncompress the sources you have downloaded and launch the +setup.py script :: + + tar xzf larpe*.tar.gz + cd larpe* + python setup.py install + +You need then to configure Apache2_ correctly. You should use the provided apache2-vhost-larpe template and adapt to your configuration. + +Don't forget to modify your /etc/hosts file if necessary. Larpe now works, the +administration interface is reachable at http://your_domain_name/admin. + +Basic Larpe configuration +========================= + +Identity Provider configuration ++++++++++++++++++++++++++++++++ + +If you don't have a configured Identity Provider yet, please read Authentic +manual to set it up. Then you must have the metadata and public key of the Identity +Provider to begin with Larpe. + +Then in Larpe administration interface, click on "Settings", then "Identity Provider". +Fill in the metadata and public key that you've got from your Identity Provider then +click Submit. +Your Identity Provider is now configured in Larpe, you can then configure as many Service +Providers as you want. + +Service Provider Configuration +++++++++++++++++++++++++++++++ + +Service Provider configuration +------------------------------ + +Click on "Hosts" then "New Host". + +Fill in the following parameters : + +* Label : the name you want to give to your Service Provider ; + +* Original Site Address : the root URL of your Service Provider ; + +* Authentication Page : if the page which contains the authentication form for + your Service Provider is on a separate page, fill the url of this page here ; + +* Authentication Form Page : if you didn't fill the previous field and if the + authentication form if not on the first page of your Service Provider either, + fill the url of the page which contains the authentication form here ; + +* Logout Address : when you want Single Sign On and Identity Federation, you probably + want Single Logout too. If so, fill the logout url of your original site here ; + +* Reversed Host Name : the domain name where you want to access your Service Provider + through the reverse proxy. It can be the domain name of Larpe or not ; + +Then click "Submit". Wait a few seconds then go to http://reversed_host_name/reverse_directory/ +to check if it works. If not, wait a bit more and try again. If it really doesn't work, +please submit a bug report at http://labs.libre-entreprise.org/tracker/?func=add&group_id=108&atid=512 + +Service Provider Example: Linuxfr +--------------------------------- + +To help you setup your own Service Provider, we provide an example of a working Service Provider +to guide you. + +To setup Linuxfr, fill in the following parameters : + +* Label : Linuxfr ; + +* Original Site Address : http://linuxfr.org/ ; + +* Authentication Page : Nothing here ; + +* Authentication Form Page : http://linuxfr.org/pub/ ; + +* Logout Address : http://linuxfr.org/close_session.html ; + +* Reversed Host Name : linuxfr.reverse-proxy.example.com. + +With "reverse-proxy.example.com" being the hostname you've set up before for your reverse-proxy + +Don't forget to add this new hostname to your /etc/hosts as well. + +You can then go to the reversed Linuxfr at http://linuxfr.reverse-proxy.example.com/ + +Service Provider Liberty Alliance final setup +--------------------------------------------- + +Now that you can access your Service Provider, you need a final step to use Liberty Alliance +features. Click on "Hosts", the click on the "Edit" icon of the Service Provider you've +just configured. Save the Service Provider Metadata (for ID-FF 1.2) and the Public Key +(right click then "Save as"). Configure this Service Provider on your Identity Provider +with these two files. + +Licenses +======== + +Larpe, Authentic_, Candle_ and Lasso_ are released under the terms of the +`GNU GPL license`_. + +.. _Lasso: http://lasso.entrouvert.org/ +.. _`Liberty Alliance`: http://projectliberty.org/ +.. _`GNU GPL License`: http://www.gnu.org/copyleft/gpl.html +.. _Debian: http://www.debian.org/ +.. _Apache2: http://httpd.apache.org/ +.. _Quixote: http://www.mems-exchange.org/software/Quixote +.. _mod_python: http://www.modpython.org/ +.. _SCGI: http://www.mems-exchange.org/software/scgi/ +.. _Candle: http://candle.labs.libre-entreprise.org/ +.. _Authentic: http://www.entrouvert.com/fr/authentic/ diff --git a/larpe/tags/release-1.1.1/doc/scripts/removealpha.sh b/larpe/tags/release-1.1.1/doc/scripts/removealpha.sh new file mode 100755 index 0000000..f29ee67 --- /dev/null +++ b/larpe/tags/release-1.1.1/doc/scripts/removealpha.sh @@ -0,0 +1,5 @@ +#! /bin/sh + +size=$(identify $1 | cut -d ' ' -f 3) +composite $1 -size $(identify $1 | cut -d ' ' -f3) xc:white $2 + diff --git a/larpe/tags/release-1.1.1/doc/scripts/rst2latex.py b/larpe/tags/release-1.1.1/doc/scripts/rst2latex.py new file mode 100755 index 0000000..4036fbf --- /dev/null +++ b/larpe/tags/release-1.1.1/doc/scripts/rst2latex.py @@ -0,0 +1,29 @@ +#! /usr/bin/python + +"""A minimal reST frontend, to create appropriate LaTeX files.""" + +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline, Publisher + +def set_io(self, source_path=None, destination_path=None): + Publisher.set_io_orig(self, source_path, destination_path='/dev/null') + +Publisher.set_io_orig, Publisher.set_io = Publisher.set_io, set_io + +output = publish_cmdline(writer_name='latex', + settings_overrides = { + 'documentclass': 'report', + 'documentoptions': '11pt,a4paper,titlepage', + 'use_latex_toc': True, + 'use_latex_docinfo': True, + 'stylesheet': 'custom.tex'}) + +output = output.replace('\\includegraphics', + '\\includegraphics[width=.9\\textwidth,height=15cm,clip,keepaspectratio]') +output = output.replace('\\begin{figure}[htbp]', '\\begin{figure}[H]') +print output diff --git a/larpe/tags/release-1.1.1/exclude_from_dist b/larpe/tags/release-1.1.1/exclude_from_dist new file mode 100644 index 0000000..d6e841d --- /dev/null +++ b/larpe/tags/release-1.1.1/exclude_from_dist @@ -0,0 +1,12 @@ +.svn +*.pyc +*.pyo +*.pye +*.ptle +*.swp +debian.sarge +make_debian_package.sh +build +dist +tests +larpe/filter diff --git a/larpe/tags/release-1.1.1/fedora/larpe-reload-apache2-script b/larpe/tags/release-1.1.1/fedora/larpe-reload-apache2-script new file mode 100755 index 0000000..928b0b7 --- /dev/null +++ b/larpe/tags/release-1.1.1/fedora/larpe-reload-apache2-script @@ -0,0 +1,22 @@ +#!/bin/sh +# +# The command "/etc/init.d/httpd reload" on Fedora actually _restarts_ Apache +# We need to _reload_ it without closing existing connections + +APACHE2CTL=/usr/sbin/apachectl + +echo -n "Testing Apache config... " +if ! $APACHE2CTL configtest > /dev/null 2>&1; then + $APACHE2CTL configtest || true + echo "[FAILED]" + exit 1 +else + echo "[OK]" +fi +echo -n "Reloading Apache config... " +if $APACHE2CTL graceful $2 ; then + echo "[OK]" +else + echo "[FAILED]" +fi + diff --git a/larpe/tags/release-1.1.1/fedora/larpe.init b/larpe/tags/release-1.1.1/fedora/larpe.init new file mode 100755 index 0000000..a41681f --- /dev/null +++ b/larpe/tags/release-1.1.1/fedora/larpe.init @@ -0,0 +1,104 @@ +#! /bin/bash +# +# larpe Startup script for the Larpe reverse proxy +# +# description: Larpe is Liberty Alliance reverse proxy. It is used to add Liberty Alliance \ +# features to some sites without modifying the sites themselves. +# processname: larpe +# config: /etc/httpd/conf.d/larpe.conf +# config: /etc/larpe/apache2-vhost-larpe-common +# config: /etc/sysconfig/larpe +# pidfile: /var/run/larpe.pid +# + +### BEGIN INIT INFO +# Provides: larpe +# Required-Start: $local_fs $network +# Required-Stop: $local_fs $network +# Default-Start: +# Default-Stop: 0 1 2 3 4 5 6 +# Short-Description: Start Larpe Liberty Alliance reverse proxy +# Description: Start Larpe Liberty Alliance reverse proxy +### END INIT INFO + +prog=larpe +LARPECTL=/usr/sbin/larpectl +PIDFILE=/var/run/larpe.pid + +# Source function library. +. /etc/rc.d/init.d/functions + +# Source networking configuration. +. /etc/sysconfig/network + +# Check that networking is up. +[ ${NETWORKING} = "no" ] && exit 0 + +[ -x $LARPECTL ] || exit 5 + +# Read config file if it is present. +if [ -f /etc/sysconfig/larpe ]; then + . /etc/sysconfig/larpe +fi + +RETVAL=0 + +# +# Function that starts the daemon/service. +# +start() { + echo -n $"Starting $prog: " + $LARPECTL start & + RETVAL=$? + if [ $RETVAL -eq 0 ] + then + touch /var/lock/subsys/$prog + fi + echo + return $RETVAL +} + +# +# Function that stops the daemon/service. +# +stop() { + echo -n $"Stopping $prog: " + killproc $LARPECTL + RETVAL=$? + if [ $RETVAL -eq 0 ] + then + rm -rf /var/lock/subsys/$prog + fi + echo + return $RETVAL +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status $prog + RETVAL=$? + ;; + restart) + stop + start + ;; + condrestart) + if [ -f ${PIDFILE} ] ; then + stop + start + fi + ;; + *) + echo $"Usage: $prog {start|stop|restart|condrestart|status}" + exit 1 +esac + +exit $RETVAL + diff --git a/larpe/tags/release-1.1.1/fedora/larpe.spec b/larpe/tags/release-1.1.1/fedora/larpe.spec new file mode 100644 index 0000000..21932dc --- /dev/null +++ b/larpe/tags/release-1.1.1/fedora/larpe.spec @@ -0,0 +1,139 @@ +%{!?python_sitearch: %define python_sitearch %(%{__python} -c 'from distutils import sysconfig; print sysconfig.get_python_lib(1)')} +# eval to 2.3 if python isn't yet present, workaround for no python in fc4 minimal buildroot +%{!?python_version: %define python_version %(%{__python} -c 'import sys; print sys.version.split(" ")[0]' || echo "2.3")} +%define apacheconfdir %{_sysconfdir}/httpd/conf.d + +Summary: Liberty Alliance Reverse Proxy +Name: larpe +Version: 0.2.9 +Release: 2%{?dist} +License: GPL +Group: System Environment/Applications +Url: http://larpe.labs.libre-entreprise.org/ +Source0: http://labs.libre-entreprise.org/frs/download.php/591/%{name}-%{version}.tar.gz +Buildroot: %{_tmppath}/%{name}-%{version}-%(id -u -n) +BuildRequires: python >= 2.3, python-quixote >= 2.0 +BuildRequires: gettext +Requires: httpd >= 2.0, mod_scgi, mod_proxy_html +Requires: lasso-python >= 0.6.3, python-quixote >= 2.0, python-scgi +Requires: initscripts +Requires(post): /sbin/chkconfig +Requires(preun):/sbin/chkconfig +Requires(preun): /sbin/service + +%description +Larpe is a Liberty Alliance Reverse Proxy. It allows any service provider (that is a website) +to use Liberty Alliance features (Identity federation, Single Sign On and Single Logout) without +changing the code of the service provider itself. + +It uses the Lasso library which is certified by the Liberty Alliance consortium. + +It is a quixote application and is commonly runned inside Apache web server. + +%package doc +Summary: Documentation files for %{name} development. +Group: Documentation +BuildRequires: python-docutils, tetex-latex + +%description doc +This package contains development documentation for %{name}. + +%prep +%setup -q + +# Change Apache vhost path in Larpe config +sed -i s#"/var/log/apache2/larpe-access.log"#"logs/larpe_access_log combined\n TransferLog logs/larpe_access_log"# conf/apache2-vhost-larpe +sed -i s#"/var/log/apache2/larpe-error.log"#"logs/larpe_error_log"# conf/apache2-vhost-larpe +sed -i s#"APACHE_MAIN_VHOST.*$"#"APACHE_MAIN_VHOST='/etc/httpd/conf.d/larpe.conf'"# larpe/Defaults.py + +%build + +%install +rm -rf %{buildroot} + +# install generic files +make install prefix=%{_prefix} DESTDIR=%{buildroot} + +# install init script +install -d %{buildroot}/%{_initrddir} +install -p -m 0755 fedora/larpe.init %{buildroot}%{_initrddir}/larpe + +# apache configuration +mkdir -p %{buildroot}%{apacheconfdir} +install -p -m 644 conf/apache2-vhost-larpe %{buildroot}%{apacheconfdir}/larpe.conf + +# apache reload script +install -p -m 0755 fedora/larpe-reload-apache2-script %{buildroot}%{_sbindir}/ + +# install doc files +install -d -m 0755 %{buildroot}%{_datadir}/gtk-doc/html/larpe +make -C doc DESTDIR=%{buildroot}%{_datadir}/gtk-doc/html/larpe + +%clean +rm -fr %{buildroot} + +%post +/sbin/chkconfig --add %{name} + +# manual post-installation +cat <<_EOF_ +You must edit first %{apacheconfdir}/larpe.conf + +You must enable Larpe with "chkconfig larpe on ; service larpe start" + +You must also restart Apache with "service httpd restart"! +_EOF_ + +%preun +if [ $1 = 0 ]; then + /sbin/service %{name} stop > /dev/null 2>&1 + /sbin/chkconfig --del %{name} +fi + +%files +%defattr(-,root,root,755) +%config %{_initrddir}/larpe +%config(noreplace) %{apacheconfdir}/larpe.conf +%config(noreplace) %{_sysconfdir}/larpe/apache2-vhost-larpe-common +%{_sbindir}/larpectl +%{_sbindir}/larpe-reload-apache2 +%{_sbindir}/larpe-reload-apache2-script +%{python_sitearch}/%{name} +%{_datadir}/%{name} +%{_datadir}/locale/fr/LC_MESSAGES/larpe.mo +/var/lib/larpe +%defattr(644,root,root,755) +%doc AUTHORS COPYING NEWS README + +%files doc +%defattr(-,root,root) +%doc %{_datadir}/gtk-doc/html/%{name} + +%changelog +* Tue Mar 05 2009 Jean-Marc Liger 0.2.9-2 +- Added missing BuildRequires gettext +- Enabled larpe init script + +* Mon Jan 19 2009 Damien Laniel 0.2.9-1 +- Updated to 0.2.9 +- Use Larpe Makefile to install generic files +- Copy fedora specific files + +* Sat Jan 17 2009 Jean-Marc Liger 0.2.1-2 +- Added missing BuildRequires tetex-latex for doc subpackage +- Rebuilt on CentOS 4,5 + +* Wed Jan 14 2009 Jean-Marc Liger 0.2.1-1 +- Updated to 0.2.1 +- Added missing Requires lasso-python +- Added missing Requires python-scgi +- Rebuilt on CentOS 4,5 + +* Fri Mar 02 2007 Jean-Marc Liger 0.2.0-1 +- Updated to 0.2.0 +- Added BuildRequires python-quixote +- Built on Fedora Core 3 / RHEL 4 and Fedora Core 6 / RHEL 5 + +* Wed Jan 24 2007 Jean-Marc Liger 0.1.0-1 +- First 0.1.0 +- Built on Fedora Core 3 / RHEL 4 and Fedora Core 6 / RHEL 5 diff --git a/larpe/tags/release-1.1.1/larpe-reload-apache2.c b/larpe/tags/release-1.1.1/larpe-reload-apache2.c new file mode 100644 index 0000000..73f681a --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe-reload-apache2.c @@ -0,0 +1,173 @@ +/* + Template for a setuid program that calls a script. + + The script should be in an unwritable directory and should itself + be unwritable. In fact all parent directories up to the root + should be unwritable. The script must not be setuid, that's what + this program is for. + + This is a template program. You need to fill in the name of the + script that must be executed. This is done by changing the + definition of FULL_PATH below. + + There are also some rules that should be adhered to when writing + the script itself. + + The first and most important rule is to never, ever trust that the + user of the program will behave properly. Program defensively. + Check your arguments for reasonableness. If the user is allowed to + create files, check the names of the files. If the program depends + on argv[0] for the action it should perform, check it. + + Assuming the script is a Bourne shell script, the first line of the + script should be + #!/bin/sh - + The - is important, don't omit it. If you're using esh, the first + line should be + #!/usr/local/bin/esh -f + and for ksh, the first line should be + #!/usr/local/bin/ksh -p + The script should then set the variable IFS to the string + consisting of , , and . After this (*not* + before!), the PATH variable should be set to a reasonable value and + exported. Do not expect the PATH to have a reasonable value, so do + not trust the old value of PATH. You should then set the umask of + the program by calling + umask 077 # or 022 if you want the files to be readable + If you plan to change directories, you should either unset CDPATH + or set it to a good value. Setting CDPATH to just ``.'' (dot) is a + good idea. + If, for some reason, you want to use csh, the first line should be + #!/bin/csh -fb + You should then set the path variable to something reasonable, + without trusting the inherited path. Here too, you should set the + umask using the command + umask 077 # or 022 if you want the files to be readable +*/ + +#include +#include +#include +#include +#include +#include + +/* CONFIGURATION SECTION */ + +#ifndef FULL_PATH/* so that this can be specified from the Makefile */ + #define FULL_PATH "/usr/sbin/larpe-reload-apache2-script" +#endif +#ifndef UMASK + #define UMASK 077 +#endif + +/* END OF CONFIGURATION SECTION */ + +#if defined(__STDC__) && defined(__sgi) +#define environ _environ +#endif + +/* don't change def_IFS */ +char def_IFS[] = "IFS= \t\n"; +/* you may want to change def_PATH, but you should really change it in */ +/* your script */ +#ifdef __sgi +char def_PATH[] = "PATH=/usr/bsd:/usr/bin:/bin:/usr/local/bin:/usr/sbin"; +#else +char def_PATH[] = "PATH=/usr/ucb:/usr/bin:/bin:/usr/local/bin"; +#endif +/* don't change def_CDPATH */ +char def_CDPATH[] = "CDPATH=."; +/* don't change def_ENV */ +char def_ENV[] = "ENV=:"; + +/* + This function changes all environment variables that start with LD_ + into variables that start with XD_. This is important since we + don't want the script that is executed to use any funny shared + libraries. + + The other changes to the environment are, strictly speaking, not + needed here. They can safely be done in the script. They are done + here because we don't trust the script writer (just like the script + writer shouldn't trust the user of the script). + If IFS is set in the environment, set it to space,tab,newline. + If CDPATH is set in the environment, set it to ``.''. + Set PATH to a reasonable default. +*/ +void +clean_environ(void) +{ + char **p; + extern char **environ; + + for (p = environ; *p; p++) { + if (strncmp(*p, "LD_", 3) == 0) + **p = 'X'; + else if (strncmp(*p, "_RLD", 4) == 0) + **p = 'X'; + else if (strncmp(*p, "PYTHON", 6) == 0) + **p = 'X'; + else if (strncmp(*p, "IFS=", 4) == 0) + *p = def_IFS; + else if (strncmp(*p, "CDPATH=", 7) == 0) + *p = def_CDPATH; + else if (strncmp(*p, "ENV=", 4) == 0) + *p = def_ENV; + } + putenv(def_PATH); +} + +int +main(int argc, char **argv) +{ + struct stat statb; + gid_t egid = getegid(); + uid_t euid = geteuid(); + + /* + Sanity check #1. + This check should be made compile-time, but that's not possible. + If you're sure that you specified a full path name for FULL_PATH, + you can omit this check. + */ + if (FULL_PATH[0] != '/') { + fprintf(stderr, "%s: %s is not a full path name\n", argv[0], + FULL_PATH); + fprintf(stderr, "You can only use this wrapper if you\n"); + fprintf(stderr, "compile it with an absolute path.\n"); + exit(1); + } + + /* + Sanity check #2. + Check that the owner of the script is equal to either the + effective uid or the super user. + */ + if (stat(FULL_PATH, &statb) < 0) { + perror("stat"); + exit(1); + } + if (statb.st_uid != 0 && statb.st_uid != euid) { + fprintf(stderr, "%s: %s has the wrong owner\n", argv[0], + FULL_PATH); + fprintf(stderr, "The script should be owned by root,\n"); + fprintf(stderr, "and shouldn't be writeable by anyone.\n"); + exit(1); + } + + if (setregid(egid, egid) < 0) + perror("setregid"); + if (setreuid(euid, euid) < 0) + perror("setreuid"); + + clean_environ(); + + umask(UMASK); + + while (**argv == '-')/* don't let argv[0] start with '-' */ + (*argv)++; + execv(FULL_PATH, argv); + fprintf(stderr, "%s: could not execute the script\n", argv[0]); + exit(1); +} diff --git a/larpe/tags/release-1.1.1/larpe/Defaults.py b/larpe/tags/release-1.1.1/larpe/Defaults.py new file mode 100644 index 0000000..ca723a0 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/Defaults.py @@ -0,0 +1,9 @@ +'''Default global variables''' + +APP_DIR = '/var/lib/larpe' +DATA_DIR = '/usr/share/larpe' +ERROR_LOG = None #'/var/log/larpe.log' +WEB_ROOT = 'larpe' +APACHE_MAIN_VHOST = '/etc/apache2/sites-available/apache2-vhost-larpe' +APACHE_VHOST_COMMON = '/etc/larpe/apache2-vhost-larpe-common' +APACHE_RELOAD = '/usr/sbin/larpe-reload-apache2' diff --git a/larpe/tags/release-1.1.1/larpe/__init__.py b/larpe/tags/release-1.1.1/larpe/__init__.py new file mode 100644 index 0000000..ee83c50 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/__init__.py @@ -0,0 +1,21 @@ +'''Setup path and load Lasso library''' +try: + from quixote.ptl import compile_package + compile_package(__path__) +except ImportError: + pass + +import sys +import os +sys.path.insert(0, os.path.dirname(__file__)) + +import qommon + +try: + import lasso +except ImportError: + lasso = None + +if lasso and not hasattr(lasso, 'SAML2_SUPPORT'): + lasso.SAML2_SUPPORT = False + diff --git a/larpe/tags/release-1.1.1/larpe/admin/__init__.py b/larpe/tags/release-1.1.1/larpe/admin/__init__.py new file mode 100644 index 0000000..d6622e6 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/admin/__init__.py @@ -0,0 +1,6 @@ +try: + from quixote.ptl import compile_package + compile_package(__path__) +except ImportError: + pass +from root import RootDirectory diff --git a/larpe/tags/release-1.1.1/larpe/admin/apache.py b/larpe/tags/release-1.1.1/larpe/admin/apache.py new file mode 100644 index 0000000..cb01760 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/admin/apache.py @@ -0,0 +1,300 @@ +import os +import re +import urllib +import base64 + +from quixote import get_publisher, get_request + +from qommon import get_cfg + +from larpe.hosts import Host +from larpe.Defaults import APP_DIR, APACHE_MAIN_VHOST, APACHE_VHOST_COMMON, APACHE_RELOAD + +def write_apache2_vhosts(): + hosts = Host.select(lambda x: x.name != 'larpe') + hosts.sort() + vhosts_dir = os.path.join(APP_DIR, 'vhosts.d') + vhost_locations_dir = os.path.join(APP_DIR, 'vhost-locations.d') + vhosts_dir_disabled = os.path.join(APP_DIR, 'vhosts.d.disabled') + vhost_locations_dir_disabled = os.path.join(APP_DIR, 'vhost-locations.d.disabled') + vhost_file_name = get_request().get_server().split(':')[0] + vhost_file = None + reversed_hostname = '' + vhost = None + + if get_publisher().cfg.get(str('allow_config_generation'), True): + vhost_file = open(os.path.join(vhosts_dir, vhost_file_name), 'w') + locations_file = open(os.path.join(vhost_locations_dir, vhost_file_name), 'w') + else: + vhost_file = open(os.path.join(vhosts_dir_disabled, vhost_file_name), 'w') + locations_file = open(os.path.join(vhost_locations_dir_disabled, vhost_file_name), 'w') + try: + main_vhost = open(APACHE_MAIN_VHOST, 'r') + file_content = main_vhost.read() + regexp = re.compile('') + vhost_ip = regexp.findall(file_content)[0] + except (IOError, IndexError): + vhost_ip = '*' + + for host in hosts: + if host.orig_site is None: + # This site hasn't been fully configured + continue + if host.reversed_hostname != reversed_hostname \ + and host.reversed_hostname != get_cfg('proxy_hostname'): + if vhost is not None: + vhost.close() + vhost = Vhost(host, vhost_ip) + vhost.write(vhost_file) + reversed_hostname = host.reversed_hostname + + if host.reversed_hostname == get_cfg('proxy_hostname'): + conf_file = locations_file + else: + conf_file = vhost_file + + Location(host).write(conf_file) + + if vhost_file is not None: + if vhost is not None: + vhost.close() + vhost_file.close() + if locations_file is not None: + locations_file.close() + + if get_publisher().cfg.get(str('allow_config_generation'), True): + os.system(APACHE_RELOAD) + + +class Vhost(object): + def __init__(self, host, main_ip_port): + self.host = host + self.main_ip_port = main_ip_port + self.conf_file = None + + def get_ip_port(self): + if self.host.scheme == 'https': + return self.main_ip_port.replace(':80', ':443') + else: + return self.main_ip_port.replace(':443', ':80') + ip_port = property(get_ip_port) + + def get_proxy_url(self): + if get_cfg('proxy', {}).get('enabled') and self.host.use_proxy == True: + return 'http://%(ip)s:%(port)s' % get_cfg('proxy', {}) + return None + proxy_url = property(get_proxy_url) + + def get_proxy_auth(self): + if self.get_proxy_url() and get_cfg('proxy', {}).get('user'): + credentials = base64.encodestring( + '%(user)s:%(password)s' % get_cfg('proxy', {}))[:-1] + return '"Basic %s"' % credentials + return None + proxy_auth = property(get_proxy_auth) + + def get_cfg(self): + return { 'ip_port': self.ip_port, + 'reversed_hostname': self.host.reversed_hostname, + 'proxy_url': self.proxy_url, + 'proxy_auth': self.proxy_auth } + cfg = property(get_cfg) + + def write(self, conf_file): + self.conf_file = conf_file + conf_lines = [] + # Start Virtual Host + conf_lines.append('' % self.cfg) + # Server name and administrator + conf_lines.append('ServerName %(reversed_hostname)s' % self.cfg) + conf_lines.append('# ServerAdmin root@localhost\n') + # Include common vhost configuration + conf_lines.append('include %s\n' % APACHE_VHOST_COMMON) + # SSL + if self.host.scheme == 'https': + conf_lines.append('SSLEngine On\n') + if self.host.orig_site.startswith('https'): + conf_lines.append('SSLProxyEngine On\n') + # Remote proxy configuration + if self.proxy_url is not None: + conf_lines.append('ProxyRemote * %(proxy_url)s' % self.cfg) + if self.proxy_auth is not None: + conf_lines.append( + 'RequestHeader set Proxy-Authorization %(proxy_auth)s\n' % self.cfg) + # Write it all + conf_file.write('\n\t'.join(conf_lines)) + + def close(self): + if self.conf_file: + self.conf_file.write('\n\n') + + +def apache_escape_chars(url): + special_characters = ('\\', '.', '?', '*', '+', '^', '$', '|', '(', ')', '[', ']') + for char in special_characters: + url = url.replace(char, '\%s' % char) + return url + +class Location(object): + def __init__(self, host): + self.host = host + + def get_reversed_directory(self): + if not self.host.reversed_directory: + return '%s/' % get_request().environ['SCRIPT_NAME'] + else: + return '%s/%s/' % (get_request().environ['SCRIPT_NAME'], self.host.reversed_directory) + reversed_directory = property(get_reversed_directory) + + def get_python_path(self): + if self.host.apache_output_python_filters and \ + self.host.apache_python_paths: + python_path = 'PythonPath "sys.path' + for path in self.host.apache_python_paths: + python_path += "+['%s']" % path + python_path += '"' + return python_path + else: + return None + python_path = property(get_python_path) + + def get_output_filters(self): + python_filters = '' + output_filters = [] + if self.host.apache_output_python_filters: + i = 0 + for filter_file in self.host.apache_output_python_filters: + filter_name = 'filter%d' % i + python_filters += 'PythonOutputFilter %s %s\n\t\t' % (filter_file, filter_name) + output_filters.append(filter_name) + i += 1 + if self.host.apache_output_filters: + for output_filter in self.host.apache_output_filters: + output_filters.append(output_filter) + if output_filters: + return python_filters + 'SetOutputFilter ' + ';'.join(output_filters) + else: + return None + output_filters = property(get_output_filters) + + def get_old_auth_url(self): + old_auth_url = None + if self.host.initiate_sso_url: + old_auth_url = self.host.initiate_sso_url + elif self.host.auth_url is not None: + if self.host.auth_url.startswith('http://'): + chars_to_skip = 5 + else: + chars_to_skip = 6 + regexp = re.compile(self.host.orig_site[chars_to_skip:]) + old_auth_url_short = regexp.sub('', self.host.auth_url[chars_to_skip:]) + if old_auth_url_short.startswith('/'): + old_auth_url = old_auth_url_short + else: + old_auth_url = '/' + old_auth_url_short + if old_auth_url: + old_auth_url = apache_escape_chars(old_auth_url) + return old_auth_url + old_auth_url = property(get_old_auth_url) + + def get_new_auth_url(self): + if not hasattr(self.host, 'base_url'): + return None + base_url_tokens = self.host.base_url.split('/') + base_url_tokens[-1] = 'login' + return '/'.join(base_url_tokens) + new_auth_url = property(get_new_auth_url) + + def get_old_logout_url(self): + old_logout_url = None + if self.host.logout_url is not None: + if self.host.logout_url.startswith('http://'): + chars_to_skip = 5 + else: + chars_to_skip = 6 + regexp = re.compile(self.host.orig_site[chars_to_skip:]) + old_logout_url_short = regexp.sub('', self.host.logout_url[chars_to_skip:]) + if old_logout_url_short.startswith('/'): + old_logout_url = old_logout_url_short + else: + old_logout_url = '/' + old_logout_url_short + old_logout_url = apache_escape_chars(old_logout_url) + return old_logout_url + old_logout_url = property(get_old_logout_url) + + def get_new_logout_url(self): + if not hasattr(self.host, 'base_url'): + return None + base_url_tokens = self.host.base_url.split('/') + base_url_tokens[-1] = 'logout' + return '/'.join(base_url_tokens) + new_logout_url = property(get_new_logout_url) + + def get_orig_site_url_and_dir(self): + # Split url + if self.host.orig_site.startswith('http://'): + orig_host, orig_query = urllib.splithost(self.host.orig_site[5:]) + else: + orig_host, orig_query = urllib.splithost(self.host.orig_site[6:]) + # Add a trailing slash if necessary + if self.host.orig_site.endswith('/'): + orig_url = self.host.orig_site + orig_dir = orig_query + else: + orig_url = self.host.orig_site + '/' + orig_dir = orig_query + '/' + return orig_url, orig_dir + + def get_orig_url(self): + orig_url, orig_dir = self.get_orig_site_url_and_dir() + return orig_url + orig_url = property(get_orig_url) + + def get_orig_dir(self): + orig_url, orig_dir = self.get_orig_site_url_and_dir() + return orig_dir + orig_dir = property(get_orig_dir) + + def get_cfg(self): + return { 'reversed_directory': self.reversed_directory, + 'old_auth_url': self.old_auth_url, + 'new_auth_url': self.new_auth_url, + 'old_logout_url': self.old_logout_url, + 'new_logout_url': self.new_logout_url, + 'orig_url': self.orig_url, + 'orig_dir': self.orig_dir } + cfg = property(get_cfg) + + def write(self, conf_file): + conf_lines = [] + # Start Location + conf_lines.append('\n\t' % self.cfg) + # No user restriction + conf_lines.append('Allow from all') + # Apache output filters + if self.python_path: + conf_lines.append(self.python_path) + if self.output_filters: + conf_lines.append(self.output_filters) + # Redirect rules + # Redirect old authentication url to the new one + if self.old_auth_url is not None and self.host.auth_form_places == 'form_once': + conf_lines.append( + 'RedirectMatch %(old_auth_url)s %(new_auth_url)s' % self.cfg) + # Redirect old logout url to the new one + if self.old_logout_url is not None: + conf_lines.append( + 'RedirectMatch %(old_logout_url)s %(new_logout_url)s' % self.cfg) + # Redirect the home page to the login page + if self.host.redirect_root_to_login is True: + conf_lines.append('RedirectMatch ^/$ %(new_auth_url)s' % self.cfg) + # Convert urls in http headers to/from the new domain + conf_lines.append('ProxyPass %(orig_url)s' % self.cfg) + conf_lines.append('ProxyPassReverse %(orig_url)s' % self.cfg) + # Convert urls in html pages to/from the new domain + conf_lines.append('ProxyHTMLURLMap %(orig_dir)s %(reversed_directory)s' % self.cfg) + conf_lines.append('ProxyHTMLURLMap %(orig_url)s %(reversed_directory)s' % self.cfg) + # Write it all and close the Location + conf_file.write('\n\t\t'.join(conf_lines)) + conf_file.write('\n\t\n') + diff --git a/larpe/tags/release-1.1.1/larpe/admin/fields_prefill.ptl b/larpe/tags/release-1.1.1/larpe/admin/fields_prefill.ptl new file mode 100644 index 0000000..c927388 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/admin/fields_prefill.ptl @@ -0,0 +1,130 @@ +from quixote import get_response, redirect +from quixote.directory import Directory + +from qommon.form import * +from qommon.admin.menu import html_top, command_icon + +from field_prefill import FieldPrefill + +class FieldUI: + def __init__(self, field_prefill): + self.field_prefill = field_prefill + + def form_edit(self): + form = Form(enctype='multipart/form-data') + form.add(StringWidget, 'name', title = _('Field name'), required = True, + size = 50, value = self.field_prefill.name) + form.add(StringWidget, 'xpath', title = _('Xpath of the attribute'), required = True, + size = 50, value = self.field_prefill.xpath, hint=_('Example: /pp:PP/pp:InformalName')) + form.add(IntWidget, 'number', title = _('Number of the field in the data'), required = True, + size = 3, value = self.field_prefill.number, + hint=_('Change it if there are multiple fields corresponding to the same Xpath and you want to get another than the first one')) + form.add(CheckboxWidget, 'raw_xml', title=_('Get raw XML value'), + value = self.field_prefill.raw_xml) + form.add(StringWidget, 'regexp_match', title = _('Python regexp of a string to match'), + size = 50, value = self.field_prefill.regexp_match) + form.add(StringWidget, 'regexp_replacing', title = _('Python regexp of the replacing string'), + size = 50, value = self.field_prefill.regexp_replacing) + form.add(WidgetDict, 'select_options', title = _('Options mapping for a select field'), + value = self.field_prefill.select_options, add_element_label = _('Add item')) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + return form + + def submit_edit(self, form): + for f in ('name', 'xpath', 'number', 'raw_xml', 'regexp_match', 'regexp_replacing', 'select_options'): + widget = form.get_widget(f) + setattr(self.field_prefill, f, widget.parse()) + self.field_prefill.store() + +class FieldPage(Directory): + _q_exports = ['', 'delete'] + + def __init__(self, field_id): + self.field_prefill = FieldPrefill.get(field_id) + self.field_ui = FieldUI(self.field_prefill) + get_response().breadcrumb.append((field_id + '/', field_id)) + + def _q_index [html] (self): + form = self.field_ui.form_edit() + redo = False + + if form.get_widget('cancel').parse(): + return redirect('..') + + if form.get_widget('select_options') and form.get_widget('select_options').get_widget('add_element').parse(): + form.clear_errors() + redo = True + + if redo is False and form.is_submitted() and not form.has_errors(): + self.field_ui.submit_edit(form) + return redirect('..') + + get_response().breadcrumb.append( ('edit', _('Edit')) ) + html_top('edit', title = _('Edit')) + '

%s

' % _('Edit') + + form.render() + + def delete [html] (self): + form = Form(enctype='multipart/form-data') + form.widgets.append(HtmlWidget('

%s

' % _( + 'You are about to irrevocably delete this field.'))) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + if form.get_widget('cancel').parse(): + return redirect('..') + if not form.is_submitted() or form.has_errors(): + get_response().breadcrumb.append(('delete', _('Delete'))) + html_top('delete_form', title = _('Delete Field')) + '

%s : %s

' % (_('Delete Field'), self.field_prefill.id) + form.render() + else: + self.field_prefill.remove_self() + return redirect('..') + + +class FieldsDirectory(Directory): + _q_exports = ['', 'new'] + + def __init__(self, form_prefill): + get_response().breadcrumb.append(('fields/', _('Fields'))) + self.form_prefill = form_prefill + + def _q_lookup(self, component): + return FieldPage(component) + + def _q_index [html] (self): + html_top('fields', title = _('Fields')) + """""" % _('New Field') + + '
    ' + + for field_prefill in FieldPrefill.select(lambda x: x.form_id == self.form_prefill.id): + if not field_prefill.name: + continue + + # Split too long xpath + xpath = field_prefill.xpath + xpath_tokens = xpath.split(str('/')) + if len(xpath_tokens) > 3: + xpath = str('.../') + str('/').join(xpath_tokens[-3:]) + + '
  • ' + '%s' % field_prefill.name + '
    %s' % xpath + '

    ' + command_icon('%s/' % field_prefill.id, 'edit') + command_icon('%s/delete' % field_prefill.id, 'remove') + '

  • ' + '
' + + def new [html] (self): + get_response().breadcrumb.append(('new', _('New')) ) + field_prefill = FieldPrefill() + field_prefill.form_id = self.form_prefill.id + field_prefill.store() + return redirect('%s/' % field_prefill.id) + diff --git a/larpe/tags/release-1.1.1/larpe/admin/forms_prefill.ptl b/larpe/tags/release-1.1.1/larpe/admin/forms_prefill.ptl new file mode 100644 index 0000000..0f34eff --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/admin/forms_prefill.ptl @@ -0,0 +1,127 @@ +from quixote import get_response, redirect +from quixote.directory import Directory + +from qommon.form import * +from qommon.admin.menu import html_top, command_icon + +from form_prefill import FormPrefill +from fields_prefill import FieldsDirectory + +class FormUI: + def __init__(self, form_prefill): + self.form_prefill = form_prefill + + def form_edit(self): + form = Form(enctype='multipart/form-data') + form.add(StringWidget, 'name', title = _('Form name'), required = True, + size = 50, value = self.form_prefill.name, hint=_('Only used for display')) + form.add(UrlWidget, 'url', title = _('Form address'), required = True, + size = 50, value = self.form_prefill.url) + form.add(StringWidget, 'profile', title = _('ID-WSF data profile'), required = True, + size = 50, value = self.form_prefill.profile, hint=_('Example: urn:liberty:id-sis-pp:2005-05')) + form.add(StringWidget, 'prefix', title = _('ID-WSF data XML prefix'), required = True, + size = 50, value = self.form_prefill.prefix, hint=_('Example: pp')) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + return form + + def submit_edit(self, form): + for f in ('name', 'url', 'profile', 'prefix'): + widget = form.get_widget(f) + setattr(self.form_prefill, f, widget.parse()) + self.form_prefill.store() + +class FormPage(Directory): + _q_exports = ['', 'edit', 'delete'] + + def __init__(self, form_id): + self.form_prefill = FormPrefill.get(form_id) + self.form_ui = FormUI(self.form_prefill) + get_response().breadcrumb.append((form_id + '/', form_id)) + + def _q_index [html] (self): + html_top('forms_prefill', title = 'Form prefilling') + + '

%s

' % _('Form prefilling configuration') + '
' + '
%s
%s
' % ( + _('Edit'), _('Configure this form')) + '
%s
%s
' % ( + _('Fields'), _('Configure the fields of this form')) + '
' + + def _q_lookup(self, component): + if component == 'fields': + return FieldsDirectory(self.form_prefill) + + def edit [html] (self): + form = self.form_ui.form_edit() + if form.get_widget('cancel').parse(): + return redirect('.') + + if form.is_submitted() and not form.has_errors(): + self.form_ui.submit_edit(form) + return redirect('.') + + get_response().breadcrumb.append( ('edit', _('Edit')) ) + html_top('edit', title = _('Edit')) + '

%s

' % _('Edit') + + form.render() + + def delete [html] (self): + form = Form(enctype='multipart/form-data') + form.widgets.append(HtmlWidget('

%s

' % _( + 'You are about to irrevocably delete this form.'))) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + if form.get_widget('cancel').parse(): + return redirect('..') + if not form.is_submitted() or form.has_errors(): + get_response().breadcrumb.append(('delete', _('Delete'))) + html_top('delete_form', title = _('Delete Form')) + '

%s : %s

' % (_('Delete Form'), self.form_prefill.id) + form.render() + else: + self.form_prefill.remove_self() + return redirect('..') + + +class FormsDirectory(Directory): + _q_exports = ['', 'new'] + + def __init__(self, host): + get_response().breadcrumb.append(('forms_prefill/', _('Forms'))) + self.host = host + + def _q_lookup(self, component): + return FormPage(component) + + def _q_index [html] (self): + html_top('forms', title = _('Forms')) + """""" % _('New Form') + + '
    ' + + for form_prefill in FormPrefill.select(lambda x: x.host_id == self.host.id): + if not form_prefill.name: + continue + '
  • ' + '%s' % form_prefill.name + url = form_prefill.url + '
    %s' % (url, url) + '

    ' + command_icon('%s/' % form_prefill.id, 'edit') + command_icon('%s/delete' % form_prefill.id, 'remove') + '

  • ' + '
' + + def new [html] (self): + get_response().breadcrumb.append(('new', _('New')) ) + form_prefill = FormPrefill() + form_prefill.host_id = self.host.id + form_prefill.store() + return redirect('%s/edit' % form_prefill.id) + diff --git a/larpe/tags/release-1.1.1/larpe/admin/hosts.ptl b/larpe/tags/release-1.1.1/larpe/admin/hosts.ptl new file mode 100644 index 0000000..db38874 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/admin/hosts.ptl @@ -0,0 +1,1352 @@ +import os +import urllib +import urlparse + +from quixote import redirect, get_request, get_response, get_publisher +from quixote.directory import Directory + +import lasso + +from qommon.admin.menu import html_top, command_icon +from qommon import get_cfg +from qommon.form import * +from qommon.misc import http_get_page, get_abs_path + +from larpe import site_authentication +from larpe import errors +from larpe import misc +from larpe.hosts import Host +from larpe.admin.apache import Location +from larpe.admin.liberty_utils import * +from larpe.admin.apache import write_apache2_vhosts +from larpe.admin.forms_prefill import FormsDirectory +from larpe.Defaults import DATA_DIR +from larpe.plugins import site_authentication_plugins + +def check_basic_configuration(form): + get_publisher().reload_cfg() + # Check reversed_hostname and reversed_directory + reversed_hostname = form.get_widget('reversed_hostname').parse() + reversed_directory = form.get_widget('reversed_directory').parse() + if reversed_hostname == get_publisher().cfg['proxy_hostname'] and not reversed_directory: + form.set_error('reversed_hostname', + _('You must either choose a different hostname from Larpe or specify a reversed directory')) + +def convert_label_to_name(label): + '''Build host name from host label''' + name = label.lower() + invalid_characters = [' ', "'"] + for char in invalid_characters: + name = name.replace(char, '_') + return name + +class DictWidget(Widget): + def render_content [html] (self): + self.render_br = False + if self.value['enabled'] is True: + htmltag('input', xml_end=True, type='checkbox', name=self.name + '_enabled', checked='checked') + else: + htmltag('input', xml_end=True, type='checkbox', name=self.name + '_enabled') + ' ' + self.name + '  ' + htmltag('input', xml_end=True, type='text', name=self.name, value=self.value['value'], size='35', **self.attrs) + + def _parse(self, request): + enabled = request.form.get(self.name + '_enabled') + value = request.form.get(self.name) + self.value = { 'enabled': enabled, 'value': value } + + +class ConfigurationAssistant(Directory): + _q_exports = ['start', 'check_new_address', 'modify_site_address_and_name', + 'authentication_and_logout_adresses', 'check_auto_detected_configuration', + 'credentials', 'send_authentication_request', 'check_authentication', + 'see_authentication_response', 'see_response_html_page', + 'see_bad_response_html_page', 'authentication_success_criteria', + 'modify_authentication_request', 'auth_request_post_parameters', + 'auth_request_http_headers', 'sso_init_link', 'metadatas', + 'check_full_configuration', 'advanced_options'] + + def __init__(self, host): + self.host = host + + def html_top [html] (self, title): + html_top('hosts', title) + '

%s

' % title + + def start [html] (self): + # Check the global domain name has been previously set + get_publisher().reload_cfg() + if not get_cfg('domain_names') or not get_cfg('domain_names')[0]: + get_response().breadcrumb.append(('start', _('Basic configuration'))) + self.html_top(_('Need domain name configuration')) + return htmltext(_('''Before configuring hosts, you must +setup a global domain name in +%(settings)s menu.''') % { 'settings': _('Settings') }) + + form = self.form_start() + + if form.get_widget('cancel').parse(): + return redirect('../..') + + connection_failure = None + if form.is_submitted() and not form.has_errors(): + try: + self.submit_start_form(form) + except Exception, e: + connection_failure = e + else: + if form.get_widget('terminate').parse(): + return redirect('..') + return redirect('check_new_address') + + get_response().breadcrumb.append(('start', _('Basic configuration'))) + self.html_top(_('Step 1 - Basic configuration')) + + if connection_failure: + '
%s
' % connection_failure + + form.render() + + def form_start(self): + form = Form(enctype='multipart/form-data') + form.add(UrlWidget, 'orig_site', title = _('Original site root address'), required = True, + size = 50, value = self.host.orig_site, + hint = _('If your site address is http://test.org/index.php, put http://test.org/ here')) + get_publisher().reload_cfg() + if get_cfg('proxy', {}).get('enabled'): + form.add(CheckboxWidget, 'use_proxy', title = _('Use a proxy'), + hint = _("Uncheck it if Larpe doesn't need to use the proxy to connect to this site"), + value = self.host.use_proxy) + else: + form.add(HtmlWidget, htmltext('

%s

' % \ + _('''If Larpe needs to use a proxy to connect to this site, you must first configure + it in global proxy parameters.'''))) + form.add_submit('cancel', _('Cancel')) + form.add_submit('submit', _('Next')) + form.add_submit('terminate', _('Terminate')) + return form + + def submit_start_form(self, form): + fields = ['orig_site'] + use_proxy = get_cfg('proxy', {}).get('enabled') + if use_proxy: + fields += ['use_proxy'] + for f in fields: + setattr(self.host, f, form.get_widget(f).parse()) + + # If no proxy is setup yet, set use_proxy to False for new hosts in case a proxy is later configured + if not use_proxy: + self.host.use_proxy = False + + # Remove what is after the last '/' + #self.host.orig_site = '/'.join(self.host.orig_site.split('/')[:-1]) + + html_page = self.get_data_after_redirects(self.host.orig_site) + + if not self.host.label: + # Look for html title in original site index page + regexp = re.compile("""(.*?)""", re.DOTALL | re.IGNORECASE) + title = regexp.findall(html_page) + if title: + self.host.label = title[0] + else: + self.host.label = 'Untitled' + # If another site already uses this site title, add trailings "_" until we find an available name + existing_label = True + while existing_label is True: + for any_host in Host.select(): + if any_host.id != self.host.id and self.host.label == any_host.label: + self.host.label += '_' + break + else: + existing_label = False + + # Fill host.name attribute + self.host.name = convert_label_to_name(self.host.label) + + if not self.host.scheme: + # Get tokens from orig site url + orig_scheme, rest = urllib.splittype(self.host.orig_site) + orig_host, rest = urllib.splithost(rest) + + get_publisher().reload_cfg() + # Set url scheme (HTTP or HTTPS) + # TODO: Handle the option "Both" + if get_cfg('sites_url_scheme'): + self.host.scheme = get_cfg('sites_url_scheme') + else: + self.host.scheme = orig_scheme + + if not self.host.reversed_hostname: + # Build a new domain name + short_name = orig_host.split('.')[0] + if short_name == 'www': + short_name = orig_host.split('.')[1] + self.host.reversed_hostname = '%s.%s' % (short_name, get_cfg('domain_names')[0]) + # If another site already uses this domain name, add some trailing "_" until we find an available name + existing_domain = True + while existing_domain is True: + for any_host in Host.select(): + if any_host.id != self.host.id and self.host.reversed_hostname == any_host.reversed_hostname: + self.host.reversed_hostname += '-' + break + else: + existing_domain = False + self.host.reversed_directory = None + + if not self.host.new_url: + # New url for this host + self.host.new_url = '%s://%s%s/' % (self.host.scheme, self.host.reversed_hostname, get_request().environ['SCRIPT_NAME']) + # FIXME: Check if the new domain name already exists + + # New url for this host + # self.host.new_url = '%s://%s%s/' % (self.host.scheme, self.host.reversed_hostname, get_request().environ['SCRIPT_NAME']) + # if self.host.reversed_directory is not None: + # self.host.new_url += '%s/' % self.host.reversed_directory + + self.host.store() + write_apache2_vhosts() + + # XXX: Should use the FancyURLopener class instead when it supports proxies + def get_data_after_redirects(self, start_url): + if not start_url: + return '' + status = 302 + location = None + while status // 100 == 3: + if location is None: + url = start_url + elif location.startswith('http'): + # Location is an absolute path + url = location + else: + # Location is a relative path + url = urlparse.urljoin(start_url, location) + response, status, data, auth_headers = http_get_page(url, use_proxy=self.host.use_proxy) + location = response.getheader('Location', None) + return data + + def create_dirs(self): + # Hack : sites must use the configuration which is stored in main Larpe directory, + # but they need to have a directory named with their hostname, which will contain the + # main domain name for Larpe so they know where is the main configuration + hostname_dir = get_abs_path(os.path.join('..', self.host.reversed_hostname)) + if not os.path.exists(hostname_dir): + os.mkdir(hostname_dir) + # Load the configuration from the main directory + get_publisher().reload_cfg() + # Write it in the site directory + get_publisher().write_cfg(hostname_dir) + + # Storage directories + if not self.host.reversed_directory: + reversed_dir = 'default' + else: + reversed_dir = self.host.reversed_directory + self.host.site_dir = \ + os.path.join(get_publisher().app_dir, 'sp', self.host.reversed_hostname, reversed_dir) + user_dir = os.path.join(self.host.site_dir, 'users') + token_dir = os.path.join(self.host.site_dir, 'tokens') + filter_dir = os.path.join(self.host.site_dir, 'filters') + for dir in (self.host.site_dir, user_dir, token_dir, filter_dir): + if not os.path.isdir(dir): + os.makedirs(dir) + + def generate_ssl_keys(self): + # Generate SSL keys + private_key_path = os.path.join(self.host.site_dir, 'private_key.pem') + public_key_path = os.path.join(self.host.site_dir, 'public_key.pem') + if not os.path.isfile(private_key_path) or not os.path.isfile(public_key_path): + set_provider_keys(private_key_path, public_key_path) + self.host.private_key = private_key_path + self.host.public_key = public_key_path + + def generate_metadatas(self): + metadata_cfg = {} + + # Organization name + self.host.organization_name = self.host.label + metadata_cfg['organization_name'] = self.host.organization_name + + # Base URL + base_url = '%s://%s%s/liberty/%s/liberty' % (self.host.scheme, + self.host.reversed_hostname, + get_request().environ['SCRIPT_NAME'], + self.host.name) + metadata_cfg['base_url'] = base_url + self.host.base_url = base_url + + if lasso.SAML2_SUPPORT: + saml2_base_url = '%s://%s%s/liberty/%s/saml' % (self.host.scheme, + self.host.reversed_hostname, + get_request().environ['SCRIPT_NAME'], + self.host.name) + metadata_cfg['saml2_base_url'] = saml2_base_url + self.host.saml2_base_url = saml2_base_url + + # Provider Id + provider_id = '%s/metadata' % base_url + metadata_cfg['provider_id'] = provider_id + self.host.provider_id = provider_id + + if lasso.SAML2_SUPPORT: + saml2_provider_id = '%s/metadata' % saml2_base_url + metadata_cfg['saml2_provider_id'] = saml2_provider_id + self.host.saml2_provider_id = saml2_provider_id + + # Read public key + public_key = '' + if self.host.public_key is not None and os.path.exists(self.host.public_key): + metadata_cfg['signing_public_key'] = open(self.host.public_key).read() + + # Write metadatas + metadata_path = os.path.join(self.host.site_dir, 'metadata.xml') + open(metadata_path, 'w').write(get_metadata(metadata_cfg)) + self.host.metadata = metadata_path + + if lasso.SAML2_SUPPORT: + saml2_metadata_path = os.path.join(self.host.site_dir, 'saml2_metadata.xml') + open(saml2_metadata_path, 'w').write(get_saml2_metadata(metadata_cfg)) + self.host.saml2_metadata = saml2_metadata_path + + def check_new_address [html] (self): + form = Form(enctype='multipart/form-data') + form.add_submit('cancel', _('Previous')) + form.add_submit('submit', _('Next')) + form.add_submit('terminate', _('Terminate')) + + if form.get_widget('cancel').parse(): + return redirect('start') + + if form.is_submitted(): + self.create_dirs() + if self.host.private_key is None: + self.generate_ssl_keys() + self.generate_metadatas() + self.host.store() + + if form.get_widget('terminate').parse(): + return redirect('..') + return redirect('authentication_and_logout_adresses') + + get_response().breadcrumb.append(('check_new_address', _('Check site address and name'))) + self.html_top(_('Step 2 - Check the new site address works')) + + '

%s

' % _('DNS configuration') + + '

%s

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

%s

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

%s

' % _('Site adress and name') + + '

%s' % _('The new address of this site is ') + '%s
' % (self.host.new_url, self.host.new_url) + '%s

' % _('The name of this site is "%s".') % self.host.label + '

%s

' % htmltext(_('''You can also +modify the address or the name of this site''')) + + form.render() + + def modify_site_address_and_name [html] (self): + form = self.form_modify_site_address_and_name() + + if form.get_widget('cancel').parse(): + return redirect('check_new_address') + + if form.is_submitted() and not form.has_errors(): + label = form.get_widget('label').parse() + name = convert_label_to_name(label) + for any_host in Host.select(): + if any_host.id != self.host.id and name == any_host.name: + form.set_error('label', _('An host with the same name already exists')) + break + + if form.is_submitted() and not form.has_errors(): + self.submit_modify_site_address_and_name_form(form) + return redirect('check_new_address') + + get_response().breadcrumb.append(('modify_site_address_and_name', _('Modify site address and name'))) + self.html_top(_('Modify site address and name')) + + form.render() + + def form_modify_site_address_and_name(self): + form = Form(enctype='multipart/form-data') + form.add(UrlWidget, 'new_url', title = _('Address'), required = True, + size = 50, value = self.host.new_url) + form.add(StringWidget, 'label', title = _('Name'), required = True, + size = 50, value = self.host.label) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + return form + + def submit_modify_site_address_and_name_form(self, form): + fields = ['new_url', 'label'] + for f in fields: + setattr(self.host, f, form.get_widget(f).parse()) + + # Split url to retrieve components + tokens = urlparse.urlparse(self.host.new_url) + self.host.scheme = tokens[0] + self.host.reversed_hostname = tokens[1] + self.host.reversed_directory = tokens[2] + if self.host.reversed_directory.startswith('/'): + self.host.reversed_directory = self.host.reversed_directory[1:] + + # Fill host.name attribute + self.host.name = convert_label_to_name(self.host.label) + + self.host.store() + write_apache2_vhosts() + + def authentication_and_logout_adresses [html] (self): + form = self.form_authentication_and_logout_adresses() + + if form.get_widget('cancel').parse(): + return redirect('check_new_address') + + if form.is_submitted() and not form.has_errors(): + self.submit_authentication_and_logout_adresses_form(form) + if form.get_widget('terminate').parse(): + return redirect('..') + return redirect('check_auto_detected_configuration') + + get_response().breadcrumb.append(('authentication_and_logout_adresses', _('Authentication and logout'))) + self.html_top(_('Step 3 - Configure authentication and logout pages')) + + form.render() + + def form_authentication_and_logout_adresses(self): + form = Form(enctype='multipart/form-data') + form.add(ValidUrlWidget, 'auth_url', title = _('Authentication form page address'), + hint = _('Address of a page on the site which contains the authentication form'), + required = True, size = 50, value = self.host.auth_url) + form.add(ValidUrlWidget, 'logout_url', title = _('Logout address'), required = False, + hint = _('Address of the logout link on the site'), + size = 50, value = self.host.logout_url) + form.add_submit('cancel', _('Previous')) + form.add_submit('submit', _('Next')) + form.add_submit('terminate', _('Terminate')) + return form + + def submit_authentication_and_logout_adresses_form(self, form): + fields = ['auth_url', 'logout_url'] + for f in fields: + setattr(self.host, f, form.get_widget(f).parse()) + self.host.auth_form_url = self.host.auth_url + + if not self.host.http_headers: + self.host.http_headers = { + 'Content-Type': { 'enabled': True, 'value': 'application/x-www-form-urlencoded', 'immutable': False }, + 'X-Forwarded-For': { 'enabled': True, 'value': _('(computed automatically)'), 'immutable': True }, + 'X-Forwarded-Host': { 'enabled': True, 'value': self.host.reversed_hostname, 'immutable': False }, + } + + self.auto_detect_configuration() + self.host.store() + write_apache2_vhosts() + + def check_auto_detected_configuration [html] (self): + plugins_name = site_authentication_plugins.get_plugins_name() + plugins_name.append(None) + plugins_name.sort() + form = Form(enctype='multipart/form-data') + form.add(SingleSelectWidget, 'plugin', title = _('Plugin'), required = False, + hint = _('You can force a plugin'), + value = self.host.site_authentication_plugin, + options = plugins_name) + form.add_submit('cancel', _('Previous')) + form.add_submit('submit', _('Next')) + form.add_submit('terminate', _('Terminate')) + + if form.get_widget('cancel').parse(): + return redirect('authentication_and_logout_adresses') + + if form.is_submitted(): + self.host.site_authentication_plugin = form.get_widget('plugin').parse() + self.host.store() + if form.get_widget('terminate').parse(): + write_apache2_vhosts() + return redirect('..') + return redirect('credentials') + + get_response().breadcrumb.append(('check_auto_detected_configuration', _('Auto detected configuration'))) + self.html_top(_('Step 4 - Check automatically detected configuration for the authentication form')) + + host_attrs = ( + ('auth_check_url', _('Address where the authentication form must be sent')), + ('login_field_name', _('Name of the login field')), + ('password_field_name', _('Name of the password field')), + ) + + html_fields = '' + success = True + for attr, name in host_attrs: + color = 'black' + if attr in ('auth_check_url', 'login_field_name', 'password_field_name') and \ + not getattr(self.host, str(attr)): + color = 'red' + success = False + html_fields += '
%s
' % (color, name) + html_fields += '
%s
' % \ + (color, getattr(self.host, str(attr))) + if getattr(self.host, str(attr)) == '': + html_fields += '
' + + '

' + if success: + htmltext(_('''\ +The following authentication form parameters have been detected. If they look right, you can go to the next step. +If you think they are wrong, go back and check your settings then try again. +''')) + else: + htmltext(_('''\ +The following authentication form parameters in red haven't been correctly detected. Go back and check +your settings then try again. +''')) + '

' + + html_fields + form.render() + + def credentials [html] (self): + form = self.form_credentials() + + if form.get_widget('cancel').parse(): + return redirect('check_auto_detected_configuration') + + if form.is_submitted() and not form.has_errors(): + self.submit_credentials_form(form) + if form.get_widget('terminate').parse(): + return redirect('..') + return redirect('send_authentication_request') + + get_response().breadcrumb.append(('credentials', _('Credentials'))) + self.html_top(_('Step 5 - Fill in a valid username/password for this site')) + form.render() + + def form_credentials(self): + form = Form(enctype='multipart/form-data') + form.add(StringWidget, 'username', title = _('Username'), required = True, + size = 30, value = self.host.valid_username) + form.add(PasswordWidget, 'password', title = _('Password'), required = True, + size = 30, value = self.host.valid_password) + for name, values in self.host.select_fields.iteritems(): + options = [] + if values: + for value in values: + options.append(value) + form.add(SingleSelectWidget, name, title = name.capitalize(), + value = values[0], options = options) + form.add_submit('cancel', _('Previous')) + form.add_submit('submit', _('Next')) + form.add_submit('terminate', _('Terminate')) + return form + + def submit_credentials_form(self, form): + self.host.valid_username = form.get_widget('username').parse() + self.host.valid_password = form.get_widget('password').parse() + self.host.valid_select = {} + for name, values in self.host.select_fields.iteritems(): + if form.get_widget(name): + self.host.valid_select[name] = form.get_widget(name).parse() + + self.host.store() + + def send_authentication_request(self): + site_auth = site_authentication.get_site_authentication(self.host) + + # Request with good credentials + self.host.auth_request_status, self.host.auth_request_data = site_auth.local_auth_check_dispatch( + self.host.valid_username, self.host.valid_password, self.host.valid_select) + self.host.auth_request_success, self.host.auth_request_return_content = \ + site_auth.check_auth(self.host.auth_request_status, self.host.auth_request_data) + + # Request with bad credentials + self.host.auth_bad_request_status, self.host.auth_bad_request_data = site_auth.local_auth_check_dispatch( + 'this_is_a_bad_login', 'this_is_a_bad_password', {}) + self.host.auth_bad_request_success, self.host.auth_bad_request_return_content = \ + site_auth.check_auth(self.host.auth_bad_request_status, self.host.auth_bad_request_data) + + self.host.store() + + return redirect('check_authentication') + + def check_authentication [html] (self): + form = Form(enctype='multipart/form-data') + form.add_submit('cancel', _('Previous')) + form.add_submit('submit', _('Next')) + form.add_submit('terminate', _('Terminate')) + + if form.get_widget('cancel').parse(): + return redirect('credentials') + + if form.is_submitted(): + if form.get_widget('terminate').parse(): + return redirect('..') + return redirect('sso_init_link') + + get_response().breadcrumb.append(('check_authentication', _('Check authentication'))) + self.html_top(_('Step 6 - Check the authentication process')) + + if self.host.auth_request_success: + good_cred_status = 'Success [OK]' + else: + good_cred_status = 'Failed [KO]Results of authentication requests :

\n' + '
    \n' + '\t
  • With good credentials : %s
  • ' % good_cred_status + '\t
  • With bad credentials : %s
  • ' % bad_cred_status + '
\n' + + if self.host.auth_request_success and not self.host.auth_bad_request_success : + '

%s

\n' % _('Authentication succeeded ! You can go to the next step.') + else: + '

%s

\n' % _('Authentication has failed. To resolve this problem, you can :') + '
    \n' + '\t
  • %s
  • \n' % \ + _('Try authentication again') + '\t
  • %s
  • \n' % \ + _('See the response of the authentication requests') + '\t
  • %s
  • \n' % \ + _('Modify the parameters of the authentication requests') + '\t
  • %s
  • \n' % \ + _('Change the way Larpe detects the authentication is successful or not') + '\t
  • %s
  • \n' % _('Go back and change your username and/or password') + '
\n' + + form.render() + + def see_authentication_response [html] (self): + get_response().breadcrumb.append(('see_authentication_response', _('Authentication response'))) + self.html_top(_('Authentication response')) + + '

%s

' % _('Response of the request with good credentials') + + '
%s
' % \ + str(_('HTTP status code')) + '
%s (%s)
' % \ + (self.host.auth_request_status, status_reasons[self.host.auth_request_status]) + + '
' + '
%s
' % _('See HTML page') + '
' + + '

%s

' % _('Response of the request with bad credentials') + + '
%s
' % \ + str(_('HTTP status code')) + '
%s (%s)
' % \ + (self.host.auth_bad_request_status, status_reasons[self.host.auth_bad_request_status]) + + '
' + '
%s
' % _('See HTML page') + '
' + + '

' % _('Back') + + def see_response_html_page (self): + return self.host.auth_request_data + + def see_bad_response_html_page (self): + return self.host.auth_bad_request_data + + def authentication_success_criteria [html] (self): + form = self.form_authentication_success_criteria() + + if form.get_widget('cancel').parse(): + return redirect('check_authentication') + + if form.is_submitted() and not form.has_errors(): + self.submit_authentication_success_criteria_form(form) + return redirect('check_authentication') + + get_response().breadcrumb.append(('authentication_success_criteria', _('Authentication success criteria'))) + self.html_top(_('Authentication success criteria')) + + form.render() + + def form_authentication_success_criteria(self): + form = Form(enctype='multipart/form-data') + form.add(RadiobuttonsWidget, 'auth_system', title = _('Authentication system of the original site'), + options=[ + ('password', _('Check the existence of a password field'), 'password'), + ('match_text', _('Match some text to detect an authentication failure'), 'match_text'), + ], + sort=False, + delim=htmltext('
'), + value = self.host.auth_system) + form.add(RegexStringWidget, 'auth_match_text', title = _('Text to match in case of authentication failure'), + required = False, size = 50, value = self.host.auth_match_text) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + return form + + def submit_authentication_success_criteria_form(self, form): + for f in ('auth_system', 'auth_match_text'): + value = form.get_widget(f).parse() + setattr(self.host, f, value) + + self.host.store() + + def modify_authentication_request [html] (self): + get_response().breadcrumb.append(('modify_authentication_request', _('Authentication request'))) + self.html_top(_('Modify the parameters of the authentication requests')) + + '
' + '
%s
%s
' % ( + _('Modify POST parameters'), _('Configure the form attributes that will be sent within the authentication POST requests')) + '
%s
%s
' % ( + _('Modify HTTP headers'), _('Configure the HTTP headers of the authentication requests made by Larpe')) + '
' + '

' % _('Back') + + def auth_request_post_parameters [html] (self): + form = self.form_auth_request_post_parameters() + + if form.get_widget('cancel').parse(): + return redirect('modify_authentication_request') + + if form.is_submitted() and not form.has_errors(): + self.submit_auth_request_post_parameters_form(form) + return redirect('modify_authentication_request') + + get_response().breadcrumb.append(('auth_request_post_parameters', _('POST parameters'))) + self.html_top(_('Configure POST parameters')) + + '

%s

' % _('''Here are the detected form fields that will be sent as parameters of the +authentication POST request. You can desactivate some or all of them, or change their value.''') + + form.render() + + def form_auth_request_post_parameters(self): + form = Form(enctype='multipart/form-data') + for name, value in self.host.post_parameters.iteritems(): + if value['immutable']: + form.add(DictWidget, name, value, disabled = 'disabled') + else: + form.add(DictWidget, name, value) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + return form + + def submit_auth_request_post_parameters_form(self, form): + for name, old_value in self.host.post_parameters.iteritems(): + value = form.get_widget(name).parse() + if value['enabled'] == 'on': + old_value['enabled'] = True + else: + old_value['enabled'] = False + if old_value['immutable'] is False: + old_value['value'] = value['value'] + self.host.post_parameters[name] = old_value + self.host.store() + + def auth_request_http_headers [html] (self): + form = self.form_auth_request_http_headers() + + if form.get_widget('cancel').parse(): + return redirect('modify_authentication_request') + + if form.is_submitted() and not form.has_errors(): + self.submit_auth_request_http_headers_form(form) + return redirect('modify_authentication_request') + + get_response().breadcrumb.append(('auth_request_http_headers', _('HTTP headers'))) + self.html_top(_('Configure HTTP headers')) + + '

%s

' % _('''Here are the HTTP headers that will be sent within the authentication +POST request. You can desactivate some or all of them, or change their value.''') + + form.render() + + def form_auth_request_http_headers(self): + form = Form(enctype='multipart/form-data') + for name, value in self.host.http_headers.iteritems(): + if value['immutable']: + form.add(DictWidget, name, value, disabled = 'disabled') + else: + form.add(DictWidget, name, value) + form.add(HtmlWidget, htmltext('

%s

' % \ + _('The headers "Host", "Accept-Encoding" and "Content-Length" will also automatically be sent.'))) + if get_cfg('proxy', {}).get('enabled') and self.host.use_proxy: + form.add(HtmlWidget, htmltext('

%s

' % \ + _('''As Larpe uses a proxy for this site, the headers "Proxy-Authorization", +"Proxy-Connection" and "Keep-Alive" will be sent as well.'''))) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + return form + + def submit_auth_request_http_headers_form(self, form): + for name, old_value in self.host.http_headers.iteritems(): + value = form.get_widget(name).parse() + if value['enabled'] == 'on': + old_value['enabled'] = True + else: + old_value['enabled'] = False + if old_value['immutable'] is False: + old_value['value'] = value['value'] + self.host.http_headers[name] = old_value + self.host.store() + + def generate_apache_filters(self): + self.host.apache_python_paths = [] + self.host.apache_output_python_filters = [] + site_auth = site_authentication.get_site_authentication(self.host) + output_filters = site_auth.output_filters + replace_login_form = self.host.auth_form_places == 'form_everywhere' and \ + self.host.auth_form_action + if replace_login_form and not 'output_replace_form' in output_filters: + output_filters.append('output_replace_form') + if output_filters: + location = Location(self.host) + conf = { 'auth_form_action': self.host.auth_form_action, + 'name': self.host.name, + 'larpe_dir': get_publisher().app_dir, + 'logout_url': location.new_logout_url, + 'login_url': location.new_auth_url } + # Set Python filter path for Apache configuration + python_path = os.path.join(self.host.site_dir, 'filters') + if python_path not in self.host.apache_python_paths: + self.host.apache_python_paths.append(python_path) + + for filter in output_filters: + python_file = open( + os.path.join(self.host.site_dir, 'filters', filter + ".py"), + 'w') + python_file.write( + open(os.path.join(DATA_DIR, "filters", filter + ".py")).read() % conf + ) + if not filter in self.host.apache_output_python_filters: + self.host.apache_output_python_filters.append(filter) + + def sso_init_link [html] (self): + form = self.form_sso_init_link() + + if form.get_widget('cancel').parse(): + return redirect('check_authentication') + + if form.is_submitted() and not form.has_errors(): + self.submit_sso_init_link_form(form) + if form.get_widget('terminate').parse(): + return redirect('..') + return redirect('metadatas') + + get_response().breadcrumb.append(('sso_init_link', _('SSO initiation'))) + self.html_top(_('Step 7 - Configure how a Single Sign On can be initiated')) + + '

%s\n' % _('Most sites use one of the following 2 ways to allow users to initialise an authentication :') + '\t

    \n' + '\t\t
  1. %s
  2. \n' % \ + _('''The site has a single authentication page. It redirects users to this page when +they click a "Login" button or try to access a page which require users to be authenticated.''') + '\t\t
  3. %s
  4. \n' % \ + _('''The site includes an authentication form in most or all of his pages. Users can +authenticate on any of these pages, and don't need to be redirected to a separate authentication page.''') + '\t
\n' + '

\n' + + '

%s

' % _('Select the way your site works :') + + form.render() + + def form_sso_init_link(self): + form = Form(enctype='multipart/form-data') + form.add(RadiobuttonsWidget, 'auth_form_places', + options=[ + ('form_once', _('The site has a single authentication page'), 'form_once'), + ('form_everywhere', _('The site includes an authentication form in most or all pages'), 'form_everywhere'), + ], + sort=False, required = True, delim=htmltext('
'), value = self.host.auth_form_places) + form.add_submit('cancel', _('Previous')) + form.add_submit('submit', _('Next')) + form.add_submit('terminate', _('Terminate')) + return form + + def submit_sso_init_link_form(self, form): + fields = [ 'auth_form_places', ] + for f in fields: + setattr(self.host, f, form.get_widget(f).parse()) + self.host.auth_form_url = self.host.auth_url + self.generate_apache_filters() + self.host.store() + write_apache2_vhosts() + + def metadatas [html] (self): + form = Form(enctype='multipart/form-data') + form.add_submit('cancel', _('Previous')) + form.add_submit('submit', _('Next')) + form.add_submit('terminate', _('Terminate')) + + if form.get_widget('cancel').parse(): + return redirect('sso_init_link') + + if form.is_submitted(): + if form.get_widget('terminate').parse(): + return redirect('..') + return redirect('advanced_options') + + get_response().breadcrumb.append(('metadatas', _('Metadatas'))) + self.html_top(_('Step 8 - Metadatas of %(site_name)s' % {'site_name': self.host.name})) + + '

%s

' % \ + _('''Download the metadatas and the public key for this site and +upload them on your identity provider in order to use Liberty Alliance features.''') + + '
' + if hasattr(self.host, str('base_url')): + if lasso.SAML2_SUPPORT: + saml2_metadata_url = '%s/metadata.xml' % self.host.saml2_base_url + '
%s
%s
' % ( + saml2_metadata_url, + _('SAML 2.0 Metadata'), + _('Download SAML 2.0 metadata file')) + metadata_url = '%s/metadata.xml' % self.host.base_url + '
%s
%s
' % ( + metadata_url, + _('ID-FF 1.2 Metadata'), + _('Download ID-FF 1.2 metadata file')) + else: + '

%s

' % _('No metadata has been generated for this host.') + + if hasattr(self.host, str('base_url')) and self.host.public_key and os.path.exists(self.host.public_key): + public_key_url = '%s/public_key' % self.host.base_url + '
%s
%s
' % ( + public_key_url, + _('Public key'), + _('Download SSL Public Key file')) + else: + '

%s

' % _('No public key has been generated for this host.') + '
' + + form.render() + + def advanced_options [html] (self): + form = self.form_advanced_options() + + if form.get_widget('cancel').parse(): + return redirect('metadatas') + + if not form.is_submitted() or form.has_errors(): + get_response().breadcrumb.append(('advanced_options', _('Advanced options'))) + self.html_top(_('Step 9 - Advanced options')) + + '

%s

' % _('Configure advanced options to setup the last details of your site.') + '

%s

' % _('''If you don't know what to configure here, just click %(next)s and +come here later if needed.''') % {'next': _('Next')} + + form.render() + else: + self.submit_advanced_options_form(form) + if form.get_widget('terminate').parse(): + return redirect('..') + return redirect('check_full_configuration') + + def form_advanced_options(self): + form = Form(enctype='multipart/form-data') + form.add(CheckboxWidget, 'redirect_root_to_login', + title=_('Redirect the root URL of the site to the login page.'), + value = self.host.redirect_root_to_login) + form.add(UrlOrAbsPathWidget, 'return_url', title = _('Return address'), + hint = _('Where the user will be redirected after a successful authentication'), + required = False, size = 50, value = self.host.return_url) + form.add(UrlOrAbsPathWidget, 'root_url', title = _('Error address'), + hint = _('Where the user will be redirected after a disconnection or an error'), + required = False, size = 50, value = self.host.root_url) + form.add(UrlOrAbsPathWidget, 'initiate_sso_url', title = _('URL which must initiate the SSO'), + hint = _('''Address which must initiate the SSO. If empty, defaults to the previously +specified "%s"''') % _('Authentication form page address'), + required = False, size = 50, value = self.host.initiate_sso_url) + form.add(CheckboxWidget, 'proxy-html', title = _('Apache HTML proxy'), + hint = _('''Converts urls in the HTML pages according to the host new domain name. +Disabled by default because it makes some sites not work correctly.'''), + value = 'proxy-html' in self.host.apache_output_filters) + + form.add_submit('cancel', _('Previous')) + form.add_submit('submit', _('Next')) + form.add_submit('terminate', _('Terminate')) + return form + + def submit_advanced_options_form(self, form): + old_redirect_root_to_login = self.host.redirect_root_to_login + + for f in ('redirect_root_to_login', 'return_url', 'root_url', 'initiate_sso_url'): + value = form.get_widget(f).parse() + setattr(self.host, f, value) + + f = 'proxy-html' + value = form.get_widget(f).parse() + if value is True and f not in self.host.apache_output_filters: + self.host.apache_output_filters.append(f) + if value is False and f in self.host.apache_output_filters: + self.host.apache_output_filters.remove(f) + + self.host.store() + + if self.host.initiate_sso_url or self.host.redirect_root_to_login is not old_redirect_root_to_login: + write_apache2_vhosts() + + def check_full_configuration [html] (self): + form = Form(enctype='multipart/form-data') + form.add_submit('cancel', _('Previous')) + form.add_submit('submit', _('Finish')) + + if form.get_widget('cancel').parse(): + return redirect('advanced_options') + + if form.is_submitted(): + return redirect('../..') + + get_response().breadcrumb.append(('check_full_configuration', _('Check everything works'))) + self.html_top(_('Step 10 - Check everything works')) + + '

%s

' % \ + _('''Now you can fully test your site, start from the home page, initiate a +Single Sign On, federate your identities and do a Single Logout.''') + + '

%s' % _('The address of your site is : ') + '%s' % (self.host.new_url, self.host.new_url) + '

' + + '

%s

' % \ + _('''If everything works, click the "%(finish)s" button, otherwise you can go +back and check your settings.''') % { 'finish': _('Finish') } + + form.render() + + def auto_detect_configuration(self): + # Reset previous detected values + self.host.auth_form = None + self.host.auth_check_url = None + self.host.login_field_name = None + self.host.password_field_name = None + if not self.host.post_parameters: + self.host.post_parameters = {} + + self.parse_page(self.host.auth_form_url) + + def parse_page(self, page_url): + # Get the authentication page + try: + response, status, page, auth_header = http_get_page(page_url, use_proxy=self.host.use_proxy) + except Exception, msg: + print msg + return + + if page is None: + return + #raise FormError, ('auth_check_url', '%s : %s' % (_('Failed to get page'), self.host.auth_form_url)) + + # Default authentication mode + self.host.auth_mode = 'form' + + if not self.host.site_authentication_plugin: + self.host.site_authentication_plugin = site_authentication_plugins.auto_detect(page) + self.parse_frames(page) + self.parse_forms(page) + if self.host.auth_form is not None: + self.parse_form_action() + input_fields = self.parse_input_fields() + self.parse_login_field(input_fields) + self.parse_password_field() + self.parse_select_fields() + self.parse_other_fields() + + def parse_frames(self, page): + '''If there are frames, parse them recursively''' + regexp = re.compile("""]*?>""", re.DOTALL | re.IGNORECASE) + found_frames = regexp.findall(page) + if found_frames: + for frame_url in found_frames: + if frame_url.startswith('http'): + frame_full_url = frame_url + else: + page_url_tokens = frame_url.split('/') + page_url_tokens[-1] = frame_url + frame_full_url = '/'.join(page_url_tokens) + self.parse_page(frame_full_url) + + def parse_forms(self, page): + '''Search for an authentication form''' + # Get all forms + regexp = re.compile("""""", re.DOTALL | re.IGNORECASE) + found_forms = regexp.findall(page) + if not found_forms: + return + #raise FormError, ('auth_check_url', '%s : %s' % (_('Failed to find any form'), self.host.auth_form_url)) + + # Get the first form with a password field + for found_form in found_forms: + regexp = re.compile("""]*?type=["']?password["']?[^>]*?>""", re.DOTALL | re.IGNORECASE) + if regexp.search(found_form) is not None: + self.host.auth_form = found_form + break + + def parse_form_action(self): + '''Get the action url of the form''' + regexp = re.compile("""].*?>""", re.DOTALL | re.IGNORECASE) + self.host.auth_form_action = regexp.findall(self.host.auth_form)[0] + # FIXME: Find a Python module which unescapes html entities + self.host.auth_check_url = self.host.auth_form_action.replace('&', '&') + if not self.host.auth_check_url.startswith('http'): + if self.host.auth_check_url.startswith('/'): + if self.host.orig_site.startswith('https'): + orig_site_root = 'https://%s' % urllib.splithost(self.host.orig_site[6:])[0] + else: + orig_site_root = 'http://%s' % urllib.splithost(self.host.orig_site[5:])[0] + self.host.auth_check_url = orig_site_root + self.host.auth_check_url + else: + auth_form_url_tokens = self.host.auth_form_url.split('/') + auth_form_url_tokens[-1] = self.host.auth_check_url + self.host.auth_check_url = '/'.join(auth_form_url_tokens) + + def parse_input_fields(self): + '''Get all input fields''' + regexp = re.compile("""]*?>""", re.DOTALL | re.IGNORECASE) + return regexp.findall(self.host.auth_form) + + def parse_login_field(self, input_fields): + '''Get login field name''' + try: + regexp = re.compile("""]*?type=["']?text["']?[^>]*?>""", re.DOTALL | re.IGNORECASE) + text_fields = regexp.findall(self.host.auth_form) + login_field = '' + if text_fields: + login_field = text_fields[0] + else: + for field in input_fields: + if re.search("""type=["']?""", field, re.DOTALL | re.IGNORECASE) is None: + login_field = field + break + regexp = re.compile("""name=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE) + self.host.login_field_name = regexp.findall(login_field)[0] + if not self.host.post_parameters.has_key(self.host.login_field_name): + self.host.post_parameters[self.host.login_field_name] = \ + { 'enabled': True, 'value': _('(filled by users)'), 'immutable': True } + self.host.store() + except IndexError, e: + self.host.login_field_name = None + print 'Error handling login field : %s' % e + + def parse_password_field(self): + '''Get password field name''' + try: + regexp = re.compile("""]*?type=["']?password["']?[^>]*?>""", re.DOTALL | re.IGNORECASE) + password_field = regexp.findall(self.host.auth_form)[0] + regexp = re.compile("""name=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE) + self.host.password_field_name = regexp.findall(password_field)[0] + if not self.host.post_parameters.has_key(self.host.password_field_name): + self.host.post_parameters[self.host.password_field_name] = \ + { 'enabled': True, 'value': _('(filled by users)'), 'immutable': True } + except IndexError, e: + self.host.password_field_name = None + print 'Error handling password field : %s' % e + + def parse_select_fields(self): + '''Add select fields to host attributes''' + # First added for Imuse (Rennes) + regexp = re.compile("""""", re.DOTALL | re.IGNORECASE) + self.host.select_fields = {} + for field in regexp.findall(self.host.auth_form): + try: + regexp = re.compile("""name=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE) + name = regexp.findall(field)[0] + regexp = re.compile("""]*?>.*?""", re.DOTALL | re.IGNORECASE) + options = regexp.findall(field) + values = [] + for option in options: + regexp = re.compile("""]*?>(.*?)""", re.DOTALL | re.IGNORECASE) + option_label = regexp.findall(option) + regexp = re.compile("""value=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE) + option_value = regexp.findall(option) + if option_label: + if not option_value: + option_value = option_label + values.append((option_value[0], option_label[0])) + else: + print >> sys.stderr, 'W: Could not parse select options' + self.host.select_fields[name] = values + if not self.host.post_parameters.has_key(name): + self.host.post_parameters[name] = \ + { 'enabled': True, 'value': _('(filled by users)'), 'immutable': True } + except IndexError, e: + continue + + def parse_other_fields(self): + '''Get the default value of all other fields''' + self.host.other_fields = {} + + # Get hidden fields + regexp = re.compile("""]*?type=["']?hidden["']?[^>]*?>""", re.DOTALL | re.IGNORECASE) + other_fields = regexp.findall(self.host.auth_form) + + # Only get first submit field + regexp = re.compile("""]*?type=["']?submit["']?[^>]*?>""", re.DOTALL | re.IGNORECASE) + found = regexp.findall(self.host.auth_form) + if found: + if other_fields: + other_fields.append(found[0]) + else: + other_fields = found[0] + + for field in other_fields: + try: + regexp = re.compile("""name=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE) + name = regexp.findall(field)[0] + regexp = re.compile("""value=["'](.*?)["'][\s/>]""", re.DOTALL | re.IGNORECASE) + value = regexp.findall(field)[0] + self.host.other_fields[name] = value + if not self.host.post_parameters.has_key(name): + self.host.post_parameters[name] = { 'enabled': True, 'value': value, 'immutable': False } + except IndexError, e: + continue + + +class HostPage(Directory): + _q_exports = ['', 'delete'] + + def __init__(self, host_id): + self.host = Host.get(host_id) + get_response().breadcrumb.append((host_id + '/', self.host.label)) + + def _q_lookup(self, component): + if component == 'configuration_assistant': + return ConfigurationAssistant(self.host) + elif component == 'forms_prefill': + return FormsDirectory(self.host) + + def _q_index [html] (self): + get_publisher().reload_cfg() + html_top('hosts', title = self.host.label) + + '

%s

' % _('Configuration assistant') + + '
' + + '
%s
%s
' % ( + _('Address of the original site'), _('Configure the root address of the site')) + + '
%s
%s
' % ( + _('New address and name'), _('Configure the new address and name of this site')) + + '
%s
%s
' % ( + _('Authentication and logout addresses'), _('Configure the authentication and logout addresses of the original site')) + + '
%s
%s
' % ( + _('Check auto detected configuration'), _('Check the automatically detected configuration is right')) + + '
%s
%s
' % ( + _('Credentials'), _('Configure some valid credentials to authenticate on the original site')) + + '
%s
%s
' % ( + _('Retry authentication'), _('Retry sending an authentication request to the site to check if your new parameters work well')) + + '
%s
%s
' % ( + _('Check authentication response'), _('Check the response from the latest authentication request')) + + '
%s
%s
' % ( + _('Configure authentication success criteria'), _('Specify how Larpe knows if the authentication has succeeded or not')) + + '
%s
%s
' % ( + _('Modify authentication request'), _('Modify POST fields or HTTP headers of the authentication request')) + + '
%s
%s
' % ( + _('Configure how a Single Sign On can be initiated'), _('Configure how a Single Sign On can be initiated')) + + '
%s
%s
' % ( + _('Metadatas and key'), _('Download SAML 2.0 or ID-FF metadatas and SSL public key')) + + '
%s
%s
' % ( + _('Adavanced options'), _('Configure advanced options to setup the last details of your site')) + + '
' + + '

%s

' % _('Form prefilling with ID-WSF') + + '
' + '
%s
%s
' % ( + _('Forms'), _('Configure the forms to prefill')) + '
' + + def delete [html] (self): + form = Form(enctype='multipart/form-data') + form.widgets.append(HtmlWidget('

%s

' % _( + 'You are about to irrevocably delete this host.'))) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + if form.get_widget('cancel').parse(): + return redirect('..') + if not form.is_submitted() or form.has_errors(): + get_response().breadcrumb.append(('delete', _('Delete'))) + html_top('hosts', title = _('Delete Host')) + '

%s : %s

' % (_('Delete Host'), self.host.label) + form.render() + else: + self.host.remove_self() + write_apache2_vhosts() + return redirect('..') + + +class HostsDirectory(Directory): + _q_exports = ['', 'new'] + + def _q_index [html] (self): + get_response().breadcrumb.append(('hosts/', _('Hosts'))) + html_top('hosts', title = _('Hosts')) + """""" % _('New Host') + + '
    ' + + for host in Host.select(lambda x: x.name != 'larpe', order_by = 'label'): + if not host.name: + continue + if not hasattr(host, str('scheme')): + host.scheme = str('http') + '
  • ' + '%s' % host.label + if hasattr(host, str('new_url')) and host.new_url: + url = host.new_url + else: + # Compat with older Larpe versions + url = '%s://%s%s/' % (host.scheme, host.reversed_hostname, get_request().environ['SCRIPT_NAME']) + if host.reversed_directory is not None: + url += '%s/' % host.reversed_directory + '
    %s' % (url, url) + '

    ' + command_icon('%s/' % host.id, 'edit') + command_icon('%s/delete' % host.id, 'remove') + '

  • ' + '
' + + def new [html] (self): + if not os.path.isdir(os.path.join(get_publisher().app_dir, str('idp'))): + html_top('hosts', title = _('New Host')) + html = '

%s

' % _('New Host') + html += 'You must ' % misc.get_root_url() + html += 'configure an Identity Provider first

' + html += '' % _('Back') + return html + + get_response().breadcrumb.append(('hosts/', _('Hosts'))) + get_response().breadcrumb.append(('new', _('New')) ) + host = Host() + host.store() + return redirect('%s/configuration_assistant/start' % host.id) + + def _q_lookup(self, component): + get_response().breadcrumb.append(('hosts/', _('Hosts'))) + return HostPage(component) + diff --git a/larpe/tags/release-1.1.1/larpe/admin/liberty_utils.py b/larpe/tags/release-1.1.1/larpe/admin/liberty_utils.py new file mode 100644 index 0000000..de324c4 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/admin/liberty_utils.py @@ -0,0 +1,129 @@ +import os + +def set_provider_keys(private_key_path, public_key_path): + # use system calls for openssl since PyOpenSSL doesn't expose the + # necessary functions. + if os.system('openssl version > /dev/null 2>&1') == 0: + os.system('openssl genrsa -out %s 2048' % private_key_path) + os.system('openssl rsa -in %s -pubout -out %s' % (private_key_path, public_key_path)) + + +def get_metadata(cfg): + prologue = """\ + +""" % cfg + + sp_head = """ + """ + + signing_public_key = '' + if cfg.has_key('signing_public_key') and cfg['signing_public_key']: + if 'CERTIF' in cfg['signing_public_key']: + signing_public_key = """ + + + %s + + """ % cfg['signing_public_key'] + elif 'KEY' in cfg['signing_public_key']: + signing_public_key = """ + + + %s + + """ % cfg['signing_public_key'] + + sp_body = """ + %(base_url)s/assertionConsumer + + %(base_url)s/soapEndpoint + + %(base_url)s/singleLogout + %(base_url)s/singleLogoutReturn + http://projectliberty.org/profiles/slo-idp-http + http://projectliberty.org/profiles/slo-sp-soap + http://projectliberty.org/profiles/slo-sp-http + + %(base_url)s/federationTermination + %(base_url)s/federationTerminationReturn + http://projectliberty.org/profiles/fedterm-idp-soap + http://projectliberty.org/profiles/fedterm-idp-http + http://projectliberty.org/profiles/fedterm-sp-soap + http://projectliberty.org/profiles/fedterm-sp-http + + true + + """ % cfg + + orga = '' + if cfg.get('organization_name'): + orga = """ + + %s + """ % unicode(cfg['organization_name'], 'iso-8859-1').encode('utf-8') + + epilogue = """ +""" + + return '\n'.join([prologue, sp_head, signing_public_key, sp_body, orga, epilogue]) + + + +def get_saml2_metadata(cfg): + prologue = """\ + +""" % cfg + + sp_head = """ + """ + + signing_public_key = '' + if cfg.has_key('signing_public_key') and cfg['signing_public_key']: + if 'CERTIF' in cfg['signing_public_key']: + signing_public_key = """ + + + %s + + """ % cfg['signing_public_key'] + elif 'KEY' in cfg['signing_public_key']: + signing_public_key = """ + + + %s + + """ % cfg['signing_public_key'] + + sp_body = """ + + + + + """ % cfg + + orga = '' + if cfg.get('organization_name'): + orga = """ + + %s + """ % unicode(cfg['organization_name'], 'iso-8859-1').encode('utf-8') + + epilogue = """ +""" + + return '\n'.join([prologue, sp_head, signing_public_key, sp_body, orga, epilogue]) + diff --git a/larpe/tags/release-1.1.1/larpe/admin/root.ptl b/larpe/tags/release-1.1.1/larpe/admin/root.ptl new file mode 100644 index 0000000..8a65592 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/admin/root.ptl @@ -0,0 +1,90 @@ +import os + +import lasso + +from quixote import get_session, get_session_manager, get_publisher, get_request, get_response +from quixote.directory import Directory, AccessControlled + +from qommon.admin.menu import html_top +from qommon.admin import logger + +from larpe import errors +from larpe import misc + +import hosts +import users +import settings + +def gpl [html] (): + """

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

+ +

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

+ +

You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 Temple + Place - Suite 330, Boston, MA 02111-1307, USA.

+ """ + + +class RootDirectory(AccessControlled, Directory): + _q_exports = ['', 'hosts', 'users', 'settings', 'logger'] + + hosts = hosts.HostsDirectory() + users = users.UsersDirectory() + settings = settings.SettingsDirectory() + logger = logger.LoggerDirectory() + + menu_items = [ + ('hosts/', N_('Hosts')), + ('users/', N_('Users')), + ('settings/', N_('Settings')), + ('logger/', N_('Logs')), + ('/', N_('Liberty Alliance Reverse Proxy'))] + + def _q_access(self): + # FIXME : this block should be moved somewhere else + get_publisher().reload_cfg() + if not get_publisher().cfg.has_key('proxy_hostname'): + get_publisher().cfg['proxy_hostname'] = get_request().get_server().split(':')[0] + get_publisher().write_cfg() + + response = get_response() + if not hasattr(response, 'breadcrumb'): + response.breadcrumb = [ ('../admin/', _('Administration')) ] + + # Cheater + if os.path.exists(os.path.join(get_publisher().app_dir, 'ADMIN_FOR_ALL')): + return + + # No admin user created yet, free access + user_list = users.User.select(lambda x: x.is_admin) + if not user_list: + return + + host_list = hosts.Host.select(lambda x: x.name == 'larpe') + if host_list: + host = host_list[0] + else: + raise errors.AccessForbiddenError() + + if misc.get_current_protocol() == lasso.PROTOCOL_SAML_2_0: + user = get_session().get_user(host.saml2_provider_id) + else: + user = get_session().get_user(host.provider_id) + if user: + if not user.name or not user.is_admin: + raise errors.AccessForbiddenError() + else: + raise errors.AccessUnauthorizedError() + + + def _q_index [html] (self): + html_top('') + gpl() + diff --git a/larpe/tags/release-1.1.1/larpe/admin/settings.ptl b/larpe/tags/release-1.1.1/larpe/admin/settings.ptl new file mode 100644 index 0000000..a1a36f1 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/admin/settings.ptl @@ -0,0 +1,361 @@ +import cStringIO +import cPickle +import re +import os +import lasso +import glob +import zipfile + +from quixote import get_publisher, get_request, get_response, redirect +from quixote.directory import Directory, AccessControlled + +from qommon.form import * +from qommon.misc import get_abs_path +from qommon.admin.cfg import cfg_submit +from qommon.admin.menu import html_top, error_page +from qommon.admin.emails import EmailsDirectory as QommonEmailsDirectory +from qommon.admin.settings import SettingsDirectory as QommonSettingsDirectory + +from larpe import misc +from larpe.hosts import Host +from larpe.admin.liberty_utils import * + +class LibertyIDPDir(Directory): + _q_exports = ['', ('metadata.xml', 'metadata')] + + def _q_index [html] (self): + form = Form(enctype="multipart/form-data") + form.add(FileWidget, "metadata", title = _("Metadata"), required=True) + form.add(FileWidget, "publickey", title = _("Public Key"), required=False) + form.add(FileWidget, "cacertchain", title = _("CA Certificate Chain"), required=False) + form.add_submit("submit", _("Submit")) + + if not form.is_submitted() or form.has_errors(): + html_top('settings', title = _('New Identity Provider')) + "

%s

" % _('New Identity Provider') + form.render() + else: + self.submit_new(form) + + def submit_new(self, form, key_provider_id = None): + metadata, publickey, cacertchain = None, None, None + if form.get_widget('metadata').parse(): + metadata = form.get_widget('metadata').parse().fp.read() + if form.get_widget('publickey').parse(): + publickey = form.get_widget('publickey').parse().fp.read() + if form.get_widget('cacertchain').parse(): + cacertchain = form.get_widget('cacertchain').parse().fp.read() + + if not key_provider_id: + try: + provider_id = re.findall(r'(provider|entity)ID="(.*?)"', metadata)[0][1] + except IndexError: + return error_page('settings', _('Bad metadata')) + key_provider_id = provider_id.replace(str('://'), str('-')).replace(str('/'), str('-')) + + dir = get_abs_path(os.path.join('idp', key_provider_id)) + if not os.path.isdir(dir): + os.makedirs(dir) + + if metadata: + metadata_fn = os.path.join(dir, 'metadata.xml') + open(metadata_fn, 'w').write(metadata) + if publickey: + publickey_fn = os.path.join(dir, 'public_key') + open(publickey_fn, 'w').write(publickey) + else: + publickey_fn = None + if cacertchain: + cacertchain_fn = os.path.join(dir, 'ca_cert_chain.pem') + open(cacertchain_fn, 'w').write(cacertchain) + else: + cacertchain_fn = None + + p = lasso.Provider(lasso.PROVIDER_ROLE_IDP, metadata_fn, publickey_fn, None) + + try: + misc.get_provider_label(p) + get_publisher().cfg['idp'] = key_provider_id + get_publisher().write_cfg() + except TypeError: + if metadata: + os.unlink(metadata_fn) + if publickey: + os.unlink(publickey_fn) + if cacertchain: + os.unlink(cacertchain_fn) + return error_page('settings', _('Bad metadata')) + + redirect('..') + + def metadata(self): + response = get_response() + response.set_content_type('text/xml', 'utf-8') + get_publisher().reload_cfg() + if get_publisher().cfg['idp']: + idp_metadata = os.path.join(get_abs_path('idp'), get_publisher().cfg['idp'], 'metadata.xml') + return unicode(open(idp_metadata).read(), 'utf-8') + return 'No IDP is configured' + + +class EmailsDirectory(QommonEmailsDirectory): + def _q_index [html] (self): + # Don't use custom emails + html_top('settings', title = _('Emails')) + '

%s

' % _('Emails') + + '
    ' + '
  • %s
  • ' % _('General Options') + '
' + + '

' + '%s' % _('Back') + '

' + + +class SettingsDirectory(QommonSettingsDirectory): + _q_exports = ['', 'liberty_sp', 'liberty_idp', 'domain_names', 'apache2_configuration_generation', + 'proxy', 'language', 'emails', 'debug_options' ] + + liberty_idp = LibertyIDPDir() + emails = EmailsDirectory() + + def _q_index [html] (self): + get_publisher().reload_cfg() + html_top('settings', title = _('Settings')) + + if lasso.SAML2_SUPPORT: + '

%s

' % _('Liberty Alliance & SAML 2.0 Service Provider') + else: + '

%s

' % _('Liberty Alliance Service Provider') + '
%s
%s
' % ( + _('Service Provider'), _('Configure Larpe as a Service Provider')) + + hosts = Host.select(lambda x: x.name == 'larpe') + if hosts: + self.host = hosts[0] + + if lasso.SAML2_SUPPORT and self.host.saml2_metadata is not None: + metadata_url = '%s/metadata.xml' % self.host.saml2_base_url + '
%s
%s
' % ( + metadata_url, + _('SAML 2.0 Metadata'), + _('Download SAML 2.0 metadata file for Larpe')) + + if self.host.metadata is not None: + metadata_url = '%s/metadata.xml' % self.host.base_url + '
%s
%s
' % ( + metadata_url, + _('ID-FF 1.2 Metadata'), + _('Download ID-FF 1.2 metadata file for Larpe')) + + if self.host.public_key is not None: + public_key_url = '%s/public_key' % self.host.base_url + '
%s
%s
' % ( + public_key_url, + _('Public key'), + _('Download SSL Public Key file')) + + if lasso.SAML2_SUPPORT: + '

%s

' % _('Liberty Alliance & SAML 2.0 Identity Provider') + else: + '

%s

' % _('Liberty Alliance Identity Provider') + + '
' + + '
%s
%s
' % ( + _('Identity Provider'), _('Configure an identity provider')) + + if get_publisher().cfg.has_key('idp'): + '
%s
%s
' % ( + _('Identity Provider metadatas'), _('See current identity provider metadatas')) + + '
' + + '

%s

' % _('Global parameters for the sites') + + '
' + '
%s
%s
' % ( + _('Domain name'), _('Configure the base domain name for the sites')) + '
%s
%s
' % ( + _('Apache 2 configuration generation'), _('Customise Apache 2 configuration generation')) + '
%s
%s
' % ( + _('Proxy'), _('Connect to the sites through a web proxy')) + '
' + + '

%s

' % _('Customisation') + + '
' + '
%s
%s
' % ( + _('Language'), _('Configure site language')) + '
%s
%s
' % ( + _('Emails'), _('Configure email settings')) + '
' + + '

%s

' % _('Misc') + + '
' + '
%s
%s
' % ( + _('Debug Options'), _('Configure options useful for debugging')) + '
' + + + def liberty_sp [html] (self): + get_publisher().reload_cfg() + + # Get the host object for the reverse proxy + hosts = Host.select(lambda x: x.name == 'larpe') + if hosts: + self.host = hosts[0] + else: + self.host = Host() + self.host.reversed_hostname = get_publisher().cfg[str('proxy_hostname')] + + form = Form(enctype='multipart/form-data') + form.add(StringWidget, 'organization_name', title=_('Organisation Name'), size=50, + required = True, value = self.host.organization_name) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + if form.get_widget('cancel').parse(): + return redirect('.') + if not form.is_submitted() or form.has_errors(): + html_top('settings', title = _('Service Provider Configuration')) + '

%s

' % _('Service Provider Configuration') + form.render() + else: + self.liberty_sp_submit(form) + redirect('.') + + def liberty_sp_submit(self, form): + get_publisher().reload_cfg() + metadata_cfg = {} + + f = 'organization_name' + if form.get_widget(f): + setattr(self.host, f, form.get_widget(f).parse()) + + metadata_cfg['organization_name'] = self.host.organization_name + + self.host.name = 'larpe' + + # Liberty Alliance / SAML parameters + base_url = '%s/liberty/%s/liberty' % (misc.get_root_url(), self.host.name) + metadata_cfg['base_url'] = base_url + self.host.base_url = base_url + + if lasso.SAML2_SUPPORT: + saml2_base_url = '%s/liberty/%s/saml' % (misc.get_root_url(), self.host.name) + metadata_cfg['saml2_base_url'] = saml2_base_url + self.host.saml2_base_url = saml2_base_url + + provider_id = '%s/metadata' % base_url + metadata_cfg['provider_id'] = provider_id + self.host.provider_id = provider_id + + if lasso.SAML2_SUPPORT: + saml2_provider_id = '%s/metadata' % saml2_base_url + metadata_cfg['saml2_provider_id'] = saml2_provider_id + self.host.saml2_provider_id = saml2_provider_id + + # Storage directories + site_dir = os.path.join(get_publisher().app_dir, 'sp', + self.host.reversed_hostname, self.host.name) + user_dir = os.path.join(site_dir, 'users') + token_dir = os.path.join(site_dir, 'tokens') + for dir in (site_dir, user_dir, token_dir): + if not os.path.isdir(dir): + os.makedirs(dir) + metadata_cfg['site_dir'] = site_dir + self.host.site_dir = site_dir + + # Generate SSL keys + private_key_path = os.path.join(site_dir, 'private_key.pem') + public_key_path = os.path.join(site_dir, 'public_key') + if not os.path.isfile(private_key_path) or not os.path.isfile(public_key_path): + set_provider_keys(private_key_path, public_key_path) + self.host.private_key = private_key_path + metadata_cfg['signing_public_key'] = open(public_key_path).read() + self.host.public_key = public_key_path + + # Write metadatas + metadata_path = os.path.join(site_dir, 'metadata.xml') + open(metadata_path, 'w').write(get_metadata(metadata_cfg)) + self.host.metadata = metadata_path + + if hasattr(self.host, 'saml2_provider_id'): + saml2_metadata_path = os.path.join(site_dir, 'saml2_metadata.xml') + open(saml2_metadata_path, 'w').write(get_saml2_metadata(metadata_cfg)) + self.host.saml2_metadata = saml2_metadata_path + + self.host.root_url = '%s/' % misc.get_root_url() + self.host.return_url = '%s/admin/' % misc.get_root_url() + + self.host.store() + + def domain_names [html] (self): + form = self.form_domain_name() + + if form.get_widget('cancel').parse(): + return redirect('.') + + if not form.is_submitted() or form.has_errors(): + html_top('settings', title = _('Domain name')) + '

%s

' % _('Domain name') + form.render() + else: + self.submit_domain_name(form) + redirect('.') + + def form_domain_name(self): + get_publisher().reload_cfg() + if get_cfg('domain_names'): + domain_name = get_cfg('domain_names')[0] + else: + domain_name = None + + form = Form(enctype='multipart/form-data') + form.add(StringWidget, 'domain_name', + title=_('Domain name for the sites'), + value = domain_name) + # TODO: Add the option "Both" and handle it in hosts configuration + form.add(SingleSelectWidget, 'sites_url_scheme', title = _('Use HTTP or HTTPS'), + value = get_cfg('sites_url_scheme'), + options = [ (None, _('Same as the site')), + ('http', 'HTTP'), + ('https', 'HTTPS') ] ) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + return form + + def submit_domain_name(self, form): + get_publisher().reload_cfg() + get_publisher().cfg['domain_names'] = [ form.get_widget('domain_name').parse() ] + get_publisher().cfg['sites_url_scheme'] = form.get_widget('sites_url_scheme').parse() + get_publisher().write_cfg() + + def apache2_configuration_generation [html] (self): + get_publisher().reload_cfg() + + form = Form(enctype='multipart/form-data') + form.add(CheckboxWidget, 'allow_config_generation', + title=_('Automatically generate Apache 2 configuration for new hosts and reload Apache 2 after changes'), + value = get_publisher().cfg.get(str('allow_config_generation'), True)) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + if form.get_widget('cancel').parse(): + return redirect('.') + if not form.is_submitted() or form.has_errors(): + html_top('settings', title = _('Apache 2 configuration generation')) + '

%s

' % _('Apache 2 configuration generation') + form.render() + else: + self.apache2_configuration_generation_submit(form) + redirect('.') + + def apache2_configuration_generation_submit(self, form): + get_publisher().reload_cfg() + + f = 'allow_config_generation' + get_publisher().cfg[f] = form.get_widget(f).parse() + + get_publisher().write_cfg() diff --git a/larpe/tags/release-1.1.1/larpe/admin/users.ptl b/larpe/tags/release-1.1.1/larpe/admin/users.ptl new file mode 100644 index 0000000..a0aee01 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/admin/users.ptl @@ -0,0 +1,276 @@ +import random + +import lasso + +from quixote import get_request, get_session, redirect, get_publisher +from quixote.directory import Directory + +from qommon.admin.menu import html_top, error_page, command_icon +from qommon.errors import EmailError +from qommon.form import * +from qommon import emails + +from larpe import errors +from larpe import misc +from larpe.users import User +from larpe.hosts import Host + +class UserUI: + def __init__(self, user): + self.user = user + + def form_new(self): + form = Form(enctype="multipart/form-data") + form.add(StringWidget, "name", title = _('User Name'), required = True, size=30) + form.add(StringWidget, "email", title = _('Email'), required = False, size=30) + form.add_submit("submit", _("Submit")) + form.add_submit("cancel", _("Cancel")) + return form + + def form_edit(self): + form = Form(enctype="multipart/form-data") + form.add(StringWidget, "name", title = _('User Name'), required = True, size=30, + value = self.user.name) + form.add(StringWidget, "email", title = _('Email'), required = False, size=30, + value = self.user.email) + form.add_submit("submit", _("Submit")) + form.add_submit("cancel", _("Cancel")) + return form + + def submit_form(self, form): + if not self.user: + self.user = User() + for f in ('name', 'email'): + widget = form.get_widget(f) + if widget: + setattr(self.user, f, widget.parse()) + self.user.is_admin = True + self.user.store() + + +class UserPage(Directory): + _q_exports = ['', 'edit', 'delete', 'token'] + + def __init__(self, component): + self.user = User.get(component) + self.user_ui = UserUI(self.user) + get_response().breadcrumb.append((component + '/', self.user.name)) + + def _q_index [html] (self): + html_top('users', '%s - %s' % (_('User'), self.user.name)) + '

%s - %s

' % (_('User'), self.user.name) + '
' + '
%s
' % _('Name') + '
%s
' % self.user.name + if self.user.email: + '
%s
' % _('Email') + '
%s
' % self.user.email +# if self.user.lasso_dump: +# identity = lasso.Identity.newFromDump(self.user.lasso_dump) +# server = misc.get_lasso_server() +# if len(identity.providerIds) and server: +# '

%s

' % _('Liberty Alliance Details') +# '
    ' +# for pid in identity.providerIds: +# provider = server.getProvider(pid) +# label = misc.get_provider_label(provider) +# if label: +# label = '%s (%s)' % (label, pid) +# else: +# label = pid +# federation = identity.getFederation(pid) +# '
  • ' +# _('Account federated with %s') % label +# '
    ' +# if federation.localNameIdentifier: +# _("local: ") + federation.localNameIdentifier.content +# if federation.remoteNameIdentifier: +# _("remote: ") + federation.remoteNameIdentifier.content +# '
  • ' +# '
' + +# # XXX: only display this in debug mode: +# '

%s

' % _('Lasso Identity Dump') +# '
%s
' % self.user.lasso_dump + '
' + + def debug [html] (self): + get_response().breadcrumb.append( ('debug', _('Debug')) ) + html_top('users', 'Debug') + "

Debug - %s

" % self.user.name + "
"
+        self.user.lasso_dump
+        "
" + + def edit [html] (self): + form = self.user_ui.form_edit() + if form.get_widget('cancel').parse(): + return redirect('..') + if not form.is_submitted() or form.has_errors(): + get_response().breadcrumb.append( ('edit', _('Edit')) ) + html_top('users', title = _('Edit User')) + '

%s

' % _('Edit User') + form.render() + else: + self.user_ui.submit_form(form) + return redirect('..') + + def delete [html] (self): + form = Form(enctype="multipart/form-data") + form.widgets.append(HtmlWidget('

%s

' % _( + "You are about to irrevocably delete this user."))) + form.add_submit("submit", _("Submit")) + form.add_submit("cancel", _("Cancel")) + if form.get_widget('cancel').parse(): + return redirect('..') + if not form.is_submitted() or form.has_errors(): + get_response().breadcrumb.append(('delete', _('Delete'))) + html_top('users', title = _('Delete User')) + '

%s %s

' % (_('Deleting User :'), self.user.name) + form.render() + else: + self.user.remove_self() + return redirect('..') + + def token [html] (self): + form = Form(enctype="multipart/form-data", use_tokens = False) + form.add_submit("submit", _("Generate")) + form.add_submit("cancel", _("Cancel")) + request = get_request() + if request.form.has_key('cancel') or request.form.has_key('done'): + return redirect('..') + + get_response().breadcrumb.append(('token', _('Identification Token'))) + + if not form.is_submitted() or form.has_errors(): + html_top('users', title = _('Identification Token')) + '

%s

' % _('Identification Token') + '

%s

' % _('You are about to generate a token than can be used to federate the account.') + '

%s

' % _('After that, you will have the choice to send it to the user by email so that he can federate his accounts.') + if self.user.identification_token: + '

%s

' % _('Note that user has already been issued an identification token : %s') % self.user.identification_token + form.render() + else: + if request.form.has_key('submit'): + html_top('users', title = _('Identification Token')) + token = '-'.join(['%04d' % random.randint(1, 9999) for x in range(4)]) + self.user.identification_token = str(token) + self.user.store() + + '

' + _('Identification Token for %s') % self.user.name + ' : %s

' % self.user.identification_token + + form = Form(enctype="multipart/form-data", use_tokens = False) + form.add_submit('done', _('Done')) + if self.user.email: + form.add_submit("submit-email", _("Send by email")) + form.render() + else: + site_url = '%s://%s%s/token?token=%s' \ + % (request.get_scheme(), request.get_server(), + get_request().environ['SCRIPT_NAME'], self.user.identification_token) + body = _("""You have been given an identification token. + +Your token is %(token)s + +Click on %(url)s to use it. +""") % {'token': self.user.identification_token, 'url': site_url} + try: + emails.email(_('Identification Token'), body, self.user.email) + except EmailError, e: + html_top('users', title = _('Identification Token')) + _('Failed sending email. Check your email configuration.') + '

' % _('Back') + else: + return redirect('..') + +class UsersDirectory(Directory): + + _q_exports = ['', 'new'] + + def _q_index [html] (self): + get_publisher().reload_cfg() + get_response().breadcrumb.append( ('users/', _('Users')) ) + html_top('users', title = _('Users')) + + + if not list(Host.select(lambda x: x.name == 'larpe')): + '

%s

' % _('Liberty support must be setup before creating users.') + else: + """""" % _('New User') + + debug_cfg = get_publisher().cfg.get('debug', {}) + + users = User.select(lambda x: x.name is not None, order_by = 'name') + + '
    ' + for user in users: + '
  • ' + '%s' % user.name + if user.email: + '

    ' + user.email + '

    ' + + '

    ' + command_icon('%s/' % user.id, 'view') + if not user.name_identifiers: + if not user.identification_token: + command_icon('%s/token' % user.id, 'token', + label = _('Identification Token'), icon = 'stock_exec_16.png') + else: + command_icon('%s/token' % user.id, 'token', + label = _('Identification Token (current: %s)') % \ + user.identification_token, + icon = 'stock_exec_16.png') + command_icon('%s/edit' % user.id, 'edit') + command_icon('%s/delete' % user.id, 'remove') + if debug_cfg.get('logger', False): + command_icon('../logger/by_user/%s/' % user.id, 'logs', + label = _('Logs'), icon = 'stock_harddisk_16.png') + '

  • ' + '
' + + def new [html] (self): + get_response().breadcrumb.append( ('users/', _('Users')) ) + get_response().breadcrumb.append( ('new', _('New')) ) + hosts = list(Host.select(lambda x: x.name == 'larpe')) + if not hosts: + return error_page('users', _('Liberty support must be setup before creating users.')) + host = hosts[0] + # XXX: user must be logged in to get here + user_ui = UserUI(None) + # FIXME : should be able to use User.count(). Track fake user creations. + users = User.select(lambda x: x.name is not None) + first_user = (len(users) == 0) + form = user_ui.form_new() + if form.get_widget('cancel').parse(): + return redirect('.') + + if not form.is_submitted() or form.has_errors(): + html_top('users', title = _('New User')) + '

%s

' % _('New User') + form.render() + else: + user_ui.submit_form(form) + if first_user: + session = get_session() + if hasattr(session, str('lasso_dump')): + user_ui.user.name_identifiers = [ session.name_identifier ] + user_ui.user.lasso_dumps = [ session.lasso_anonymous_identity_dump ] + user_ui.user.store() + if misc.get_current_protocol() == lasso.PROTOCOL_SAML_2_0: + get_session().set_user(user_ui.user.id, host.saml2_provider_id) + else: + get_session().set_user(user_ui.user.id, host.provider_id) + return redirect('.') + + def _q_lookup(self, component): + get_response().breadcrumb.append( ('users/', _('Users')) ) + try: + return UserPage(component) + except KeyError: + raise errors.TraversalError() diff --git a/larpe/tags/release-1.1.1/larpe/ctl/__init__.py b/larpe/tags/release-1.1.1/larpe/ctl/__init__.py new file mode 100644 index 0000000..35a5923 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/ctl/__init__.py @@ -0,0 +1,2 @@ +from start import start + diff --git a/larpe/tags/release-1.1.1/larpe/ctl/start.py b/larpe/tags/release-1.1.1/larpe/ctl/start.py new file mode 100644 index 0000000..c404202 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/ctl/start.py @@ -0,0 +1,52 @@ +import socket +import sys +import quixote.server.simple_server + +from qommon.scgi_server import run + +import publisher + +def start(args): + run_function = run + run_kwargs = { + 'port': 3007, + 'script_name': '' + } + http = 0 + + i = 0 + while i < len(args): + if args[i] == '--port': + run_kwargs['port'] = int(args[i+1]) + i += 1 + elif args[i] == '--silent': + sys.stdout = open('/dev/null', 'w') + sys.stderr = open('/dev/null', 'w') + elif args[i] == '--script-name': + run_kwargs['script_name'] = args[i+1] + i += 1 + elif args[i] == '--app-dir': + publisher.LarpePublisher.APP_DIR = args[i+1] + i += 1 + elif args[i] == '--data-dir': + publisher.LarpePublisher.DATA_DIR = args[i+1] + i += 1 + elif args[i] == '--http': + http = 1 + i += 1 + + if http == 1: + run_function = quixote.server.simple_server.run + if run_kwargs['script_name']: + print "--http option is incompatible with --script-name" + del run_kwargs['script_name'] + try: + run_function(publisher.LarpePublisher.create_publisher, **run_kwargs) + except socket.error, err: + if err[0] == 98: + print >> sys.stderr, 'address already in use' + sys.exit(1) + raise + except KeyboardInterrupt: + sys.exit(1) + diff --git a/larpe/tags/release-1.1.1/larpe/errors.ptl b/larpe/tags/release-1.1.1/larpe/errors.ptl new file mode 100644 index 0000000..c1f0274 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/errors.ptl @@ -0,0 +1,15 @@ +from quixote import get_session, get_request, redirect + +from qommon.errors import * + +class AccessUnauthorizedError(AccessError): + def render [html] (self): + session = get_session() + request = get_request() + query = request.get_query() + session.after_url = request.get_url() + if query: + session.after_url += '?' + query + session.after_url = str(session.after_url) + login_url = '%s/liberty/larpe/login' % request.environ['SCRIPT_NAME'] + redirect(login_url) diff --git a/larpe/tags/release-1.1.1/larpe/federations.py b/larpe/tags/release-1.1.1/larpe/federations.py new file mode 100644 index 0000000..e76328f --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/federations.py @@ -0,0 +1,35 @@ +'''Federation object. Configuration variables and utilities''' + +from qommon.storage import StorableObject + +class Federation(StorableObject): + _names = 'federations' + + username = None + password = None + host_id = None + name_identifiers = None + cookies = None + select_fields = {} + + def __init__(self, username, password, host_id, name_identifier, cookies=None, select=None): + select = select or {} + StorableObject.__init__(self) + self.username = username + self.password = password + self.host_id = host_id + self.name_identifiers = [ name_identifier ] + self.cookies = cookies + self.select_fields = select + + def remove_name_identifier(self, name_identifier): + self.name_identifiers.remove(name_identifier) + if not self.name_identifiers: + self.remove_self() + + def set_cookies(self, cookies): + self.cookies = cookies + + def __str__(self): + return 'Federation username : %s, name identifiers : %s, cookies : %s' \ + % (self.username, self.name_identifiers, self.cookies) diff --git a/larpe/tags/release-1.1.1/larpe/field_prefill.py b/larpe/tags/release-1.1.1/larpe/field_prefill.py new file mode 100644 index 0000000..389d887 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/field_prefill.py @@ -0,0 +1,13 @@ +from qommon.storage import StorableObject + +class FieldPrefill(StorableObject): + _names = 'field_prefill' + + form_id = 0 + name = None + xpath = None + number = 1 + raw_xml = False + regexp_match = None + regexp_replacing = None + select_options = {} diff --git a/larpe/tags/release-1.1.1/larpe/form_prefill.py b/larpe/tags/release-1.1.1/larpe/form_prefill.py new file mode 100644 index 0000000..2c4727a --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/form_prefill.py @@ -0,0 +1,10 @@ +from qommon.storage import StorableObject + +class FormPrefill(StorableObject): + _names = 'form_prefill' + + host_id = 0 + name = None + url = None + profile = None + prefix = None diff --git a/larpe/tags/release-1.1.1/larpe/hosts.py b/larpe/tags/release-1.1.1/larpe/hosts.py new file mode 100644 index 0000000..9b48ebb --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/hosts.py @@ -0,0 +1,136 @@ +'''Host object. Configuration variables and utilities''' + +import os +from shutil import rmtree + +from quixote import get_request + +from qommon.storage import StorableObject + +from Defaults import APP_DIR + +def get_proxied_site_name(): + nb_subdirs = get_request().environ['SCRIPT_NAME'].count('/') + return get_request().get_path().split('/')[nb_subdirs + 2] + +class Host(StorableObject): + '''Host object. Configuration variables and utilities''' + _names = 'hosts' + + # Main settings + label = None + name = None + orig_site = None + new_url = None + scheme = None + auth_url = None + auth_form_places = 'form_once' + auth_form_page_url = None + auth_form = None + auth_form_url = None + logout_url = None + reversed_hostname = None + reversed_directory = None + organization_name = None + use_ssl = False + private_key = None + public_key = None + site_dir = None + + # Auto detected settings + auth_mode = 'form' + auth_form_action = None + auth_check_url = None + login_field_name = None + password_field_name = None + select_fields = {} + post_parameters = {} + http_headers = {} + + # Advanced settings + return_url = '/' + root_url = '/' + auth_system = 'password' + auth_match_text = '' + send_hidden_fields = True + initiate_sso_url = None + redirect_root_to_login = False + + # Other attributes + provider_id = None + # Default value that indicates the proxy (if configured) is not disabled for this host yet + use_proxy = True + + valid_username = None + valid_password = None + apache_output_filters = [] + apache_output_python_filters = [] + apache_python_paths = [] + + # Plugins + # If name is set to None, use the default site authentication class + site_authentication_plugin = None + + def get_host_from_url(cls): + try: + host = list(Host.select(lambda x: x.name == get_proxied_site_name()))[0] + if hasattr(host, 'site_authentication_instance'): + del host.site_authentication_instance + return list(Host.select(lambda x: x.name == get_proxied_site_name()))[0] + except IndexError: + return None + get_host_from_url = classmethod(get_host_from_url) + + def get_host_with_provider_id(cls, provider_id): + try: + return list(Host.select(lambda x: x.provider_id == provider_id))[0] + except IndexError: + return None + get_host_with_provider_id = classmethod(get_host_with_provider_id) + + def get_root_url(self): + if self.root_url.startswith('/'): + if self.reversed_directory: + return '%s/%s%s' % (get_request().environ['SCRIPT_NAME'], + self.reversed_directory, + self.root_url) + else: + return '%s%s' % (get_request().environ['SCRIPT_NAME'], self.root_url) + # In this case, must be a full url + return self.root_url + + def get_return_url(self): + if self.return_url.startswith('/'): + if self.reversed_directory: + return '%s/%s%s' % (get_request().environ['SCRIPT_NAME'], + self.reversed_directory, + self.return_url) + else: + return '%s%s' % (get_request().environ['SCRIPT_NAME'], self.return_url) + # In this case, must be a full url + return self.return_url + + def __cmp__(self, other): + hostname_cmp = cmp(self.reversed_hostname, other.reversed_hostname) + if hostname_cmp != 0: + return hostname_cmp + return cmp(self.reversed_directory, other.reversed_directory) + + def remove_self(self): + # Main configuration file + StorableObject.remove_self(self) + # Other generated files + if self.site_dir and os.path.exists(self.site_dir): + rmtree(self.site_dir, ignore_errors=1) + # Also remove hostname directory if empty (meaning there was no other subdirectory + # for this hostname) + try: + os.rmdir('/'.join(self.site_dir.split('/')[:-1])) + except OSError: + pass + # Virtual host directory + if self.reversed_hostname: + path = os.path.join(APP_DIR, self.reversed_hostname) + if os.path.exists(path): + rmtree(path, ignore_errors=1) + diff --git a/larpe/tags/release-1.1.1/larpe/idwsf2.ptl b/larpe/tags/release-1.1.1/larpe/idwsf2.ptl new file mode 100644 index 0000000..fbf807f --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/idwsf2.ptl @@ -0,0 +1,199 @@ +import os +import sys +import re + +try: + import lasso +except ImportError: + print >> sys.stderr, 'Missing Lasso module, IdWsf 2.0 support disabled' +else: + if not lasso.WSF_SUPPORT: + print >> sys.stderr, 'Found Lasso module, but IdWsf 2.0 support not enabled' + +from quixote import get_publisher, get_session, get_request, get_response, redirect +from quixote.directory import Directory + +from qommon.liberty import SOAPException, soap_call +from qommon import template +from qommon.misc import http_get_page + +import misc +from form_prefill import FormPrefill +from field_prefill import FieldPrefill + +def cleanup_html_value(value): + # Ensure the field value can be properly integrated in HTML code + value = value.replace('"', "'") + # Conversion to iso-8859-1 + try: + value = unicode(value, 'utf-8').encode('iso-8859-1') + except UnicodeEncodeError: + return None + +class IdWsf2(Directory): + _q_exports = [] + + def _q_lookup(self, component): + if not hasattr(get_session(), 'prefill_form'): + get_session().prefill_form = component + get_session().after_url = get_request().get_url() + if get_request().get_query(): + get_session().after_url += '?' + get_request().get_query() + return redirect('../saml/login') + else: + prefill_form = FormPrefill.get(get_session().prefill_form) + del get_session().prefill_form + if prefill_form: + try: + response, status, page, auth_header = http_get_page(prefill_form.url) + except: + return template.error_page(_('Failed connecting to the original site.')) + try: + fields = self.do_prefill_form(prefill_form) + if not fields: + raise lasso.Error + for key, value in get_request().get_fields().iteritems(): + value = cleanup_html_value(value) + if value: + fields[key] = value + except lasso.Error: + return page + '' % \ + _('Failed getting attributes from the attribute provider.') + except: + return page + '' % \ + _('Failed getting attributes for an unknown reason.') + + return self.send_prefilled_form(prefill_form, page, fields) + + def do_prefill_form(self, prefill_form): + server = misc.get_lasso_server(protocol = 'saml2') + disco = lasso.IdWsf2Discovery(server) + if not get_session().lasso_session_dumps or not get_session().lasso_session_dumps[server.providerId]: + return None + disco.setSessionFromDump(get_session().lasso_session_dumps[server.providerId]) + + disco.initQuery() + disco.addRequestedServiceType(prefill_form.profile) + disco.buildRequestMsg() + + try: + soap_answer = soap_call(disco.msgUrl, disco.msgBody) + except SOAPException: + return None + disco.processQueryResponseMsg(soap_answer) + + service = disco.getService() + lasso.registerIdWsf2DstService(prefill_form.prefix, prefill_form.profile) + + service.initQuery() + + fields = FieldPrefill.select(lambda x: x.form_id == prefill_form.id) + for field in fields: + if field.xpath and field.name: + service.addQueryItem(field.xpath, field.name) + + service.buildRequestMsg() + + try: + soap_answer = soap_call(service.msgUrl, service.msgBody) + except SOAPException: + return None + service.processQueryResponseMsg(soap_answer) + + fields_dict = {} + for field in fields: + if not field.xpath or not field.name: + continue + if field.number > 0: + number = field.number -1 + try: + if field.raw_xml: + value = service.getAttributeNodes(field.name)[number] + else: + value = service.getAttributeStrings(field.name)[number] + except (IndexError, TypeError): + value = '' + # Log + if value: + # Regexp transformation + if field.regexp_match: + value = re.sub(field.regexp_match, field.regexp_replacing, value) + value = cleanup_html_value(value) + # Conversion of select field options + if field.select_options: + try: + value = field.select_options[value] + except (IndexError, KeyError): + pass + if not value: + continue + fields_dict[field.name] = value + + return fields_dict + + def send_prefilled_form(self, prefill_form, page, fields): + for field_name, new_value in fields.iteritems(): + # Input + regex = re.compile('(.*)(]*? id="%s".*?>)(.*)' % field_name, + re.DOTALL | re.IGNORECASE) + match = regex.match(page) + if not match: + regex = re.compile('(.*)(]*? name="%s".*?>)(.*)' % field_name, + re.DOTALL | re.IGNORECASE) + match = regex.match(page) + if match: + before, input_field, after = match.groups() + if 'value="' in input_field.lower(): + regex_sub = re.compile('value=".*?"', re.DOTALL | re.IGNORECASE) + input_field = regex_sub.sub('value="%s"' % new_value, input_field) + else: + input_field = input_field.replace(']*? id="%s".*?>)[^<]*(.*)' % field_name, + re.DOTALL | re.IGNORECASE) + match = regex.match(page) + if not match: + regex = re.compile('(.*]*? name="%s".*?>)[^<]*(.*)' % field_name, + re.DOTALL | re.IGNORECASE) + match = regex.match(page) + if match: + before, after = match.groups() + page = ''.join([before, new_value, after]) + continue + + # Select + regex = re.compile('(.*]*? id="%s".*?>)(.*?)(.*)' % field_name, + re.DOTALL | re.IGNORECASE) + match = regex.match(page) + if not match: + regex = re.compile('(.*]*? name="%s".*?>)(.*?)(.*)' % field_name, + re.DOTALL | re.IGNORECASE) + match = regex.match(page) + if match: + before, options, after = match.groups() + # If the option to select is found, first unselect the previoulsy selected one + regex2 = re.compile('(.*]*? value="%s".*?)(>[^<]*.*)' % new_value, + re.DOTALL | re.IGNORECASE) + match2 = regex2.match(options) + if match2: + before2, after2 = match2.groups() + regex3 = re.compile('(.*]*?)( selected(="selected")?)(.*?>[^<]*.*)', + re.DOTALL | re.IGNORECASE) + match3 = regex3.match(options) + if match3: + before3, selected, selected_value, after3 = match3.groups() + options = ''.join([before3, after3]) + regex2 = re.compile('(.*]*? value="%s".*?)(>[^<]*.*)' % new_value, + re.DOTALL | re.IGNORECASE) + match2 = regex2.match(options) + if match2: + before2, after2 = match2.groups() + options = ''.join([before2, ' selected="selected"', after2]) + + page = ''.join([before, options, after]) + + return page + diff --git a/larpe/tags/release-1.1.1/larpe/liberty.ptl b/larpe/tags/release-1.1.1/larpe/liberty.ptl new file mode 100644 index 0000000..193dd19 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/liberty.ptl @@ -0,0 +1,372 @@ +import libxml2 +import urllib +import urlparse +import httplib +import re +import os + +from quixote import get_field, get_request, get_response, get_session, get_session_manager, redirect +from quixote.directory import Directory +from quixote.http_request import parse_header + +import lasso + +from qommon import get_logger +from qommon.form import * +from qommon.template import * +from qommon.liberty import soap_call, SOAPException + +import misc +from users import User +from hosts import Host +from federations import Federation +import site_authentication + +class Liberty(Directory): + _q_exports = ['', 'login', 'assertionConsumer', 'soapEndpoint', + 'singleLogout', 'singleLogoutReturn', + 'federationTermination', 'federationTerminationReturn', + ('metadata.xml', 'metadata'), 'public_key', 'local_auth'] + + def perform_login(self, idp = None): + server = misc.get_lasso_server() + login = lasso.Login(server) + login.initAuthnRequest(idp, lasso.HTTP_METHOD_REDIRECT) + login.request.nameIdPolicy = 'federated' + login.request.forceAuthn = False + login.request.isPassive = False + login.request.consent = 'urn:liberty:consent:obtained' + login.buildAuthnRequestMsg() + return redirect(login.msgUrl) + + def assertionConsumer(self): + server = misc.get_lasso_server() + if not server: + return error_page(_('Liberty support is not yet configured')) + login = lasso.Login(server) + request = get_request() + if request.get_method() == 'GET' or get_field('LAREQ'): + if request.get_method() == 'GET': + login.initRequest(request.get_query(), lasso.HTTP_METHOD_REDIRECT) + else: + login.initRequest(get_field('LAREQ'), lasso.HTTP_METHOD_POST) + + login.buildRequestMsg() + try: + soap_answer = soap_call(login.msgUrl, login.msgBody) + except SOAPException: + return error_page(_('Failure to communicate with identity provider')) + try: + login.processResponseMsg(soap_answer) + except lasso.Error, error: + if error[0] == lasso.LOGIN_ERROR_STATUS_NOT_SUCCESS: + return error_page(_('Unknown authentication failure')) + if hasattr(lasso, 'LOGIN_ERROR_UNKNOWN_PRINCIPAL'): + if error[0] == lasso.LOGIN_ERROR_UNKNOWN_PRINCIPAL: + return error_page(_('Authentication failure; unknown principal')) + return error_page(_("Identity Provider didn't accept artifact transaction.")) + else: + login.processAuthnResponseMsg(get_field('LARES')) + login.acceptSso() + session = get_session() + if login.isSessionDirty: + if login.session: + session.lasso_session_dumps[server.providerId] = login.session.dump() + else: + session.lasso_session_dumps[server.providerId] = None + + # Look for an existing user + user = self.lookup_user(session, login) + + # Check if it is for Larpe administration or token + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + if host.name == 'larpe': + if user: + session.set_user(user.id, server.providerId) + else: + session.name_identifier = login.nameIdentifier.content + session.lasso_anonymous_identity_dump = login.identity.dump() + session.provider_id = server.providerId + + if session.after_url: + # Access to an admin page or token url with parameter + after_url = session.after_url + session.after_url = None + return redirect(after_url) + + if user and user.is_admin: + return redirect('%s/admin/' % get_request().environ['SCRIPT_NAME']) + else: + return redirect('%s/token' % get_request().environ['SCRIPT_NAME']) + + # Set session user + if not user: + user = User() + user.name_identifiers = [ login.nameIdentifier.content ] + user.lasso_dumps = [ login.identity.dump() ] + user.store() + session.set_user(user.id, server.providerId) + + federations = Federation.select(lambda x: host.id == x.host_id \ + and user.name_identifiers[0] in x.name_identifiers) + + if federations: + return site_authentication.get_site_authentication(host).sso_local_login(federations[0]) + else: + response = get_response() + if session.after_url: + after_url = session.after_url + session.after_url = None + return redirect(after_url) + response.set_status(303) + response.headers['location'] = urlparse.urljoin(request.get_url(), str('local_auth')) + response.content_type = 'text/plain' + return 'Your browser should redirect you' + + def lookup_user(self, session, login): + found_users = list(User.select(lambda x: login.nameIdentifier.content in x.name_identifiers)) + if found_users: + return found_users[0] + return None + + def singleLogout(self): + request = get_request() + logout = lasso.Logout(misc.get_lasso_server()) + if lasso.isLibertyQuery(request.get_query()): + try: + logout.processRequestMsg(request.get_query()) + except lasso.Error, error: + if error[0] == lasso.DS_ERROR_INVALID_SIGNATURE: + return error_page(_('Failed to check single logout request signature.')) + raise + session = get_session() + if not session.id: + # session has not been found, this may be because the user has + # its browser configured so that cookies are not sent for + # remote queries and IdP is using image-based SLO. + # so we look up a session with the appropriate name identifier + for session in get_session_manager().values(): + # This block differs from qommon + user = session.get_user(logout.server.providerId) + if user and logout.nameIdentifier.content in user.name_identifiers: + break + else: + session = get_session() + return self.slo_idp(logout, session) + else: + return self.slo_sp(logout, get_session()) + + def singleLogoutReturn(self): + logout = lasso.Logout(misc.get_lasso_server()) + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + + try: + logout.processResponseMsg(get_request().get_query()) + except lasso.Error, error: + if error[0] == lasso.PROFILE_ERROR_INVALID_QUERY: + raise AccessError() + if error[0] == lasso.DS_ERROR_INVALID_SIGNATURE: + return error_page(_('Failed to check single logout request signature.')) + if hasattr(lasso, 'LOGOUT_ERROR_REQUEST_DENIED') and \ + error[0] == lasso.LOGOUT_ERROR_REQUEST_DENIED: + return redirect(host.get_root_url()) # ignore silently + elif error[0] == lasso.ERROR_UNDEFINED: + # XXX: unknown status; ignoring for now. + return redirect(host.get_root_url()) # ignore silently + raise + return redirect(host.get_root_url()) + + def slo_idp(self, logout, session): + '''Single Logout initiated by IdP''' + # This block differs from qommon + if session.lasso_session_dumps.has_key(logout.server.providerId): + logout.setSessionFromDump(session.lasso_session_dumps[logout.server.providerId]) + user = session.get_user(logout.server.providerId) + if user and user.lasso_dumps: + logout.setIdentityFromDump(user.lasso_dumps[0]) + if user and logout.nameIdentifier.content not in user.name_identifiers: + raise 'No appropriate name identifier in user (%s and %s)' % ( + logout.nameIdentifier.content, user.name_identifiers) + + host = Host.get_host_with_provider_id(logout.server.providerId) + if host is not None: + site_authentication.get_site_authentication(host).local_logout(user=user) + + try: + logout.validateRequest() + except lasso.Error, error: + if error[0] != lasso.PROFILE_ERROR_SESSION_NOT_FOUND: + raise + else: + get_session_manager().expire_session(logout.server.providerId) + + logout.buildResponseMsg() + if logout.msgBody: # soap answer + return logout.msgBody + else: + return redirect(logout.msgUrl) + + def slo_sp(self, logout, session): + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + + if not session.id or not session.users.has_key(logout.server.providerId) \ + or not session.lasso_session_dumps.has_key(logout.server.providerId): + get_session_manager().expire_session(logout.server.providerId) + return redirect(host.get_root_url()) + + logout.setSessionFromDump(session.lasso_session_dumps[logout.server.providerId]) + user = session.get_user(logout.server.providerId) + + if host.name != 'larpe' and user: + site_authentication.get_site_authentication(host).local_logout(user=user) + + if user and user.lasso_dumps: + logout.setIdentityFromDump(user.lasso_dumps[0]) + else: + get_session_manager().expire_session(logout.server.providerId) + return redirect(host.get_root_url()) + + return self.slo_sp_redirect(logout, host) + + def slo_sp_redirect(self, logout, host): + try: + logout.initRequest(None, lasso.HTTP_METHOD_REDIRECT) + except lasso.Error, error: + if error[0] == lasso.PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND: + get_session_manager().expire_session() + return redirect(host.get_root_url()) + raise + logout.buildRequestMsg() + get_session_manager().expire_session(logout.server.providerId) + return redirect(logout.msgUrl) + + def soapEndpoint(self): + request = get_request() + ctype = request.environ.get('CONTENT_TYPE') + if not ctype: + return + + ctype, ctype_params = parse_header(ctype) + if ctype != 'text/xml': + return + + response = get_response() + response.set_content_type('text/xml') + + length = int(request.environ.get('CONTENT_LENGTH')) + soap_message = request.stdin.read(length) + + request_type = lasso.getRequestTypeFromSoapMsg(soap_message) + + if request_type == lasso.REQUEST_TYPE_LOGOUT: + logout = lasso.Logout(misc.get_lasso_server()) + logout.processRequestMsg(soap_message) + name_identifier = logout.nameIdentifier.content + for session in get_session_manager().values(): + user = session.get_user(logout.server.providerId) + if user and logout.nameIdentifier.content in user.name_identifiers: + break + else: + session = None + return self.slo_idp(logout, session) + + if request_type == lasso.REQUEST_TYPE_DEFEDERATION: + defederation = lasso.Defederation(misc.get_lasso_server()) + defederation.processNotificationMsg(soap_message) + for session in get_session_manager().values(): + user = session.get_user(defederation.server.providerId) + if user and defederation.nameIdentifier.content in user.name_identifiers: + break + else: + session = None + return self.fedterm(defederation, session) + + def federationTermination(self): + request = get_request() + if not lasso.isLibertyQuery(request.get_query()): + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + + defederation = lasso.Defederation(misc.get_lasso_server()) + defederation.processNotificationMsg(request.get_query()) + return self.fedterm(defederation, get_session()) + + def fedterm(self, defederation, session): + if session is not None: + host = Host.get_host_with_provider_id(defederation.server.providerId) + if host is not None: + site_authentication.get_site_authentication(host).local_defederate(session, defederation.server.providerId) + if session.lasso_session_dumps.has_key(defederation.server.providerId): + defederation.setSessionFromDump(session.lasso_session_dumps[defederation.server.providerId]) + user = session.get_user(defederation.server.providerId) + if user and user.lasso_dumps: + defederation.setIdentityFromDump(user.lasso_dumps[0]) + else: + user = None + + try: + defederation.validateNotification() + except lasso.Error, error: + pass # ignore failure (?) + else: + if user: + if not defederation.identity: + # if it was the last federation the whole identity dump collapsed + del user.lasso_dumps[0] + else: + user.lasso_dumps[0] = defederation.identity.dump() + user.store() + + if user and defederation.nameIdentifier.content: + user.remove_name_identifier(defederation.nameIdentifier.content) + user.store() + + if defederation.isSessionDirty and session is not None: + if not defederation.session: + del session.lasso_session_dumps[defederation.server.providerId] + else: + session.lasso_session_dumps[defederation.server.providerId] = defederation.session.dump() + session.store() + + get_session_manager().expire_session(defederation.server.providerId) + + if defederation.msgUrl: + return redirect(defederation.msgUrl) + else: + response = get_response() + response.set_status(204) + return '' + + def federationTerminationReturn(self): + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + return redirect(host.get_return_url()) + + def local_auth(self): + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + return site_authentication.get_site_authentication(host).local_auth + local_auth = property(local_auth) + + def metadata(self): + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + get_response().set_content_type('text/xml', 'utf-8') + metadata = unicode(open(host.metadata).read(), 'utf-8') + return metadata + + def public_key(self): + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + get_response().set_content_type('text/plain') + public_key = open(host.public_key).read() + return public_key diff --git a/larpe/tags/release-1.1.1/larpe/liberty_root.ptl b/larpe/tags/release-1.1.1/larpe/liberty_root.ptl new file mode 100644 index 0000000..f15c953 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/liberty_root.ptl @@ -0,0 +1,9 @@ +from quixote.directory import Directory +from quixote import get_response + +from liberty_site import LibertySite + +class LibertyRootDirectory(Directory): + + def _q_lookup(self, component): + return LibertySite(component) diff --git a/larpe/tags/release-1.1.1/larpe/liberty_site.ptl b/larpe/tags/release-1.1.1/larpe/liberty_site.ptl new file mode 100644 index 0000000..b247a4c --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/liberty_site.ptl @@ -0,0 +1,68 @@ +import sys +import random + +from quixote import get_publisher, get_response, redirect, get_request +from quixote.directory import Directory +from quixote.errors import TraversalError + +import lasso + +import admin +import liberty +import saml2 +import idwsf2 +import httplib +import urllib + +from qommon.form import * +from qommon.misc import get_abs_path, get_current_protocol +from qommon import template, get_logger + +import errors +import misc + +from users import User +from hosts import Host + +class LibertySite(Directory): + + _q_exports = ['', 'login', 'logout', 'liberty', 'saml', 'idwsf2'] + + liberty = liberty.Liberty() + saml = saml2.Saml2() + idwsf2 = idwsf2.IdWsf2() + + def __init__(self, component): + self.name = component + + def _q_index (self): + raise errors.TraversalError() + + def login [html] (self): + get_logger().info('login') + get_publisher().reload_cfg() + + if not get_publisher().cfg.has_key('idp'): + return template.error_page(_('SSO support is not yet configured')) + else: + server = misc.get_lasso_server('liberty') + if server is not None: + return self.liberty.perform_login() + + server = misc.get_lasso_server('saml2') + if server is not None: + return self.saml.perform_login() + + return template.error_page(_('SSO support is not yet configured')) + + def logout(self): + get_logger().info('logout') + session = get_session() + if not session: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + + if misc.get_current_protocol() == lasso.PROTOCOL_SAML_2_0: + return self.saml.slo_sp() + else: + return self.liberty.singleLogout() + diff --git a/larpe/tags/release-1.1.1/larpe/logger.py b/larpe/tags/release-1.1.1/larpe/logger.py new file mode 100644 index 0000000..3849613 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/logger.py @@ -0,0 +1,34 @@ +import logging + +from quixote import get_request, get_session + +from qommon.logger import BotFilter + +from hosts import Host + +class Formatter(logging.Formatter): + def format(self, record): + request = get_request() + + record.address = request.get_environ('REMOTE_ADDR', '-') + record.path = request.get_path() + record.session_id = get_session().get_session_id() or '[nosession]' + + user = None + host = Host.get_host_from_url() + if not host: + host = Host.select(lambda x: x.name == 'larpe')[0] + if host: + user = get_session().get_user(host.provider_id) + if not user: + user = get_session().get_user(host.saml2_provider_id) + + if user: + user_id = user.id + else: + user_id = 'unlogged' + if BotFilter.is_bot(): + user_id = 'bot' + record.user_id = user_id + + return logging.Formatter.format(self, record) diff --git a/larpe/tags/release-1.1.1/larpe/misc.py b/larpe/tags/release-1.1.1/larpe/misc.py new file mode 100644 index 0000000..15492a5 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/misc.py @@ -0,0 +1,105 @@ +import re +import os + +import lasso + +from quixote import get_publisher, get_request + +from qommon.misc import get_abs_path + +from hosts import Host + +def get_root_url(): + req = get_request() + return '%s://%s%s' % (req.get_scheme(), req.get_server(), req.environ['SCRIPT_NAME']) + +def get_proxied_site_path(): + host = Host.get_host_from_url() + if host is None: + return None + return host.site_dir + +def get_proxied_site_domain(): + return get_request().get_server().split(':')[0] + +def get_identity_provider_config(): + get_publisher().reload_cfg() + idps_dir = get_abs_path('idp') + if get_publisher().cfg.has_key('idp'): + idp_dir = os.path.join(idps_dir, get_publisher().cfg['idp']) + + metadata_path = os.path.join(idp_dir, 'metadata.xml') + + public_key_path = os.path.join(idp_dir, 'public_key') + if not os.path.isfile(public_key_path): + public_key_path = None + + ca_cert_chain_path = os.path.join(idp_dir, 'ca_cert_chain.pem') + if not os.path.isfile(ca_cert_chain_path): + ca_cert_chain_path = None + + return metadata_path, public_key_path, ca_cert_chain_path + return None, None, None + +def get_lasso_server(protocol='liberty'): + proxied_site_path = get_proxied_site_path() + if proxied_site_path is None: + return None + if protocol == 'liberty': + server = lasso.Server( + os.path.join(proxied_site_path, 'metadata.xml'), + os.path.join(proxied_site_path, 'private_key.pem'), + None, None) + elif protocol == 'saml2': + server = lasso.Server( + os.path.join(proxied_site_path, 'saml2_metadata.xml'), + os.path.join(proxied_site_path, 'private_key.pem'), + None, None) + else: + raise 'Unknown protocol' + + metadata_path, public_key_path, ca_cert_chain_path = get_identity_provider_config() + if metadata_path: + try: + server.addProvider( + lasso.PROVIDER_ROLE_IDP, + metadata_path, + public_key_path, + ca_cert_chain_path) + except lasso.Error, error: + if error[0] == lasso.SERVER_ERROR_ADD_PROVIDER_PROTOCOL_MISMATCH: + return None + if error[0] == lasso.SERVER_ERROR_ADD_PROVIDER_FAILED: + return None + raise + + return server + +def get_provider_label(provider): + if not provider: + return None + if not hasattr(provider, str('getOrganization')): + return provider.providerId + + organization = provider.getOrganization() + if not organization: + return provider.providerId + + name = re.findall("(.*?)", organization) + if not name: + name = re.findall("(.*?)", organization) + if not name: + return provider.providerId + return name[0] + +def get_current_protocol(): + metadata_path, public_key_path, ca_cert_chain_path = get_identity_provider_config() + if not metadata_path: + return None + try: + provider = lasso.Provider(lasso.PROVIDER_ROLE_IDP, metadata_path, public_key_path, None) + except lasso.Error: + return None + else: + return provider.getProtocolConformance() + diff --git a/larpe/tags/release-1.1.1/larpe/plugins/__init__.py b/larpe/tags/release-1.1.1/larpe/plugins/__init__.py new file mode 100644 index 0000000..0233184 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/plugins/__init__.py @@ -0,0 +1,3 @@ +from larpe.plugins.site_authentication_plugins import SiteAuthenticationPlugins + +site_authentication_plugins = SiteAuthenticationPlugins() diff --git a/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/__init__.py b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/agirhe.py b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/agirhe.py new file mode 100644 index 0000000..d3c0f2b --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/agirhe.py @@ -0,0 +1,142 @@ +import re +import urllib + +from quixote import get_request, get_response, get_session + +from qommon.misc import http_post_request +from qommon.errors import ConnectionError +from qommon import get_logger + +from larpe.qommon.misc import http_get_page +from larpe.plugins import site_authentication_plugins +from larpe.site_authentication import SiteAuthentication + +class AgirheSiteAuthentication(SiteAuthentication): + plugin_name = 'agirhe' + + def auto_detect_site(cls, html_doc): + if re.search( + """""", re.DOTALL | re.IGNORECASE) + found_forms = regexp.findall(page) + if not found_forms: + return + + # Get the first form with a password field + for found_form in found_forms: + regexp = re.compile( + """]*?type=["']?password["']?[^>]*?>""", re.DOTALL | re.IGNORECASE) + if regexp.search(found_form) is not None: + self.host.auth_form = found_form + break + + def parse_other_fields(self): + '''Get the default value of all other fields''' + self.host.other_fields = {} + + # Get hidden fields + regexp = re.compile( + """]*?type=["']?hidden["']?[^>]*?>""", re.DOTALL | re.IGNORECASE) + other_fields = regexp.findall(self.host.auth_form) + + # Only get first submit field + regexp = re.compile( + """]*?type=["']?submit["']?[^>]*?>""", re.DOTALL | re.IGNORECASE) + found = regexp.findall(self.host.auth_form) + if found: + if other_fields: + other_fields.append(found[0]) + else: + other_fields = found[0] + + for field in other_fields: + try: + regexp = re.compile("""name=["']?(.*?)["']?[\s/>]""", re.DOTALL | re.IGNORECASE) + name = regexp.findall(field)[0] + regexp = re.compile("""value=["'](.*?)["'][\s/>]""", re.DOTALL | re.IGNORECASE) + value = regexp.findall(field)[0] + self.host.other_fields[name] = value + if not self.host.post_parameters.has_key(name): + self.host.post_parameters[name] = { 'enabled': True, + 'value': value, + 'immutable': False } + except IndexError: + continue + +site_authentication_plugins.register(AgirheSiteAuthentication) diff --git a/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/ciril_net_rh.py b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/ciril_net_rh.py new file mode 100644 index 0000000..417804c --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/ciril_net_rh.py @@ -0,0 +1,44 @@ + +import re + +from quixote import redirect + +from larpe.plugins import site_authentication_plugins +from larpe.site_authentication import SiteAuthentication + +class CirilSiteAuthentication(SiteAuthentication): + + plugin_name = 'ciril' + output_filters = ['output_ciril_net_rh'] + + def auto_detect_site(cls, html_doc): + if re.search( + """
""", + html_doc): + return True + return False + auto_detect_site = classmethod(auto_detect_site) + + def local_auth_check_post(self, username, password, select=None, session_cookies=False): + select = select or {} + url = self.host.auth_check_url + + # Build request body + body = '%s=%s&%s=%s' % ( + self.host.login_field_name, username, self.host.password_field_name, password) + # Add select fields to the body + for name, value in select.iteritems(): + body += '&%s=%s' % (name, value) + # Add hidden fields to the body + if self.host.send_hidden_fields: + for key, value in self.host.other_fields.iteritems(): + body += '&%s=%s' % (key, value) + + # Build request HTTP headers + headers = {'Content-Type': 'application/x-www-form-urlencoded', + 'X-Forwarded-For': get_request().get_environ('REMOTE_ADDR', '-'), + 'X-Forwarded-Host': self.host.reversed_hostname} + + # Add session id cookie + if session_cookies is True: + for key, value in self.host.other_fields.iteritems(): + headers['Cookie'] = 'JSESSIONID=' + value + + # Send request + response, status, data, auth_headers = http_post_request( + url, body, headers, self.host.use_proxy) + + cookies = response.getheader('Set-Cookie', None) + self.host.cookies = [] + new_session_id = None + if cookies is not None: + cookies_list = [] + cookies_set_list = [] + for cookie in cookies.split(', '): + # Drop the path and other attributes + cookie_only = cookie.split('; ')[0] + regexp = re.compile('=') + if regexp.search(cookie_only) is None: + continue + # Split name and value + cookie_split = cookie_only.split('=') + cookie_name = cookie_split[0] + cookie_value = cookie_split[1] + if cookie_name == 'JSESSIONID': + new_session_id = cookie_value + cookies_list.append('%s=%s' % (cookie_name, cookie_value)) + set_cookie = '%s=%s; path=/demo' % (cookie_name, cookie_value) + cookies_set_list.append(set_cookie) + self.host.cookies.append(cookie_name) + cookies_headers = '\r\nSet-Cookie: '.join(cookies_set_list) + get_response().set_header('Set-Cookie', cookies_headers) + self.host.store() + get_session().cookies = '; '.join(cookies_list) + else: + get_logger().warn('No cookie from local authentication') + + if session_cookies is False: + # Change idSession hidden field with new session id + self.host.other_fields['idSession'] = new_session_id + # Retry the request with the new session id + return self.local_auth_check_post(username, password, select, session_cookies=True) + else: + return response.status, data + +site_authentication_plugins.register(ConcertoSiteAuthentication) + diff --git a/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/egroupware.py b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/egroupware.py new file mode 100644 index 0000000..9b58634 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/egroupware.py @@ -0,0 +1,91 @@ +import re +import urlparse + +from quixote import get_request, get_response, get_session + +from qommon.misc import http_post_request, http_get_page +from qommon import get_logger + +from larpe.plugins import site_authentication_plugins +from larpe.site_authentication import SiteAuthentication + +class EgroupwareSiteAuthentication(SiteAuthentication): + plugin_name = 'egroupware' + + def auto_detect_site(cls, html_doc): + if re.search("""""", html_doc): + return True + return False + auto_detect_site = classmethod(auto_detect_site) + + def local_auth_check_post(self, username, password, select=None): + select = select or {} + url = self.host.auth_check_url + + # Build request body + body = '%s=%s&%s=%s' % ( + self.host.login_field_name, username, self.host.password_field_name, password) + # Add select fields to the body + for name, value in select.iteritems(): + body += '&%s=%s' % (name, value) + # Add hidden fields to the body + if self.host.send_hidden_fields: + for key, value in self.host.other_fields.iteritems(): + body += '&%s=%s' % (key, value) + + # Build request HTTP headers + headers = {'Content-Type': 'application/x-www-form-urlencoded', + 'X-Forwarded-For': get_request().get_environ('REMOTE_ADDR', '-'), + 'X-Forwarded-Host': self.host.reversed_hostname} + + # Send request + response, status, data, auth_headers = http_post_request( + url, body, headers, self.host.use_proxy) + + # The specific code is these 2 lines and the called function + if self.host.name.startswith('egroupware'): + data = self.get_data_after_redirects(response, data) + + cookies = response.getheader('Set-Cookie', None) + self.host.cookies = [] + if cookies is not None: + cookies_list = [] + cookies_set_list = [] + for cookie in cookies.split(', '): + # Drop the path and other attributes + cookie_only = cookie.split('; ')[0] + regexp = re.compile('=') + if regexp.search(cookie_only) is None: + continue + # Split name and value + cookie_split = cookie_only.split('=') + cookie_name = cookie_split[0] + cookie_value = cookie_split[1] + cookies_list.append('%s=%s' % (cookie_name, cookie_value)) + set_cookie = '%s=%s; path=/' % (cookie_name, cookie_value) + cookies_set_list.append(set_cookie) + self.host.cookies.append(cookie_name) + cookies_headers = '\r\nSet-Cookie: '.join(cookies_set_list) + get_response().set_header('Set-Cookie', cookies_headers) + self.host.store() + get_session().cookies = '; '.join(cookies_list) + else: + get_logger().warn('No cookie from local authentication') + + return response.status, data + + def get_data_after_redirects(self, response, data): + status = response.status + headers = {'X-Forwarded-For': get_request().get_environ('REMOTE_ADDR', '-'), + 'X-Forwarded-Host': self.host.reversed_hostname} + while status == 302: + location = response.getheader('Location', None) + if location is not None: + url_tokens = urlparse.urlparse(self.host.auth_check_url) + url = '%s://%s%s'% (url_tokens[0], url_tokens[1], location) + response, status, data, auth_headers = http_get_page( + url, headers, self.host.use_proxy) + return data + +site_authentication_plugins.register(EgroupwareSiteAuthentication) + diff --git a/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/sympa.py b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/sympa.py new file mode 100644 index 0000000..734ba23 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication/sympa.py @@ -0,0 +1,45 @@ +import re + +from quixote import get_response, redirect +from quixote.html import htmltext + +from larpe.plugins import site_authentication_plugins +from larpe.site_authentication import SiteAuthentication + +class SympaSiteAuthentication(SiteAuthentication): + plugin_name = 'sympa' + + def auto_detect_site(cls, html_doc): + if re.search("""""", html_doc): + return True + return False + auto_detect_site = classmethod(auto_detect_site) + + def check_auth(self, status, data): + success = False + return_content = '' + + if self.host.auth_system == 'password': + # If there is a password field, authentication probably failed + regexp = re.compile( + """]*?type=["']?password["']?[^>]*?>""", re.DOTALL | re.IGNORECASE) + if not regexp.findall(data): + success = True + # The specific part is only these 2 lines + get_response().filter.update({'no_template': True}) + return_content = htmltext(data) + elif self.host.auth_system == 'status': + match_status = int(self.host.auth_match_status) + if match_status == status: + success = True + return_content = redirect(self.host.return_url) + elif self.host.auth_system == 'match_text': + # If the auth_match_text is not matched, it means the authentication is successful + regexp = re.compile(self.host.auth_match_text, re.DOTALL) + if not regexp.findall(data): + success = True + return_content = redirect(self.host.get_return_url()) + + return success, return_content + +site_authentication_plugins.register(SympaSiteAuthentication) diff --git a/larpe/tags/release-1.1.1/larpe/plugins/site_authentication_plugins.py b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication_plugins.py new file mode 100644 index 0000000..504b82d --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/plugins/site_authentication_plugins.py @@ -0,0 +1,34 @@ + +class SiteAuthenticationPlugins: + """ This class manages the plugins for site authentification """ + + def __init__(self): + self.site_authentication_classes = dict() + + def register(self, klass): + """ Register a custom SiteAuthentification instance """ + self.site_authentication_classes[klass.plugin_name] = klass + + def get(self, plugin_name): + """ Return a custom SiteAuthentification instance """ + if self.site_authentication_classes.has_key(plugin_name): + return self.site_authentication_classes[plugin_name] + else: + return None + + def get_plugins_name(self): + plugins_name = list() + for plugin_name in self.site_authentication_classes.iterkeys(): + plugins_name.append(plugin_name) + return plugins_name + + def auto_detect(self, html_doc): + """ + Try to find automatically the right plugin name + Return the plugin name or None + """ + for name, klass in self.site_authentication_classes.iteritems(): + if klass.auto_detect_site(html_doc): + return klass.plugin_name + return None + diff --git a/larpe/tags/release-1.1.1/larpe/publisher.py b/larpe/tags/release-1.1.1/larpe/publisher.py new file mode 100644 index 0000000..6c9932f --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/publisher.py @@ -0,0 +1,53 @@ +import os +import cPickle + +from quixote import get_request + +from Defaults import * + +from qommon.publisher import set_publisher_class, QommonPublisher + +from root import RootDirectory +from admin import RootDirectory as AdminRootDirectory + +from sessions import StorageSessionManager +from users import User + +class LarpePublisher(QommonPublisher): + APP_NAME = 'larpe' + APP_DIR = APP_DIR + DATA_DIR = DATA_DIR + ERROR_LOG = ERROR_LOG + WEB_ROOT = WEB_ROOT + + supported_languages = ['fr'] + + root_directory_class = RootDirectory + admin_directory_class = AdminRootDirectory + + session_manager_class = StorageSessionManager + user_class = User + + def get_application_static_files_root_url(self): + return '%s/%s/' % (get_request().environ['SCRIPT_NAME'], WEB_ROOT) + + def set_app_dir(self, request): + self.app_dir = os.path.join(self.APP_DIR, request.get_server().lower().split(':')[0]) + self.reload_cfg() + if self.cfg.has_key('proxy_hostname'): + self.app_dir = os.path.join(self.APP_DIR, self.cfg['proxy_hostname']) + if self.app_dir is not None and not os.path.exists(self.app_dir): + os.mkdir(self.app_dir) + return True + + cfg = None + def write_cfg(self, directory=None): + dump = cPickle.dumps(self.cfg) + if directory is None: + directory = self.app_dir + filename = os.path.join(directory, 'config.pck') + open(filename, 'w').write(dump) + +set_publisher_class(LarpePublisher) +extra_dir = os.path.join(os.path.dirname(__file__), 'plugins','site_authentication') +LarpePublisher.register_extra_dir(extra_dir) diff --git a/larpe/tags/release-1.1.1/larpe/root.ptl b/larpe/tags/release-1.1.1/larpe/root.ptl new file mode 100644 index 0000000..db8408b --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/root.ptl @@ -0,0 +1,106 @@ +import os +import httplib + +import lasso + +from quixote import get_request, get_response, get_session, redirect +from quixote.directory import Directory + +from qommon.form import * +from qommon import template + +import admin +import liberty_root +import errors + +from hosts import Host +from users import User +from Defaults import WEB_ROOT + +class RootDirectory(Directory): + _q_exports = ['', 'admin', 'liberty', 'logout', 'token'] + + admin = admin.RootDirectory() + liberty = liberty_root.LibertyRootDirectory() + + def _q_index [html] (self): + template.html_top(_('Welcome to Larpe reverse proxy')) + '' % (get_request().environ['SCRIPT_NAME'], + _('Configure Larpe')) + + def _q_traverse(self, path): + response = get_response() + response.filter = {} + + return Directory._q_traverse(self, path) + + def _q_lookup(self, component): + return redirect(component + '/') + + def logout(self): + return redirect(get_publisher().get_root_url() + 'liberty/larpe/logout') + + def token [html] (self): + session = get_session() + + if not session.name_identifier or not session.lasso_anonymous_identity_dump: + raise errors.AccessUnauthorizedError() + + # If the token is in the query string, use it + query_string = get_request().get_query() + if query_string: + parameters = query_string.split(str('&')) + for param in parameters: + values = param.split(str('=')) + if len(values) < 2: + continue + if values[0] == str('token'): + return self._federate_token(values[1]) + + # Otherwise, display a form to ask for the token + form = Form(enctype='multipart/form-data') + form.add(StringWidget, 'token', title = _('Identification Token'), + required = True, size = 30) + form.add_submit('submit', _('Submit')) + form.add_submit('cancel', _('Cancel')) + + if form.get_widget('cancel').parse(): + return redirect('.') + + if not form.is_submitted() or form.has_errors(): + template.html_top(_('Identification Token')) + '

' + _('Please enter your identification token. ') + _('Your local account will be federated with your Liberty Alliance account.') + '

' + form.render() + else: + token = form.get_widget('token').parse() + return self._federate_token(token) + + def _federate_token(self, token): + session = get_session() + + # Get the user who owns this token + users_with_token = list(User.select(lambda x: x.identification_token == token)) + if len(users_with_token) == 0: + return template.error_page(_('Unknown Token')) + + # Fill user attributes + user = users_with_token[0] + user.name_identifiers = [ session.name_identifier ] + user.lasso_dumps = [ session.lasso_anonymous_identity_dump ] + user.identification_token = None + user.is_admin = True + user.store() + + # Set this user in the session + session.set_user(user.id, session.provider_id) + + # Delete now useless session attributes + session.name_identifier = None + session.lasso_anonymous_identity_dump = None + session.provider_id = None + + return redirect('%s/admin/' % get_request().environ['SCRIPT_NAME']) + diff --git a/larpe/tags/release-1.1.1/larpe/saml2.ptl b/larpe/tags/release-1.1.1/larpe/saml2.ptl new file mode 100644 index 0000000..20a3fc4 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/saml2.ptl @@ -0,0 +1,448 @@ +import os +import sys +import urlparse + +try: + import lasso +except ImportError: + print >> sys.stderr, 'Missing Lasso module, SAMLv2 support disabled' + +from quixote import get_publisher, get_request, get_response, get_session, get_session_manager, redirect + +from qommon.liberty import SOAPException, soap_call +from qommon.saml2 import Saml2Directory +from qommon import template +from qommon import get_logger + +import misc +from users import User +from hosts import Host +from federations import Federation +import site_authentication + +class Saml2(Saml2Directory): + _q_exports = Saml2Directory._q_exports + ['local_auth'] + + def login(self): + return self.perform_login() + + def perform_login(self, idp = None): + server = misc.get_lasso_server(protocol = 'saml2') + if not server: + return template.error_page(_('SAML 2.0 support not yet configured.')) + login = lasso.Login(server) + login.initAuthnRequest(idp, lasso.HTTP_METHOD_REDIRECT) + login.request.nameIDPolicy.format = lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT + login.request.nameIDPolicy.allowCreate = True + login.request.forceAuthn = False + login.request.isPassive = False + login.request.consent = 'urn:oasis:names:tc:SAML:2.0:consent:current-implicit' + login.buildAuthnRequestMsg() + return redirect(login.msgUrl) + + def singleSignOnArtifact(self): + server = misc.get_lasso_server(protocol = 'saml2') + if not server: + return template.error_page(_('SAML 2.0 support not yet configured.')) + login = lasso.Login(server) + request = get_request() + try: + login.initRequest(request.get_query(), lasso.HTTP_METHOD_ARTIFACT_GET) + except lasso.Error, error: + if error[0] == lasso.PROFILE_ERROR_MISSING_ARTIFACT: + return template.error_page(_('Missing SAML Artifact')) + else: + raise + + login.buildRequestMsg() + #remote_provider_cfg = get_cfg('idp', {}).get(misc.get_provider_key(login.remoteProviderId)) + #client_cert = remote_provider_cfg.get('clientcertificate') + + try: + soap_answer = soap_call(login.msgUrl, login.msgBody) + except SOAPException: + return template.error_page(_('Failure to communicate with identity provider')) + + try: + login.processResponseMsg(soap_answer) + except lasso.Error, error: + if error[0] == lasso.LOGIN_ERROR_STATUS_NOT_SUCCESS: + return template.error_page(_('Unknown authentication failure')) + if error[0] == lasso.LOGIN_ERROR_UNKNOWN_PRINCIPAL: + return template.error_page(_('Authentication failure; unknown principal')) + if error[0] == lasso.LOGIN_ERROR_FEDERATION_NOT_FOUND: + return template.error_page('there was no federation') + raise + + return self.sso_after_response(login) + + def sso_after_response(self, login): + providerId = login.server.providerId + try: + assertion = login.response.assertion[0] + if assertion.subject.subjectConfirmation.subjectConfirmationData.recipient != \ + get_request().get_url(): + return template.error_page('SubjectConfirmation Recipient Mismatch') + except: + return template.error_page('SubjectConfirmation Recipient Mismatch') + + assertions_dir = os.path.join(get_publisher().app_dir, 'assertions') + if not os.path.exists(assertions_dir): + os.mkdir(assertions_dir) + + assertion_fn = os.path.join(assertions_dir, assertion.iD) + if os.path.exists(assertion_fn): + return template.error_page('Assertion replay') + + try: + if assertion.subject.subjectConfirmation.method != \ + 'urn:oasis:names:tc:SAML:2.0:cm:bearer': + return template.error_page('Unknown SubjectConfirmation Method') + except: + return template.error_page('Unknown SubjectConfirmation Method') + + try: + audience_ok = False + for audience_restriction in assertion.conditions.audienceRestriction: + if audience_restriction.audience != providerId: + return template.error_page('Incorrect AudienceRestriction') + audience_ok = True + if not audience_ok: + return template.error_page('Incorrect AudienceRestriction') + except: + return template.error_page('Incorrect AudienceRestriction') + +# try: +# current_time = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()) +# not_before = assertion.subject.subjectConfirmation.subjectConfirmationData.notBefore +# not_on_or_after = assertion.subject.subjectConfirmation.subjectConfirmationData.notOnOrAfter +# if not_before and current_time < not_before: +# return template.error_page('Assertion received too early') +# if not_on_or_after and current_time > not_on_or_after: +# return template.error_page('Assertion expired') +# except: +# return template.error_page('Error checking Assertion Time') + + # TODO: check for unknown conditions + + login.acceptSso() + + session = get_session() + if login.isSessionDirty: + if login.session: + session.lasso_session_dumps[providerId] = login.session.dump() + session.lasso_session_indexes[providerId] = assertion.authnStatement[0].sessionIndex + session.lasso_session_name_identifiers[providerId] = login.nameIdentifier.content + else: + session.lasso_session_dumps[login.server.providerId] = None + + if assertion.authnStatement[0].sessionIndex: + session.lasso_session_index = assertion.authnStatement[0].sessionIndex + + user = self.lookup_user(session, login) + + # Check if it is for Larpe administration or token + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + if host.name == 'larpe': + if user: + session.set_user(user.id, login.server.providerId) + else: + session.name_identifier = login.nameIdentifier.content + session.lasso_anonymous_identity_dump = login.identity.dump() + session.provider_id = login.server.providerId + + if session.after_url: + # Access to an admin page or token url with parameter + after_url = session.after_url + session.after_url = None + return redirect(after_url) + + if user and user.is_admin: + return redirect('%s/admin/' % get_request().environ['SCRIPT_NAME']) + else: + return redirect('%s/token' % get_request().environ['SCRIPT_NAME']) + + # Set session user + if not user: + user = User() + user.name_identifiers = [ login.nameIdentifier.content ] + user.lasso_dumps = [ login.identity.dump() ] + user.store() + session.set_user(user.id, login.server.providerId) + + # Check if a federation already exist + federations = Federation.select(lambda x: host.id == x.host_id \ + and user.name_identifiers[0] in x.name_identifiers) + + if federations: + return site_authentication.get_site_authentication(host).sso_local_login(federations[0]) + else: + # Build response redirection + response = get_response() + if session.after_url: + after_url = session.after_url + session.after_url = None + return redirect(after_url) + response.set_status(303) + response.headers['location'] = urlparse.urljoin(get_request().get_url(), str('local_auth')) + response.content_type = 'text/plain' + return 'Your browser should redirect you' + + def lookup_user(self, session, login): + found_users = list(User.select(lambda x: login.nameIdentifier.content in x.name_identifiers, ignore_errors = True)) + if found_users: + return found_users[0] + return None + + def slo_sp(self, method = None): + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + + if method is None: + method = lasso.HTTP_METHOD_REDIRECT + + logout = lasso.Logout(misc.get_lasso_server(protocol = 'saml2')) + session = get_session() + + if not session.id or not session.users.has_key(logout.server.providerId) \ + or not session.lasso_session_dumps.has_key(logout.server.providerId): + get_session_manager().expire_session(logout.server.providerId) + return redirect(host.get_root_url()) + logout.setSessionFromDump(session.lasso_session_dumps[logout.server.providerId]) + user = session.get_user(logout.server.providerId) + + if host.name != 'larpe' and user: + site_authentication.get_site_authentication(host).local_logout(user=user) + + if user and user.lasso_dumps: + logout.setIdentityFromDump(user.lasso_dumps[0]) + else: + get_session_manager().expire_session(logout.server.providerId) + return redirect(host.get_root_url()) + + if method == lasso.HTTP_METHOD_REDIRECT: + return self.slo_sp_redirect(logout) + + # Not implemented yet + if method == lasso.HTTP_METHOD_SOAP: + return self.slo_sp_soap(logout) + + def slo_sp_redirect(self, logout): + session = get_session() + try: + logout.initRequest(None, lasso.HTTP_METHOD_REDIRECT) + except lasso.Error, error: + if error[0] == lasso.PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND: + get_session_manager().expire_session(logout.server.providerId) + return redirect(host.get_root_url()) + if error[0] == lasso.PROFILE_ERROR_SESSION_NOT_FOUND: + get_session_manager().expire_session(logout.server.providerId) + return redirect(host.get_root_url()) + raise + + logout.buildRequestMsg() + return redirect(logout.msgUrl) + + def singleLogoutReturn(self): + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + + logout = lasso.Logout(misc.get_lasso_server(protocol = 'saml2')) + session = get_session() + + if not session.id or not session.users.has_key(logout.server.providerId) \ + or not session.lasso_session_dumps.has_key(logout.server.providerId): + get_session_manager().expire_session(logout.server.providerId) + return redirect(host.get_root_url()) + logout.setSessionFromDump(session.lasso_session_dumps[logout.server.providerId]) + + message = get_request().get_query() + return self.slo_return(logout, message) + + def slo_return(self, logout, message): + host = Host.get_host_from_url() + + session = get_session() + + try: + logout.processResponseMsg(message) + except lasso.Error, error: + if error[0] == lasso.PROFILE_ERROR_INVALID_QUERY: + get_logger().warn('Invalid response') + elif error[0] == lasso.DS_ERROR_INVALID_SIGNATURE: + get_logger().warn('Failed to check single logout request signature') + elif error[0] == lasso.LOGOUT_ERROR_REQUEST_DENIED: + get_logger().warn('Request Denied') + elif error[0] == lasso.LOGOUT_ERROR_UNKNOWN_PRINCIPAL: + get_logger().warn('Unknown principal on logout, probably session stopped already on IdP') + else: + get_logger().error('Unknown Lasso exception on logout return: ' + repr(error)) + except Exception, exception: + get_logger().error('Unknown exception on logout return: ' + repr(exception)) + + get_session_manager().expire_session(logout.server.providerId) + + return redirect(host.get_root_url()) + + def singleLogoutSOAP(self): + try: + soap_message = self.get_soap_message() + except: + return + + response = get_response() + response.set_content_type('text/xml') + + request_type = lasso.getRequestTypeFromSoapMsg(soap_message) + + if request_type != lasso.REQUEST_TYPE_LOGOUT: + get_logger().warn('SOAP message on single logout url not a slo message') + return + + logout = lasso.Logout(misc.get_lasso_server(protocol = 'saml2')) + providerId = logout.server.providerId + logout.processRequestMsg(soap_message) + name_identifier = logout.nameIdentifier.content + # find one session matching the name identifier, and eventually the request + for session in get_session_manager().values(): + session_index = session.lasso_session_indexes.get(providerId) + name_identifier = session.lasso_session_name_identifiers.get(providerId) + request_name_identifier = logout.nameIdentifier.content + request_session_index = logout.request.sessionIndex + if request_name_identifier == name_identifier and \ + (not session_index or request_session_index == session_index) \ + and session.lasso_session_dumps.get(providerId): + get_logger().info('SLO/SOAP from %s' % logout.remoteProviderId) + break + else: + # no session, build straight failure answer + logout.buildResponseMsg() + return logout.msgBody + + return self.slo_idp(logout, session) + + def singleLogout(self): + logout = lasso.Logout(misc.get_lasso_server(protocol = 'saml2')) + try: + logout.processRequestMsg(get_request().get_query()) + except lasso.Error, error: + if error[0] == lasso.DS_ERROR_INVALID_SIGNATURE: + return template.error_page(_('Failed to check single logout request signature.')) + raise + session = get_session() + if not session.id: + # session has not been found, this may be because the user has + # its browser configured so that cookies are not sent for + # remote queries and IdP is using image-based SLO. + # so we look up a session with the appropriate name identifier + # find a matching + for session in get_session_manager().values(): + session_index = session.lasso_session_indexes.get(providerId) + name_identifier = session.lasso_session_name_identifiers.get(providerId) + request_name_identifier = logout.nameIdentifier.content + request_session_index = logout.request.sessionIndex + if request_name_identifier == name_identifier and \ + (not session_index or request_session_index == session_index) \ + and session.lasso_session_dump.get(providerId): + get_logger().info('SLO/SOAP from %s' % logout.remoteProviderId) + break + else: + # no session, build straight failure answer + logout.buildResponseMsg() + return logout.msgBody + + return self.slo_idp(logout, session) + + def slo_idp(self, logout, session): + # This block differs from qommon + if session.lasso_session_dumps.has_key(logout.server.providerId): + logout.setSessionFromDump(session.lasso_session_dumps[logout.server.providerId]) + user = session.get_user(logout.server.providerId) + if user and user.lasso_dumps: + logout.setIdentityFromDump(user.lasso_dumps[0]) + + if user and logout.nameIdentifier.content not in user.name_identifiers: + raise 'no appropriate name identifier in session (%s and %s)' % ( + logout.nameIdentifier.content, session.name_identifier) + + try: + assertion = logout.session.getAssertions(logout.remoteProviderId)[0] + if logout.request.sessionIndex and ( + assertion.authnStatement[0].sessionIndex != logout.request.sessionIndex): + logout.setSessionFromDump('') + except: + pass + + try: + logout.validateRequest() + except lasso.Error, error: + if error[0] == lasso.PROFILE_ERROR_SESSION_NOT_FOUND: + pass + elif error[0] == lasso.PROFILE_ERROR_IDENTITY_NOT_FOUND: + pass + elif error[0] == lasso.PROFILE_ERROR_MISSING_ASSERTION: + pass + elif error[0] == lasso.SERVER_ERROR_PROVIDER_NOT_FOUND: + pass + elif error[0] == lasso.NAME_IDENTIFIER_NOT_FOUND: + pass + else: + raise + else: + providerId = logout.server.providerId + session_index = logout.request.sessionIndex + name_identifier = logout.nameIdentifier.content + # Remove reference to local authentication on this SP in the session + # if a user is present, try a local logout + for session2 in get_session_manager().values(): + if session2.lasso_session_name_identifiers.get(providerId) == name_identifier \ + and ( not session_index + or session2.lasso_session_indexes.get(providerId) == session_index): + if session2.users.has_key(providerId): + # local logout + site_auth = site_authentication.get_site_authentication(Host.get_host_from_url()) + site_auth.local_logout(user=session2.get_user(providerId), + cookies=getattr(session2,'cookies', None)) + del session2.users[providerId] + if session2.lasso_session_dumps.has_key(providerId): + del session2.lasso_session_dumps[providerId] + if session2.lasso_session_indexes.has_key(providerId): + del session2.lasso_session_indexes[providerId] + if session2.lasso_session_name_identifiers.has_key(providerId): + del session2.lasso_session_name_identifiers[providerId] + session2.store() + get_session_manager().expire_session(logout.server.providerId) + + logout.buildResponseMsg() + if logout.msgBody: # soap answer + return logout.msgBody + else: + return redirect(logout.msgUrl) + + def local_auth(self): + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + return site_authentication.get_site_authentication(host).local_auth + local_auth = property(local_auth) + + def metadata(self): + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + get_response().set_content_type('text/xml', 'utf-8') + metadata = unicode(open(host.saml2_metadata).read(), 'utf-8') + return metadata + + def public_key(self): + host = Host.get_host_from_url() + if host is None: + return redirect('%s/' % get_request().environ['SCRIPT_NAME']) + get_response().set_content_type('text/plain') + public_key = open(host.public_key).read() + return public_key + diff --git a/larpe/tags/release-1.1.1/larpe/sessions.py b/larpe/tags/release-1.1.1/larpe/sessions.py new file mode 100644 index 0000000..aaa3a1d --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/sessions.py @@ -0,0 +1,92 @@ +'''Session and SessionManager objects. Configuration variables and utilities''' + +from quixote import get_request + +import qommon.sessions +from qommon.sessions import Session +from qommon.sessions import StorageSessionManager as SessionManager + +from users import User +from hosts import Host + +class BasicSession(Session): + '''Session object. Configuration variables and utilities''' + _names = 'sessions' + + def __init__(self, id): + self.users = {} + self.lasso_session_dumps = {} + self.lasso_session_indexes = {} + self.lasso_session_name_identifiers = {} + self.provider_id = None + Session.__init__(self, id) + + # lasso_session_indexes newly introduced + def __setstate__(self, dict): + self.lasso_session_indexes = {} + self.lasso_session_name_identifiers = {} + self.__dict__.update(dict) + + def has_info(self): + return self.users or self.lasso_session_dumps or self.provider_id or Session.has_info(self) + is_dirty = has_info + + def get_user(self, provider_id=None): + # Defaults to getting Larpe user. + # It allows get_request().user to work in administration interface. + if not provider_id: + user_id = None + host = Host.get_host_from_url() + if not host: + host_list = Host.select(lambda x: x.name == 'larpe') + if host_list: + host = host_list[0] + if host: + user_id = self.users.get(host.provider_id) + if not user_id: + user_id = self.users.get(host.saml2_provider_id) + else: + user_id = self.users.get(provider_id) + + if user_id: + try: + user = User.get(user_id) + except KeyError: + user = User() +# if str(user_id).startswith('anonymous-'): + user.id = user_id +# user.anonymous = True +# if self.name_identifiers.has_key(providerId): +# if not user.name_identifiers.has_key(providerId): +# user.name_identifiers[providerId] = [ self.name_identifiers[providerId] ] + +# if self.name_identifiers.has_key(providerId): +# user.name_identifiers[providerId] = [ self.name_identifiers[providerId] ] +# else: +# user.name_identifiers[providerId] = [] +# user.lasso_dumps[providerId] = self.lasso_anonymous_identity_dump + return user + return None + + def set_user(self, user_id, provider_id): + self.users[provider_id] = user_id + +class StorageSessionManager(SessionManager): + '''SessionManager object. Subclass with multi-hosts specific features.''' + def expire_session(self, provider_id=None): + session = get_request().session + if session.id is not None: + if provider_id: + if session.users.has_key(provider_id): + del session.users[provider_id] + if session.lasso_session_dumps.has_key(provider_id): + del session.lasso_session_dumps[provider_id] + if session.lasso_session_indexes.has_key(provider_id): + del session.lasso_session_indexes[provider_id] + if session.lasso_session_name_identifiers.has_key(provider_id): + del session.lasso_session_name_identifiers[provider_id] + session.store() + if not session.users: + SessionManager.expire_session(self) + +qommon.sessions.BasicSession = BasicSession diff --git a/larpe/tags/release-1.1.1/larpe/site_authentication.ptl b/larpe/tags/release-1.1.1/larpe/site_authentication.ptl new file mode 100644 index 0000000..bb5f5a6 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/site_authentication.ptl @@ -0,0 +1,321 @@ +import libxml2 +import urllib +import urlparse +import httplib +import re +import os +import socket +import base64 + +from quixote import get_request, get_response, get_session, redirect, get_publisher +from quixote.directory import Directory +from quixote.http_request import parse_header + +import lasso + +from qommon import get_logger +from qommon.form import * +from qommon.errors import ConnectionError, ConfigurationError, LoginError +from qommon.misc import http_post_request, http_get_page +from qommon.template import * + +from larpe.plugins import site_authentication_plugins + +import misc +from users import User +from federations import Federation + +class SiteAuthentication: + + output_filters = [] + + def __init__(self, host): + self.host = host + + def federate(self, username, password, provider_id, cookies, select): + user = get_session().get_user(provider_id) + if user is not None: + Federation(username, password, self.host.id, user.name_identifiers[0], cookies, select).store() + + def sso_local_login(self, federation): + status, data = self.local_auth_check_dispatch( + federation.username, federation.password, federation.select_fields) + success, return_content = self.check_auth(status, data) + if success: + session = get_session() + if hasattr(session, 'cookies'): + federation.set_cookies(session.cookies) + federation.store() + return return_content + else: + return redirect('local_auth') + + def local_auth [html] (self, first_time=True): + response = get_response() + response.set_content_type('text/html') + + if hasattr(get_response(), str('breadcrumb')): + del get_response().breadcrumb + + get_response().filter['default_org'] = '%s - %s' % (self.host.label, _('Local authentication')) + get_response().filter['body_class'] = 'login' + + form = self.form_local_auth() + form.add_submit('submit', _('Submit')) + #form.add_submit('cancel', _('Cancel')) + +# if form.get_widget('cancel').parse(): +# return redirect('.') + authentication_failure = None + if form.is_submitted() and not form.has_errors(): + try: + return self.submit_local_auth_form(form) + except LoginError: + authentication_failure = _('Authentication failure') + get_logger().info('local auth page : %s' % authentication_failure) + except ConnectionError, err: + authentication_failure = _('Connection failed : %s') % err + get_logger().info('local auth page : %s' % authentication_failure) + except ConfigurationError, err: + authentication_failure = _('This service provider is not fully configured : %s') % err + get_logger().info('local auth page : %s' % authentication_failure) + except Exception, err: + authentication_failure = _('Unknown error : %s' % err) + get_logger().info('local auth page : %s' % authentication_failure) + + if authentication_failure: + '
%s
' % authentication_failure + '

' + _('Please type your login and password for this Service Provider.') + _('Your local account will be federated with your Liberty Alliance account.') + '

' + + form.render() + + # Also used in admin/hosts.ptl + def form_local_auth(self): + form = Form(enctype='multipart/form-data') + form.add(StringWidget, 'username', title = _('Username'), required = True, + size = 30) + form.add(PasswordWidget, 'password', title = _('Password'), required = True, + size = 30) + for name, values in self.host.select_fields.iteritems(): + options = [] + if values: + for value in values: + options.append(value) + form.add(SingleSelectWidget, name, title = name.capitalize(), + value = values[0], options = options) + return form + + def submit_local_auth_form(self, form): + username = form.get_widget('username').parse() + password = form.get_widget('password').parse() + select = {} + for name, values in self.host.select_fields.iteritems(): + if form.get_widget(name): + select[name] = form.get_widget(name).parse() + return self.local_auth_check(username, password, select) + + def local_auth_check(self, username, password, select=None): + select = select or {} + status, data = self.local_auth_check_dispatch(username, password, select) + if status == 0: + raise + success, return_content = self.check_auth(status, data) + if success: + if misc.get_current_protocol() == lasso.PROTOCOL_SAML_2_0: + provider_id = self.host.saml2_provider_id + else: + provider_id = self.host.provider_id + session = get_session() + + if hasattr(session, 'cookies'): + self.federate(username, password, provider_id, session.cookies, select) + else: + self.federate(username, password, provider_id, None, select) + return return_content + raise LoginError() + + def local_auth_check_dispatch(self, username, password, select=None): + select = select or {} + if self.host.auth_mode == 'http_basic': + return self.local_auth_check_http_basic(username, password) + elif self.host.auth_mode == 'form' and hasattr(self.host, 'auth_check_url') \ + and self.host.auth_check_url is not None: + return self.local_auth_check_post(username, password, select) + else: + raise ConfigurationError('No authentication form was found') + + def local_auth_check_post(self, username, password, select=None): + select = select or {} + url = self.host.auth_check_url + + # Build request body + if self.host.post_parameters: + body_params = {} + # Login field + if self.host.post_parameters[self.host.login_field_name]['enabled'] is True: + body_params[self.host.login_field_name] = username + # Password field + if self.host.post_parameters[self.host.password_field_name]['enabled'] is True: + body_params[self.host.password_field_name] = password + # Select fields + for name, value in select.iteritems(): + if self.host.post_parameters[name]['enabled'] is True: + body_params[name] = value + # Other fields (hidden, submit and custom) + for name, value in self.host.other_fields.iteritems(): + if self.host.post_parameters[name]['enabled'] is True: + body_params[name] = self.host.post_parameters[name]['value'] + body = urllib.urlencode(body_params) + else: + # XXX: Legacy (to be removed later) Send all parameters for sites configured with a previous version of Larpe + body = '%s=%s&%s=%s' % (self.host.login_field_name, username, self.host.password_field_name, password) + # Add select fields to the body + for name, value in select.iteritems(): + body += '&%s=%s' % (name, value) + # Add hidden fields to the body + if self.host.send_hidden_fields: + for name, value in self.host.other_fields.iteritems(): + body += '&%s=%s' % (name, value) + + # Build request HTTP headers + if self.host.http_headers: + headers = {} + if self.host.http_headers['X-Forwarded-For']['enabled'] is True: + headers['X-Forwarded-For'] = get_request().get_environ('REMOTE_ADDR', '-') + for name, value in self.host.http_headers.iteritems(): + if value['enabled'] is True and value['immutable'] is False: + headers[name] = value['value'] + else: + # XXX: (to be removed later) Send default headers for sites configured with a previous version of Larpe + headers = { 'Content-Type': 'application/x-www-form-urlencoded', + 'X-Forwarded-For': get_request().get_environ('REMOTE_ADDR', '-'), + 'X-Forwarded-Host': self.host.reversed_hostname } + + # Send request + response, status, data, auth_headers = http_post_request(url, body, headers, self.host.use_proxy) + + cookies = response.getheader('Set-Cookie', None) + self.host.cookies = [] + if cookies is not None: + cookies_list = [] + cookies_set_list = [] + for cookie in cookies.split(', '): + # Drop the path and other attributes + cookie_only = cookie.split('; ')[0] + regexp = re.compile('=') + if regexp.search(cookie_only) is None: + continue + # Split name and value + cookie_split = cookie_only.split('=') + cookie_name = cookie_split[0] + cookie_value = cookie_split[1] + cookies_list.append('%s=%s' % (cookie_name, cookie_value)) + set_cookie = '%s=%s; path=/' % (cookie_name, cookie_value) + cookies_set_list.append(set_cookie) + self.host.cookies.append(cookie_name) + cookies_headers = '\r\nSet-Cookie: '.join(cookies_set_list) + get_response().set_header('Set-Cookie', cookies_headers) + self.host.store() + get_session().cookies = '; '.join(cookies_list) + else: + get_logger().warn('No cookie from local authentication') + + return response.status, data + + def local_auth_check_http_basic(self, username, password): + url = self.host.auth_form_url + hostname, query = urllib.splithost(url[5:]) + conn = httplib.HTTPConnection(hostname) + + auth_header = 'Basic %s' % base64.encodestring('%s:%s' % (username, password)) + + try: + conn.request('GET', query, headers={'Authorization': auth_header}) + except socket.gaierror, err: + print err + conn.close() + return 0, None + else: + response = conn.getresponse() + conn.close() + return response.status, response.read() + + def check_auth(self, status, data): + success = False + return_content = '' + + # If status is 500, fail without checking other criterias + if status // 100 == 5: + success = False + return_content = redirect(self.host.get_return_url()) + + + # For http auth, only check status code + elif self.host.auth_mode == 'http_basic': + # If failed, status code should be 401 + if status // 100 == 2 or status // 100 == 3: + success = True + return_content = redirect(self.host.get_return_url()) + + else: + if self.host.auth_system == 'password': + # If there is a password field, authentication probably failed + regexp = re.compile("""]*?type=["']?password["']?[^>]*?>""", re.DOTALL | re.IGNORECASE) + if not regexp.findall(data): + success = True + return_content = redirect(self.host.get_return_url()) + elif self.host.auth_system == 'status': + match_status = int(self.host.auth_match_status) + if match_status == status: + success = True + return_content = redirect(self.host.get_return_url()) + elif self.host.auth_system == 'match_text': + # If the auth_match_text is not matched, it means the authentication is successful + regexp = re.compile(self.host.auth_match_text, re.DOTALL) + if not regexp.findall(data): + success = True + return_content = redirect(self.host.get_return_url()) + + return success, return_content + + def local_logout(self, federation=None, user=None, cookies=None): + if cookies is None and federation is None and user is not None: + federations = Federation.select(lambda x: user.name_identifiers[0] in x.name_identifiers) + if federations: + cookies = federations[0].cookies + + # Logout request to the site + url = self.host.logout_url + if url is not None and cookies is not None: + try: + http_get_page(url, {'Cookie': cookies}) + except ConnectionError, err: + get_logger().warning(_("%s logout failed") % url) + get_logger().debug(err) + + # Remove cookies from the browser + # TODO: this should be removed because this only works + # with a 'direct' logout + if hasattr(self.host, 'cookies'): + for cookie in self.host.cookies: + get_response().expire_cookie(cookie, path='/') + + def local_defederate(self, session, provider_id): + if session is None: + return + user = session.get_user(provider_id) + if user is not None: + federations = Federation.select(lambda x: user.name_identifiers[0] in x.name_identifiers) + for federation in federations: + self.local_logout(provider_id, federation) + federation.remove_name_identifier(user.name_identifiers[0]) + federation.store() + +def get_site_authentication(host): + if host.site_authentication_plugin is None: + return SiteAuthentication(host) + return site_authentication_plugins.get(host.site_authentication_plugin)(host) + diff --git a/larpe/tags/release-1.1.1/larpe/users.py b/larpe/tags/release-1.1.1/larpe/users.py new file mode 100644 index 0000000..1a387a9 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpe/users.py @@ -0,0 +1,44 @@ +'''User object. Configuration variables and utilities''' + +from qommon.storage import StorableObject + +class User(StorableObject): + '''User object. Configuration variables and utilities''' + _names = 'users' + + name = None + email = None + name_identifiers = None + identification_token = None + lasso_dumps = None + is_admin = False + anonymous = False + + def __init__(self, name=None): + StorableObject.__init__(self) + self.name = name + self.name_identifiers = [] + self.lasso_dumps = [] + + def migrate(self): + pass + + def remove_name_identifier(self, name_identifier): + self.name_identifiers.remove(name_identifier) + if not self.name_identifiers: + self.remove_self() + else: + self.store() + + def get_display_name(self): + if self.name: + return self.name + if self.email: + return self.email + return _('Unknown User') + display_name = property(get_display_name) + + def __str__(self): + return 'User %s, name : %s, name identifiers : %s, lasso_dumps : %s, token : %s' \ + % (self.id, self.name, self.name_identifiers, self.lasso_dumps, + self.identification_token) diff --git a/larpe/tags/release-1.1.1/larpectl b/larpe/tags/release-1.1.1/larpectl new file mode 100755 index 0000000..a7c7237 --- /dev/null +++ b/larpe/tags/release-1.1.1/larpectl @@ -0,0 +1,25 @@ +#!/usr/bin/python + +import sys + +from larpe import ctl + +def print_usage(): + print 'Usage: larpectl command [...]' + print '' + print 'Commands:' + print ' start start server' + print ' cache_modulesets parse and cache jhbuild module sets' + +if len(sys.argv) < 2: + print_usage() + sys.exit(1) +else: + command = sys.argv[1] + + if command == 'start': + ctl.start(sys.argv[2:]) + elif command == 'cache_modulesets': + ctl.cache_modulesets() + else: + print_usage() diff --git a/larpe/tags/release-1.1.1/po/Makefile b/larpe/tags/release-1.1.1/po/Makefile new file mode 100644 index 0000000..0653e37 --- /dev/null +++ b/larpe/tags/release-1.1.1/po/Makefile @@ -0,0 +1,49 @@ +prefix = /usr + +POFILES=$(wildcard *.po) +MOFILES=$(POFILES:.po=.mo) +PYFILES=$(shell find -L ../larpe -name '*.py' -or -name '*.ptl') +RM=rm -f + +all: $(MOFILES) + +install: all + for file in $(MOFILES); do \ + lang=`echo $$file | sed 's/\.mo//'`; \ + install -d $(DESTDIR)$(prefix)/share/locale/$$lang/LC_MESSAGES/; \ + install -m 0644 $$file $(DESTDIR)$(prefix)/share/locale/$$lang/LC_MESSAGES/larpe.mo; \ + done + +uninstall: + @for file in $(MOFILES); do \ + lang=`echo $$file | sed 's/\.mo//'`; \ + $(RM) $(DESTDIR)$(prefix)/share/locale/$$lang/LC_MESSAGES/larpe.mo; \ + done + +clean: + -$(RM) messages.mo $(MOFILES) + +larpe.pot: $(PYFILES) + @echo "Rebuilding the pot file" + $(RM) larpe.pot tmp.*.pot + cnt=0; + for file in $(PYFILES); do \ + cnt=$$(expr $$cnt + 1); \ + bn=$$cnt.`basename $$file`; \ + xgettext --keyword=N_ -c -L Python -o tmp.$$bn.pot $$file; \ + done + msgcat tmp.*.pot > larpe.pot + $(RM) tmp.*.pot + +%.mo: %.po + msgfmt -o $@ $< + +%.po: larpe.pot + @echo -n "Merging larpe.pot and $@" + @msgmerge $@ larpe.pot -o $@.new + @if [ "`diff $@ $@.new | grep '[<>]' | wc -l`" -ne 2 ]; then \ + mv -f $@.new $@; \ + else \ + $(RM) $@.new; \ + fi + @msgfmt --statistics $@ diff --git a/larpe/tags/release-1.1.1/po/fr.po b/larpe/tags/release-1.1.1/po/fr.po new file mode 100644 index 0000000..5e7fb6a --- /dev/null +++ b/larpe/tags/release-1.1.1/po/fr.po @@ -0,0 +1,2661 @@ +msgid "" +msgstr "" +"Project-Id-Version: Larpe 0.2.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-07-19 13:53+0200\n" +"PO-Revision-Date: 2010-07-19 13:51+0100\n" +"Last-Translator: Jérôme Schneider \n" +"Language-Team: French\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../larpe/idwsf2.ptl:50 +msgid "Failed connecting to the original site." +msgstr "Échec de connexion au site d'origine" + +#: ../larpe/idwsf2.ptl:61 +msgid "Failed getting attributes from the attribute provider." +msgstr "" +"Échec lors de la récupération d'attributs depuis le fournisseur d'attributs." + +#: ../larpe/idwsf2.ptl:64 +msgid "Failed getting attributes for an unknown reason." +msgstr "Échec lors de la récupération d'attributs pour une raison inconnue" + +#: ../larpe/liberty_site.ptl:46 ../larpe/liberty_site.ptl:56 +msgid "SSO support is not yet configured" +msgstr "Le support SSO n'est pas encore configuré" + +#: ../larpe/admin/users.ptl:24 ../larpe/admin/users.ptl:32 +msgid "User Name" +msgstr "Nom de l'utilisateur" + +#: ../larpe/admin/users.ptl:25 ../larpe/admin/users.ptl:34 +#: ../larpe/admin/users.ptl:66 +msgid "Email" +msgstr "Courriel" + +#: ../larpe/admin/users.ptl:26 ../larpe/admin/users.ptl:36 +#: ../larpe/admin/users.ptl:122 ../larpe/admin/forms_prefill.ptl:24 +#: ../larpe/admin/forms_prefill.ptl:76 ../larpe/admin/settings.ptl:31 +#: ../larpe/admin/settings.ptl:217 ../larpe/admin/settings.ptl:326 +#: ../larpe/admin/settings.ptl:343 ../larpe/admin/fields_prefill.ptl:30 +#: ../larpe/admin/fields_prefill.ptl:73 ../larpe/admin/hosts.ptl:384 +#: ../larpe/admin/hosts.ptl:692 ../larpe/admin/hosts.ptl:740 +#: ../larpe/admin/hosts.ptl:787 ../larpe/admin/hosts.ptl:1286 +#: ../larpe/site_authentication.ptl:64 ../larpe/root.ptl:64 +msgid "Submit" +msgstr "Valider" + +#: ../larpe/admin/users.ptl:27 ../larpe/admin/users.ptl:37 +#: ../larpe/admin/users.ptl:123 ../larpe/admin/users.ptl:138 +#: ../larpe/admin/forms_prefill.ptl:25 ../larpe/admin/forms_prefill.ptl:77 +#: ../larpe/admin/settings.ptl:218 ../larpe/admin/settings.ptl:327 +#: ../larpe/admin/settings.ptl:344 ../larpe/admin/fields_prefill.ptl:31 +#: ../larpe/admin/fields_prefill.ptl:74 ../larpe/admin/hosts.ptl:124 +#: ../larpe/admin/hosts.ptl:385 ../larpe/admin/hosts.ptl:693 +#: ../larpe/admin/hosts.ptl:741 ../larpe/admin/hosts.ptl:788 +#: ../larpe/admin/hosts.ptl:1287 ../larpe/root.ptl:65 +msgid "Cancel" +msgstr "Annuler" + +#: ../larpe/admin/users.ptl:60 ../larpe/admin/users.ptl:61 +msgid "User" +msgstr "Utilisateur" + +#: ../larpe/admin/users.ptl:63 ../larpe/admin/hosts.ptl:382 +msgid "Name" +msgstr "Nom" + +#: ../larpe/admin/users.ptl:98 +msgid "Debug" +msgstr "Debug" + +#: ../larpe/admin/users.ptl:110 ../larpe/admin/forms_prefill.ptl:48 +#: ../larpe/admin/forms_prefill.ptl:66 ../larpe/admin/forms_prefill.ptl:67 +#: ../larpe/admin/forms_prefill.ptl:68 ../larpe/admin/fields_prefill.ptl:63 +#: ../larpe/admin/fields_prefill.ptl:64 ../larpe/admin/fields_prefill.ptl:65 +msgid "Edit" +msgstr "Modifier" + +#: ../larpe/admin/users.ptl:111 ../larpe/admin/users.ptl:112 +msgid "Edit User" +msgstr "Modifier l'utilisateur" + +#: ../larpe/admin/users.ptl:121 +msgid "You are about to irrevocably delete this user." +msgstr "Vous allez définitivement supprimer cet utilisateur." + +#: ../larpe/admin/users.ptl:127 ../larpe/admin/forms_prefill.ptl:81 +#: ../larpe/admin/fields_prefill.ptl:78 ../larpe/admin/hosts.ptl:1291 +msgid "Delete" +msgstr "Supprimer" + +#: ../larpe/admin/users.ptl:128 +msgid "Delete User" +msgstr "Supprimer l'utilisateur" + +#: ../larpe/admin/users.ptl:129 +msgid "Deleting User :" +msgstr "Suppression de l'utilisateur :" + +#: ../larpe/admin/users.ptl:137 +msgid "Generate" +msgstr "Générer" + +#: ../larpe/admin/users.ptl:143 ../larpe/admin/users.ptl:146 +#: ../larpe/admin/users.ptl:147 ../larpe/admin/users.ptl:155 +#: ../larpe/admin/users.ptl:180 ../larpe/admin/users.ptl:182 +#: ../larpe/admin/users.ptl:223 ../larpe/root.ptl:62 ../larpe/root.ptl:71 +msgid "Identification Token" +msgstr "Jeton d'identification" + +#: ../larpe/admin/users.ptl:148 +msgid "" +"You are about to generate a token than can be used to federate the account." +msgstr "" +"Vous allez générer un jeton qui pourra être utilisé pour fédérer le compte." + +#: ../larpe/admin/users.ptl:149 +msgid "" +"After that, you will have the choice to send it to the user by email so that " +"he can federate his accounts." +msgstr "" +"Ensuite, vous aurez la possibilité de l'envoyer à l'utilisateur par courriel " +"pour qu'il puisse fédérer ses comptes." + +#: ../larpe/admin/users.ptl:151 +#, python-format +msgid "Note that user has already been issued an identification token : %s" +msgstr "À noter que l'utilisateur a déjà un jeton d'identification : %s" + +#: ../larpe/admin/users.ptl:161 +#, python-format +msgid "Identification Token for %s" +msgstr "Jeton d'identification pour %s" + +#: ../larpe/admin/users.ptl:165 +msgid "Done" +msgstr "Fait" + +#: ../larpe/admin/users.ptl:167 +msgid "Send by email" +msgstr "Envoyer par courriel" + +#: ../larpe/admin/users.ptl:173 +#, python-format +msgid "" +"You have been given an identification token.\n" +"\n" +"Your token is %(token)s\n" +"\n" +"Click on %(url)s to use it.\n" +msgstr "" +"Un jeton d'identification vous a été attribué.\n" +"\n" +"Votre jeton est %(token)s\n" +"\n" +"Cliquez sur %(url)s pour l'utiliser.\n" + +#: ../larpe/admin/users.ptl:183 +msgid "Failed sending email. Check your email configuration." +msgstr "" +"Échec de l'envoi du courriel. Vérifiez votre configuration des courriels." + +#: ../larpe/admin/users.ptl:184 ../larpe/admin/settings.ptl:112 +#: ../larpe/admin/hosts.ptl:657 ../larpe/admin/hosts.ptl:713 +#: ../larpe/admin/hosts.ptl:1340 +msgid "Back" +msgstr "Retour" + +#: ../larpe/admin/users.ptl:194 ../larpe/admin/users.ptl:195 +#: ../larpe/admin/users.ptl:238 ../larpe/admin/users.ptl:272 +#: ../larpe/admin/root.ptl:45 +msgid "Users" +msgstr "Utilisateurs" + +#: ../larpe/admin/users.ptl:199 ../larpe/admin/users.ptl:242 +msgid "Liberty support must be setup before creating users." +msgstr "" +"Le support Liberty doit être configuré avant de créer des utilisateurs." + +#: ../larpe/admin/users.ptl:203 ../larpe/admin/users.ptl:254 +#: ../larpe/admin/users.ptl:255 +msgid "New User" +msgstr "Nouvel utilisateur" + +#: ../larpe/admin/users.ptl:226 +#, python-format +msgid "Identification Token (current: %s)" +msgstr "Jeton d'identification (actuellement: %s)" + +#: ../larpe/admin/users.ptl:233 ../larpe/admin/root.ptl:47 +msgid "Logs" +msgstr "Journaux" + +#: ../larpe/admin/users.ptl:239 ../larpe/admin/forms_prefill.ptl:122 +#: ../larpe/admin/fields_prefill.ptl:125 ../larpe/admin/hosts.ptl:1344 +msgid "New" +msgstr "Nouveau" + +#: ../larpe/admin/forms_prefill.ptl:16 +msgid "Form name" +msgstr "Nom du formulaire" + +#: ../larpe/admin/forms_prefill.ptl:17 +msgid "Only used for display" +msgstr "Utilisé uniquement pour l'affichage" + +#: ../larpe/admin/forms_prefill.ptl:18 +msgid "Form address" +msgstr "Addresse du formulaire" + +#: ../larpe/admin/forms_prefill.ptl:20 +msgid "ID-WSF data profile" +msgstr "Profile des données ID-WSF" + +#: ../larpe/admin/forms_prefill.ptl:21 +msgid "Example: urn:liberty:id-sis-pp:2005-05" +msgstr "Exemple : urn:liberty:id-sis-pp:2005-05" + +#: ../larpe/admin/forms_prefill.ptl:22 +msgid "ID-WSF data XML prefix" +msgstr "Préfixe XML des données ID-WSF" + +#: ../larpe/admin/forms_prefill.ptl:23 +msgid "Example: pp" +msgstr "Exemple : pp" + +#: ../larpe/admin/forms_prefill.ptl:45 +msgid "Form prefilling configuration" +msgstr "Configuration du pré-remplissage de formulaire" + +#: ../larpe/admin/forms_prefill.ptl:48 +msgid "Configure this form" +msgstr "Configurer ce formulaire" + +#: ../larpe/admin/forms_prefill.ptl:50 ../larpe/admin/fields_prefill.ptl:91 +#: ../larpe/admin/fields_prefill.ptl:98 +msgid "Fields" +msgstr "Champs" + +#: ../larpe/admin/forms_prefill.ptl:50 +msgid "Configure the fields of this form" +msgstr "Configurer les champs de ce formulaire" + +#: ../larpe/admin/forms_prefill.ptl:75 +msgid "You are about to irrevocably delete this form." +msgstr "Vous allez définitivement supprimer ce fomulaire." + +#: ../larpe/admin/forms_prefill.ptl:82 ../larpe/admin/forms_prefill.ptl:83 +msgid "Delete Form" +msgstr "Supprimer le formulaire" + +#: ../larpe/admin/forms_prefill.ptl:94 ../larpe/admin/forms_prefill.ptl:101 +#: ../larpe/admin/hosts.ptl:1279 +msgid "Forms" +msgstr "Formulaires" + +#: ../larpe/admin/forms_prefill.ptl:104 +msgid "New Form" +msgstr "Nouveau formulaire" + +#: ../larpe/admin/settings.ptl:28 +msgid "Metadata" +msgstr "Méta-données" + +#: ../larpe/admin/settings.ptl:29 +msgid "Public Key" +msgstr "Clé publique" + +#: ../larpe/admin/settings.ptl:30 +msgid "CA Certificate Chain" +msgstr "Chaîne de certification" + +#: ../larpe/admin/settings.ptl:34 ../larpe/admin/settings.ptl:35 +msgid "New Identity Provider" +msgstr "Nouveau fournisseur d'identité" + +#: ../larpe/admin/settings.ptl:53 ../larpe/admin/settings.ptl:87 +msgid "Bad metadata" +msgstr "Mauvaises méta-données" + +#. Don't use custom emails +#: ../larpe/admin/settings.ptl:104 ../larpe/admin/settings.ptl:105 +#: ../larpe/admin/settings.ptl:192 +msgid "Emails" +msgstr "Courriels" + +#: ../larpe/admin/settings.ptl:108 +msgid "General Options" +msgstr "Options générales" + +#: ../larpe/admin/settings.ptl:125 ../larpe/admin/hosts.ptl:84 +#: ../larpe/admin/root.ptl:46 +msgid "Settings" +msgstr "Paramètres" + +#: ../larpe/admin/settings.ptl:128 +msgid "Liberty Alliance & SAML 2.0 Service Provider" +msgstr "Fournisseur de service Liberty Alliance et SAML 2.0" + +#: ../larpe/admin/settings.ptl:130 +msgid "Liberty Alliance Service Provider" +msgstr "Fournisseur de service Liberty Alliance" + +#: ../larpe/admin/settings.ptl:132 +msgid "Service Provider" +msgstr "Fournisseur de service" + +#: ../larpe/admin/settings.ptl:132 +msgid "Configure Larpe as a Service Provider" +msgstr "Configurer Larpe en tant que fournisseur de service" + +#: ../larpe/admin/settings.ptl:142 ../larpe/admin/hosts.ptl:913 +msgid "SAML 2.0 Metadata" +msgstr "Méta-données SAML 2.0" + +#: ../larpe/admin/settings.ptl:143 +msgid "Download SAML 2.0 metadata file for Larpe" +msgstr "Télécharger le fichier des méta-données SAML 2.0 pour Larpe" + +#: ../larpe/admin/settings.ptl:149 ../larpe/admin/hosts.ptl:918 +msgid "ID-FF 1.2 Metadata" +msgstr "Méta-données ID-FF 1.2" + +#: ../larpe/admin/settings.ptl:150 +msgid "Download ID-FF 1.2 metadata file for Larpe" +msgstr "Télécharger le fichier des méta-données ID-FF 1.2 pour Larpe" + +#: ../larpe/admin/settings.ptl:156 ../larpe/admin/hosts.ptl:927 +msgid "Public key" +msgstr "Clé publique" + +#: ../larpe/admin/settings.ptl:157 ../larpe/admin/hosts.ptl:928 +msgid "Download SSL Public Key file" +msgstr "Télécharger le fichier de clé SSL publique" + +#: ../larpe/admin/settings.ptl:160 +msgid "Liberty Alliance & SAML 2.0 Identity Provider" +msgstr "Fournisseur d'identité Liberty Alliance et SAML 2.0" + +#: ../larpe/admin/settings.ptl:162 +msgid "Liberty Alliance Identity Provider" +msgstr "Fournisseur d'identité Liberty Alliance" + +#: ../larpe/admin/settings.ptl:167 +msgid "Identity Provider" +msgstr "Fournisseur d'identité" + +#: ../larpe/admin/settings.ptl:167 +msgid "Configure an identity provider" +msgstr "Configurer un fournisseur d'identité" + +#: ../larpe/admin/settings.ptl:171 +msgid "Identity Provider metadatas" +msgstr "Méta-données du fournisseur d'identité" + +#: ../larpe/admin/settings.ptl:171 +msgid "See current identity provider metadatas" +msgstr "Voir les méta-données du fournisseur d'identité actuel" + +#: ../larpe/admin/settings.ptl:175 +msgid "Global parameters for the sites" +msgstr "Paramètres globaux des sites" + +#: ../larpe/admin/settings.ptl:179 ../larpe/admin/settings.ptl:302 +#: ../larpe/admin/settings.ptl:303 +msgid "Domain name" +msgstr "Nom de domaine" + +#: ../larpe/admin/settings.ptl:179 +msgid "Configure the base domain name for the sites" +msgstr "Configurer le nom de domaine de base pour les sites" + +#: ../larpe/admin/settings.ptl:181 ../larpe/admin/settings.ptl:348 +#: ../larpe/admin/settings.ptl:349 +msgid "Apache 2 configuration generation" +msgstr "Génération de la configuration d'Apache 2" + +#: ../larpe/admin/settings.ptl:181 +msgid "Customise Apache 2 configuration generation" +msgstr "Personnaliser la génération de la configuration d'Apache 2" + +#: ../larpe/admin/settings.ptl:183 +msgid "Proxy" +msgstr "Mandataire (proxy)" + +#: ../larpe/admin/settings.ptl:183 +msgid "Connect to the sites through a web proxy" +msgstr "Se connecter aux sites en passant par un mandataire (proxy)" + +#: ../larpe/admin/settings.ptl:186 +msgid "Customisation" +msgstr "Personnalisation" + +#: ../larpe/admin/settings.ptl:190 +msgid "Language" +msgstr "Langue" + +#: ../larpe/admin/settings.ptl:190 +msgid "Configure site language" +msgstr "Configurer la langue du site" + +#: ../larpe/admin/settings.ptl:192 +msgid "Configure email settings" +msgstr "Configurer les paramètres des courriels" + +#: ../larpe/admin/settings.ptl:195 +msgid "Misc" +msgstr "Divers" + +#: ../larpe/admin/settings.ptl:199 +msgid "Debug Options" +msgstr "Options de débogage" + +#: ../larpe/admin/settings.ptl:199 +msgid "Configure options useful for debugging" +msgstr "Configurer les options utiles au debogage" + +#: ../larpe/admin/settings.ptl:215 +msgid "Organisation Name" +msgstr "Nom de l'organisation" + +#: ../larpe/admin/settings.ptl:222 ../larpe/admin/settings.ptl:223 +msgid "Service Provider Configuration" +msgstr "Configuration du fournisseur d'identité" + +#: ../larpe/admin/settings.ptl:318 +msgid "Domain name for the sites" +msgstr "Noms de domaine pour les sites" + +#. TODO: Add the option "Both" and handle it in hosts configuration +#: ../larpe/admin/settings.ptl:321 +msgid "Use HTTP or HTTPS" +msgstr "Utiliser HTTP ou HTTPS" + +#: ../larpe/admin/settings.ptl:323 +msgid "Same as the site" +msgstr "Identique au site d'origine" + +#: ../larpe/admin/settings.ptl:341 +msgid "" +"Automatically generate Apache 2 configuration for new hosts and reload " +"Apache 2 after changes" +msgstr "" +"Générer automatiquement la configuration Apache 2 pour les nouveaux hôtes et " +"recharger Apache 2 après les changements" + +#: ../larpe/admin/fields_prefill.ptl:15 +msgid "Field name" +msgstr "Nom du champ" + +#: ../larpe/admin/fields_prefill.ptl:17 +msgid "Xpath of the attribute" +msgstr "Xpath de l'attribut" + +#: ../larpe/admin/fields_prefill.ptl:18 +msgid "Example: /pp:PP/pp:InformalName" +msgstr "Exemple : /pp:PP/pp:InformalName" + +#: ../larpe/admin/fields_prefill.ptl:19 +msgid "Number of the field in the data" +msgstr "Numéro du champ dans les données" + +#: ../larpe/admin/fields_prefill.ptl:21 +msgid "" +"Change it if there are multiple fields corresponding to the same Xpath and " +"you want to get another than the first one" +msgstr "" +"À changer s'il existe plusieurs champs correspondants au même Xpath et que " +"vous voulez obtenir un autre élément que le premier" + +#: ../larpe/admin/fields_prefill.ptl:22 +msgid "Get raw XML value" +msgstr "Récupérer la valeur XML brute" + +#: ../larpe/admin/fields_prefill.ptl:24 +msgid "Python regexp of a string to match" +msgstr "" +"Expression régulière en Python correspondant à la chaîne de caractères à " +"chercher" + +#: ../larpe/admin/fields_prefill.ptl:26 +msgid "Python regexp of the replacing string" +msgstr "" +"Expression régulière en Python de la chaîne de caractères de remplacement" + +#: ../larpe/admin/fields_prefill.ptl:28 +msgid "Options mapping for a select field" +msgstr "Correspondance d'options pour un champ select" + +#: ../larpe/admin/fields_prefill.ptl:29 +msgid "Add item" +msgstr "Ajouter un élément" + +#: ../larpe/admin/fields_prefill.ptl:72 +msgid "You are about to irrevocably delete this field." +msgstr "Vous allez définitivement supprimer ce champ." + +#: ../larpe/admin/fields_prefill.ptl:79 ../larpe/admin/fields_prefill.ptl:80 +msgid "Delete Field" +msgstr "Supprimer le champ" + +#: ../larpe/admin/fields_prefill.ptl:101 +msgid "New Field" +msgstr "Nouveau champ" + +#: ../larpe/admin/hosts.ptl:33 +msgid "" +"You must either choose a different hostname from Larpe or specify a reversed " +"directory" +msgstr "" +"Vous devez soit choisir un nom d'hôte différent de celui de Larpe, soit " +"spécifier un répertoire inversé" + +#: ../larpe/admin/hosts.ptl:80 ../larpe/admin/hosts.ptl:102 +msgid "Basic configuration" +msgstr "Configuration de base" + +#: ../larpe/admin/hosts.ptl:81 +msgid "Need domain name configuration" +msgstr "Nécessite la configuration du nom de domaine" + +#: ../larpe/admin/hosts.ptl:82 +#, python-format +msgid "" +"Before configuring hosts, you must\n" +"setup a global domain name " +"in\n" +"%(settings)s menu." +msgstr "" +"Avant des configurer les sites, vous devez définir un nom de domaine global dans le menu " +"%(settings)s." + +#: ../larpe/admin/hosts.ptl:103 +msgid "Step 1 - Basic configuration" +msgstr "Étape 1 - Configuration de base" + +#: ../larpe/admin/hosts.ptl:112 +msgid "Original site root address" +msgstr "Adresse racine du site d'origine" + +#: ../larpe/admin/hosts.ptl:114 +msgid "" +"If your site address is http://test.org/index.php, put http://test.org/ here" +msgstr "" +"Si l'adresse de votre site est http://test.org/index.php, mettez http://test." +"org/ ici" + +#: ../larpe/admin/hosts.ptl:117 +msgid "Use a proxy" +msgstr "Utiliser un mandataire (proxy)" + +#: ../larpe/admin/hosts.ptl:118 +msgid "" +"Uncheck it if Larpe doesn't need to use the proxy to connect to this site" +msgstr "" +"Décocher cette case si Larpe ne doit pas utiliser un mandataire (proxy) pour " +"se connecter à ce site" + +#: ../larpe/admin/hosts.ptl:122 +msgid "" +"If Larpe needs to use a proxy to connect to this site, you must first " +"configure\n" +" it in global proxy parameters." +msgstr "" +"Si Larpe doit utiliser un mandataire (proxy) pour se connecter à ce site, " +"vous devez d'abord le configurer dans les paramètres globaux du mandataire." + +#: ../larpe/admin/hosts.ptl:125 ../larpe/admin/hosts.ptl:315 +#: ../larpe/admin/hosts.ptl:343 ../larpe/admin/hosts.ptl:433 +#: ../larpe/admin/hosts.ptl:464 ../larpe/admin/hosts.ptl:547 +#: ../larpe/admin/hosts.ptl:583 ../larpe/admin/hosts.ptl:873 +#: ../larpe/admin/hosts.ptl:889 ../larpe/admin/hosts.ptl:947 +#: ../larpe/admin/hosts.ptl:977 +msgid "Next" +msgstr "Suivant" + +#: ../larpe/admin/hosts.ptl:126 ../larpe/admin/hosts.ptl:316 +#: ../larpe/admin/hosts.ptl:434 ../larpe/admin/hosts.ptl:465 +#: ../larpe/admin/hosts.ptl:548 ../larpe/admin/hosts.ptl:584 +#: ../larpe/admin/hosts.ptl:874 ../larpe/admin/hosts.ptl:890 +#: ../larpe/admin/hosts.ptl:978 +msgid "Terminate" +msgstr "Terminer" + +#: ../larpe/admin/hosts.ptl:314 ../larpe/admin/hosts.ptl:343 +#: ../larpe/admin/hosts.ptl:432 ../larpe/admin/hosts.ptl:463 +#: ../larpe/admin/hosts.ptl:546 ../larpe/admin/hosts.ptl:582 +#: ../larpe/admin/hosts.ptl:872 ../larpe/admin/hosts.ptl:888 +#: ../larpe/admin/hosts.ptl:976 ../larpe/admin/hosts.ptl:1002 +msgid "Previous" +msgstr "Précédent" + +#: ../larpe/admin/hosts.ptl:332 +msgid "Check site address and name" +msgstr "Vérifier l'adresse et le nom du site" + +#: ../larpe/admin/hosts.ptl:333 +msgid "Step 2 - Check the new site address works" +msgstr "Étape 2 - Vérifier que la nouvelle adresse du site fonctionne" + +#: ../larpe/admin/hosts.ptl:335 +msgid "DNS configuration" +msgstr "Configuration DNS" + +#: ../larpe/admin/hosts.ptl:337 +msgid "" +"Before opening the following link, ensure you have configured your DNS\n" +"for this address. If you don't have a DNS server and you just want to test " +"Larpe, add this\n" +"domain name in the file \"/etc/hosts\"." +msgstr "" +"Avant d'ouvrir le lien suivant, assurez vous d'avoir configuré votre DNS " +"pour cette adresse. Si vous n'avez pas de serveur DNS et que vous souhaitez " +"seulement tester Larpe, ajoutez ce nom de domaine dans le fichier \"/etc/" +"hosts\"." + +#: ../larpe/admin/hosts.ptl:341 +#, python-format +msgid "" +"Then you can open this link in a new window or tab and see if your site\n" +"is displayed. If it's ok, you can click the \"%(next)s\" button. Otherwise, " +"click the \"%(previous)s\"\n" +"button and check your settings." +msgstr "" +"Vous pouvez ensuite ouvrir ce lien dans une nouvelle fenêtre ou un nouvel " +"onglet et voir si votre site est affiché. Si cela fonctionne, vous pouvez " +"cliquer sur le bouton \"%(next)s\". Sinon, cliquez sur le bouton" +"\"%(previous)s\" et vérifiez vos paramètres." + +#: ../larpe/admin/hosts.ptl:345 +msgid "Site adress and name" +msgstr "Adresse et nom du site" + +#: ../larpe/admin/hosts.ptl:347 +msgid "The new address of this site is " +msgstr "La nouvelle adresse du site est " + +#: ../larpe/admin/hosts.ptl:349 +#, python-format +msgid "The name of this site is \"%s\"." +msgstr "Le nom du site est \"%s\"." + +#: ../larpe/admin/hosts.ptl:350 +msgid "" +"You can also \n" +"modify the address or the name of this site" +msgstr "" +"Vous pouvez aussi modifier " +"l'adresse ou le nom du site" + +#: ../larpe/admin/hosts.ptl:366 +msgid "An host with the same name already exists" +msgstr "Un hôte avec le même nom existe déjà" + +#: ../larpe/admin/hosts.ptl:373 ../larpe/admin/hosts.ptl:374 +msgid "Modify site address and name" +msgstr "Modifier l'adresse et le nom du site" + +#: ../larpe/admin/hosts.ptl:380 +msgid "Address" +msgstr "Adresse" + +#: ../larpe/admin/hosts.ptl:419 +msgid "Authentication and logout" +msgstr "Authentification et déconnexion" + +#: ../larpe/admin/hosts.ptl:420 +msgid "Step 3 - Configure authentication and logout pages" +msgstr "Étape 3 - Configurer les pages d'authentification et de déconnexion" + +#: ../larpe/admin/hosts.ptl:426 ../larpe/admin/hosts.ptl:969 +msgid "Authentication form page address" +msgstr "Adresse de la page du formulaire d'authentification" + +#: ../larpe/admin/hosts.ptl:427 +msgid "Address of a page on the site which contains the authentication form" +msgstr "Adresse d'une page du site contenant le formulaire d'authentification" + +#: ../larpe/admin/hosts.ptl:429 +msgid "Logout address" +msgstr "Adresse de déconnexion" + +#: ../larpe/admin/hosts.ptl:430 +msgid "Address of the logout link on the site" +msgstr "Adresse du lien de déconnexion du site" + +#: ../larpe/admin/hosts.ptl:446 +msgid "(computed automatically)" +msgstr "(calculé automatiquement)" + +#: ../larpe/admin/hosts.ptl:459 +msgid "Plugin" +msgstr "Extension" + +#: ../larpe/admin/hosts.ptl:460 +msgid "You can force a plugin" +msgstr "Vous pouvez forcer une extension" + +#: ../larpe/admin/hosts.ptl:478 +msgid "Auto detected configuration" +msgstr "Configuration détectée automatiquement" + +#: ../larpe/admin/hosts.ptl:479 +msgid "" +"Step 4 - Check automatically detected configuration for the authentication " +"form" +msgstr "" +"Étape 4 - Vérifier la configuration détectée automatiquement pour " +"l'authentification" + +#: ../larpe/admin/hosts.ptl:482 +msgid "Address where the authentication form must be sent" +msgstr "Adresse à laquelle le formulaire d'authentification doit être envoyé" + +#: ../larpe/admin/hosts.ptl:483 +msgid "Name of the login field" +msgstr "Nom du champ identifiant" + +#: ../larpe/admin/hosts.ptl:484 +msgid "Name of the password field" +msgstr "Nom du champ mot de passe" + +#: ../larpe/admin/hosts.ptl:503 +msgid "" +"The following authentication form parameters have been detected. If they " +"look right, you can go to the next step.\n" +"If you think they are wrong, go back and check your settings then try " +"again.\n" +msgstr "" +"Les paramètres d'authentification suivants ont été détectés. Si ils semblent " +"corrects, vous pouvez passer à l'étape suivante.\n" +"Si vous pensez qu'ils sont incorrects, retournez à l'étape précédente et " +"vérifiez vos paramètres, puis essayez à nouveau.\n" + +#: ../larpe/admin/hosts.ptl:508 +msgid "" +"The following authentication form parameters in red haven't been correctly " +"detected. Go back and check\n" +"your settings then try again.\n" +msgstr "" +"Les paramètres d'authentification suivants en rouge n'ont pas été détectés " +"correctement. Retournez à une étape précédente vérifiez vos paramètres, puis " +"essayez à nouveau.\n" + +#: ../larpe/admin/hosts.ptl:529 ../larpe/admin/hosts.ptl:1250 +msgid "Credentials" +msgstr "Identifiant et mot de passe" + +#: ../larpe/admin/hosts.ptl:530 +msgid "Step 5 - Fill in a valid username/password for this site" +msgstr "Étape 5 - Nom d'utilisateur et mot de passe pour ce site" + +#: ../larpe/admin/hosts.ptl:535 ../larpe/site_authentication.ptl:98 +msgid "Username" +msgstr "Identifiant" + +#: ../larpe/admin/hosts.ptl:537 ../larpe/site_authentication.ptl:100 +msgid "Password" +msgstr "Mot de passe" + +#: ../larpe/admin/hosts.ptl:594 +msgid "Check authentication" +msgstr "Vérifier l'authentification" + +#: ../larpe/admin/hosts.ptl:595 +msgid "Step 6 - Check the authentication process" +msgstr "Étape 6 - Vérifier la procédure d'authentification" + +#: ../larpe/admin/hosts.ptl:614 +msgid "Authentication succeeded ! You can go to the next step." +msgstr "" +"L'authentification a réussi ! Vous pouvez continuer à l'étape suivante." + +#: ../larpe/admin/hosts.ptl:616 +msgid "Authentication has failed. To resolve this problem, you can :" +msgstr "L'authentification a échoué. Pour résoudre ce problème, vous pouvez :" + +#: ../larpe/admin/hosts.ptl:619 +msgid "Try authentication again" +msgstr "Retenter une authentification" + +#: ../larpe/admin/hosts.ptl:621 +msgid "See the response of the authentication requests" +msgstr "Voir la réponse de la requête d'authentification" + +#: ../larpe/admin/hosts.ptl:623 ../larpe/admin/hosts.ptl:705 +msgid "Modify the parameters of the authentication requests" +msgstr "Modifier les paramètres des requêtes d'authentification" + +#: ../larpe/admin/hosts.ptl:625 +msgid "Change the way Larpe detects the authentication is successful or not" +msgstr "" +"Changer la façon donc Larpe détecte que l'authentification a réussi ou pas" + +#: ../larpe/admin/hosts.ptl:626 +msgid "Go back and change your username and/or password" +msgstr "Revenir en arrière et changer vos nom d'utilisateur et/ou mot de passe" + +#: ../larpe/admin/hosts.ptl:632 ../larpe/admin/hosts.ptl:633 +msgid "Authentication response" +msgstr "Réponse de l'authentification" + +#: ../larpe/admin/hosts.ptl:635 +msgid "Response of the request with good credentials" +msgstr "Réponse de la requête avec un bon couple identifiant/mot de passe" + +#: ../larpe/admin/hosts.ptl:638 ../larpe/admin/hosts.ptl:649 +msgid "HTTP status code" +msgstr "Code de status HTTP" + +#: ../larpe/admin/hosts.ptl:643 ../larpe/admin/hosts.ptl:654 +msgid "See HTML page" +msgstr "Voir la page HTML" + +#: ../larpe/admin/hosts.ptl:646 +msgid "Response of the request with bad credentials" +msgstr "Réponse de la requête avec un mauvais couple identifiant/mot de passe" + +#: ../larpe/admin/hosts.ptl:675 ../larpe/admin/hosts.ptl:676 +msgid "Authentication success criteria" +msgstr "Critères de succès de l'authentification" + +#: ../larpe/admin/hosts.ptl:682 +msgid "Authentication system of the original site" +msgstr "Système d'authentification du site d'origine" + +#: ../larpe/admin/hosts.ptl:684 +msgid "Check the existence of a password field" +msgstr "Vérifier l'existence d'un champ mot de passe" + +#: ../larpe/admin/hosts.ptl:685 +msgid "Match some text to detect an authentication failure" +msgstr "Trouver du texte pour détecter un échec d'authentification" + +#: ../larpe/admin/hosts.ptl:690 +msgid "Text to match in case of authentication failure" +msgstr "Texte à trouver dans le cas d'un échec d'authentification" + +#: ../larpe/admin/hosts.ptl:704 +msgid "Authentication request" +msgstr "Requête d'authentification" + +#: ../larpe/admin/hosts.ptl:709 +msgid "Modify POST parameters" +msgstr "Modifier les parameters du POST" + +#: ../larpe/admin/hosts.ptl:709 +msgid "" +"Configure the form attributes that will be sent within the authentication " +"POST requests" +msgstr "" +"Configurer les attributes du formulaire qui seront envoyés dans les requêtes " +"POST d'authentification" + +#: ../larpe/admin/hosts.ptl:711 +msgid "Modify HTTP headers" +msgstr "Modifier les entêtes HTTP" + +#: ../larpe/admin/hosts.ptl:711 +msgid "Configure the HTTP headers of the authentication requests made by Larpe" +msgstr "" +"Configurer les entêtes HTTP des requêtes d'authentification envoyées par " +"Larpe" + +#: ../larpe/admin/hosts.ptl:725 +msgid "POST parameters" +msgstr "Paramètres POST" + +#: ../larpe/admin/hosts.ptl:726 +msgid "Configure POST parameters" +msgstr "Configurer les paramètres POST" + +#: ../larpe/admin/hosts.ptl:728 +msgid "" +"Here are the detected form fields that will be sent as parameters of the\n" +"authentication POST request. You can desactivate some or all of them, or " +"change their value." +msgstr "" +"Voici les champs du formulaire détectés et qui seront envoyés en tant que " +"paramètres de la requête POST\n" +"d'authentification. Vous pouvez désactiver certains ou tous ces champs, ou " +"modifier leur valeur." + +#: ../larpe/admin/hosts.ptl:766 +msgid "HTTP headers" +msgstr "Entêtes HTTP" + +#: ../larpe/admin/hosts.ptl:767 +msgid "Configure HTTP headers" +msgstr "Configurer les entêtes HTTP" + +#: ../larpe/admin/hosts.ptl:769 +msgid "" +"Here are the HTTP headers that will be sent within the authentication\n" +"POST request. You can desactivate some or all of them, or change their value." +msgstr "" +"Voici les entêtes HTTP qui seront envoyés dans la requête POST\n" +"d'authentification. Vous pouvez désactiver certains ou tous ces champs, ou " +"modifier leur valeur." + +#: ../larpe/admin/hosts.ptl:782 +msgid "" +"The headers \"Host\", \"Accept-Encoding\" and \"Content-Length\" will also " +"automatically be sent." +msgstr "" +"Les entêtes \"Host\", \"Accept-Encoding\" et \"Content-Length\" seront " +"également envoyées automatiquement." + +#: ../larpe/admin/hosts.ptl:785 +msgid "" +"As Larpe uses a proxy for this site, the headers \"Proxy-Authorization\",\n" +"\"Proxy-Connection\" and \"Keep-Alive\" will be sent as well." +msgstr "" +"Comme Larpe utilise un mandataire (proxy) pour ce site, les entêtes\"Proxy-" +"Authorization\", \"Proxy-Connection\" et \"Keep-Alive\" seront aussienvoyées." + +#: ../larpe/admin/hosts.ptl:846 +msgid "SSO initiation" +msgstr "Initiation de l'authentification unique" + +#: ../larpe/admin/hosts.ptl:847 +msgid "Step 7 - Configure how a Single Sign On can be initiated" +msgstr "" +"Étape 7 - Configurer la façon dont l'authentification unique peut être " +"initiée" + +#: ../larpe/admin/hosts.ptl:849 +msgid "" +"Most sites use one of the following 2 ways to allow users to initialise an " +"authentication :" +msgstr "" +"La plupart des sites utilisent une des 2 méthodes suivantes pour permettre " +"aux utilisateursd'initier une authentification :" + +#: ../larpe/admin/hosts.ptl:852 +msgid "" +"The site has a single authentication page. It redirects users to this page " +"when\n" +"they click a \"Login\" button or try to access a page which require users to " +"be authenticated." +msgstr "" +"Le site a une page unique d'authentification. Il redirige les utilisateurs " +"vers cettepas lorsqu'ils cliquent sur un bouton \"Connexion\" ou essaient " +"d'accéder à une pagequi nécessitent que les utilisateurs soient authentifiés" + +#: ../larpe/admin/hosts.ptl:855 +msgid "" +"The site includes an authentication form in most or all of his pages. Users " +"can\n" +"authenticate on any of these pages, and don't need to be redirected to a " +"separate authentication page." +msgstr "" +"Le site inclut un formulaire d'authentification dans toutes ou la plupart de " +"ses pages.Les utilisateurs peuvent s'authentifier sur n'importe laquelle de " +"ces pages, et n'ont pasbesoin d'être redirigés vers une page " +"d'authentification séparée" + +#: ../larpe/admin/hosts.ptl:860 +msgid "Select the way your site works :" +msgstr "Sélectionner la façon dont votre site fonctionne :" + +#: ../larpe/admin/hosts.ptl:868 +msgid "The site has a single authentication page" +msgstr "Le site a une page d'authentification séparée" + +#: ../larpe/admin/hosts.ptl:869 +msgid "The site includes an authentication form in most or all pages" +msgstr "" +"Le site inclut un formulaire d'authentification imbriqué dans les pages" + +#: ../larpe/admin/hosts.ptl:900 +msgid "Metadatas" +msgstr "Méta-données" + +#: ../larpe/admin/hosts.ptl:901 +#, python-format +msgid "Step 8 - Metadatas of %(site_name)s" +msgstr "Étape 8- Méta-données de %(site_name)s" + +#: ../larpe/admin/hosts.ptl:904 +msgid "" +"Download the metadatas and the public key for this site and\n" +"upload them on your identity provider in order to use Liberty Alliance " +"features." +msgstr "" +"Téléchargez les méta-données et la clé publique de ce site et\n" +"fournissez-les au fournisseur d'identité afin d'utiliser les fonctionnalités " +"Liberty Alliance" + +#: ../larpe/admin/hosts.ptl:914 +msgid "Download SAML 2.0 metadata file" +msgstr "Télécharger le fichier des méta-données SAML 2.0" + +#: ../larpe/admin/hosts.ptl:919 +msgid "Download ID-FF 1.2 metadata file" +msgstr "Télécharger le fichier des méta-données ID-FF 1.2" + +#: ../larpe/admin/hosts.ptl:921 +msgid "No metadata has been generated for this host." +msgstr "Les méta-données pour ce site n'ont pas été générées." + +#: ../larpe/admin/hosts.ptl:930 +msgid "No public key has been generated for this host." +msgstr "La clé publique pour ce site n'a pas été générée." + +#: ../larpe/admin/hosts.ptl:942 +msgid "Advanced options" +msgstr "Options avancées" + +#: ../larpe/admin/hosts.ptl:943 +msgid "Step 9 - Advanced options" +msgstr "Étape 9 - Options avancées" + +#: ../larpe/admin/hosts.ptl:945 +msgid "Configure advanced options to setup the last details of your site." +msgstr "" +"Configurer les options avancées afin de paramétrer les derniers détails de " +"votre site" + +#: ../larpe/admin/hosts.ptl:946 +#, python-format +msgid "" +"If you don't know what to configure here, just click %(next)s and\n" +"come here later if needed." +msgstr "" +"Si vous ne savez pas quoi configurer ici, cliquez simplement sur %(next)s " +"etrevenez sur cette page plus tard si besoin" + +#: ../larpe/admin/hosts.ptl:959 +msgid "Redirect the root URL of the site to the login page." +msgstr "Rediriger la racine du site vers la page de d'authentification unique" + +#: ../larpe/admin/hosts.ptl:961 +msgid "Return address" +msgstr "Adresse de retour" + +#: ../larpe/admin/hosts.ptl:962 +msgid "Where the user will be redirected after a successful authentication" +msgstr "" +"Adresse vers laquelle l'utilisateur sera redirigé après s'être authentifié" + +#: ../larpe/admin/hosts.ptl:964 +msgid "Error address" +msgstr "Addresse en cas d'erreur" + +#: ../larpe/admin/hosts.ptl:965 +msgid "Where the user will be redirected after a disconnection or an error" +msgstr "Où l'utilisateur sera redirigé après une déconnexion ou une erreur" + +#: ../larpe/admin/hosts.ptl:967 +msgid "URL which must initiate the SSO" +msgstr "URL qui doit initier l'authentification unique" + +#: ../larpe/admin/hosts.ptl:968 +#, python-format +msgid "" +"Address which must initiate the SSO. If empty, defaults to the previously\n" +"specified \"%s\"" +msgstr "" +"Adresse qui doit initier l'authentification unique. Si ce champ est vide, " +"l'adresse utilisée sera celle qui a été précédemment renseignée en tant que " +"\"%s\"" + +#: ../larpe/admin/hosts.ptl:971 +msgid "Apache HTML proxy" +msgstr "Mandataire (proxy) HTML d'Apache" + +#: ../larpe/admin/hosts.ptl:972 +msgid "" +"Converts urls in the HTML pages according to the host new domain name.\n" +"Disabled by default because it makes some sites not work correctly." +msgstr "" +"Convertir les urls des pages HTML en fonction du nouveau nom de domaine du " +"site. Cette option est désactivée par défaut car elle empêche certains sites " +"de fonctionner correctement." + +#: ../larpe/admin/hosts.ptl:1003 ../larpe/admin/hosts.ptl:1024 +msgid "Finish" +msgstr "Terminer" + +#: ../larpe/admin/hosts.ptl:1011 +msgid "Check everything works" +msgstr "Vérifier que tout fonctionne" + +#: ../larpe/admin/hosts.ptl:1012 +msgid "Step 10 - Check everything works" +msgstr "Étape 10 - Vérifier que tout fonctionne" + +#: ../larpe/admin/hosts.ptl:1015 +msgid "" +"Now you can fully test your site, start from the home page, initiate a\n" +"Single Sign On, federate your identities and do a Single Logout." +msgstr "" +"Vous pouvez maintenant tester vote nouveau site complètement.\n" +"Commencez par la page d'accueil, initiez une authentification unique,\n" +"fédérez vos identités puis faites une déconnexion unique." + +#: ../larpe/admin/hosts.ptl:1018 +msgid "The address of your site is : " +msgstr "L'adresse du site est : " + +#: ../larpe/admin/hosts.ptl:1023 +#, python-format +msgid "" +"If everything works, click the \"%(finish)s\" button, otherwise you can go\n" +"back and check your settings." +msgstr "" +"Si tout fonctionne, cliquez sur le bouton \"%(finish)s\", sinon vous pouvez " +"revenir en arrière et vérifier votre configuration" + +#: ../larpe/admin/hosts.ptl:1136 ../larpe/admin/hosts.ptl:1151 +#: ../larpe/admin/hosts.ptl:1182 +msgid "(filled by users)" +msgstr "(rempli par les utilisateurs)" + +#: ../larpe/admin/hosts.ptl:1233 +msgid "Configuration assistant" +msgstr "Assistant de configuration" + +#: ../larpe/admin/hosts.ptl:1238 +msgid "Address of the original site" +msgstr "Adresse du site d'origine" + +#: ../larpe/admin/hosts.ptl:1238 +msgid "Configure the root address of the site" +msgstr "Configurer l'adresse racine de ce site" + +#: ../larpe/admin/hosts.ptl:1241 +msgid "New address and name" +msgstr "Nouvelle adresse et nouveau nom du site" + +#: ../larpe/admin/hosts.ptl:1241 +msgid "Configure the new address and name of this site" +msgstr "Configurer la nouvelle adresse et le nouveau nom du site" + +#: ../larpe/admin/hosts.ptl:1244 +msgid "Authentication and logout addresses" +msgstr "Adresses des pages d'authentification et de déconnexion" + +#: ../larpe/admin/hosts.ptl:1244 +msgid "Configure the authentication and logout addresses of the original site" +msgstr "" +"Configurer les adresses des pages d'authentification et de déconnexion du " +"site d'origine" + +#: ../larpe/admin/hosts.ptl:1247 +msgid "Check auto detected configuration" +msgstr "Vérifier la configuration détectée automatiquement" + +#: ../larpe/admin/hosts.ptl:1247 +msgid "Check the automatically detected configuration is right" +msgstr "Vérifier que la configuration détectée automatiquement est correcte" + +#: ../larpe/admin/hosts.ptl:1250 +msgid "Configure some valid credentials to authenticate on the original site" +msgstr "" +"Configurer un couple identifiant / mot de passe pour s'authentifier sur le " +"site d'origine" + +#: ../larpe/admin/hosts.ptl:1253 +msgid "Retry authentication" +msgstr "Retenter l'authentification" + +#: ../larpe/admin/hosts.ptl:1253 +msgid "" +"Retry sending an authentication request to the site to check if your new " +"parameters work well" +msgstr "" +"Retenter d'envoyer une requête d'authentification au site pour vérifier si " +"vos nouveaux paramètres fonctionnent bien" + +#: ../larpe/admin/hosts.ptl:1256 +msgid "Check authentication response" +msgstr "Vérifier la réponse de l'authentification" + +#: ../larpe/admin/hosts.ptl:1256 +msgid "Check the response from the latest authentication request" +msgstr "Vérifier la réponse de la dernière requête d'authentification" + +#: ../larpe/admin/hosts.ptl:1259 +msgid "Configure authentication success criteria" +msgstr "Configurer les critères de succès de l'authentification" + +#: ../larpe/admin/hosts.ptl:1259 +msgid "Specify how Larpe knows if the authentication has succeeded or not" +msgstr "" +"Spécifier comment Larpe détermine si l'authentification a réussi ou pas" + +#: ../larpe/admin/hosts.ptl:1262 +msgid "Modify authentication request" +msgstr "Modifier la requête d'authentification" + +#: ../larpe/admin/hosts.ptl:1262 +msgid "Modify POST fields or HTTP headers of the authentication request" +msgstr "" +"Modifier les champs POST ou les entêtes HTTP de la requête d'authentification" + +#: ../larpe/admin/hosts.ptl:1265 +msgid "Configure how a Single Sign On can be initiated" +msgstr "Configurer la façon dont l'authentification unique peut être initiée" + +#: ../larpe/admin/hosts.ptl:1268 +msgid "Metadatas and key" +msgstr "Méta-données et clé" + +#: ../larpe/admin/hosts.ptl:1268 +msgid "Download SAML 2.0 or ID-FF metadatas and SSL public key" +msgstr "Télécharger les méta-données SAML 2.0 ou ID-FF et la clé SSL publique" + +#: ../larpe/admin/hosts.ptl:1271 +msgid "Adavanced options" +msgstr "Options avancées" + +#: ../larpe/admin/hosts.ptl:1271 +msgid "Configure advanced options to setup the last details of your site" +msgstr "" +"Configurer les options avancées afin de paramétrer les derniers détails de " +"votre site" + +#: ../larpe/admin/hosts.ptl:1275 +msgid "Form prefilling with ID-WSF" +msgstr "Pré-remplissage de formulaire avec ID-WSF" + +#: ../larpe/admin/hosts.ptl:1279 +msgid "Configure the forms to prefill" +msgstr "Configurer les formulaires à pré-remplir" + +#: ../larpe/admin/hosts.ptl:1285 +msgid "You are about to irrevocably delete this host." +msgstr "Vous allez définitivement supprimer cet hôte." + +#: ../larpe/admin/hosts.ptl:1292 ../larpe/admin/hosts.ptl:1293 +msgid "Delete Host" +msgstr "Supprimer l'hôte" + +#: ../larpe/admin/hosts.ptl:1305 ../larpe/admin/hosts.ptl:1306 +#: ../larpe/admin/hosts.ptl:1343 ../larpe/admin/hosts.ptl:1350 +#: ../larpe/admin/root.ptl:44 +msgid "Hosts" +msgstr "Hôtes" + +#: ../larpe/admin/hosts.ptl:1309 ../larpe/admin/hosts.ptl:1336 +#: ../larpe/admin/hosts.ptl:1337 +msgid "New Host" +msgstr "Nouvel hôte" + +#: ../larpe/admin/root.ptl:48 +msgid "Liberty Alliance Reverse Proxy" +msgstr "Relais inverse Liberty Alliance" + +#: ../larpe/admin/root.ptl:59 +msgid "Administration" +msgstr "Administration" + +#: ../larpe/saml2.ptl:32 ../larpe/saml2.ptl:46 +msgid "SAML 2.0 support not yet configured." +msgstr "Le support SAML 2.0 n'est pas encore configuré" + +#: ../larpe/saml2.ptl:53 +msgid "Missing SAML Artifact" +msgstr "Artifact SAML manquant" + +#: ../larpe/saml2.ptl:64 ../larpe/liberty.ptl:58 +msgid "Failure to communicate with identity provider" +msgstr "Impossible de communiquer avec le fournisseur d'identités." + +#: ../larpe/saml2.ptl:70 ../larpe/liberty.ptl:63 +msgid "Unknown authentication failure" +msgstr "Erreur d'authentification inconnue" + +#: ../larpe/saml2.ptl:72 ../larpe/liberty.ptl:66 +msgid "Authentication failure; unknown principal" +msgstr "Erreur d'authentification: utilisateur inconnu" + +#: ../larpe/saml2.ptl:334 ../larpe/liberty.ptl:142 ../larpe/liberty.ptl:173 +msgid "Failed to check single logout request signature." +msgstr "Erreur à la vérification de la signature de la demande de déconnexion" + +#: ../larpe/site_authentication.ptl:60 +msgid "Local authentication" +msgstr "Authentification locale" + +#: ../larpe/site_authentication.ptl:74 +msgid "Authentication failure" +msgstr "Erreur d'authentification" + +#: ../larpe/site_authentication.ptl:77 +#, python-format +msgid "Connection failed : %s" +msgstr "Échec de la connexion : %s" + +#: ../larpe/site_authentication.ptl:80 +#, python-format +msgid "This service provider is not fully configured : %s" +msgstr "Ce fournisseur de service n'est pas complètement configuré : %s" + +#: ../larpe/site_authentication.ptl:83 +#, python-format +msgid "Unknown error : %s" +msgstr "Erreur inconnue : %s" + +#: ../larpe/site_authentication.ptl:89 +msgid "Please type your login and password for this Service Provider." +msgstr "" +"Entrez votre identifiant et votre mot de passe pour ce fournisseur de " +"service." + +#: ../larpe/site_authentication.ptl:90 ../larpe/root.ptl:74 +msgid "" +"Your local account will be federated with your Liberty Alliance account." +msgstr "Votre compte local sera fédéré avec votre compte Liberty Alliance." + +#: ../larpe/site_authentication.ptl:296 +#, python-format +msgid "%s logout failed" +msgstr "%s échec de la déconnexion" + +#: ../larpe/root.ptl:27 +msgid "Welcome to Larpe reverse proxy" +msgstr "Bienvenue sur le reverse proxy Larpe" + +#: ../larpe/root.ptl:29 +msgid "Configure Larpe" +msgstr "Configurer Larpe" + +#: ../larpe/root.ptl:73 +msgid "Please enter your identification token. " +msgstr "Veuillez saisir votre jeton d'identification. " + +#: ../larpe/root.ptl:87 +msgid "Unknown Token" +msgstr "Jeton inconnu" + +#: ../larpe/liberty.ptl:45 +msgid "Liberty support is not yet configured" +msgstr "Le support Liberty n'est pas encore configuré" + +#: ../larpe/liberty.ptl:67 +msgid "Identity Provider didn't accept artifact transaction." +msgstr "Le fournisseur d'identité n'a pas accepté l'artifact." + +#: ../larpe/users.py:38 +msgid "Unknown User" +msgstr "Utilisateur inconnu" + +#~ msgid "My Space" +#~ msgstr "Mon espace" + +#~ msgid "back office" +#~ msgstr "backoffice" + +#~ msgid "admin" +#~ msgstr "admin" + +#~ msgid "My Profile" +#~ msgstr "Mon profil" + +#~ msgid "Empty profile" +#~ msgstr "Profile vide" + +#~ msgid "Edit My Profile" +#~ msgstr "Editer mon profil" + +#~ msgid "Change My Password" +#~ msgstr "Changement de mot de passe" + +#~ msgid "Remove My Account" +#~ msgstr "Supprimer un compte" + +#~ msgid "Apply Changes" +#~ msgstr "Appliquer les changements" + +#~ msgid "Edit Profile" +#~ msgstr "Editer le profile" + +#~ msgid "New Password" +#~ msgstr "Nouveau mot de passe" + +#~ msgid "New Password (confirm)" +#~ msgstr "Nouveau mot de passe (confirmation)" + +#~ msgid "Change Password" +#~ msgstr "Changement de mot de passe" + +#~ msgid "Passwords do not match" +#~ msgstr "Les mots de passe sont différents" + +#~ msgid "Are you really sure you want to remove your account?" +#~ msgstr "Etes vous vraiment sûr de vouloir supprimer votre compte ?" + +#~ msgid "Remove my account" +#~ msgstr "Supprimer mon compte" + +#~ msgid "Removing Account" +#~ msgstr "Supression du compte" + +#~ msgid "Text on top of the profile page" +#~ msgstr "Texte en haut de la page de profil" + +#~ msgid "day" +#~ msgstr "Moi" + +#, fuzzy +#~ msgid "minute" +#~ msgstr "moins" + +#, fuzzy +#~ msgid "minutes" +#~ msgstr "moins" + +#, fuzzy +#~ msgid "%s minutes" +#~ msgstr "moins" + +#~ msgid "registered" +#~ msgstr "enregistré" + +#~ msgid "running" +#~ msgstr "en fonctionnement" + +#~ msgid "completed" +#~ msgstr "terminé" + +#~ msgid "Access Forbidden" +#~ msgstr "Accès interdit" + +#~ msgid "the homepage" +#~ msgstr "la page d'accueil" + +#~ msgid "Oops, the server borked severely" +#~ msgstr "Oups, le serveur s'est méchamment planté" + +#~ msgid "" +#~ "This is bad bad bad; perhaps you will have more luck if you retry in a " +#~ "few minutes ? " +#~ msgstr "" +#~ "C'est mal mal mal; peut-être aurez-vous plus de chance en réessayant dans " +#~ "quelques minutes ? " + +#~ msgid "" +#~ "Alternatively you could harass the webmaster (who may have been emailed " +#~ "automatically with this incident but you can't be sure about this." +#~ msgstr "" +#~ "Autrement vous pouvez harceler le webmestre (qui devrait avoir été " +#~ "prévenu automatiquement de cet incident par un courriel, mais en êtes " +#~ "vous sûr ?)." + +#~ msgid "Page not found" +#~ msgstr "Page non trouvée" + +#~ msgid "" +#~ "The requested link does not exist on this site. If you arrived here by " +#~ "following a link from an external page, please inform that page's " +#~ "maintainer." +#~ msgstr "" +#~ "La page demandée n'existe pas sur ce site. Si vous êtes arrivé ici en " +#~ "suivant un lien depuis un autre site, veuillez informer le propriétaire " +#~ "de cette autre page." + +#~ msgid "Password is too short. It must be at least %d characters." +#~ msgstr "" +#~ "Le mot de passe est trop court. Il doit contenir au moins %d caractères." + +#~ msgid "Password is too long. It must be at most %d characters." +#~ msgstr "" +#~ "Le mot de passe est trop long. Il doit contenir au plus %d caractères." + +#, fuzzy +#~ msgid "Invalid Token" +#~ msgstr "date invalide" + +#~ msgid "Account Creation Confirmed" +#~ msgstr "Création du compte confirmée" + +#~ msgid "Log in" +#~ msgstr "S'identifier" + +#~ msgid "Login" +#~ msgstr "S'identifier" + +#~ msgid "Invalid credentials" +#~ msgstr "Identifiant ou mot de passe invalide" + +#~ msgid "This account is waiting for moderation" +#~ msgstr "Ce compte est en attente de modération" + +#~ msgid "This account is waiting for confirmation" +#~ msgstr "Ce compte est en attente de confirmation" + +#~ msgid "This account has been disabled" +#~ msgstr "Ce compte a été désactivé" + +#~ msgid "Submit Request" +#~ msgstr "Valider la requête" + +#~ msgid "Forgotten password" +#~ msgstr "Mot de passe oublié" + +#~ msgid "There is no user with that name or it has no email contact." +#~ msgstr "" +#~ "Il n'y a pas d'utilisateur avec ce nom ou cet utilisateur n'a pas " +#~ "d'adresse de courriel de contact" + +#~ msgid "Failed to send email (server error)" +#~ msgstr "Échec lors de l'envoi du courriel (erreur du serveur)" + +#~ msgid "Forgotten Password" +#~ msgstr "Mot de passe oublié" + +#~ msgid "" +#~ "The token you submitted does not exist, has expired, or has been " +#~ "cancelled." +#~ msgstr "" +#~ "Le jeton que vous avez entré n'existe pas, a expiré, ou a été annulé" + +#~ msgid "home page" +#~ msgstr "page d'accueil" + +#~ msgid "The token you submitted is not appropriate for the requested task." +#~ msgstr "" +#~ "Le jeton que vous avez entré n'est pas approprié pour la tâche demandée" + +#~ msgid "Request Cancelled" +#~ msgstr "Requête annulée" + +#~ msgid "Your request has been cancelled" +#~ msgstr "Votre requête a été annulée" + +#~ msgid "Continue to home page

" +#~ msgstr "Continuez vers page d'accueil

" + +#~ msgid "New password sent by email" +#~ msgstr "Un nouveau mot de passe a été envoyé par courriel" + +#, fuzzy +#~ msgid "Password (confirm)" +#~ msgstr "Nouveau mot de passe (confirmation)" + +#~ msgid "Create Account" +#~ msgstr "Création un compte" + +#~ msgid "New Account" +#~ msgstr "Nouveau compte" + +#~ msgid "There is already a user with that username" +#~ msgstr "Il y a déjà un utilisateur avec ce nom" + +#~ msgid "There is already a user with that email address" +#~ msgstr "Il y a déjà un utilisateur avec cette adresse de courriel" + +#~ msgid "" +#~ "Accounts are configured to require confirmation but accounts can be " +#~ "created without emails" +#~ msgstr "" +#~ "Les comptes sont configurés pour nécessiter une confirmation mais les " +#~ "comptes peuvent être crées sans courriel" + +#, fuzzy +#~ msgid "" +#~ "Accounts are configured to have a generated password but accounts can be " +#~ "created without emails" +#~ msgstr "" +#~ "Les comptes sont configurés pour nécessiter une confirmation mais les " +#~ "comptes peuvent être crées sans courriel" + +#~ msgid "Account created, waiting for moderation" +#~ msgstr "Compte créé, en attente de modération" + +#~ msgid "A site administrator will now review then activate your account." +#~ msgstr "" +#~ "Un administrateur du site va maintenant vérifier puis activer votre compte" + +#~ msgid "You will then get your password by email." +#~ msgstr "Votre mot de passe vous sera ensuite envoyé par courriel" + +#~ msgid "Back to home page" +#~ msgstr "Retour à la page d'accueil" + +#~ msgid "Email sent" +#~ msgstr "Courriel envoyé" + +#~ msgid "Username / Password" +#~ msgstr "Identifiant / Mot de passe" + +#~ msgid "Configure username/password identification method" +#~ msgstr "Configurer la méthode d'identification par identifiant/mot de passe" + +#~ msgid "Identities" +#~ msgstr "Identités" + +#~ msgid "Configure identities creation" +#~ msgstr "Configurer la création des identités" + +#~ msgid "Passwords" +#~ msgstr "Mots de passe" + +#~ msgid "Configure all password things" +#~ msgstr "Configurer les paramètres relatifs aux mots de passe" + +#~ msgid "Bulk Import" +#~ msgstr "Import de masse" + +#~ msgid "Import accounts from a CSV file" +#~ msgstr "Comptes importer depuis un fichier CSV" + +#~ msgid "Users can change their password" +#~ msgstr "Les utilisateurs peuvent changer leur mot de passe" + +#~ msgid "Generate initial password" +#~ msgstr "Générer le mot de passe initial" + +#~ msgid "Lost Password Behaviour" +#~ msgstr "Comportement en cas de perte de mot de passe" + +#~ msgid "Nothing (contact admin)" +#~ msgstr "Rien (contactez l'administrateur)" + +#~ msgid "Email reminder" +#~ msgstr "Rappel par courriel" + +#~ msgid "Question selected by user" +#~ msgstr "Question selectionnée par l'utilisateur" + +#~ msgid "Minimum password length" +#~ msgstr "Taille minimum des mots de passe" + +#~ msgid "Maximum password length" +#~ msgstr "Taille maximum des mots de passe" + +#~ msgid "0 for unlimited length" +#~ msgstr "0 pour une taille illimitée" + +#~ msgid "Email address (for questions...)" +#~ msgstr "Addresse de courriel (pour des questions ...)" + +#~ msgid "None" +#~ msgstr "Aucun" + +#~ msgid "Password Hashing Algorithm" +#~ msgstr "Algorithm de hachage de mots de passe" + +#~ msgid "Identity Creation" +#~ msgstr "Création d'identité" + +#~ msgid "Site Administrator" +#~ msgstr "Administrateur du site" + +#~ msgid "Self-registration" +#~ msgstr "Inscription par l'utilisateur" + +#~ msgid "Moderated user registration" +#~ msgstr "Inscription par l'utilisateur avec modération" + +#~ msgid "Require email confirmation for new accounts" +#~ msgstr "Demander une confirmation par courriel pour les nouveaux comptes" + +#~ msgid "Notify Administrators on Registration" +#~ msgstr "Notifier les administrateurs lors d'inscriptions" + +#~ msgid "Use email as username" +#~ msgstr "Utiliser le courriel comme identifiant" + +#~ msgid "Warn about unused account after so many days" +#~ msgstr "Avertir lorsque des comptes sont inutilisés depuis plusieurs jours" + +#~ msgid "0 for no warning" +#~ msgstr "0 pour aucun avertissement" + +#~ msgid "Removed unused account after so many days" +#~ msgstr "Compte inutilisés qui ont été supprimés après plusieurs jours" + +#~ msgid "0 for no automatic removal" +#~ msgstr "0 pour désactiver la suppression automatique" + +#~ msgid "Identities Interface" +#~ msgstr "Interface des identités" + +#~ msgid "File" +#~ msgstr "Fichier" + +#, fuzzy +#~ msgid "Send notifications to users" +#~ msgstr "Jeton d'identification" + +#, fuzzy +#~ msgid "Add Role" +#~ msgstr "Ajouter un élément" + +#~ msgid "The CSV file must strictly adhere to the following structure:" +#~ msgstr "Le fichier CSV doit correspondre à la structure suivante :" + +#~ msgid "Charset: %s" +#~ msgstr "Encodage: %s" + +#~ msgid "Column Separator: ;" +#~ msgstr "Séparateur de colonne: ;" + +#~ msgid "Columns:" +#~ msgstr "Colonnes :" + +#, fuzzy +#~ msgid "(empty to get an automatically generated password)" +#~ msgstr "Nouveau mot de passe généré" + +#~ msgid "Incorrect number of columns (line: %s)" +#~ msgstr "Numéro de colonne incorrect (ligne : %s)" + +#~ msgid "Duplicate username (line: %s)" +#~ msgstr "Nom d'utilisateur dupliqué (ligne: %s)" + +#~ msgid "Number of accounts created: %s" +#~ msgstr "Nombre de compte créé : %s" + +#, fuzzy +#~ msgid "Sending subscription emails" +#~ msgstr "Configuration de souscription" + +#, fuzzy +#~ msgid "Notifications" +#~ msgstr "Jeton d'identification" + +#~ msgid "Awaiting Confirmation" +#~ msgstr "En attente de confirmation" + +#~ msgid "Awaiting Moderation" +#~ msgstr "En attente de modération" + +#~ msgid "Disabled Account" +#~ msgstr "Nouvel hôte" + +#~ msgid "Username / password" +#~ msgstr "Identifiant / mot de passe" + +#~ msgid "Duplicate user name" +#~ msgstr "Nom d'utilisateur en double" + +#~ msgid "Accounts" +#~ msgstr "Comptes" + +#~ msgid "Account - %s" +#~ msgstr "Compte - %s" + +#~ msgid "Moderation of account" +#~ msgstr "Modération de compte" + +#~ msgid "Reply by email" +#~ msgstr "Répondre par courriel" + +#~ msgid "Accept" +#~ msgstr "Accepter" + +#~ msgid "Reject" +#~ msgstr "Rejeter" + +#~ msgid "To" +#~ msgstr "À" + +#~ msgid "Subject" +#~ msgstr "Sujet" + +#~ msgid "Message" +#~ msgstr "Message" + +#~ msgid "Submit and don't send email" +#~ msgstr "Valider et ne pas envoyer de courriel" + +#~ msgid "Rejection" +#~ msgstr "Rejet" + +#~ msgid "About your account request" +#~ msgstr "À propos de votre demande de compte" + +#~ msgid "You are not allowed to access Accounts Management" +#~ msgstr "Vous n'êtes pas autorisé à accéder à la gestion des comptes" + +#~ msgid "Accounts Management" +#~ msgstr "Gestion des comptes" + +#~ msgid "New accounts waiting for moderation" +#~ msgstr "De nouveaux comptes sont en attente de modération" + +#~ msgid "Username:" +#~ msgstr "Identifiant :" + +#~ msgid "Subscription notification for password account" +#~ msgstr "Notification d'inscription pour un compte à mot de passe" + +#~ msgid "" +#~ "Available variables: email, website, token_url, admin_email, username, " +#~ "password" +#~ msgstr "" +#~ "Variables disponibles : email, website, token_url, admin_email, username, " +#~ "password" + +#, fuzzy +#~ msgid "Identification" +#~ msgstr "Jeton d'identification" + +#~ msgid "Subscription Confirmation" +#~ msgstr "Configuration de souscription" + +#~ msgid "" +#~ "We have received a request for subscription of your email address,\n" +#~ "\"[email]\", to the [website] web site.\n" +#~ "\n" +#~ "To confirm that you want to be subscribed to the web site, simply\n" +#~ "visit this web page:\n" +#~ "\n" +#~ "[token_url]\n" +#~ "\n" +#~ "If you do not wish to be subscribed to the web site, pleasy simply\n" +#~ "disregard this message. If you think you are being maliciously\n" +#~ "subscribed to the web site, or have any other questions, send them\n" +#~ "to [admin_email].\n" +#~ msgstr "" +#~ "Nous avons reçu une demande d'inscription provenant de votre adresse\n" +#~ "de courriel,\"[email]\", pour le site internet [website].\n" +#~ "\n" +#~ "Pour confirmer votre inscription à ce site, visitez simplement cette\n" +#~ "page :\n" +#~ "\n" +#~ "[token_url]\n" +#~ "\n" +#~ "Si vous ne souhaitez pas être inscrit au site internet, ignorez ce\n" +#~ "message. Si vous pensez que vous avez été inscrit à votre insu, ou\n" +#~ "avez toute autre question à nous poser, envoyer nous un courriel\n" +#~ "à [admin_email].\n" + +#~ msgid "Request for password change" +#~ msgstr "Demande de changement de mot de passe" + +#~ msgid "Available variables: change_url, cancel_url, time" +#~ msgstr "Variables disponibles : change_url, cancel_url, time" + +#~ msgid "Change Password Request" +#~ msgstr "Requête de changement de mot de passe" + +#~ msgid "" +#~ "You have (or someone impersonating you has) requested to change your\n" +#~ "password. To complete the change, visit the following link:\n" +#~ "\n" +#~ "[change_url]\n" +#~ "\n" +#~ "If you are not the person who made this request, or you wish to cancel\n" +#~ "this request, visit the following link:\n" +#~ "\n" +#~ "[cancel_url]\n" +#~ "\n" +#~ "If you do nothing, the request will lapse after 3 days (precisely on\n" +#~ "[time]).\n" +#~ msgstr "" +#~ "Vous avez (ou quelqu'un se faisant passer pour vous) demandé à changer " +#~ "de\n" +#~ "mot de passe. Pour accomplir ce changement, visitez cette page :\n" +#~ "\n" +#~ "[change_url]\n" +#~ "\n" +#~ "Si vous n'êtes pas la personne qui a fait cette requête, ou si vous " +#~ "voulez\n" +#~ "l'annuler, allez sur la page suivante :\n" +#~ "\n" +#~ "[cancel_url]\n" +#~ "\n" +#~ "Si vous ne faites rien, la demande expirera automatiquement dans 3 " +#~ "jours,\n" +#~ "précisement le [time]).\n" + +#~ msgid "New generated password" +#~ msgstr "Nouveau mot de passe généré" + +#~ msgid "Available variable: password" +#~ msgstr "Variables disponibles : password" + +#~ msgid "Your new password" +#~ msgstr "Votre nouveau mot de passe" + +#~ msgid "Your new password: [password]\n" +#~ msgstr "Votre nouveau mot de passe : [password]\n" + +#~ msgid "Approval of new account" +#~ msgstr "Acceptation du nouveau compte" + +#~ msgid "Available variables: username, password" +#~ msgstr "Variables disponibles : username, password" + +#~ msgid "Your account has been approved" +#~ msgstr "Votre compte a été validé" + +#~ msgid "" +#~ "Your account has been approved.\n" +#~ "\n" +#~ "Account details:\n" +#~ "\n" +#~ "- username: [username]\n" +#~ "[if-any password]- password: [password][end]\n" +#~ msgstr "" +#~ "Votre compte a été validé.\n" +#~ "\n" +#~ "Détails du compte :\n" +#~ "\n" +#~ "- identifiant: [username]\n" +#~ "[if-any password]- mot de passe: [password][end]\n" + +#~ msgid "Warning about unusued account" +#~ msgstr "Avertissement pour les comptes inutilisés" + +#~ msgid "Available variables: username" +#~ msgstr "Variables disponibles : username" + +#~ msgid "Your account is unused" +#~ msgstr "Votre compte est inutilisé" + +#~ msgid "Your account ([username]) is not being used.\n" +#~ msgstr "Votre compte ([username]) n'est pas utilisé.\n" + +#~ msgid "Notification of removal of unused account" +#~ msgstr "Notification de suppression de compte inutilisé" + +#~ msgid "Your account has been removed" +#~ msgstr "Votre compte a été supprimé" + +#~ msgid "" +#~ "Your account ([username]) was not being used, it has therefore been " +#~ "removed.\n" +#~ msgstr "" +#~ "Votre compte ([username]) n'était plus utilisé et a donc été supprimé.\n" + +#~ msgid "Notification of new registration to administrators" +#~ msgstr "Notification des nouvelles inscriptions aux administrateurs" + +#~ msgid "Available variables: hostname, email_as_username, username" +#~ msgstr "Variables disponibles : hostname, email_as_username, username" + +#~ msgid "New Registration" +#~ msgstr "Nouvelle inscription" + +#~ msgid "" +#~ "Hello,\n" +#~ "\n" +#~ "A new account has been created on [hostname].\n" +#~ "\n" +#~ " - name: [name]\n" +#~ " - username: [username]\n" +#~ msgstr "" +#~ "Bonjour,\n" +#~ "\n" +#~ "Un nouveau compte a été créé sur [hostname].\n" +#~ "\n" +#~ " - nom : [name]\n" +#~ " - identifiant : [username]\n" + +#, fuzzy +#~ msgid "Welcome email, with generated password" +#~ msgstr "Nouveau mot de passe généré" + +#, fuzzy +#~ msgid "Available variables: hostname, username, password, email_as_username" +#~ msgstr "Variables disponibles : hostname, email_as_username, username" + +#, fuzzy +#~ msgid "" +#~ "Welcome to [hostname],\n" +#~ "\n" +#~ "Your password is: [password]\n" +#~ msgstr "Votre nouveau mot de passe : [password]\n" + +#~ msgid "Text when account confirmed by user but waiting moderator approval" +#~ msgstr "" +#~ "Texte quand le compte a été confirmé par l'utilisateur mais en attente de " +#~ "validation d'un modérateur" + +#~ msgid "" +#~ "

\n" +#~ "Your account has been created. In order to be effective\n" +#~ "it must be activated by a moderator. You will receive an\n" +#~ "email when this is done.\n" +#~ "

" +#~ msgstr "" +#~ "

\n" +#~ "Votre compte a été créé. Afin d'être utilisable,\n" +#~ "il doit être activé par un modérateur. Vous recevrez un\n" +#~ "courriel quand ce sera fait.\n" +#~ "

" + +#~ msgid "Text when account confirmed by user" +#~ msgstr "Texte quand le compte a été confirmé par l'utilisateur" + +#~ msgid "" +#~ "

\n" +#~ "Your account has been created.\n" +#~ "

" +#~ msgstr "" +#~ "

\n" +#~ "Votre compte a été créé.\n" +#~ "

" + +#~ msgid "Text when an email with a change password token has been sent" +#~ msgstr "" +#~ "Texte quand un courriel avec un jeton de changement de mot de passe a été " +#~ "envoyé" + +#~ msgid "" +#~ "

\n" +#~ "A token for changing your password has been emailed to you. Follow the " +#~ "instructions in that email to change your password.\n" +#~ "

\n" +#~ "

\n" +#~ " Log In\n" +#~ "

" +#~ msgstr "" +#~ "

\n" +#~ "Un jeton de changement de mot de passe vous a été envoyé par courriel. " +#~ "Suivez les instructions dans celui-ci pour changer votre mot de passe.\n" +#~ "

\n" +#~ "

\n" +#~ " S'identifier\n" +#~ "

" + +#~ msgid "Text when new password has been sent" +#~ msgstr "Texte quand un nouveau mot de passe a été envoyé" + +#~ msgid "" +#~ "

\n" +#~ "Your new password has been sent to you by email.\n" +#~ "

\n" +#~ "

\n" +#~ " Login\n" +#~ "

" +#~ msgstr "" +#~ "

\n" +#~ "Votre nouveau mot de passe vous a été envoyé par courriel.\n" +#~ "

\n" +#~ "

\n" +#~ " S'identifier\n" +#~ "

" + +#~ msgid "Text on top of registration form" +#~ msgstr "Texte en haut du formulaire d'enregistrement" + +#~ msgid "Text on forgotten password request page" +#~ msgstr "Texte sur la page de demande de mot de passe oublié" + +#~ msgid "" +#~ "

\n" +#~ "If you have an account, but have forgotten your password, enter your user " +#~ "name\n" +#~ "below and submit a request to change your password.\n" +#~ "

" +#~ msgstr "" +#~ "

\n" +#~ "Si vous avez un compte, mais avez oublié votre mot de passe, entrez votre " +#~ "nom d'utilisateur\n" +#~ "ci-dessous et validez la requête de changement de mot de passe.\n" +#~ "

" + +#~ msgid "Text linking the login page to the account creation page" +#~ msgstr "Texte liant la page de connexion à la page de création de compte" + +#~ msgid "Available variable: register_url" +#~ msgstr "Variables disponibles: register_url" + +#~ msgid "" +#~ "

\n" +#~ "If you do not have an account, you should go to the \n" +#~ "New Account page.\n" +#~ "

" +#~ msgstr "" +#~ "

\n" +#~ "Si vous n'avez pas de compte, vous devez aller à la page de \n" +#~ "Nouveau Compte.\n" +#~ "

" + +#, fuzzy +#~ msgid "Text when an invalid password token is used" +#~ msgstr "" +#~ "Texte quand un courriel avec un jeton de changement de mot de passe a été " +#~ "envoyé" + +#, fuzzy +#~ msgid "Text on top of the login page" +#~ msgstr "Texte en haut de la page de profil" + +#, fuzzy +#~ msgid "" +#~ "Text when a mail for confirmation of an account creation has been sent" +#~ msgstr "" +#~ "Texte quand un courriel avec un jeton de changement de mot de passe a été " +#~ "envoyé" + +#~ msgid "" +#~ "An email has been sent to you so you can confirm your account creation." +#~ msgstr "" +#~ "Un courriel vous a été envoyé afin que vous confirmiez la création de " +#~ "votre compte." + +#~ msgid "Liberty/SAML2" +#~ msgstr "Liberty/SAML2" + +#~ msgid "Select the identity provider you want to use." +#~ msgstr "Choisissez le fournisseur d'identités que vous voulez utiliser." + +#~ msgid "Identity Providers" +#~ msgstr "Fournisseurs d'identité" + +#~ msgid "Create new from remote URL" +#~ msgstr "Nouveau créé à partir d'une URL distante" + +#~ msgid "Broken" +#~ msgstr "Cassé" + +#~ msgid "Client Key and Certificate" +#~ msgstr "Clé et certificat du client" + +#~ msgid "Hide this provider from user lists" +#~ msgstr "Cacher ce fournisseur de la liste présentée à l'utilisateur" + +#~ msgid "URL to metadata" +#~ msgstr "URL vers les méta-données" + +#~ msgid "Resource not found" +#~ msgstr "Ressource non trouvée" + +#~ msgid "HTTP error on retrieval: %s" +#~ msgstr "Erreur HTTP à la récupération : %s" + +#~ msgid "Failed to retrieve file" +#~ msgstr "Échec à la récupération du fichier" + +#~ msgid "URL to public key" +#~ msgstr "URL de la clé publique" + +#~ msgid "Error in this metadata file" +#~ msgstr "Fichier de méta-données erroné" + +#~ msgid "File looks like a bad metadata file" +#~ msgstr "Le fichier de méta-données semble invalide" + +#~ msgid "" +#~ "The metadata file does not embed a public key, please provide it here." +#~ msgstr "" +#~ "Ce fichier de meta-données ne contient pas de clé publique, vous devez " +#~ "donc en fournir une ici." + +#~ msgid "Update from remote URL" +#~ msgstr "Mettre à jour à partir de l'URL distante" + +#~ msgid "Edit Identity Provider" +#~ msgstr "Modifier le fournisseur d'identités" + +#~ msgid "You are about to irrevocably remove this identity provider." +#~ msgstr "Vous allez définitivement supprimer ce fournisseur d'identités." + +#~ msgid "Deleting" +#~ msgstr "Suppression" + +#~ msgid "Deleting Identity Provider" +#~ msgstr "Suppression du fournisseur d'identité" + +#~ msgid "Bad metadata or missing public key" +#~ msgstr "Mauvaises méta-données ou clé publique manquante" + +#~ msgid "Configure Liberty/SAML identification method" +#~ msgstr "Configurer la méthode d'identification Liberty/SAML" + +#~ msgid "Configure Liberty / SAML 2.0 parameters" +#~ msgstr "Configurer les paramètres Liberty / SAML 2.0" + +#~ msgid "Configure Liberty parameters" +#~ msgstr "Configurer les paramètres Liberty" + +#~ msgid "ID-FF 1.2 Service Provider Metadata" +#~ msgstr "Méta-données ID-FF 1.2 du fournisseur de service" + +#~ msgid "Download Service Provider ID-FF 1.2 Metadata file" +#~ msgstr "" +#~ "Télécharger le fichier des méta-données ID-FF 1.2 du fournisseur de " +#~ "service" + +#~ msgid "SAML 2.0 Service Provider Metadata" +#~ msgstr "Méta-données du fournisseur de service SAML 2.0" + +#~ msgid "Download Service Provider SAML 2.0 Metadata file" +#~ msgstr "" +#~ "Télécharger le fichier des méta-données SAML 2.0 du fournisseur de service" + +#~ msgid "Add and remove identity providers" +#~ msgstr "Ajouter et supprimer des fournisseurs d'identités" + +#~ msgid "Liberty Provider ID" +#~ msgstr "Identifiant du fournisseur Liberty (Provider ID)" + +#~ msgid "Liberty Base URL" +#~ msgstr "URL de la racine Liberty" + +#~ msgid "SAML 2.0 Provider ID" +#~ msgstr "Identifiant du fournisseur SAML 2.0 (Provider ID)" + +#~ msgid "SAML 2.0 Base URL" +#~ msgstr "URL de la racine SAML 2.0" + +#~ msgid "Provider ID" +#~ msgstr "Identifiant du fournisseur (Provider ID)" + +#~ msgid "Base URL" +#~ msgstr "URL de la racine" + +#~ msgid "Signing Private Key" +#~ msgstr "Clé privée de signature" + +#~ msgid "Signing Public Key" +#~ msgstr "Clé publique de signature" + +#~ msgid "Encryption Private Key" +#~ msgstr "Clé privée de chiffrement" + +#~ msgid "Encryption Public Key" +#~ msgstr "Clé publique de chiffrement" + +#~ msgid "Identity Provider Introduction, Common Domain" +#~ msgstr "Domaine commun, pour 'Identity Provider Introduction'" + +#~ msgid "Disabled if empty" +#~ msgstr "Désactivé si vide" + +#~ msgid "Identity Provider Introduction, URL of Cookie Getter" +#~ msgstr "Identity Provider Introduction, URL de récupération" + +#, fuzzy +#~ msgid "Sign authentication request" +#~ msgstr "Modifier la requête d'authentification" + +#~ msgid "Grab user details with ID-WSF on first logon" +#~ msgstr "" +#~ "Récupérer les détails de l'utilisateur avec ID-WSF à la première connexion" + +#~ msgid "Lasso version is too old for this support." +#~ msgstr "La version de Lasso est trop vieille pour ce support" + +#~ msgid "Liberty/SAML2 identity provider" +#~ msgstr "Fournisseur d'identité Liberty Alliance/SAML2" + +#~ msgid "This feature is not yet implemented." +#~ msgstr "Cette fonctionnalité n'a pas encore été implémentée." + +#~ msgid "Sorry" +#~ msgstr "Désolé" + +#~ msgid "" +#~ "The server encountered an internal error and was unable to complete your " +#~ "request." +#~ msgstr "" +#~ "Une erreur s'est produite sur le serveur; votre requête n'a ainsi pas pu " +#~ "complètement être traîtée." + +#~ msgid "Internal Server Error" +#~ msgstr "Erreur interne du serveur" + +#~ msgid "Bad log file: %s" +#~ msgstr "Mauvais fichier journal : %s" + +#~ msgid "Nothing to show" +#~ msgstr "Rien à afficher" + +#~ msgid "Download Raw Log File" +#~ msgstr "Télécharger le fichier journal" + +#~ msgid "Time" +#~ msgstr "Horodatage" + +#~ msgid "Anonymous" +#~ msgstr "Anonyme" + +#~ msgid "Unlogged" +#~ msgstr "Non authentifié" + +#~ msgid "Unknown" +#~ msgstr "Inconnu" + +#~ msgid "Select another logfile:" +#~ msgstr "Choisir un autre fichier journal :" + +#~ msgid "Since: %s" +#~ msgstr "Depuis: %s" + +#~ msgid "Texts" +#~ msgstr "Textes" + +#, fuzzy +#~ msgid "Custom Texts" +#~ msgstr "Texte personnalisé :" + +#~ msgid "Restore default text" +#~ msgstr "Restaurer le texte par défaut" + +#~ msgid "Invalid template" +#~ msgstr "Squelette invalide" + +#~ msgid "Text" +#~ msgstr "Texte" + +#~ msgid "System Default" +#~ msgstr "Valeur du système" + +#~ msgid "English" +#~ msgstr "Anglais" + +#~ msgid "French" +#~ msgstr "Français" + +#~ msgid "Use a web proxy" +#~ msgstr "Utiliser un mandataire (proxy) web" + +#~ msgid "Proxy IP address or domain name" +#~ msgstr "Adresse IP or nom de domaine du mandataire" + +#~ msgid "Proxy port" +#~ msgstr "Port du mandataire (proxy)" + +#~ msgid "User name" +#~ msgstr "Identifiant" + +#~ msgid "User password" +#~ msgstr "Mot de passe" + +#~ msgid "Email for Tracebacks" +#~ msgstr "Courriel pour les exceptions" + +#~ msgid "Display Exceptions" +#~ msgstr "Afficher les exceptions" + +#~ msgid "No display" +#~ msgstr "Aucun affichage" + +#~ msgid "Display as Text" +#~ msgstr "Afficher sous forme de texte" + +#~ msgid "Display as Text in an HTML error page" +#~ msgstr "Afficher sous forme de texte dans une page d'erreur HTML" + +#~ msgid "Display as HTML" +#~ msgstr "Afficher sous de forme de HTML" + +#~ msgid "Logger" +#~ msgstr "Journalisation" + +#~ msgid "Enable debug mode" +#~ msgstr "Activer le mode de débogage" + +#, fuzzy +#~ msgid "Certificate %s" +#~ msgstr "Certificats" + +#~ msgid "You are about to delete this certificate." +#~ msgstr "Vous allez définitivement supprimer ce certificat." + +#~ msgid "certificates" +#~ msgstr "certificats" + +#~ msgid "Certificates" +#~ msgstr "Certificats" + +#~ msgid "Certificate Authorities" +#~ msgstr "Autorités de certification" + +#~ msgid "Add Certificate Authority" +#~ msgstr "Ajoutez une autorité de certification" + +#~ msgid "You need to install M2Crypto to use this feature" +#~ msgstr "Vous devez installer M2Crypto pour utiliser cette fonctionnalité" + +#~ msgid "Add" +#~ msgstr "Ajouter" + +#~ msgid "Certificate" +#~ msgstr "Certificat" + +#~ msgid "Bad certificate" +#~ msgstr "Mauvais certificat" + +#~ msgid "backoffice" +#~ msgstr "backoffice" + +#~ msgid "logout" +#~ msgstr "déconnexion" + +#~ msgid "help" +#~ msgstr "aide" + +#~ msgid "Administration of %s" +#~ msgstr "Administration de %s" + +#~ msgid "Remove" +#~ msgstr "Supprimer" + +#~ msgid "Duplicate" +#~ msgstr "Dupliquer" + +#~ msgid "View" +#~ msgstr "Voir" + +#~ msgid "Export" +#~ msgstr "Exporter" + +#~ msgid "Error" +#~ msgstr "Erreur" + +#~ msgid "SMTP Server" +#~ msgstr "Serveur SMTP" + +#~ msgid "Email Sender" +#~ msgstr "Émetteur des courriels" + +#~ msgid "Reply-To Address" +#~ msgstr "Adresse de réponse (Reply-To)" + +#~ msgid "Handle Bounces" +#~ msgstr "Gérer les rebonds" + +#~ msgid "Check DNS for domain name" +#~ msgstr "Vérifier le nom de domaine à l'aide d'une requête DNS" + +#~ msgid "Use a DNS request to check domain names used in email fields" +#~ msgstr "" +#~ "Utiliser une requête DNS pour vérifier les noms de domaine utilisés dans " +#~ "les champs courriel" + +#~ msgid "Enabled Email" +#~ msgstr "Courriel activé" + +#~ msgid "Restore default email" +#~ msgstr "Restaurer le courriel par défaut" + +#~ msgid "required field" +#~ msgstr "champ obligatoire" + +#~ msgid "" +#~ "The form you have submitted is invalid. Most likely it has been " +#~ "successfully submitted once already. Please review the form data and " +#~ "submit the form again." +#~ msgstr "" +#~ "Le formulaire que vous avez transmis n'est pas valide. Une raison " +#~ "probable est qu'il ait déjà été transmis une fois. Vérifiez les données " +#~ "du formulaire avant de le soumettre à nouveau." + +#~ msgid "There were errors processing your form. See below for details." +#~ msgstr "" +#~ "Il y a eu un problème à la soumission du formulaire. Regardez ci-dessous " +#~ "pour le détail." + +#~ msgid "must be a valid email address" +#~ msgstr "doit être une adresse électronique valide" + +#~ msgid "invalid address domain" +#~ msgstr "adresse du domaine invalide" + +#~ msgid "Prefill" +#~ msgstr "Préremplir" + +#~ msgid "wrong format" +#~ msgstr "format invalide" + +#~ msgid "invalid date" +#~ msgstr "date invalide" + +#~ msgid "invalid date: date must be on or after %s" +#~ msgstr "date invalide ; la date doit être antérieure à %s" + +#~ msgid "invalid date; date must be on or before %s" +#~ msgstr "date invalide ; la date doit être postérieure à %s" + +#~ msgid "Previous Year" +#~ msgstr "Année précédente" + +#~ msgid "Previous Month" +#~ msgstr "Mois précédent" + +#~ msgid "Next Year" +#~ msgstr "Année Suivante" + +#~ msgid "Next Month" +#~ msgstr "Mois suivant" + +#~ msgid "Close" +#~ msgstr "Fermer" + +#~ msgid "Choose Date" +#~ msgstr "Choisir la date" + +#~ msgid "invalid regular expression" +#~ msgstr "expression rationnelle invalide" + +#~ msgid "You must select at most %d answers." +#~ msgstr "Vous devez sélectionner au maximum %d réponses." + +#~ msgid "must start with http:// or https:// and have a domain name" +#~ msgstr "doit commencer par http:// ou https:// et avoir un nom de domaine" + +#~ msgid "client error: access forbidden (error 403)" +#~ msgstr "erreur du client : accès interdit (erreur 403)" + +#~ msgid "client error: page not found (error 404)" +#~ msgstr "erreur du client : page non trouvée (erreur 404)" + +#~ msgid "client error: %(reason)s (error %(code)s)" +#~ msgstr "erreur du client : %(reason)s (erreur %(code)s)" + +#~ msgid "server error: %(reason)s (error %(code)s)" +#~ msgstr "erreur du serveur : %(reason)s (erreur %(code)s)" + +#~ msgid "" +#~ "must start with http:// or https:// and have a domain name or start with /" +#~ msgstr "" +#~ "doit commencer par http:// ou https:// et avoir un nom de domaine ou " +#~ "commencer par /" + +#~ msgid "times" +#~ msgstr "fois" + +#~ msgid "plus" +#~ msgstr "plus" + +#~ msgid "minus" +#~ msgstr "moins" + +#~ msgid "What is the result of %(a)d %(op)s %(b)d?" +#~ msgstr "Quel est le résultat de %(a)d %(op)s %(b)d ?" + +#~ msgid "" +#~ "Please answer this simple mathematical question as proof you are not a " +#~ "bot." +#~ msgstr "" +#~ "Répondez à cette simple question mathématique comme preuve que vous " +#~ "n'êtes pas un robot'" + +#~ msgid "wrong answer" +#~ msgstr "mauvaise réponse" + +#~ msgid "January" +#~ msgstr "Janvier" + +#~ msgid "February" +#~ msgstr "Février" + +#~ msgid "March" +#~ msgstr "Mars" + +#~ msgid "April" +#~ msgstr "Avril" + +#~ msgid "May" +#~ msgstr "Mai" + +#~ msgid "June" +#~ msgstr "Juin" + +#~ msgid "July" +#~ msgstr "Juillet" + +#~ msgid "August" +#~ msgstr "Août" + +#~ msgid "September" +#~ msgstr "Septembre" + +#~ msgid "October" +#~ msgstr "Octobre" + +#~ msgid "November" +#~ msgstr "Novembre" + +#~ msgid "December" +#~ msgstr "Décembre" + +#~ msgid "Monday" +#~ msgstr "Lundi" + +#~ msgid "Tuesday" +#~ msgstr "Mardi" + +#~ msgid "Wednesday" +#~ msgstr "Mercredi" + +#~ msgid "Thursday" +#~ msgstr "Jeudi" + +#~ msgid "Friday" +#~ msgstr "Vendredi" + +#~ msgid "Saturday" +#~ msgstr "Samedi" + +#~ msgid "Sunday" +#~ msgstr "Dimanche" + +#~ msgid "Back Office of %s" +#~ msgstr "Back Office de %s" + +#, fuzzy +#~ msgid "Invalid authentication response" +#~ msgstr "Réponse de l'authentification" + +#~ msgid "Authentication failure; federation not found" +#~ msgstr "Erreur d'authentification: pas de fédération" + +#~ msgid "Authentication failure; failed to get response" +#~ msgstr "Erreur d'authentification: pas de réponse reçue" + +#, fuzzy +#~ msgid "Unknown error" +#~ msgstr "Erreur inconnue : %s" + +#~ msgid "No SAML Response" +#~ msgstr "Pas de réponse SAML" + +#~ msgid "No SAML Response in query string" +#~ msgstr "Pas de réponse SAML dans la 'query string'" + +#~ msgid "Request from unknown provider ID" +#~ msgstr "Requête d'un fournisseur inconnu" + +#~ msgid "Error checking signature" +#~ msgstr "Erreur à la vérification de signature" + +#, fuzzy +#~ msgid "Could not send logout request to the identity provider" +#~ msgstr "Ajouter et supprimer des fournisseurs d'identités" + +#~ msgid "It has been sent to the site administrator for analyse." +#~ msgstr "Elle a été envoyée à l'administrateur du site pour analyse." + +#~ msgid "Continue to %s" +#~ msgstr "Continuer vers %s" + +#~ msgid "View Error Details" +#~ msgstr "Afficher le détail de l'erreur" + +#~ msgid "Logged in as %s." +#~ msgstr "Identifié en tant que %s." + +#~ msgid "Passwords will be automatically generated." +#~ msgstr "Les mots de passe vont être générés automatiquement." + +#~ msgid "description" +#~ msgstr "description" + +#~ msgid "hint" +#~ msgstr "astuce" + +#~ msgid "Authentication request initiated by an unaffiliated provider." +#~ msgstr "Requête d'authentification initié par un fournisseur non-affilié" + +#~ msgid "Custom Email:" +#~ msgstr "Courriel personnalisé :" diff --git a/larpe/tags/release-1.1.1/po/larpe.pot b/larpe/tags/release-1.1.1/po/larpe.pot new file mode 100644 index 0000000..a47bb22 --- /dev/null +++ b/larpe/tags/release-1.1.1/po/larpe.pot @@ -0,0 +1,1247 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-07-19 13:53+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../larpe/idwsf2.ptl:50 +msgid "Failed connecting to the original site." +msgstr "" + +#: ../larpe/idwsf2.ptl:61 +msgid "Failed getting attributes from the attribute provider." +msgstr "" + +#: ../larpe/idwsf2.ptl:64 +msgid "Failed getting attributes for an unknown reason." +msgstr "" + +#: ../larpe/liberty_site.ptl:46 ../larpe/liberty_site.ptl:56 +msgid "SSO support is not yet configured" +msgstr "" + +#: ../larpe/admin/users.ptl:24 ../larpe/admin/users.ptl:32 +msgid "User Name" +msgstr "" + +#: ../larpe/admin/users.ptl:25 ../larpe/admin/users.ptl:34 +#: ../larpe/admin/users.ptl:66 +msgid "Email" +msgstr "" + +#: ../larpe/admin/users.ptl:26 ../larpe/admin/users.ptl:36 +#: ../larpe/admin/users.ptl:122 ../larpe/admin/forms_prefill.ptl:24 +#: ../larpe/admin/forms_prefill.ptl:76 ../larpe/admin/settings.ptl:31 +#: ../larpe/admin/settings.ptl:217 ../larpe/admin/settings.ptl:326 +#: ../larpe/admin/settings.ptl:343 ../larpe/admin/fields_prefill.ptl:30 +#: ../larpe/admin/fields_prefill.ptl:73 ../larpe/admin/hosts.ptl:384 +#: ../larpe/admin/hosts.ptl:692 ../larpe/admin/hosts.ptl:740 +#: ../larpe/admin/hosts.ptl:787 ../larpe/admin/hosts.ptl:1286 +#: ../larpe/site_authentication.ptl:64 ../larpe/root.ptl:64 +msgid "Submit" +msgstr "" + +#: ../larpe/admin/users.ptl:27 ../larpe/admin/users.ptl:37 +#: ../larpe/admin/users.ptl:123 ../larpe/admin/users.ptl:138 +#: ../larpe/admin/forms_prefill.ptl:25 ../larpe/admin/forms_prefill.ptl:77 +#: ../larpe/admin/settings.ptl:218 ../larpe/admin/settings.ptl:327 +#: ../larpe/admin/settings.ptl:344 ../larpe/admin/fields_prefill.ptl:31 +#: ../larpe/admin/fields_prefill.ptl:74 ../larpe/admin/hosts.ptl:124 +#: ../larpe/admin/hosts.ptl:385 ../larpe/admin/hosts.ptl:693 +#: ../larpe/admin/hosts.ptl:741 ../larpe/admin/hosts.ptl:788 +#: ../larpe/admin/hosts.ptl:1287 ../larpe/root.ptl:65 +msgid "Cancel" +msgstr "" + +#: ../larpe/admin/users.ptl:60 ../larpe/admin/users.ptl:61 +msgid "User" +msgstr "" + +#: ../larpe/admin/users.ptl:63 ../larpe/admin/hosts.ptl:382 +msgid "Name" +msgstr "" + +#: ../larpe/admin/users.ptl:98 +msgid "Debug" +msgstr "" + +#: ../larpe/admin/users.ptl:110 ../larpe/admin/forms_prefill.ptl:48 +#: ../larpe/admin/forms_prefill.ptl:66 ../larpe/admin/forms_prefill.ptl:67 +#: ../larpe/admin/forms_prefill.ptl:68 ../larpe/admin/fields_prefill.ptl:63 +#: ../larpe/admin/fields_prefill.ptl:64 ../larpe/admin/fields_prefill.ptl:65 +msgid "Edit" +msgstr "" + +#: ../larpe/admin/users.ptl:111 ../larpe/admin/users.ptl:112 +msgid "Edit User" +msgstr "" + +#: ../larpe/admin/users.ptl:121 +msgid "You are about to irrevocably delete this user." +msgstr "" + +#: ../larpe/admin/users.ptl:127 ../larpe/admin/forms_prefill.ptl:81 +#: ../larpe/admin/fields_prefill.ptl:78 ../larpe/admin/hosts.ptl:1291 +msgid "Delete" +msgstr "" + +#: ../larpe/admin/users.ptl:128 +msgid "Delete User" +msgstr "" + +#: ../larpe/admin/users.ptl:129 +msgid "Deleting User :" +msgstr "" + +#: ../larpe/admin/users.ptl:137 +msgid "Generate" +msgstr "" + +#: ../larpe/admin/users.ptl:143 ../larpe/admin/users.ptl:146 +#: ../larpe/admin/users.ptl:147 ../larpe/admin/users.ptl:155 +#: ../larpe/admin/users.ptl:180 ../larpe/admin/users.ptl:182 +#: ../larpe/admin/users.ptl:223 ../larpe/root.ptl:62 ../larpe/root.ptl:71 +msgid "Identification Token" +msgstr "" + +#: ../larpe/admin/users.ptl:148 +msgid "" +"You are about to generate a token than can be used to federate the account." +msgstr "" + +#: ../larpe/admin/users.ptl:149 +msgid "" +"After that, you will have the choice to send it to the user by email so that " +"he can federate his accounts." +msgstr "" + +#: ../larpe/admin/users.ptl:151 +#, python-format +msgid "Note that user has already been issued an identification token : %s" +msgstr "" + +#: ../larpe/admin/users.ptl:161 +#, python-format +msgid "Identification Token for %s" +msgstr "" + +#: ../larpe/admin/users.ptl:165 +msgid "Done" +msgstr "" + +#: ../larpe/admin/users.ptl:167 +msgid "Send by email" +msgstr "" + +#: ../larpe/admin/users.ptl:173 +#, python-format +msgid "" +"You have been given an identification token.\n" +"\n" +"Your token is %(token)s\n" +"\n" +"Click on %(url)s to use it.\n" +msgstr "" + +#: ../larpe/admin/users.ptl:183 +msgid "Failed sending email. Check your email configuration." +msgstr "" + +#: ../larpe/admin/users.ptl:184 ../larpe/admin/settings.ptl:112 +#: ../larpe/admin/hosts.ptl:657 ../larpe/admin/hosts.ptl:713 +#: ../larpe/admin/hosts.ptl:1340 +msgid "Back" +msgstr "" + +#: ../larpe/admin/users.ptl:194 ../larpe/admin/users.ptl:195 +#: ../larpe/admin/users.ptl:238 ../larpe/admin/users.ptl:272 +#: ../larpe/admin/root.ptl:45 +msgid "Users" +msgstr "" + +#: ../larpe/admin/users.ptl:199 ../larpe/admin/users.ptl:242 +msgid "Liberty support must be setup before creating users." +msgstr "" + +#: ../larpe/admin/users.ptl:203 ../larpe/admin/users.ptl:254 +#: ../larpe/admin/users.ptl:255 +msgid "New User" +msgstr "" + +#: ../larpe/admin/users.ptl:226 +#, python-format +msgid "Identification Token (current: %s)" +msgstr "" + +#: ../larpe/admin/users.ptl:233 ../larpe/admin/root.ptl:47 +msgid "Logs" +msgstr "" + +#: ../larpe/admin/users.ptl:239 ../larpe/admin/forms_prefill.ptl:122 +#: ../larpe/admin/fields_prefill.ptl:125 ../larpe/admin/hosts.ptl:1344 +msgid "New" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:16 +msgid "Form name" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:17 +msgid "Only used for display" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:18 +msgid "Form address" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:20 +msgid "ID-WSF data profile" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:21 +msgid "Example: urn:liberty:id-sis-pp:2005-05" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:22 +msgid "ID-WSF data XML prefix" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:23 +msgid "Example: pp" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:45 +msgid "Form prefilling configuration" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:48 +msgid "Configure this form" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:50 ../larpe/admin/fields_prefill.ptl:91 +#: ../larpe/admin/fields_prefill.ptl:98 +msgid "Fields" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:50 +msgid "Configure the fields of this form" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:75 +msgid "You are about to irrevocably delete this form." +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:82 ../larpe/admin/forms_prefill.ptl:83 +msgid "Delete Form" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:94 ../larpe/admin/forms_prefill.ptl:101 +#: ../larpe/admin/hosts.ptl:1279 +msgid "Forms" +msgstr "" + +#: ../larpe/admin/forms_prefill.ptl:104 +msgid "New Form" +msgstr "" + +#: ../larpe/admin/settings.ptl:28 +msgid "Metadata" +msgstr "" + +#: ../larpe/admin/settings.ptl:29 +msgid "Public Key" +msgstr "" + +#: ../larpe/admin/settings.ptl:30 +msgid "CA Certificate Chain" +msgstr "" + +#: ../larpe/admin/settings.ptl:34 ../larpe/admin/settings.ptl:35 +msgid "New Identity Provider" +msgstr "" + +#: ../larpe/admin/settings.ptl:53 ../larpe/admin/settings.ptl:87 +msgid "Bad metadata" +msgstr "" + +#. Don't use custom emails +#: ../larpe/admin/settings.ptl:104 ../larpe/admin/settings.ptl:105 +#: ../larpe/admin/settings.ptl:192 +msgid "Emails" +msgstr "" + +#: ../larpe/admin/settings.ptl:108 +msgid "General Options" +msgstr "" + +#: ../larpe/admin/settings.ptl:125 ../larpe/admin/hosts.ptl:84 +#: ../larpe/admin/root.ptl:46 +msgid "Settings" +msgstr "" + +#: ../larpe/admin/settings.ptl:128 +msgid "Liberty Alliance & SAML 2.0 Service Provider" +msgstr "" + +#: ../larpe/admin/settings.ptl:130 +msgid "Liberty Alliance Service Provider" +msgstr "" + +#: ../larpe/admin/settings.ptl:132 +msgid "Service Provider" +msgstr "" + +#: ../larpe/admin/settings.ptl:132 +msgid "Configure Larpe as a Service Provider" +msgstr "" + +#: ../larpe/admin/settings.ptl:142 ../larpe/admin/hosts.ptl:913 +msgid "SAML 2.0 Metadata" +msgstr "" + +#: ../larpe/admin/settings.ptl:143 +msgid "Download SAML 2.0 metadata file for Larpe" +msgstr "" + +#: ../larpe/admin/settings.ptl:149 ../larpe/admin/hosts.ptl:918 +msgid "ID-FF 1.2 Metadata" +msgstr "" + +#: ../larpe/admin/settings.ptl:150 +msgid "Download ID-FF 1.2 metadata file for Larpe" +msgstr "" + +#: ../larpe/admin/settings.ptl:156 ../larpe/admin/hosts.ptl:927 +msgid "Public key" +msgstr "" + +#: ../larpe/admin/settings.ptl:157 ../larpe/admin/hosts.ptl:928 +msgid "Download SSL Public Key file" +msgstr "" + +#: ../larpe/admin/settings.ptl:160 +msgid "Liberty Alliance & SAML 2.0 Identity Provider" +msgstr "" + +#: ../larpe/admin/settings.ptl:162 +msgid "Liberty Alliance Identity Provider" +msgstr "" + +#: ../larpe/admin/settings.ptl:167 +msgid "Identity Provider" +msgstr "" + +#: ../larpe/admin/settings.ptl:167 +msgid "Configure an identity provider" +msgstr "" + +#: ../larpe/admin/settings.ptl:171 +msgid "Identity Provider metadatas" +msgstr "" + +#: ../larpe/admin/settings.ptl:171 +msgid "See current identity provider metadatas" +msgstr "" + +#: ../larpe/admin/settings.ptl:175 +msgid "Global parameters for the sites" +msgstr "" + +#: ../larpe/admin/settings.ptl:179 ../larpe/admin/settings.ptl:302 +#: ../larpe/admin/settings.ptl:303 +msgid "Domain name" +msgstr "" + +#: ../larpe/admin/settings.ptl:179 +msgid "Configure the base domain name for the sites" +msgstr "" + +#: ../larpe/admin/settings.ptl:181 ../larpe/admin/settings.ptl:348 +#: ../larpe/admin/settings.ptl:349 +msgid "Apache 2 configuration generation" +msgstr "" + +#: ../larpe/admin/settings.ptl:181 +msgid "Customise Apache 2 configuration generation" +msgstr "" + +#: ../larpe/admin/settings.ptl:183 +msgid "Proxy" +msgstr "" + +#: ../larpe/admin/settings.ptl:183 +msgid "Connect to the sites through a web proxy" +msgstr "" + +#: ../larpe/admin/settings.ptl:186 +msgid "Customisation" +msgstr "" + +#: ../larpe/admin/settings.ptl:190 +msgid "Language" +msgstr "" + +#: ../larpe/admin/settings.ptl:190 +msgid "Configure site language" +msgstr "" + +#: ../larpe/admin/settings.ptl:192 +msgid "Configure email settings" +msgstr "" + +#: ../larpe/admin/settings.ptl:195 +msgid "Misc" +msgstr "" + +#: ../larpe/admin/settings.ptl:199 +msgid "Debug Options" +msgstr "" + +#: ../larpe/admin/settings.ptl:199 +msgid "Configure options useful for debugging" +msgstr "" + +#: ../larpe/admin/settings.ptl:215 +msgid "Organisation Name" +msgstr "" + +#: ../larpe/admin/settings.ptl:222 ../larpe/admin/settings.ptl:223 +msgid "Service Provider Configuration" +msgstr "" + +#: ../larpe/admin/settings.ptl:318 +msgid "Domain name for the sites" +msgstr "" + +#. TODO: Add the option "Both" and handle it in hosts configuration +#: ../larpe/admin/settings.ptl:321 +msgid "Use HTTP or HTTPS" +msgstr "" + +#: ../larpe/admin/settings.ptl:323 +msgid "Same as the site" +msgstr "" + +#: ../larpe/admin/settings.ptl:341 +msgid "" +"Automatically generate Apache 2 configuration for new hosts and reload " +"Apache 2 after changes" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:15 +msgid "Field name" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:17 +msgid "Xpath of the attribute" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:18 +msgid "Example: /pp:PP/pp:InformalName" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:19 +msgid "Number of the field in the data" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:21 +msgid "" +"Change it if there are multiple fields corresponding to the same Xpath and " +"you want to get another than the first one" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:22 +msgid "Get raw XML value" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:24 +msgid "Python regexp of a string to match" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:26 +msgid "Python regexp of the replacing string" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:28 +msgid "Options mapping for a select field" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:29 +msgid "Add item" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:72 +msgid "You are about to irrevocably delete this field." +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:79 ../larpe/admin/fields_prefill.ptl:80 +msgid "Delete Field" +msgstr "" + +#: ../larpe/admin/fields_prefill.ptl:101 +msgid "New Field" +msgstr "" + +#: ../larpe/admin/hosts.ptl:33 +msgid "" +"You must either choose a different hostname from Larpe or specify a reversed " +"directory" +msgstr "" + +#: ../larpe/admin/hosts.ptl:80 ../larpe/admin/hosts.ptl:102 +msgid "Basic configuration" +msgstr "" + +#: ../larpe/admin/hosts.ptl:81 +msgid "Need domain name configuration" +msgstr "" + +#: ../larpe/admin/hosts.ptl:82 +#, python-format +msgid "" +"Before configuring hosts, you must\n" +"setup a global domain name " +"in\n" +"%(settings)s menu." +msgstr "" + +#: ../larpe/admin/hosts.ptl:103 +msgid "Step 1 - Basic configuration" +msgstr "" + +#: ../larpe/admin/hosts.ptl:112 +msgid "Original site root address" +msgstr "" + +#: ../larpe/admin/hosts.ptl:114 +msgid "" +"If your site address is http://test.org/index.php, put http://test.org/ here" +msgstr "" + +#: ../larpe/admin/hosts.ptl:117 +msgid "Use a proxy" +msgstr "" + +#: ../larpe/admin/hosts.ptl:118 +msgid "" +"Uncheck it if Larpe doesn't need to use the proxy to connect to this site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:122 +msgid "" +"If Larpe needs to use a proxy to connect to this site, you must first " +"configure\n" +" it in global proxy parameters." +msgstr "" + +#: ../larpe/admin/hosts.ptl:125 ../larpe/admin/hosts.ptl:315 +#: ../larpe/admin/hosts.ptl:343 ../larpe/admin/hosts.ptl:433 +#: ../larpe/admin/hosts.ptl:464 ../larpe/admin/hosts.ptl:547 +#: ../larpe/admin/hosts.ptl:583 ../larpe/admin/hosts.ptl:873 +#: ../larpe/admin/hosts.ptl:889 ../larpe/admin/hosts.ptl:947 +#: ../larpe/admin/hosts.ptl:977 +msgid "Next" +msgstr "" + +#: ../larpe/admin/hosts.ptl:126 ../larpe/admin/hosts.ptl:316 +#: ../larpe/admin/hosts.ptl:434 ../larpe/admin/hosts.ptl:465 +#: ../larpe/admin/hosts.ptl:548 ../larpe/admin/hosts.ptl:584 +#: ../larpe/admin/hosts.ptl:874 ../larpe/admin/hosts.ptl:890 +#: ../larpe/admin/hosts.ptl:978 +msgid "Terminate" +msgstr "" + +#: ../larpe/admin/hosts.ptl:314 ../larpe/admin/hosts.ptl:343 +#: ../larpe/admin/hosts.ptl:432 ../larpe/admin/hosts.ptl:463 +#: ../larpe/admin/hosts.ptl:546 ../larpe/admin/hosts.ptl:582 +#: ../larpe/admin/hosts.ptl:872 ../larpe/admin/hosts.ptl:888 +#: ../larpe/admin/hosts.ptl:976 ../larpe/admin/hosts.ptl:1002 +msgid "Previous" +msgstr "" + +#: ../larpe/admin/hosts.ptl:332 +msgid "Check site address and name" +msgstr "" + +#: ../larpe/admin/hosts.ptl:333 +msgid "Step 2 - Check the new site address works" +msgstr "" + +#: ../larpe/admin/hosts.ptl:335 +msgid "DNS configuration" +msgstr "" + +#: ../larpe/admin/hosts.ptl:337 +msgid "" +"Before opening the following link, ensure you have configured your DNS\n" +"for this address. If you don't have a DNS server and you just want to test " +"Larpe, add this\n" +"domain name in the file \"/etc/hosts\"." +msgstr "" + +#: ../larpe/admin/hosts.ptl:341 +#, python-format +msgid "" +"Then you can open this link in a new window or tab and see if your site\n" +"is displayed. If it's ok, you can click the \"%(next)s\" button. Otherwise, " +"click the \"%(previous)s\"\n" +"button and check your settings." +msgstr "" + +#: ../larpe/admin/hosts.ptl:345 +msgid "Site adress and name" +msgstr "" + +#: ../larpe/admin/hosts.ptl:347 +msgid "The new address of this site is " +msgstr "" + +#: ../larpe/admin/hosts.ptl:349 +#, python-format +msgid "The name of this site is \"%s\"." +msgstr "" + +#: ../larpe/admin/hosts.ptl:350 +msgid "" +"You can also \n" +"modify the address or the name of this site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:366 +msgid "An host with the same name already exists" +msgstr "" + +#: ../larpe/admin/hosts.ptl:373 ../larpe/admin/hosts.ptl:374 +msgid "Modify site address and name" +msgstr "" + +#: ../larpe/admin/hosts.ptl:380 +msgid "Address" +msgstr "" + +#: ../larpe/admin/hosts.ptl:419 +msgid "Authentication and logout" +msgstr "" + +#: ../larpe/admin/hosts.ptl:420 +msgid "Step 3 - Configure authentication and logout pages" +msgstr "" + +#: ../larpe/admin/hosts.ptl:426 ../larpe/admin/hosts.ptl:969 +msgid "Authentication form page address" +msgstr "" + +#: ../larpe/admin/hosts.ptl:427 +msgid "Address of a page on the site which contains the authentication form" +msgstr "" + +#: ../larpe/admin/hosts.ptl:429 +msgid "Logout address" +msgstr "" + +#: ../larpe/admin/hosts.ptl:430 +msgid "Address of the logout link on the site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:446 +msgid "(computed automatically)" +msgstr "" + +#: ../larpe/admin/hosts.ptl:459 +msgid "Plugin" +msgstr "" + +#: ../larpe/admin/hosts.ptl:460 +msgid "You can force a plugin" +msgstr "" + +#: ../larpe/admin/hosts.ptl:478 +msgid "Auto detected configuration" +msgstr "" + +#: ../larpe/admin/hosts.ptl:479 +msgid "" +"Step 4 - Check automatically detected configuration for the authentication " +"form" +msgstr "" + +#: ../larpe/admin/hosts.ptl:482 +msgid "Address where the authentication form must be sent" +msgstr "" + +#: ../larpe/admin/hosts.ptl:483 +msgid "Name of the login field" +msgstr "" + +#: ../larpe/admin/hosts.ptl:484 +msgid "Name of the password field" +msgstr "" + +#: ../larpe/admin/hosts.ptl:503 +msgid "" +"The following authentication form parameters have been detected. If they " +"look right, you can go to the next step.\n" +"If you think they are wrong, go back and check your settings then try " +"again.\n" +msgstr "" + +#: ../larpe/admin/hosts.ptl:508 +msgid "" +"The following authentication form parameters in red haven't been correctly " +"detected. Go back and check\n" +"your settings then try again.\n" +msgstr "" + +#: ../larpe/admin/hosts.ptl:529 ../larpe/admin/hosts.ptl:1250 +msgid "Credentials" +msgstr "" + +#: ../larpe/admin/hosts.ptl:530 +msgid "Step 5 - Fill in a valid username/password for this site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:535 ../larpe/site_authentication.ptl:98 +msgid "Username" +msgstr "" + +#: ../larpe/admin/hosts.ptl:537 ../larpe/site_authentication.ptl:100 +msgid "Password" +msgstr "" + +#: ../larpe/admin/hosts.ptl:594 +msgid "Check authentication" +msgstr "" + +#: ../larpe/admin/hosts.ptl:595 +msgid "Step 6 - Check the authentication process" +msgstr "" + +#: ../larpe/admin/hosts.ptl:614 +msgid "Authentication succeeded ! You can go to the next step." +msgstr "" + +#: ../larpe/admin/hosts.ptl:616 +msgid "Authentication has failed. To resolve this problem, you can :" +msgstr "" + +#: ../larpe/admin/hosts.ptl:619 +msgid "Try authentication again" +msgstr "" + +#: ../larpe/admin/hosts.ptl:621 +msgid "See the response of the authentication requests" +msgstr "" + +#: ../larpe/admin/hosts.ptl:623 ../larpe/admin/hosts.ptl:705 +msgid "Modify the parameters of the authentication requests" +msgstr "" + +#: ../larpe/admin/hosts.ptl:625 +msgid "Change the way Larpe detects the authentication is successful or not" +msgstr "" + +#: ../larpe/admin/hosts.ptl:626 +msgid "Go back and change your username and/or password" +msgstr "" + +#: ../larpe/admin/hosts.ptl:632 ../larpe/admin/hosts.ptl:633 +msgid "Authentication response" +msgstr "" + +#: ../larpe/admin/hosts.ptl:635 +msgid "Response of the request with good credentials" +msgstr "" + +#: ../larpe/admin/hosts.ptl:638 ../larpe/admin/hosts.ptl:649 +msgid "HTTP status code" +msgstr "" + +#: ../larpe/admin/hosts.ptl:643 ../larpe/admin/hosts.ptl:654 +msgid "See HTML page" +msgstr "" + +#: ../larpe/admin/hosts.ptl:646 +msgid "Response of the request with bad credentials" +msgstr "" + +#: ../larpe/admin/hosts.ptl:675 ../larpe/admin/hosts.ptl:676 +msgid "Authentication success criteria" +msgstr "" + +#: ../larpe/admin/hosts.ptl:682 +msgid "Authentication system of the original site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:684 +msgid "Check the existence of a password field" +msgstr "" + +#: ../larpe/admin/hosts.ptl:685 +msgid "Match some text to detect an authentication failure" +msgstr "" + +#: ../larpe/admin/hosts.ptl:690 +msgid "Text to match in case of authentication failure" +msgstr "" + +#: ../larpe/admin/hosts.ptl:704 +msgid "Authentication request" +msgstr "" + +#: ../larpe/admin/hosts.ptl:709 +msgid "Modify POST parameters" +msgstr "" + +#: ../larpe/admin/hosts.ptl:709 +msgid "" +"Configure the form attributes that will be sent within the authentication " +"POST requests" +msgstr "" + +#: ../larpe/admin/hosts.ptl:711 +msgid "Modify HTTP headers" +msgstr "" + +#: ../larpe/admin/hosts.ptl:711 +msgid "Configure the HTTP headers of the authentication requests made by Larpe" +msgstr "" + +#: ../larpe/admin/hosts.ptl:725 +msgid "POST parameters" +msgstr "" + +#: ../larpe/admin/hosts.ptl:726 +msgid "Configure POST parameters" +msgstr "" + +#: ../larpe/admin/hosts.ptl:728 +msgid "" +"Here are the detected form fields that will be sent as parameters of the\n" +"authentication POST request. You can desactivate some or all of them, or " +"change their value." +msgstr "" + +#: ../larpe/admin/hosts.ptl:766 +msgid "HTTP headers" +msgstr "" + +#: ../larpe/admin/hosts.ptl:767 +msgid "Configure HTTP headers" +msgstr "" + +#: ../larpe/admin/hosts.ptl:769 +msgid "" +"Here are the HTTP headers that will be sent within the authentication\n" +"POST request. You can desactivate some or all of them, or change their value." +msgstr "" + +#: ../larpe/admin/hosts.ptl:782 +msgid "" +"The headers \"Host\", \"Accept-Encoding\" and \"Content-Length\" will also " +"automatically be sent." +msgstr "" + +#: ../larpe/admin/hosts.ptl:785 +msgid "" +"As Larpe uses a proxy for this site, the headers \"Proxy-Authorization\",\n" +"\"Proxy-Connection\" and \"Keep-Alive\" will be sent as well." +msgstr "" + +#: ../larpe/admin/hosts.ptl:846 +msgid "SSO initiation" +msgstr "" + +#: ../larpe/admin/hosts.ptl:847 +msgid "Step 7 - Configure how a Single Sign On can be initiated" +msgstr "" + +#: ../larpe/admin/hosts.ptl:849 +msgid "" +"Most sites use one of the following 2 ways to allow users to initialise an " +"authentication :" +msgstr "" + +#: ../larpe/admin/hosts.ptl:852 +msgid "" +"The site has a single authentication page. It redirects users to this page " +"when\n" +"they click a \"Login\" button or try to access a page which require users to " +"be authenticated." +msgstr "" + +#: ../larpe/admin/hosts.ptl:855 +msgid "" +"The site includes an authentication form in most or all of his pages. Users " +"can\n" +"authenticate on any of these pages, and don't need to be redirected to a " +"separate authentication page." +msgstr "" + +#: ../larpe/admin/hosts.ptl:860 +msgid "Select the way your site works :" +msgstr "" + +#: ../larpe/admin/hosts.ptl:868 +msgid "The site has a single authentication page" +msgstr "" + +#: ../larpe/admin/hosts.ptl:869 +msgid "The site includes an authentication form in most or all pages" +msgstr "" + +#: ../larpe/admin/hosts.ptl:900 +msgid "Metadatas" +msgstr "" + +#: ../larpe/admin/hosts.ptl:901 +#, python-format +msgid "Step 8 - Metadatas of %(site_name)s" +msgstr "" + +#: ../larpe/admin/hosts.ptl:904 +msgid "" +"Download the metadatas and the public key for this site and\n" +"upload them on your identity provider in order to use Liberty Alliance " +"features." +msgstr "" + +#: ../larpe/admin/hosts.ptl:914 +msgid "Download SAML 2.0 metadata file" +msgstr "" + +#: ../larpe/admin/hosts.ptl:919 +msgid "Download ID-FF 1.2 metadata file" +msgstr "" + +#: ../larpe/admin/hosts.ptl:921 +msgid "No metadata has been generated for this host." +msgstr "" + +#: ../larpe/admin/hosts.ptl:930 +msgid "No public key has been generated for this host." +msgstr "" + +#: ../larpe/admin/hosts.ptl:942 +msgid "Advanced options" +msgstr "" + +#: ../larpe/admin/hosts.ptl:943 +msgid "Step 9 - Advanced options" +msgstr "" + +#: ../larpe/admin/hosts.ptl:945 +msgid "Configure advanced options to setup the last details of your site." +msgstr "" + +#: ../larpe/admin/hosts.ptl:946 +#, python-format +msgid "" +"If you don't know what to configure here, just click %(next)s and\n" +"come here later if needed." +msgstr "" + +#: ../larpe/admin/hosts.ptl:959 +msgid "Redirect the root URL of the site to the login page." +msgstr "" + +#: ../larpe/admin/hosts.ptl:961 +msgid "Return address" +msgstr "" + +#: ../larpe/admin/hosts.ptl:962 +msgid "Where the user will be redirected after a successful authentication" +msgstr "" + +#: ../larpe/admin/hosts.ptl:964 +msgid "Error address" +msgstr "" + +#: ../larpe/admin/hosts.ptl:965 +msgid "Where the user will be redirected after a disconnection or an error" +msgstr "" + +#: ../larpe/admin/hosts.ptl:967 +msgid "URL which must initiate the SSO" +msgstr "" + +#: ../larpe/admin/hosts.ptl:968 +#, python-format +msgid "" +"Address which must initiate the SSO. If empty, defaults to the previously\n" +"specified \"%s\"" +msgstr "" + +#: ../larpe/admin/hosts.ptl:971 +msgid "Apache HTML proxy" +msgstr "" + +#: ../larpe/admin/hosts.ptl:972 +msgid "" +"Converts urls in the HTML pages according to the host new domain name.\n" +"Disabled by default because it makes some sites not work correctly." +msgstr "" + +#: ../larpe/admin/hosts.ptl:1003 ../larpe/admin/hosts.ptl:1024 +msgid "Finish" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1011 +msgid "Check everything works" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1012 +msgid "Step 10 - Check everything works" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1015 +msgid "" +"Now you can fully test your site, start from the home page, initiate a\n" +"Single Sign On, federate your identities and do a Single Logout." +msgstr "" + +#: ../larpe/admin/hosts.ptl:1018 +msgid "The address of your site is : " +msgstr "" + +#: ../larpe/admin/hosts.ptl:1023 +#, python-format +msgid "" +"If everything works, click the \"%(finish)s\" button, otherwise you can go\n" +"back and check your settings." +msgstr "" + +#: ../larpe/admin/hosts.ptl:1136 ../larpe/admin/hosts.ptl:1151 +#: ../larpe/admin/hosts.ptl:1182 +msgid "(filled by users)" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1233 +msgid "Configuration assistant" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1238 +msgid "Address of the original site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1238 +msgid "Configure the root address of the site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1241 +msgid "New address and name" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1241 +msgid "Configure the new address and name of this site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1244 +msgid "Authentication and logout addresses" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1244 +msgid "Configure the authentication and logout addresses of the original site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1247 +msgid "Check auto detected configuration" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1247 +msgid "Check the automatically detected configuration is right" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1250 +msgid "Configure some valid credentials to authenticate on the original site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1253 +msgid "Retry authentication" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1253 +msgid "" +"Retry sending an authentication request to the site to check if your new " +"parameters work well" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1256 +msgid "Check authentication response" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1256 +msgid "Check the response from the latest authentication request" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1259 +msgid "Configure authentication success criteria" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1259 +msgid "Specify how Larpe knows if the authentication has succeeded or not" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1262 +msgid "Modify authentication request" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1262 +msgid "Modify POST fields or HTTP headers of the authentication request" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1265 +msgid "Configure how a Single Sign On can be initiated" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1268 +msgid "Metadatas and key" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1268 +msgid "Download SAML 2.0 or ID-FF metadatas and SSL public key" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1271 +msgid "Adavanced options" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1271 +msgid "Configure advanced options to setup the last details of your site" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1275 +msgid "Form prefilling with ID-WSF" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1279 +msgid "Configure the forms to prefill" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1285 +msgid "You are about to irrevocably delete this host." +msgstr "" + +#: ../larpe/admin/hosts.ptl:1292 ../larpe/admin/hosts.ptl:1293 +msgid "Delete Host" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1305 ../larpe/admin/hosts.ptl:1306 +#: ../larpe/admin/hosts.ptl:1343 ../larpe/admin/hosts.ptl:1350 +#: ../larpe/admin/root.ptl:44 +msgid "Hosts" +msgstr "" + +#: ../larpe/admin/hosts.ptl:1309 ../larpe/admin/hosts.ptl:1336 +#: ../larpe/admin/hosts.ptl:1337 +msgid "New Host" +msgstr "" + +#: ../larpe/admin/root.ptl:48 +msgid "Liberty Alliance Reverse Proxy" +msgstr "" + +#: ../larpe/admin/root.ptl:59 +msgid "Administration" +msgstr "" + +#: ../larpe/saml2.ptl:32 ../larpe/saml2.ptl:46 +msgid "SAML 2.0 support not yet configured." +msgstr "" + +#: ../larpe/saml2.ptl:53 +msgid "Missing SAML Artifact" +msgstr "" + +#: ../larpe/saml2.ptl:64 ../larpe/liberty.ptl:58 +msgid "Failure to communicate with identity provider" +msgstr "" + +#: ../larpe/saml2.ptl:70 ../larpe/liberty.ptl:63 +msgid "Unknown authentication failure" +msgstr "" + +#: ../larpe/saml2.ptl:72 ../larpe/liberty.ptl:66 +msgid "Authentication failure; unknown principal" +msgstr "" + +#: ../larpe/saml2.ptl:334 ../larpe/liberty.ptl:142 ../larpe/liberty.ptl:173 +msgid "Failed to check single logout request signature." +msgstr "" + +#: ../larpe/site_authentication.ptl:60 +msgid "Local authentication" +msgstr "" + +#: ../larpe/site_authentication.ptl:74 +msgid "Authentication failure" +msgstr "" + +#: ../larpe/site_authentication.ptl:77 +#, python-format +msgid "Connection failed : %s" +msgstr "" + +#: ../larpe/site_authentication.ptl:80 +#, python-format +msgid "This service provider is not fully configured : %s" +msgstr "" + +#: ../larpe/site_authentication.ptl:83 +#, python-format +msgid "Unknown error : %s" +msgstr "" + +#: ../larpe/site_authentication.ptl:89 +msgid "Please type your login and password for this Service Provider." +msgstr "" + +#: ../larpe/site_authentication.ptl:90 ../larpe/root.ptl:74 +msgid "" +"Your local account will be federated with your Liberty Alliance account." +msgstr "" + +#: ../larpe/site_authentication.ptl:296 +#, python-format +msgid "%s logout failed" +msgstr "" + +#: ../larpe/root.ptl:27 +msgid "Welcome to Larpe reverse proxy" +msgstr "" + +#: ../larpe/root.ptl:29 +msgid "Configure Larpe" +msgstr "" + +#: ../larpe/root.ptl:73 +msgid "Please enter your identification token. " +msgstr "" + +#: ../larpe/root.ptl:87 +msgid "Unknown Token" +msgstr "" + +#: ../larpe/liberty.ptl:45 +msgid "Liberty support is not yet configured" +msgstr "" + +#: ../larpe/liberty.ptl:67 +msgid "Identity Provider didn't accept artifact transaction." +msgstr "" + +#: ../larpe/users.py:38 +msgid "Unknown User" +msgstr "" diff --git a/larpe/tags/release-1.1.1/pylintrc b/larpe/tags/release-1.1.1/pylintrc new file mode 100644 index 0000000..18f2afd --- /dev/null +++ b/larpe/tags/release-1.1.1/pylintrc @@ -0,0 +1,310 @@ +# lint Python modules using external checkers. +# +# This is the main checker controlling the other ones and the reports +# generation. It is itself both a raw checker and an astng checker in order +# to: +# * handle message activation / deactivation at the module level +# * handle some basic but necessary stats'data (number of classes, methods...) +# +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add to the black list. It should be a base name, not a +# path. You may set this option multiple times. +ignore=.svn,qommon + +# Pickle collected data for later comparisons. +persistent=yes + +# Set the cache size for astng objects. +cache-size=500 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[MESSAGES CONTROL] + +# Enable only checker(s) with the given id(s). This option conflicts with the +# disable-checker option +#enable-checker= + +# Enable all checker(s) except those with the given id(s). This option +# conflicts with the enable-checker option +#disable-checker= + +# Enable all messages in the listed categories. +#enable-msg-cat= + +# Disable all messages in the listed categories. +#disable-msg-cat= + +# Enable the message(s) with the given id(s). +#enable-msg= + +# Disable the message(s) with the given id(s). +disable-msg=C0111,R0904,W0403 + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html +output-format=text + +# Include message's id in output +include-ids=yes + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells wether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectivly contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (R0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (R0004). +comment=no + +# Enable the report(s) with the given id(s). +#enable-report= + +# Disable the report(s) with the given id(s). +#disable-report= + + +# try to find bugs in the code using type inference +# +[TYPECHECK] + +# Tells wether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamicaly set). +ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. +generated-members=REQUEST,acl_users,aq_parent + + +# checks for +# * unused variables / imports +# * undefined variables +# * redefinition of variable from builtins or from an outer scope +# * use of variable before assigment +# +[VARIABLES] + +# Tells wether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching names used for dummy variables (i.e. not used). +dummy-variables-rgx=_|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +# checks for : +# * doc strings +# * modules / classes / functions / methods / arguments / variables name +# * number of arguments, local variables, branchs, returns and statements in +# functions, methods +# * required module attributes +# * dangerous default values as arguments +# * redefinition of function / method / class +# * uses of the global statement +# +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +#const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ +const-rgx=[a-z\_][a-z0-9\_]{2,30}$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + + +# checks for sign of poor/misdesign: +# * number of methods, attributes, local variables... +# * size, complexity of functions, methods +# +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +# checks for : +# * methods without self as first argument +# * overridden methods signature +# * access only to existant members via self +# * attributes not defined in the __init__ method +# * supported interfaces implementation +# * unreachable code +# +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + + +# checks for +# * external modules dependencies +# * relative / wildcard imports +# * cyclic imports +# * uses of deprecated modules +# +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report R0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report R0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report R0402 must +# not be disabled) +int-import-graph= + + +# checks for : +# * unauthorized constructions +# * strict indentation +# * line length +# * use of <> instead of != +# +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=100 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + + +# checks for similarities and duplicated code. This computation may be +# memory / CPU intensive, so you should disable it if you experiments some +# problems. +# +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +# checks for: +# * warning notes in the code like FIXME, XXX +# * PEP 263: source code with non ascii character but no encoding declaration +# +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO diff --git a/larpe/tags/release-1.1.1/root/index.html b/larpe/tags/release-1.1.1/root/index.html new file mode 100644 index 0000000..cf449e7 --- /dev/null +++ b/larpe/tags/release-1.1.1/root/index.html @@ -0,0 +1,18 @@ + + + Larpe + + + + +

+ Larpe +

+ + diff --git a/larpe/tags/release-1.1.1/root/larpe/css/arrow-right-2.0.png b/larpe/tags/release-1.1.1/root/larpe/css/arrow-right-2.0.png new file mode 100644 index 0000000..f6a66f5 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/arrow-right-2.0.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/bg-footer.png b/larpe/tags/release-1.1.1/root/larpe/css/bg-footer.png new file mode 100644 index 0000000..812ee25 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/bg-footer.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/dc2/admin.css b/larpe/tags/release-1.1.1/root/larpe/css/dc2/admin.css new file mode 100644 index 0000000..7a7caac --- /dev/null +++ b/larpe/tags/release-1.1.1/root/larpe/css/dc2/admin.css @@ -0,0 +1,283 @@ +@import url(../larpe-common.css); + +html, body { + margin: 0; + background: white url(page-bg.png) repeat-y; +} + +div#main-content { + margin-left: 160px; + margin-top: -10px; + margin-right: 20px; +} + +div#main-content h1 { + color: #006699; + font-size: 120%; +} + +div#main-content h2 { + color: #006699; + font-size: 115%; +} + +div#main-content h3 { + color: #006699; + font-size: 108% +} + + + +div#header { + margin: 0; + background: white url(head-bg.png) repeat-x; + height: 58px; +} + +ul#menu { + background: transparent url(head-logo.png) no-repeat; + width: 177px; + margin: 0; + padding: 80px 0 0 5px; +} + +a { + color: #0066cc; + text-decoration: none; + border-bottom: 1px dotted #ff9900; +} + +p.commands a { + border: 0; +} + +ul#menu a { + font-weight: bold; +} + +ul#menu li.active a { + border-bottom: 1px solid #ff9900; +} + +ul#menu li { + font-size: 90%; + margin-bottom: 1em; + max-width: 130px; +} + +div#footer { + display: none; +} + +ul.user-info { + position: absolute; + margin: 0; + padding: 0; + right: 25px; + top: 13px; + font-size: 70%; + font-weight: bold; +} + +ul.user-info li { + display: inline; + padding-left: 10px; +} + +/** end of dc2 changes **/ + + + +ul.biglist { + margin: 0; + padding: 0; +} + +ul.biglist li { + list-style-type: none; + margin: 4px 0; + padding: 0 2px; + border: 1px solid #888; + background: #ffe; + clear: both; +} + +ul.biglist li p.details { + display: block; + margin: 0; + color: #555; + font-size: 80%; +} + + +ul.biglist li p.commands { + float: right; + margin-top: -17px; +} + +ul.biglist li p.commands img { + padding-right: 5px; +} + +a img { + border: 0; +} + +td.time { + text-align: right; +} + +ul.biglist li.disabled, ul.biglist li.disabled p.details { + color: #999; + background: #ddd; +} + + +dl dt { + margin : 0; + padding : 0 0 0 0; +} + +dl dd { + margin : 0.3em 0 1.5em 10px; +} + + +img.theme-icon { + float: right; + margin: -16px 4px 0px 3px; + border: 1px solid #999; +} + +div#new-field table { + margin: 0; + padding: 0; +} + +div#new-field div.widget { + margin: 0; + padding: 0; +} + +div#new-field div.buttons { + margin: 0; + padding: 0; +} + +div#new-field div.buttons input { + margin: 0; + padding: 0; +} + +div#new-field { + border: 1px solid #888; + background: #ffe; + margin: 2em 0 4px 0; + padding: 0 2px; +} + +div#new-field div.widget { +} + +div#new-field h3 { + margin: 0; + font-size: 100%; +} + +div#new-field br { + display: none; +} + +div#new-field p.commands { + float: right; + margin-top: -17px; + margin-right: 3px; +} + +div.WorkflowStatusWidget { + border-left: 1px solid black; +} + +p#breadcrumb { + background: #e6e6e6; + -moz-border-radius: 6px; + padding: 3px 8px; + font-size: 80%; + border: 1px solid #bfbfbf; +} + +/** steps **/ +#steps { + height: 32px; + margin-bottom: 1em; + background: #f0f0f0; + color: #aaa; +} + +#steps ol { + list-style: none; + padding: 0 20px; +} + +#steps li { + display: inline; + padding-right: 1em; + display: block; + float: left; + width: 30%; + list-style: none; +} + +#steps ol ul { + display: none; +} + +#steps span.marker { + font-size: 26px; + padding: 2px 9px; + font-weight: bold; + color: white; + text-align: center; + background: #ddd; + border: 1px solid #ddd; + -moz-border-radius: 0.7ex; +} + +#steps li.current span.marker { + background: #ffa500; + border: 1px solid #ffc400; +} + +#steps span.label { + font-size: 90%; +} + +#steps li.current span.label { + color: black; +} + +#steps ol ul { + display: none; +} + + +/** logs **/ +form#other-log-select { + margin-top: 2em; + padding-top: 1em; + border-top: 1px solid #999; +} + +form#other-log-select select { + margin: 0 1em; +} + +tr.level-error td { + border: 1px solid #800; + background: red; +} + +tr.level-error td.message { + font-weight: bold; +} + diff --git a/larpe/tags/release-1.1.1/root/larpe/css/dc2/head-bg.png b/larpe/tags/release-1.1.1/root/larpe/css/dc2/head-bg.png new file mode 100644 index 0000000..1622ef8 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/dc2/head-bg.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/dc2/head-logo-empty.png b/larpe/tags/release-1.1.1/root/larpe/css/dc2/head-logo-empty.png new file mode 100644 index 0000000..d347825 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/dc2/head-logo-empty.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/dc2/head-logo.png b/larpe/tags/release-1.1.1/root/larpe/css/dc2/head-logo.png new file mode 100644 index 0000000..215542f Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/dc2/head-logo.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/dc2/page-bg.png b/larpe/tags/release-1.1.1/root/larpe/css/dc2/page-bg.png new file mode 100644 index 0000000..729154e Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/dc2/page-bg.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/deg-top.png b/larpe/tags/release-1.1.1/root/larpe/css/deg-top.png new file mode 100644 index 0000000..fab62e3 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/deg-top.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/dot999.png b/larpe/tags/release-1.1.1/root/larpe/css/dot999.png new file mode 100644 index 0000000..a78020f Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/dot999.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/fond.jpg b/larpe/tags/release-1.1.1/root/larpe/css/fond.jpg new file mode 100644 index 0000000..bfd94dc Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/fond.jpg differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/ico_user.png b/larpe/tags/release-1.1.1/root/larpe/css/ico_user.png new file mode 100644 index 0000000..560be6f Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/ico_user.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/bulle.png b/larpe/tags/release-1.1.1/root/larpe/css/img/bulle.png new file mode 100644 index 0000000..171402b Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/bulle.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/day-date.png b/larpe/tags/release-1.1.1/root/larpe/css/img/day-date.png new file mode 100644 index 0000000..cbad44d Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/day-date.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/footer-500.png b/larpe/tags/release-1.1.1/root/larpe/css/img/footer-500.png new file mode 100644 index 0000000..74002d7 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/footer-500.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/footer.jpg b/larpe/tags/release-1.1.1/root/larpe/css/img/footer.jpg new file mode 100644 index 0000000..a1c8131 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/footer.jpg differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/h2.png b/larpe/tags/release-1.1.1/root/larpe/css/img/h2.png new file mode 100644 index 0000000..add8cb6 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/h2.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/li.png b/larpe/tags/release-1.1.1/root/larpe/css/img/li.png new file mode 100644 index 0000000..01f038a Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/li.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/linkscat.png b/larpe/tags/release-1.1.1/root/larpe/css/img/linkscat.png new file mode 100644 index 0000000..59516c5 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/linkscat.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/page-500.png b/larpe/tags/release-1.1.1/root/larpe/css/img/page-500.png new file mode 100644 index 0000000..9ff0f0f Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/page-500.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/page.png b/larpe/tags/release-1.1.1/root/larpe/css/img/page.png new file mode 100644 index 0000000..b436915 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/page.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/search.png b/larpe/tags/release-1.1.1/root/larpe/css/img/search.png new file mode 100644 index 0000000..6d1f037 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/search.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/sidebarh2.png b/larpe/tags/release-1.1.1/root/larpe/css/img/sidebarh2.png new file mode 100644 index 0000000..b187493 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/sidebarh2.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/top-500.png b/larpe/tags/release-1.1.1/root/larpe/css/img/top-500.png new file mode 100644 index 0000000..1fb77e7 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/top-500.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/top.jpg b/larpe/tags/release-1.1.1/root/larpe/css/img/top.jpg new file mode 100644 index 0000000..bab94c3 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/top.jpg differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/img/top.png b/larpe/tags/release-1.1.1/root/larpe/css/img/top.png new file mode 100644 index 0000000..f2adbb0 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/img/top.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/active-bg.gif b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/active-bg.gif new file mode 100644 index 0000000..d608c54 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/active-bg.gif differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/dark-bg.gif b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/dark-bg.gif new file mode 100644 index 0000000..1dea48a Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/dark-bg.gif differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/hover-bg.gif b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/hover-bg.gif new file mode 100644 index 0000000..fbf94fc Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/hover-bg.gif differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/menuarrow.gif b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/menuarrow.gif new file mode 100644 index 0000000..40c0aad Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/menuarrow.gif differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/normal-bg.gif b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/normal-bg.gif new file mode 100644 index 0000000..bdb5068 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/normal-bg.gif differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/rowhover-bg.gif b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/rowhover-bg.gif new file mode 100644 index 0000000..7715342 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/rowhover-bg.gif differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/status-bg.gif b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/status-bg.gif new file mode 100644 index 0000000..857108c Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/status-bg.gif differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/theme.css b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/theme.css new file mode 100644 index 0000000..d8b6af2 --- /dev/null +++ b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/theme.css @@ -0,0 +1,236 @@ +/* Distributed as part of The Coolest DHTML Calendar + Author: Mihai Bazon, www.bazon.net/mishoo + Copyright Dynarch.com 2005, www.dynarch.com +*/ + +/* The main calendar widget. DIV containing a table. */ + +div.calendar { position: relative; } + +.calendar, .calendar table { + border: 1px solid #bdb2bf; + font-size: 11px; + color: #000; + cursor: default; + background: url("/css/jscalendar/aqua/normal-bg.gif"); + font-family: "trebuchet ms",verdana,tahoma,sans-serif; +} + +.calendar { + border-color: #797979; +} + +/* Header part -- contains navigation buttons and day names. */ + +.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ + text-align: center; /* They are the navigation buttons */ + padding: 2px; /* Make the buttons seem like they're pressing */ + background: url("/css/jscalendar/aqua/title-bg.gif") repeat-x 0 100%; color: #000; + font-weight: bold; +} + +.calendar .nav { + font-family: verdana,tahoma,sans-serif; +} + +.calendar .nav div { + background: transparent url("/css/jscalendar/aqua/menuarrow.gif") no-repeat 100% 100%; +} + +.calendar thead tr { background: url("/css/jscalendar/aqua/title-bg.gif") repeat-x 0 100%; color: #000; } + +.calendar thead .title { /* This holds the current "month, year" */ + font-weight: bold; /* Pressing it will take you to the current date */ + text-align: center; + padding: 2px; + background: url("/css/jscalendar/aqua/title-bg.gif") repeat-x 0 100%; color: #000; +} + +.calendar thead .headrow { /* Row containing navigation buttons */ +} + +.calendar thead .name { /* Cells containing the day names */ + border-bottom: 1px solid #797979; + padding: 2px; + text-align: center; + color: #000; +} + +.calendar thead .weekend { /* How a weekend day name shows in header */ + color: #c44; +} + +.calendar thead .hilite { /* How do the buttons in header appear when hover */ + background: url("/css/jscalendar/aqua/hover-bg.gif"); + border-bottom: 1px solid #797979; + padding: 2px 2px 1px 2px; +} + +.calendar thead .active { /* Active (pressed) buttons in header */ + background: url("/css/jscalendar/aqua/active-bg.gif"); color: #fff; + padding: 3px 1px 0px 3px; + border-bottom: 1px solid #797979; +} + +.calendar thead .daynames { /* Row containing the day names */ + background: url("/css/jscalendar/aqua/dark-bg.gif"); +} + +/* The body part -- contains all the days in month. */ + +.calendar tbody .day { /* Cells containing month days dates */ + font-family: verdana,tahoma,sans-serif; + width: 2em; + color: #000; + text-align: right; + padding: 2px 4px 2px 2px; +} +.calendar tbody .day.othermonth { + font-size: 80%; + color: #999; +} +.calendar tbody .day.othermonth.oweekend { + color: #f99; +} + +.calendar table .wn { + padding: 2px 3px 2px 2px; + border-right: 1px solid #797979; + background: url("/css/jscalendar/aqua/dark-bg.gif"); +} + +.calendar tbody .rowhilite td, +.calendar tbody .rowhilite td.wn { + background: url("/css/jscalendar/aqua/rowhover-bg.gif"); +} + +.calendar tbody td.today { font-weight: bold; /* background: url("/css/jscalendar/aqua/today-bg.gif") no-repeat 70% 50%; */ } + +.calendar tbody td.hilite { /* Hovered cells */ + background: url("/css/jscalendar/aqua/hover-bg.gif"); + padding: 1px 3px 1px 1px; + border: 1px solid #bbb; +} + +.calendar tbody td.active { /* Active (pressed) cells */ + padding: 2px 2px 0px 2px; +} + +.calendar tbody td.weekend { /* Cells showing weekend days */ + color: #c44; +} + +.calendar tbody td.selected { /* Cell showing selected date */ + font-weight: bold; + border: 1px solid #797979; + padding: 1px 3px 1px 1px; + background: url("/css/jscalendar/aqua/active-bg.gif"); color: #fff; +} + +.calendar tbody .disabled { color: #999; } + +.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ + visibility: hidden; +} + +.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ + display: none; +} + +/* The footer part -- status bar and "Close" button */ + +.calendar tfoot .footrow { /* The in footer (only one right now) */ + text-align: center; + background: #565; + color: #fff; +} + +.calendar tfoot .ttip { /* Tooltip (status bar) cell */ + padding: 2px; + background: url("/css/jscalendar/aqua/status-bg.gif") repeat-x 0 0; color: #000; +} + +.calendar tfoot .hilite { /* Hover style for buttons in footer */ + background: #afa; + border: 1px solid #084; + color: #000; + padding: 1px; +} + +.calendar tfoot .active { /* Active (pressed) style for buttons in footer */ + background: #7c7; + padding: 2px 0px 0px 2px; +} + +/* Combo boxes (menus that display months/years for direct selection) */ + +.calendar .combo { + position: absolute; + display: none; + top: 0px; + left: 0px; + width: 4em; + cursor: default; + border-width: 0 1px 1px 1px; + border-style: solid; + border-color: #797979; + background: url("/css/jscalendar/aqua/normal-bg.gif"); color: #000; + z-index: 100; + font-size: 90%; +} + +.calendar .combo .label, +.calendar .combo .label-IEfix { + text-align: center; + padding: 1px; +} + +.calendar .combo .label-IEfix { + width: 4em; +} + +.calendar .combo .hilite { + background: url("/css/jscalendar/aqua/hover-bg.gif"); color: #000; +} + +.calendar .combo .active { + background: url("/css/jscalendar/aqua/active-bg.gif"); color: #fff; + font-weight: bold; +} + +.calendar td.time { + border-top: 1px solid #797979; + padding: 1px 0px; + text-align: center; + background: url("/css/jscalendar/aqua/dark-bg.gif"); +} + +.calendar td.time .hour, +.calendar td.time .minute, +.calendar td.time .ampm { + padding: 0px 5px 0px 6px; + font-weight: bold; + background: url("/css/jscalendar/aqua/normal-bg.gif"); color: #000; +} + +.calendar td.time .hour, +.calendar td.time .minute { + font-family: monospace; +} + +.calendar td.time .ampm { + text-align: center; +} + +.calendar td.time .colon { + padding: 0px 2px 0px 3px; + font-weight: bold; +} + +.calendar td.time span.hilite { + background: url("/css/jscalendar/aqua/hover-bg.gif"); color: #000; +} + +.calendar td.time span.active { + background: url("/css/jscalendar/aqua/active-bg.gif"); color: #fff; +} diff --git a/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/title-bg.gif b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/title-bg.gif new file mode 100644 index 0000000..6a541b3 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/title-bg.gif differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/today-bg.gif b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/today-bg.gif new file mode 100644 index 0000000..7161538 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/jscalendar/aqua/today-bg.gif differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/larpe-admin.css b/larpe/tags/release-1.1.1/root/larpe/css/larpe-admin.css new file mode 100644 index 0000000..5109ae3 --- /dev/null +++ b/larpe/tags/release-1.1.1/root/larpe/css/larpe-admin.css @@ -0,0 +1,410 @@ +@import url(larpe-common.css); + +body { + font-family: sans-serif; + background : white url(fond.jpg) repeat; +} + +div#main-content { + clear: both; + max-width: 800px; + margin: 0 4em; + background: white url(deg-top.png) top left repeat-x; + border: 1px solid #999; + padding: 1em; +} + +div#main-content h1 { + margin: 0 140px 1em 0; + border: 1px solid #666; + padding: 0 0.5ex; + background: white url(bg-footer.png) top right repeat-y; + font-size: 150%; +} + +#header { + max-width: 800px; + margin: 0 4em; + padding: 0 1em; + background-image : url(dot999.png); + background-repeat : repeat-x; + background-position : 0 100%; + position: relative; + top: 1px; +} + +#header ul { + margin : 0; + padding : 0; + list-style : none; +} + +#header li { + float : left; + margin : 0 -1px 0 0; + padding : 0 0 0 8px; + background-repeat : no-repeat; + background-position : 0 -110px; + background-image: url(onglet_left.png); + border-bottom: 1px solid #999; +} +#header a { + float : left; + display : block; + background-image : url(onglet_right.png); + background-repeat : no-repeat; + background-position : 100% -110px; + padding : 10px 10px 4px 3px; + font-weight : bold; + text-decoration : none; + color : #000; +} + +/* Commented Backslash Hack +Cache des règles à IE5-Mac \*/ +#header a {float:none;} +/* Fin du hack IE5-Mac */ + +#header li.active, #header li.active:hover { + background-position : 0 0; +} +#header li.active a, #header li.active:hover a { + background-position : 100% 0; +} +#header li:hover { + background-position : 0 -220px; +} +#header li:hover a { + background-position : 100% -220px; +} + +#header li.active { + border-bottom: 1px solid #eceade; +} + +/* +#header li.inactive, +#header li.inactive:hover { + background-position: 0 0; +} + +#header li.inactive a, +#header li.inactive:hover a { + background-position: 100% 0; + color: gray; +} +*/ + +div#footer { + max-width: 800px; + margin: 0 4em; + border: 1px solid #999; + border-top: 0; + background: #eceade; + padding: 0 1em; +} + +div#footer p { + margin: 0; + text-align: right; + font-size: 80%; + font-weight: bold; +} + + +div#login-top, +div#logout-top, +div#identity-top { + margin: 6em auto 1em auto; + border: 1px solid #999; + background: white; + padding: 0.5ex 1em; +} + +div#login-top, +div#login-form { + width: 20em; + max-width: 200px; +} + +div#logout-top, +div#logout-sps, +div#identity-top, +div#identity-content { + width: 40em; + max-width: 400px; +} + +div#login-top h1, +div#logout-top h1, +div#identity-top h1 { + margin: 0; + text-align: center; +} + +div#login-form, +div#logout-sps, +div#identity-content { + margin: 0 auto; + background: white url(deg-top.png) top left repeat-x; + border: 1px solid #999; + padding: 1em; +} + +div#login-form br { + display: none; +} + +div#login-form div.StringWidget { + margin-bottom: 1ex; +} + +p#cookies { + margin: 0 1em; + text-align: center; + font-size: 90%; +} + +form#login span.required { + display: none +} + +div#logout-sps ul li { + list-style: circle; +} + +div#logout-sps ul { + padding-left: 2em; +} + +div#logout-sps ul li img { + padding-left: 1em; +} + +ul.user-info { + float : right; + width : 102px; + position : relative; + margin : 0 0 1em 1em; + padding : 5px 0 0 30px; + background : transparent url(user_info_top.png) no-repeat top left; + list-style : none; +} +li.ui-name { +} +li.ui-logout { + display : block; + background : transparent url(user_info_bottom.png) no-repeat bottom left; + padding : 8px 0 10px 10px; + margin : 0 0 0 -30px; +} + +li.ui-logout a { + padding-left: 20px; +} + +table { + clear: both; +} + +table th { + text-align: left; + border-bottom: 1px solid #999; +} + +table td { + padding-right: 1ex; +} + +dl dt { + margin : 0; + padding : 0 0 0 0; +} + +dl dd { + margin : 0.3em 0 1.5em 10px; +} + +div#identity-content hr { + margin: 1em 2em; + height: 1px; + background: #999; + border: 0; + +} + +div.FieldWidget div.StringWidget { + float: left; + width: 30%; +} + +br.FieldWidget, +div.FieldWidget br { + display: none; +} + +pre { + overflow: scroll; +} + +div.explanation { + margin: 0 140px 1em 0; + background: white url(bg-footer.png) top right repeat-y; + border: 1px solid #ccc; + padding: 3px; +} + +div.explanation ol, +div.explanation p { + margin: 0; +} + +div#error-page { + border: 1px solid #a00; +} + +div#error-page h2 { + margin: 0; + border-bottom: 1px solid #a00; + background: #f52; + padding: 0 3px; +} + +div#error-page p { + padding: 0 3px; +} + +img.theme-icon { + float: right; + margin: -16px 4px 0px 3px; + border: 1px solid #999; +} + +a.arrow { + text-decoration: none; +} + +ul.biglist { + margin: 0; + padding: 0; +} + +#fields-list li { + cursor: move; +} + +ul.biglist li { + list-style-type: none; + margin: 4px 0; + padding: 0 2px; + border: 1px solid #888; + background: #ffe; + clear: both; +} + +ul.biglist li p.details { + display: block; + margin: 0; + color: #555; + font-size: 80%; +} + + +ul.biglist li p.commands { + float: right; + margin-top: -17px; +} + +ul.biglist li p.commands img { + padding-right: 5px; +} + +a img { + border: 0; +} + +td.time { + text-align: right; +} + +ul.biglist li.disabled, ul.biglist li.disabled p.details { + color: #999; + background: #ddd; +} + +form#other-log-select { + margin-top: 2em; + padding-top: 1em; + border-top: 1px solid #999; +} + +form#other-log-select select { + margin: 0 1em; +} + +tr.level-error td { + border: 1px solid #800; + background: red; +} + +tr.level-error td.message { + font-weight: bold; +} + +div#new-field table { + margin: 0; + padding: 0; +} + +div#new-field div.widget { + margin: 0; + padding: 0; +} + +div#new-field div.buttons { + margin: 0; + padding: 0; +} + +div#new-field div.buttons input { + margin: 0; + padding: 0; +} + +div#new-field { + border: 1px solid #888; + background: #ffe; + margin: 2em 0 4px 0; + padding: 0 2px; +} + +div#new-field div.widget { +} + +div#new-field h3 { + margin: 0; + font-size: 100%; +} + +div#new-field br { + display: none; +} + +div#new-field p.commands { + float: right; + margin-top: -17px; + margin-right: 3px; +} + +div.WorkflowStatusWidget { + border-left: 1px solid black; +} + +hr { + border: none; + border-top: 1px solid #666; + height: 1px; + width: 80%; +} + + diff --git a/larpe/tags/release-1.1.1/root/larpe/css/larpe-common.css b/larpe/tags/release-1.1.1/root/larpe/css/larpe-common.css new file mode 100644 index 0000000..498b2af --- /dev/null +++ b/larpe/tags/release-1.1.1/root/larpe/css/larpe-common.css @@ -0,0 +1,260 @@ +a { + color: #028; +} + +div.content { + margin-left: 5px; +} + +div.TextWidget textarea, +div.StringWidget input, +div.DateWidget input, +div.WcsExtraStringWidget input, +div.RegexStringWidget input, +div.EmailWidget input, +div.PasswordWidget input, +div.UrlWidget input, +div.ValidUrlWidget input { + border: 1px inset #ccc; + margin: 1px; + padding: 2px 3px; +} + +div.SingleSelectWidget select { + margin: 1px; +} + +div.widget input.prefill-button { + border: 1px outset #ccc; + margin: 0 0 0 1em; + padding: 0px 0px; +} + +div.widget input.prefill-button:focus { + border: 1px outset #ccc; + margin: 0 0 0 1em; + padding: 0; +} + + +div.widget textarea.readonly, +div.widget input.readonly { + border: 1px solid #ccc; + background: #eee; + margin: 0 0 0 1em; +} + +div.TextWidget textarea:focus, +div.DateWidget input:focus, +div.StringWidget input:focus, +div.WcsExtraStringWidget input:focus, +div.RegexStringWidget input:focus, +div.EmailWidget input:focus, +div.PasswordWidget input:focus, +div.UrlWidget input:focus, +div.ValidUrlWidget input:focus { + border: 2px solid #ccf; + /*margin: 0px; */ + padding: 1px 2px; +} + +div.AccountSettingWidget label { + padding-right: 2em; +} + +div.SubmitWidget input, input[type=submit] { + margin-top: 1em; + border: 1px outset #ccc; +} + +div.form .title, form.quixote .title { + font-weight: bold; +} + +div.errornotice { + background: #fd6; + border: 1px solid #ffae15; + margin: 0em 1em 1em 1em; + padding: 5px; +} + +div.infonotice { + background: #7b95a6; + border: 1px solid #153eaf; + margin: 0em 1em 1em 1em; + padding: 5px; +} + +div.error { + color: black; + font-weight: bold; + background: transparent url(warning.png) top left no-repeat; + padding-left: 20px; +} + +div.buttons div.SubmitWidget, +div.buttons div.SubmitWidget div.content { + display: inline; +} + +div.buttons br { display: none; } + +div.widget { + margin-bottom: 0.5em; + clear: both; +} + +input[type="submit"][name="submit"] { + font-weight: bold; +} + +div.form pre { + overflow: scroll; +} + + +div#error h1 { + margin: 0; +} + +div#error { + width: 40em; + max-width: 500px; + margin: 15% auto; + background: white; + border: 1px solid #999; + padding: 1em; +} + +div.hint { + font-size: 80%; +} + +span.required { + background: transparent url(required.png) 0px 0.5ex no-repeat; + padding: 0 0 0 24px; + margin-left: 1ex; + overflow: hidden; + color: white; +} + +div.buttons { + margin-top: 1em; +} + +div.RadiobuttonsWidget div.content { + display: block; +} + +div.error-page { + margin: 1em; +} + +pre#exception { + overflow: scroll; + padding: 1em; + border: 1px solid #bbb; + background: #f0f0f0; + font-size: 90%; +} + +div.StringWidget ul { + margin: 0; + padding-left: 2em; + list-style: circle; +} + +div.inline-first div.title, +div.inline div.title { + display: inline; + float: left; + max-width: 20em; + text-align: left; + padding-top: 6px; +} + +div.inline-first div.title span.required, +div.inline div.title span.required { + margin-left: 1ex; + padding-left: 12px; +} + +div.inline-first div.content, +div.inline div.content { + margin-left: 1ex; +} + +div.inline-first div.hint, +div.inline div.hint { + display: none; +} + +div.inline-first { + float: left; + clear: both; +} + +div.inline { + float: left; + clear: none; +} + +div.inline-first div.content, +div.inline div.content { + margin-right: 1.5em; +} + + + +div.inline-first div.content, +div.inline div.content { + display: inline; +} + +.clear-both { + clear: both; +} + +div.CheckboxesWidget div.content ul { + list-style: none; + padding: 0; + margin: 0; +} + +div.CheckboxesWidget div.content ul li { + display: inline; + margin-right: 2em; +} + +div#receipt { + clear: both; +} + +div#receipt span.label { + font-weight: bold; + display: block; +} + +div#receipt span.value { + display: block; + margin-left: 1em; +} + +form div.page, +div#receipt div.page { + border: 1px solid #aaa; + padding: 1ex; + margin-bottom: 1em; +} + +form div.page p, +div#receipt div.page p { + margin-top: 0; +} + +form div.page h3, +div#receipt div.page h3 { + margin: 0; + margin-bottom: 1ex; +} + diff --git a/larpe/tags/release-1.1.1/root/larpe/css/larpe.css b/larpe/tags/release-1.1.1/root/larpe/css/larpe.css new file mode 100644 index 0000000..b582d9f --- /dev/null +++ b/larpe/tags/release-1.1.1/root/larpe/css/larpe.css @@ -0,0 +1,331 @@ +@import url(larpe-common.css); +@import url(jscalendar/aqua/theme.css); +/* derived from soFresh, a DotClear theme by Maurice Svay (GPL) + * http://www.svay.com/files/soFresh/theme-sofresh-1.2.zip */ + +html, body { + font-family: sans-serif; + text-align: center; + background: #eee; + color: black; +} + +div#page { + width: 800px; + margin: 2em auto; + text-align: justify; + background: white url(img/page.png) repeat-y; + color: black; +} + +body.login div#page { + width: 500px; + background: white url(img/page-500.png) repeat-y; +} +#top { + color: #09F; + background: #FFF url(img/top.jpg) no-repeat; + height: 100px; + margin: 0; +} + +body.login #top { + background: white url(img/top-500.png) no-repeat; +} + +#top h1 { + margin: 0; + padding-left: 30px; + padding-right: 30px; + line-height: 100px; + height: 100px; + overflow: hidden; +} + +#footer { + background: #FFF url(img/footer.jpg) no-repeat; + color: #999; + text-align: center; + min-height: 30px; +} + +body.login #footer { + background: white url(img/footer-500.png) no-repeat; +} + +div#main-content { + margin: 0 2em; +} + +div#main-content h1 { + color: #09F; +} + +#steps { + height: 32px; + margin-bottom: 1em; +} + +#steps ol { + list-style: none; + padding: 0 20px; +} + +#steps li { + display: inline; + padding-right: 1em; + display: block; + float: left; + width: 30%; + list-style: none; +} + +#steps ol ul { + border: 1px solid #ffa500; + margin-left: 2em; + background: #ffdb94; + margin-bottom: 1em; + padding: 0; + width: auto; +} + +#steps li li { + display: block; + width: auto; + float: none; + text-align: left; + margin-left: 1em; + font-size: 90%; +} + +#steps li li.current { + color: black; +} + + +#steps span.marker { + font-size: 26px; + padding: 2px 9px; + font-weight: bold; + color: white; + text-align: center; + background: #ddd; + border: 1px solid #ddd; + -moz-border-radius: 0.7ex; +} + +#steps li.current span.marker { + background: #ffa500; + border: 1px solid #ffc400; +} + +#steps span.label { + font-size: 90%; +} + +#steps li.current span.label { + color: black; +} + +#steps { + background: #f0f0f0; + color: #aaa; +} + +#steps ol ul { + display: none; +} + +#steps ol li.current ul { + display: block; +} + +form { + clear: both; +} + +p#receiver { + margin: 0; + margin-left: 2em; + margin-top: -0.7em; + margin-bottom: 1em; + padding: 2px 5px; + border: 1px solid #ccc; + float: left; + background: #ffe; +} + +p#login, +p#logout { + margin-top: 2em; + text-align: right; +} + +p#login a, p#logout a { + text-decoration: underline; + /* + text-decoration: none; + -moz-border-radius: 2em !important; + padding: 1px 6px !important; + border: 1px solid #ccc !important; + border-bottom: 2px solid #999 !important;*/ +} + +p#login a:hover { + background-color: #ddeeff; +} + +h2#submitted, h2#done { + margin-top: 2em; + color: #09F; + font-size: 130%; +} + +h2#done { + margin-top: 1em; +} + +ul li { + list-style-image: url(img/li.png); +} + +h2, h3 { + color: #09F; + margin-left: 0.5em; + margin-bottom: 0; +} + +h3 { + margin-left: 1em; +} + +table#listing { + margin: 1em 0; +} + +table#listing th { + text-align: left; + border-bottom: 1px solid #999; + background: #eee; +} + +table#listing td { + padding-right: 1ex; +} + +table#listing th a { + text-decoration: none; + color: #666; +} + +table.sortable span.sortarrow { + color: black; + text-decoration: none; +} + +table#listing tr.status-new { + background: #aea; +} + +table#listing tr.status-finished, +table#listing tr.status-rejected { + color: #444; +} + +table#listing tr.status-rejected td { + text-decoration: line-through; +} + +div.question p.label { + font-weight: bold; +} + +img.bar { + border: 1px solid black; +} + +div.question table { + margin-left: 10px; +} + +div.question table td { +} + +div.question table td.percent { + text-align: right; + padding: 0 1em; + width: 6em; +} + +div.question table td.label { + width: 6em; +} + +span.user { + margin-left: 1em; + font-style: italic; +} + +a.listing { + font-size: 80%; + padding-left: 1em; +} + +a { + text-decoration: none; + color: #113; +} + +a:hover { + color: #06C; + text-decoration: underline; +} + + +#prelude { + color: #aaa; + background: transparent; + text-align: right; + position: relative; + top: -85px; + margin: 0; +} + +p#breadcrumb { + margin-top: 0; +} + +div.error-page { + margin-bottom: 2em; +} + +div.hint { + display: inline; + padding-left: 1ex; + font-style: italic; +} + +a.standalone { + background: white url(img/h2.png) top left no-repeat; + padding-left: 20px; +} + +div#welcome-message a { + text-decoration: underline; +} + +input.cancel { + margin-left: 5em; +} + +hr { + border: none; + border-top: 1px solid #666; + height: 1px; + width: 80%; +} + +div.buttons { + clear: both; +} + diff --git a/larpe/tags/release-1.1.1/root/larpe/css/onglet_left.png b/larpe/tags/release-1.1.1/root/larpe/css/onglet_left.png new file mode 100644 index 0000000..dc1ce47 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/onglet_left.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/onglet_right.png b/larpe/tags/release-1.1.1/root/larpe/css/onglet_right.png new file mode 100644 index 0000000..72a6497 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/onglet_right.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/required.png b/larpe/tags/release-1.1.1/root/larpe/css/required.png new file mode 100644 index 0000000..95c2219 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/required.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/user_info_bottom.png b/larpe/tags/release-1.1.1/root/larpe/css/user_info_bottom.png new file mode 100644 index 0000000..92da7de Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/user_info_bottom.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/user_info_top.png b/larpe/tags/release-1.1.1/root/larpe/css/user_info_top.png new file mode 100644 index 0000000..c91b707 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/user_info_top.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/css/warning.png b/larpe/tags/release-1.1.1/root/larpe/css/warning.png new file mode 100644 index 0000000..9a8c5bb Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/css/warning.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/images/bar.png b/larpe/tags/release-1.1.1/root/larpe/images/bar.png new file mode 100644 index 0000000..f460fd1 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/images/bar.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/images/stock_add_16.png b/larpe/tags/release-1.1.1/root/larpe/images/stock_add_16.png new file mode 100644 index 0000000..41e14de Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/images/stock_add_16.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/images/stock_copy_16.png b/larpe/tags/release-1.1.1/root/larpe/images/stock_copy_16.png new file mode 100644 index 0000000..72bb707 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/images/stock_copy_16.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/images/stock_edit_16.png b/larpe/tags/release-1.1.1/root/larpe/images/stock_edit_16.png new file mode 100644 index 0000000..7c7d597 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/images/stock_edit_16.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/images/stock_exec_16.png b/larpe/tags/release-1.1.1/root/larpe/images/stock_exec_16.png new file mode 100644 index 0000000..aafc029 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/images/stock_exec_16.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/images/stock_file_16.png b/larpe/tags/release-1.1.1/root/larpe/images/stock_file_16.png new file mode 100644 index 0000000..db8b087 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/images/stock_file_16.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/images/stock_harddisk_16.png b/larpe/tags/release-1.1.1/root/larpe/images/stock_harddisk_16.png new file mode 100644 index 0000000..af068e8 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/images/stock_harddisk_16.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/images/stock_properties_16.png b/larpe/tags/release-1.1.1/root/larpe/images/stock_properties_16.png new file mode 100644 index 0000000..b2ba923 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/images/stock_properties_16.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/images/stock_remove_16.png b/larpe/tags/release-1.1.1/root/larpe/images/stock_remove_16.png new file mode 100644 index 0000000..04156d5 Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/images/stock_remove_16.png differ diff --git a/larpe/tags/release-1.1.1/root/larpe/images/view_16.png b/larpe/tags/release-1.1.1/root/larpe/images/view_16.png new file mode 100644 index 0000000..346afce Binary files /dev/null and b/larpe/tags/release-1.1.1/root/larpe/images/view_16.png differ diff --git a/larpe/tags/release-1.1.1/setup.py b/larpe/tags/release-1.1.1/setup.py new file mode 100644 index 0000000..bd95463 --- /dev/null +++ b/larpe/tags/release-1.1.1/setup.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +import os +import distutils.core +from quixote.ptl.qx_distutils import qx_build_py + +local_cfg = None +if os.path.exists('larpe/larpe_cfg.py'): + local_cfg = open('larpe/larpe_cfg.py').read() + os.unlink('larpe/larpe_cfg.py') + +def data_tree(destdir, sourcedir): + extensions = ['.css', '.png', '.jpeg', '.jpg', '.xml', '.html', '.js', '.py'] + r = [] + for root, dirs, files in os.walk(sourcedir): + l = [os.path.join(root, x) for x in files if os.path.splitext(x)[1] in extensions] + r.append( (root.replace(sourcedir, destdir, 1), l) ) + if '.svn' in dirs: + dirs.remove('.svn') + return r + +distutils.core.setup( + name = 'larpe', + version = '1.1.1', + maintainer = 'Jerome Schneider', + maintainer_email = 'jschneider@entrouvert.com', + url = 'http://larpe.labs.libre-entreprise.org', + package_dir = { 'larpe': 'larpe' }, + packages = ['larpe', 'larpe.admin', 'larpe.ctl', 'larpe.plugins', 'larpe.plugins.site_authentication', 'larpe.qommon', + 'larpe.qommon.admin', 'larpe.qommon.ident', 'larpe.qommon.backoffice', 'larpe.qommon.vendor'], + cmdclass = {'build_py': qx_build_py}, + data_files = data_tree('share/larpe/web/', 'root/') + \ + data_tree('share/larpe/web/larpe/qo/', 'larpe/qommon/static/') + \ + data_tree('share/larpe/', 'conf/') + ) + +if local_cfg: + open('larpe/larpe_cfg.py', 'w').write(local_cfg) + diff --git a/larpe/tags/release-1.1.1/tests/all4dev/slo_check b/larpe/tags/release-1.1.1/tests/all4dev/slo_check new file mode 100644 index 0000000..7920630 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/all4dev/slo_check @@ -0,0 +1,2 @@ +url http://all4dev.test.org/index.php/Main_Page +find "Create an account or log in" diff --git a/larpe/tags/release-1.1.1/tests/all4dev/sso_check b/larpe/tags/release-1.1.1/tests/all4dev/sso_check new file mode 100644 index 0000000..121f0e6 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/all4dev/sso_check @@ -0,0 +1,3 @@ +url http://all4dev.test.org/index.php/Main_Page +find $find_username +find logout diff --git a/larpe/tags/release-1.1.1/tests/blueprint/slo_check b/larpe/tags/release-1.1.1/tests/blueprint/slo_check new file mode 100644 index 0000000..98f1e21 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/blueprint/slo_check @@ -0,0 +1 @@ +find " twill_output + grep "ERROR" twill_output &> /dev/null + if [ $? -eq 0 ]; + then + echo " [FAILED]" + cat twill_output + exit 1 + else + echo " [OK]" + fi +} + +echo +# Check loop +for site in $sites; +do + if [ ! -d $site ]; + then + continue + fi + + echo "Testing $site :" + + echo -n " Defederation ..." + cat $site/config defederation idp_login | twill-sh &> /dev/null + echo " [OK]" + check $site "Federation" + check $site "SSO" + check $site "SLO" + check $site "SSO" "SLO" + check $site "SLO" "SSO" "SLO" "SLO" "SSO" "SLO" + + rm -f twill_output + echo +done diff --git a/larpe/tags/release-1.1.1/tests/defederation b/larpe/tags/release-1.1.1/tests/defederation new file mode 100644 index 0000000..a25bb7b --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/defederation @@ -0,0 +1 @@ +go $defederation_url diff --git a/larpe/tags/release-1.1.1/tests/dotclear/slo_check b/larpe/tags/release-1.1.1/tests/dotclear/slo_check new file mode 100644 index 0000000..36ffbc0 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/dotclear/slo_check @@ -0,0 +1,2 @@ +#url http://dotclear.test.org/ +url https://dotclear.test.org/ diff --git a/larpe/tags/release-1.1.1/tests/dotclear/sso_check b/larpe/tags/release-1.1.1/tests/dotclear/sso_check new file mode 100644 index 0000000..e92a866 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/dotclear/sso_check @@ -0,0 +1,4 @@ +#url http://dotclear.test.org/ecrire/ +url https://dotclear.test.org/ecrire/ +find $find_username +find déconnexion diff --git a/larpe/tags/release-1.1.1/tests/dotclear_subdir/slo_check b/larpe/tags/release-1.1.1/tests/dotclear_subdir/slo_check new file mode 100644 index 0000000..e1e0688 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/dotclear_subdir/slo_check @@ -0,0 +1 @@ +url http://listes.test.org/dotclear/ diff --git a/larpe/tags/release-1.1.1/tests/dotclear_subdir/sso_check b/larpe/tags/release-1.1.1/tests/dotclear_subdir/sso_check new file mode 100644 index 0000000..7231809 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/dotclear_subdir/sso_check @@ -0,0 +1,3 @@ +url http://listes.test.org/dotclear/ecrire/ +find $find_username +find déconnexion diff --git a/larpe/tags/release-1.1.1/tests/federation b/larpe/tags/release-1.1.1/tests/federation new file mode 100644 index 0000000..68e0a2b --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/federation @@ -0,0 +1,3 @@ +formvalue 1 username $sp_username +formvalue 1 password $sp_password +submit diff --git a/larpe/tags/release-1.1.1/tests/gen_config.sh b/larpe/tags/release-1.1.1/tests/gen_config.sh new file mode 100755 index 0000000..2b60b0d --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/gen_config.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +if [ $# -eq 0 ]; +then + echo "Usage : $0 site_name" + exit 1 +fi + +while [ $# -ne 0 ]; +do + if [ -d $1 ]; + then + config_file="$1/config" + echo -n "Generating config template for $1 ... " + echo "setlocal sp_login_url " >> $config_file + echo "setlocal sp_logout_url " >> $config_file + echo "setlocal defederation_url " >> $config_file + echo "setlocal idp_username " >> $config_file + echo "setlocal idp_password " >> $config_file + echo "setlocal sp_username " >> $config_file + echo "setlocal sp_password " >> $config_file + echo "setlocal find_username " >> $config_file + echo "[OK]" + fi + shift +done diff --git a/larpe/tags/release-1.1.1/tests/idp_login b/larpe/tags/release-1.1.1/tests/idp_login new file mode 100644 index 0000000..42c0c41 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/idp_login @@ -0,0 +1,3 @@ +formvalue 1 username $idp_username +formvalue 1 password $idp_password +submit diff --git a/larpe/tags/release-1.1.1/tests/libre-entreprise/slo_check b/larpe/tags/release-1.1.1/tests/libre-entreprise/slo_check new file mode 100644 index 0000000..ad99d02 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/libre-entreprise/slo_check @@ -0,0 +1,3 @@ +#url http://libre-entreprise.reverse-proxy.entrouvert.org/index.php/Accueil +url http://le.test.org/index.php/Accueil +find "Créer un compte ou se connecter" diff --git a/larpe/tags/release-1.1.1/tests/libre-entreprise/sso_check b/larpe/tags/release-1.1.1/tests/libre-entreprise/sso_check new file mode 100644 index 0000000..c2ef7aa --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/libre-entreprise/sso_check @@ -0,0 +1,4 @@ +#url http://libre-entreprise.reverse-proxy.entrouvert.org/index.php/Accueil +url http://le.test.org/index.php/Accueil +find $find_username +find déconnexion diff --git a/larpe/tags/release-1.1.1/tests/listes_entrouvert/slo_check b/larpe/tags/release-1.1.1/tests/listes_entrouvert/slo_check new file mode 100644 index 0000000..17a4d28 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/listes_entrouvert/slo_check @@ -0,0 +1 @@ +find Login diff --git a/larpe/tags/release-1.1.1/tests/listes_entrouvert/sso_check b/larpe/tags/release-1.1.1/tests/listes_entrouvert/sso_check new file mode 100644 index 0000000..b328dd0 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/listes_entrouvert/sso_check @@ -0,0 +1,2 @@ +find $find_username +find "You have logged in" diff --git a/larpe/tags/release-1.1.1/tests/listes_libre_entreprise/slo_check b/larpe/tags/release-1.1.1/tests/listes_libre_entreprise/slo_check new file mode 100644 index 0000000..17a4d28 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/listes_libre_entreprise/slo_check @@ -0,0 +1 @@ +find Login diff --git a/larpe/tags/release-1.1.1/tests/listes_libre_entreprise/sso_check b/larpe/tags/release-1.1.1/tests/listes_libre_entreprise/sso_check new file mode 100644 index 0000000..62eff4e --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/listes_libre_entreprise/sso_check @@ -0,0 +1,2 @@ +find $find_username +find "Vous êtes identifié" diff --git a/larpe/tags/release-1.1.1/tests/slo b/larpe/tags/release-1.1.1/tests/slo new file mode 100644 index 0000000..8746cfa --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/slo @@ -0,0 +1 @@ +go $sp_logout_url diff --git a/larpe/tags/release-1.1.1/tests/sso b/larpe/tags/release-1.1.1/tests/sso new file mode 100644 index 0000000..c1b8540 --- /dev/null +++ b/larpe/tags/release-1.1.1/tests/sso @@ -0,0 +1 @@ +go $sp_login_url