|
Hi all, as discussed in the LDAP mapping thread, we have two potential contributions for the Apache Directory Project: a small object to LDAP mapping library and a PXE server software which could form the basis for a full DHCP server implementation. In order to get this going, I'll give you a quick wrap up of what the state of the components is. In the next few days I'll then extract the relevant stuff from our code-base and make it available in the Apache DS sandbox. 1. The LDAP mapper ---------------------- The LDAP mapper strives to achieve for LDAP what Hibernate, JPA, et. al. do for relational databases: map Java objects to LDAP objects in a transparent fashion. For an overview about what it can and can not do, I'll just refer you to my previous message. Instead, I'll give you a rough idea of how using the LDAP mapper looks like. Just as using an ORM leaks some details of the underlying persistence mechanism into the domain model, namely having to deal with the object identity and the difference between relational and object oriented association semantics, one has to pay some tribute to the way LDAP works when implementing persistent objects: every LDAP-persistent class must have an attribute holding the DN and every class must have an attribute for the RDN. In our data model all classes inherit from DirectoryObject which has a dn attribute, but that isn't a requirement. Each domain model class maps to a particular combination of LDAP object classes. Since the mapping layer supports polymorphic results (well, you can't just restrict what objects are referenced in a group under LDAP), the mapping has to be able to determine the domain class for an LDAP object. For those cases, the mapper currently requires exactly one "key class" which is an LDAP object class it expects to be unique for a given domain object class. Access to object properties is currently done using simple property getter/setter access. No fancy bytecode enhancement or private field access. Sorry. Now, lets consider we have a domain class for users which maps to inetOrgPersons in LDAP: public class User extends DirectoryObject {The DirectoryObject super-class provides for the dn and description attributes: public abstract class DirectoryObject implements Serializable {This object might be mapped to the directory using the following descriptor: <class name="org.openthinclient.common.model.User" base-rdn="ou=users"As you can see, you have to tell the mapping - the Java and LDAP class names - the key-class (in cases where the mapping isn't told the type of domain class otherwise, it will use this key class to determine the Java class for a given LDAP object) - the name of the DN attribute - the name of the RDN attribute (this is semi-redundant, but required in the current design) - mappings for the attributes. Currently Strings, ints, and byte-arrays are supported - mappings for associations. In our case, there is a many-to-one association for the location and several many-to-many associations for group memberships. The "filter" attribute of the many-to-many mapping should probably be optimized away, since it is redundant in almost all cases. - the base-rdn is the name relative to the base DN where an object will be saved if no explicit dn of a container is specified. In the default directory layout of openthinclient.org objects are nicely sorted into separate ous. The rationale behind this would lead too far for now. I'll elaborate on this some time later. Now let's suppose we want to do something with this mapping. The first thing we need is an LDAP connection descriptor. This is basically a fancy way of specifying a JNDI environment: LDAPConnectionDescriptor lcd = new LDAPConnectionDescriptor();Next, we need an instance of the Mapper itself. We create it, by loading a mapping specification (xml file): Mapping m = Mapping.load(new getClass().getResourceAsStream("myLDAPMapping.xml");Mapping.initialize() has to be called manually, since openthinclient.org also supports hybrid mappings where one part of the domain model resides in Apache DS and another part (Users!) is pulled from a MS-ADS. After constructing a hybrid mapping, both directories transparently appear as one. Or at least, that's the theory. In practice some awkwardnesses are hard to abstract away. Now's the time to create a new user and assign him/her to a group: User user = new User();Thanks to transitive persistence, this could also be done in one go: User user = new User();Now, finally some examples for loading/querying: User user = m.load(UserGroup.class, "cn=jdoe,ou=users,...");Ok, so this should give you a rough idea about the LDAP mapping component. As I said, the component is rather simple (a mere 19 classes) and still has some deficiencies (as mentioned in the earlier post), however, it gets the job done of mapping our rather complex domain model. 2. the PXE proxy. ------------------ Currently we don't do full DHCP, i.e. users are supposed to supply IP addresses to thin clients using their existing DHCP infrastructure. I'll get to that later. PXE piggy-backs on the DHCP protocol, to support booting of diskless clients. For a rough overview, Wikipedia has this: http://en.wikipedia.org/wiki/Preboot_Execution_Environment For the PXE proxy (I think the term "proxy" is inadequate for the PXE server, but that's what most people call it) this means that it has to listen for DHCP requests from PXE-enabled clients (detected from vendor-ID) and "inject" a special type of DHCP offer when one is detected. The boot-information is then transferred using a separate exchange using DHCP on a separate port (4011 instead of 67/68). Implementing a PXE service is quite a bit simpler than implementing full DHCP since a PXE proxy usually doesn't need to manage client state as a DHCP server does. Although we currently only do PXE, protocol-wise we already have most of what DHCP needs. The state of the DHCP code as we picked it up wasn't there yet, as far as I remember. The real challenge of implementing DHCP comes from some limitations of the Java networking API, though. DHCP talks to clients which don't have an IP address yet. Therefore the initial exchange takes place via UDP broadcast. Serving clients with an IP address, requires knowledge about the physical network (or vLAN) on which the device resides. Acquiring this piece of information is harder than what one would expect. We have a summary here https://issues.openthinclient.org/otc/browse/SUITE-39, but the bottom-line after doing quite some research is that there is no solution that works on every system: - For Windows the solution is to bind to each network interface individually. Broadcasts are received by the interface bound to the address corresponding to the primrary IO address of the network interface. Nice, bit not RFC compliant. - For single-homed systems, one can weasel out of the problem by just using a static configuration for a single LAN segment. - UNIX systems only receive broadcasts for sockets bound to the 0.0.0.0 address, but doing so loses information about the network from which the request arrived. Currently I only see using raw sockets as a feasible solution. Either through http://www.savarese.org/software/rocksaw/ or - even more crowbar-style - JPCAP http://netresearch.ics.uci.edu/kfujii/jpcap/doc/. Both require some native code, unfortunately. And, of course, a corresponding MINA IoAcceptor driver and raw IP protocol handlers. *sigh* Since openthinclient.org only needs to do PXE for clients served by an existing DHCP server, we used the sneaky solution of not listening for the DHCP request, but for the RESPONSE. That way we can easily learn the address assigned to the client. :-) So much for today. Joerg Henne |
