October 12, 2009

Dynamic presentations with Jessyink

Some time ago, I attended a presentation made with Prezi and I was pretty impressed. As I looked into it, a few things bugged me though:

  • it's in flash

  • I can't really share my presentations with anyone

  • I have to design my slides online, or use an offline app (paid) which will connect online

  • There is no good support for full screen presentations in Linux

  • It doesn't use a portable format




From looking at the features, I really couldn't see why it couldn't be implemented using SVG (except for the flash movies embedded in the presentation maybe...), so I began to search for a project that would do the same, using SVG, and I found Jessyink.

Jessyink is exactly what I was searching for. It's a plugin for Inkscape which adds the possibility to design slides from an SVG, and ships a javascript library inside the resulting SVG for execution. The result is that:

  • It's portable: apps that understands SVG and javascript can play it (e.g. Firefox, on any platform. Arora did fine too, but Konqueror wouldn't work)

  • It's an open format, with open standards: I can send the svg to someone, and they can edit it with inkscape using the Jessyink plugin

  • The possibilities are endless: I'm not limited to styles and fonts found on prezi.com, I can choose whatever font I want, whatever style I want

  • It's open-source!

  • It not only supports prezi-like effects inside slides, but also traditional slides, that can each behave like prezi-like presentations



Jessyink is harder to use than prezi.com though, but if you know how to use Inkscape, you will soon be able to do what you want with it.


Here is a quick & dirty example I made with Jessyink. Some tips:

  • Use the arrows to navigate through the presentation

  • Use the 'i' key to get an index of the slides (two slides in that case)

  • Use the 'd' key to draw on the presentation as you go through it!

  • See this page for more tips!

October 9, 2009

Authentication on both PostgreSQL and LDAP in Gforge

I am currently working on migrating a Gforge platform from authenticating on the local PostgreSQL to a centralized LDAP server.

Apart from setting up PAM-LDAP (Martin Owens can tell you all about the mess it is), the fun thing was to have some users authenticate on PostgreSQL and others on LDAP during the time of the migration.

Using a modified version of the LDAP plugin for Gforge, users are prompted for their LDAP login and password when they log in, and we fill a plugin_ldapextauth_users table with the Gforge IDs of the migrated users. Then comes the fun part. Users that are not yet migrated have to be able to log in using their Gforge login, but not their LDAP login. Users that are migrated have to be able to use their LDAP login, but their Gforge login should fail.

Note: This post is not a tutorial on how to set up libnss-pgsql2 or libnss-ldap. I won't be explaining these.

This is the solution I've come to. The machines are running on Debian Etch.

In /etc/nsswitch.conf



passwd: compat pgsql ldap
group: compat pgsql ldap
shadow: compat pgsql ldap


PostgreSQL is tried before ldap, but must fail when the user has been migrated.


In /etc/nss-pgsql.conf and /etc/nss-pgsql-root.conf



#getpwnam = SELECT login AS username,passwd,gecos,('/var/lib/gforge/chroot/home/users/' || login) AS homedir,shell,uid,gid FROM nss_passwd WHERE login = $1
getpwnam = SELECT nss.login AS username,nss.passwd,nss.gecos,('/var/lib/gforge/chroot/home/users/' || login) AS homedir,nss.shell,nss.uid,nss.gid FROM nss_passwd nss JOIN users ON users.user_name=nss.login LEFT JOIN plugin_ldapextauth_users ldap ON users.user_id=ldap.user_id WHERE ldap.user_id IS NULL AND login = $1;



#shadowbyname = SELECT login AS shadow_name, passwd AS shadow_passwd, 14087 AS shadow_lstchg, 0 AS shadow_min, 99999 AS shadow_max, 7 AS shadow_warn, '' AS shadow_inact, '' AS shadow_expire, '' AS shadow_flag FROM nss_passwd WHERE login = $1 AND ldap = 0
shadowbyname = SELECT nss.login AS shadow_name,nss.passwd AS shadow_passwd,14087 AS shadow_lstchg, 0 AS shadow_min, 99999 AS shadow_max, 7AS shadow_warn, '' AS shadow_inact, '' AS shadow_expire, '' AS shadow_flag FROM nss_passwd nss JOIN users ON users.user_name=nss.login LEFT JOIN plugin_ldapextauth_users ldap ON users.user_id=ldap.user_id WHERE ldap.user_id IS NULL AND login = $1;


This requires to GRANT SELECT access to tables users and plugin_ldapextauth_users to user gforge_nss. As a result, the request fails if the user id is found in the plugin_ldapextauth_users table, so it goes to try LDAP instead.


In /etc/pam.d/common-auth



# pam_unix fails permanently when users are migrated
auth sufficient pam_unix.so nullok_secure
# Filter accounts that are not migrated
# Since pam_unix fails for migrated accounts,
# uid then comes from ldap
auth required pam_succeed_if.so uid > 60000
# Note: try_first_pass will prompt for LDAP password
# if provided password failed
auth required pam_ldap.so try_first_pass


This is the only thing I needed to modify in /etc/pam.d. Gforge accounts use the 20xxx uid range, while our LDAP uses 60xxx, hence the pam_succeed_if.so condition to filter LDAP accounts only. This works because the uid that is returned by "getent passwd $user" corresponds to the one in the LDAP when a user is migrated, since the PostgreSQL query fails in that case (see /etc/nss-pgsql*.conf).


Chowning homes



When migrating users, uids change, and sometimes even login names. I've chosen to use inotify (incron) to fix that issue. When a user is migrated in the web interface, it drops a file in /var/lib/gforge/ldap_users named after the Gforge user name, which contains the LDAP user name.

Incron watches /var/lib/gforge/ldap_users with the following conf:
/var/lib/gforge/ldap_users IN_CREATE /usr/lib/gforge-dop-pamldap/chown_home.sh $# $@

The chown_home.sh script then achieves the following tasks:

  • Symlink the new home directory (/home/$ldap_user) to the old one (/var/lib/gforge/chroot/home/users/$gforge_user)

  • Chown the directory with the new user (chown $ldap_user. $home)




Remaining issues



The main remaining issue is groups. The Gforge database uses the login to map users to groups, instead of the Gforge id, so when the Gforge login is different from the LDAP login, migrated users currently lose their groups. The easiest option is probably to change all occurrences of the login with the LDAP login in all group tables, but it's a bit violent...