Overview
We want to map the following entry in passwd NIS map:
jbond:x:507:507:James Bond:/home/jbond:/bin/bash
into the following LDAP entry in Penrose:
dn: uid=jbond,ou=Users,dc=NIS,dc=Example,dc=com loginShell: /bin/bash sn: Bond objectClass: account objectClass: posixAccount gidNumber: 507 uid: jbond uidNumber: 507 gecos: James Bond cn: James Bond userPassword:: e2NyeXB0fSQxJHBXZzl3RWxEJDJBVmtsUG1jbjRiWlRtcnYweVJoZDA= homeDirectory: /home/jbond
Configuration
Define the following sources in sources.xml:
<source name="users"> <connection-name>NIS</connection-name> <field name="uid" primaryKey="true"/> <field name="uidNumber"/> <field name="gidNumber"/> <field name="homeDirectory"/> <field name="userPassword"/> <field name="loginShell"/> <field name="gecos"/> <field name="description"/> <parameter> <param-name>objectClasses</param-name> <param-value>posixAccount</param-value> </parameter> <parameter> <param-name>base</param-name> <param-value>passwd</param-value> </parameter> </source> <source name="shadow"> <connection-name>NIS</connection-name> <field name="uid" primaryKey="true"/> <field name="userPassword"/> <field name="shadowLastChange"/> <field name="shadowMin"/> <field name="shadowMax"/> <field name="shadowWarning"/> <field name="shadowInactive"/> <field name="shadowExpire"/> <field name="shadowFlag"/> <field name="description"/> <parameter> <param-name>objectClasses</param-name> <param-value>shadowAccount</param-value> </parameter> <parameter> <param-name>base</param-name> <param-value>passwd.adjunct.byname</param-value> </parameter> </source>
Then define the following entry in directory.xml:
<entry dn="uid=...,ou=Users,dc=NIS,dc=Example,dc=com"> <entry-class>org.safehaus.penrose.nis.directory.NISEntry</entry-class> <oc>account</oc> <oc>posixAccount</oc> <oc>shadowAccount</oc> <at name="uid" rdn="true"> <variable>u.uid</variable> </at> <at name="cn"> <expression> if (u.gecos != void && u.gecos != null) { return u.gecos; } return u.uid; </expression> </at> <at name="uidNumber"> <variable>u.uidNumber</variable> </at> <at name="gidNumber"> <variable>u.gidNumber</variable> </at> <at name="homeDirectory"> <expression> if (u == void || u == null || u.homeDirectory == void || u.homeDirectory == null || "".equals(u.homeDirectory)) return "/tmp"; return u.homeDirectory; </expression> </at> <at name="userPassword"> <expression> if (s != void && s != null && s.userPassword != void && s.userPassword != null) { return "{crypt}"+s.userPassword; } if (u.userPassword != void && u.userPassword != null) { return "{crypt}"+u.userPassword; } return null; </expression> </at> <at name="loginShell"> <variable>u.loginShell</variable> </at> <at name="gecos"> <variable>u.gecos</variable> </at> <at name="description"> <variable>u.description</variable> </at> <at name="shadowLastChange"> <variable>s.shadowLastChange</variable> </at> <at name="shadowMin"> <variable>s.shadowMin</variable> </at> <at name="shadowMax"> <variable>s.shadowMax</variable> </at> <at name="shadowWarning"> <variable>s.shadowWarning</variable> </at> <at name="shadowInactive"> <variable>s.shadowInactive</variable> </at> <at name="shadowExpire"> <variable>s.shadowExpire</variable> </at> <at name="shadowFlag"> <variable>s.shadowFlag</variable> </at> </entry>
Also configure the reverse mapping in the same entry:
<entry dn="uid=...,ou=Users,dc=NIS,dc=Example,dc=com"> <source alias="u"> <source-name>users</source-name> <field name="uid"> <variable>uid</variable> </field> <field name="uidNumber"> <variable>uidNumber</variable> </field> <field name="gidNumber"> <variable>gidNumber</variable> </field> <field name="homeDirectory"> <variable>homeDirectory</variable> </field> <field name="userPassword"> <expression> import org.safehaus.penrose.util.*; if (userPassword == void || userPassword == null) return; String method = PasswordUtil.getEncryptionMethod(userPassword); if (method == null) { return PasswordUtil.encrypt("crypt", userPassword); } else if ("crypt".equals(method)) { return PasswordUtil.getEncryptedPassword(userPassword); } else { throw new Exception("Unsupported encryption: "+method); } return bytes; </expression> </field> <field name="loginShell"> <variable>loginShell</variable> </field> <field name="gecos"> <variable>gecos</variable> </field> <field name="description"> <variable>description</variable> </field> </source> <source alias="s"> <source-name>shadow</source-name> <field name="uid"> <variable>u.uid</variable> </field> <field name="userPassword"> <expression> import org.safehaus.penrose.util.*; if (userPassword == void || userPassword == null) return; String method = PasswordUtil.getEncryptionMethod(userPassword); if (method == null) { return PasswordUtil.encrypt("crypt", userPassword); } else if ("crypt".equals(method)) { return PasswordUtil.getEncryptedPassword(userPassword); } else { throw new Exception("Unsupported encryption: "+method); } return bytes; </expression> </field> <field name="description"> <variable>description</variable> </field> <field name="shadowLastChange"> <variable>shadowLastChange</variable> </field> <field name="shadowMin"> <variable>shadowMin</variable> </field> <field name="shadowMax"> <variable>shadowMax</variable> </field> <field name="shadowWarning"> <variable>shadowWarning</variable> </field> <field name="shadowInactive"> <variable>shadowInactive</variable> </field> <field name="shadowExpire"> <variable>shadowExpire</variable> </field> <field name="shadowFlag"> <variable>shadowFlag</variable> </field> </source> </entry>
Authentication
When the client tries to authenticate a NIS user, Penrose will validate the password supplied in the bind request against the encrypted password returned by the NIS server. The comparison is done in Penrose, not in the NIS server.
