Vereinfachen Sie den Verzeichniszugriff mit Spring LDAP

Spring LDAP ist ein Spring-basiertes Framework, das die LDAP-Programmierung auf der Java-Plattform vereinfacht. In dieser schrittweisen Anleitung zur Verwendung von Spring LDAP erfahren Sie, wie das Framework mit der für die meisten LDAP-Clients erforderlichen Codierung auf niedriger Ebene umgeht, damit Sie sich auf die Entwicklung der Geschäftslogik Ihrer Anwendung konzentrieren können. Sie üben auch einfache CRUD-Operationen mit Spring LDAP und lernen erweiterte Operationen wie das Erstellen dynamischer Filter und das Konvertieren von LDAP-Einträgen in Java-Beans kennen.

Das Lightweight Directory Access Protocol ist heute ein wesentlicher Bestandteil der meisten umfangreichen Bereitstellungen von Unternehmensanwendungen. LDAP wird hauptsächlich zum Speichern von Informationen verwendet, die sich auf die Benutzeridentität beziehen, z. B. Benutzername, Kennwort und E-Mail-Adresse eines Benutzers. Es wird auch in Sicherheitsimplementierungen verwendet, in denen Benutzerzugriffsrechte für Authentifizierungs- und Autorisierungszwecke gespeichert werden müssen.

Java Naming and Directory Interface (JDNI) ist die API, die für die LDAP-Programmierung auf der Java-Plattform verwendet wird. Es definiert eine Standardschnittstelle, die in Ihrer Anwendung für die Interaktion mit jedem LDAP-Server verwendet werden kann. Leider bedeutet die Verwendung von JNDI normalerweise das Schreiben einer Menge sich wiederholenden Codes auf niedriger Ebene. JNDI erledigt viel zu viel Arbeit mit einfachen Verfahren, z. B. um sicherzustellen, dass die Ressourcen ordnungsgemäß geöffnet und geschlossen wurden. Darüber hinaus lösen die meisten JNDI-Methoden geprüfte Ausnahmen aus, deren Behandlung zeitaufwändig ist. Bei näherer Betrachtung scheinen 50 bis 60 Prozent der Zeit, die für die Programmierung von JNDI aufgewendet wurde, für die Bearbeitung sich wiederholender Aufgaben verschwendet zu werden.

Spring LDAP ist eine Open-Source-Java-Bibliothek, die die LDAP-Programmierung auf der Java-Plattform vereinfacht. So wie das Spring Framework einen Großteil der Low-Level-Programmierung aus der Entwicklung von Java-Unternehmensanwendungen herausholt, befreit Sie Spring LDAP von den infrastrukturellen Details der Verwendung von LDAP. Anstatt sich um NamingExceptions zu sorgen und s zu bekommen InitialContext, können Sie sich auf die Geschäftslogik Ihrer Anwendung konzentrieren. Spring LDAP definiert auch eine umfassende ungeprüfte Ausnahmehierarchie und bietet Hilfsklassen zum Erstellen von LDAP-Filtern und definierten Namen.

Spring LDAP und JNDI

Beachten Sie, dass das Spring LDAP-Framework JNDI nicht ersetzt. Vielmehr werden Wrapper- und Utility-Klassen über JNDI bereitgestellt, um die LDAP-Programmierung auf der Java-Plattform zu vereinfachen.

In diesem Artikel, einem Leitfaden für Anfänger zur Verwendung von Spring LDAP, werde ich zunächst ein einfaches JNDI-Programm zum Ausführen einer LDAP-Suche entwickeln. Ich werde dann zeigen, wie viel einfacher es ist, dasselbe mit dem Spring LDAP-Framework zu tun. Ich werde Ihnen zeigen, wie Sie mit Spring LDAPs AttributeMapperLDAP-Attribute Java-Beans zuordnen und mit ihren dynamischen Filtern Abfragen erstellen. Abschließend werde ich Schritt für Schritt eine Einführung in die Verwendung des Spring LDAP-Frameworks zum Hinzufügen, Löschen und Ändern von Daten auf Ihrem LDAP-Server geben.

Beachten Sie, dass in diesem Artikel davon ausgegangen wird, dass Sie mit den Konzepten und der Terminologie des Spring Framework vertraut sind. Weitere Informationen zu Spring Framework, LDAP und JNDI sowie zum Herunterladen der Beispielanwendung finden Sie im Abschnitt Ressourcen.

Ein einfacher JNDI-Client

Listing 1 zeigt ein einfaches JNDI-Programm, das die cn- Attribute aller PersonTypobjekte auf Ihrer Konsole druckt .

Listing 1. SimpleLDAPClient.java

public class SimpleLDAPClient { public static void main(String[] args) { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://localhost:10389/ou=system"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system"); env.put(Context.SECURITY_CREDENTIALS, "secret"); DirContext ctx = null; NamingEnumeration results = null; try { ctx = new InitialDirContext(env); SearchControls controls = new SearchControls(); controls.setSearchScope(SearchControls.SUBTREE_SCOPE); results = ctx.search("", "(objectclass=person)", controls); while (results.hasMore()) { SearchResult searchResult = (SearchResult) results.next(); Attributes attributes = searchResult.getAttributes(); Attribute attr = attributes.get("cn"); String cn = (String) attr.get(); System.out.println(" Person Common Name = " + cn); } } catch (NamingException e) { throw new RuntimeException(e); } finally { if (results != null) { try { results.close(); } catch (Exception e) { } } if (ctx != null) { try { ctx.close(); } catch (Exception e) { } } } } }

Als erstes habe ich in Listing 1 ein InitialDirContextObjekt erstellt, das dann als Kontext für die folgenden Verzeichnisoperationen verwendet wird. Beim Erstellen eines neuen ContextObjekts konfiguriere ich Eigenschaften wie Benutzername, Kennwort und Authentifizierungsmechanismus, mit denen eine Verbindung zum LDAP-Server hergestellt werden kann. Ich habe dies geschafft, indem ich ein HashtableObjekt erstellt, alle diese Eigenschaften als Schlüssel / Wert-Paare im Hashtableund eingerichtet und Hashtablean den InitialDirContextKonstruktor übergeben habe.

Das unmittelbare Problem bei diesem Ansatz ist, dass ich alle Konfigurationsparameter in eine Java-Datei fest codiert habe. Dies funktioniert gut für mein Beispiel, aber nicht für eine reale Anwendung. In einer realen Anwendung möchte ich die Verbindungseigenschaften in einer Datei jndi.properties speichern und diese Datei entweder im Klassenpfad meines Projekts oder im Ordner / lib ablegen. Beim Erstellen eines neuen InitialDirContextObjekts sucht die JNDI-API an beiden Stellen nach der Datei jndi.properties und stellt damit eine Verbindung zum LDAP-Server her.

JNDI-Konfigurationsparameter

Listing 2 zeigt die JNDI-Konfigurationsparameter für die Verbindung zu meinem LDAP-Server. Ich erkläre die Bedeutung der Parameter unten.

Listing 2. JNDI-Konfigurationsparameter für LDAP

java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory java.naming.provider.url=ldap://localhost:10389/ou=system java.naming.security.authentication=simple java.naming.security.principal=uid=admin,ou=system java.naming.security.credentials=secret
  1. Context.INITIAL_CONTEXT_FACTORY ( java.naming.factory.initial) sollte dem vollständig qualifizierten Klassennamen entsprechen, der zum Erstellen eines neuen Anfangskontexts verwendet wird. Wenn kein Wert angegeben wird, NoInitialContextExceptionwird der ausgelöst.
  2. Context.PROVIDER_URL ( java.naming.provider.url) sollte der URL des LDAP-Servers entsprechen, zu dem Sie eine Verbindung herstellen möchten. Es sollte im Format sein ldap://:.
  3. Context.SECURITY_AUTHENTICATION ( java.naming.security.authentication) repräsentiert den Typ des Authentifizierungsmechanismus, den Sie verwenden möchten. Ich habe in meinem Beispiel einen Benutzernamen und ein Kennwort für die Authentifizierung verwendet, daher ist der Wert dieser Eigenschaft einfach .
  4. Context.SECURITY_PRINCIPAL ( java.naming.security.principal) repräsentiert den definierten Benutzernamen (DN), der zum Herstellen einer Verbindung verwendet werden soll.
  5. Context.SECURITY_CREDENTIALS ( java.naming.security.credentials) repräsentiert das Passwort des Benutzers.

Der JNDI-Clientcode

Nachdem ich das ContextObjekt erhalten habe, besteht mein nächster Schritt darin, ein SearchControlObjekt zu erstellen , das die Faktoren zusammenfasst, die den Umfang meiner Suche bestimmen und angeben, was zurückgegeben wird. Ich möchte den gesamten Teilbaum durchsuchen, der im Kontext verwurzelt ist, daher setze ich den Suchbereich auf, SUBTREE_SCOPEindem ich die setSearchScope()Methode von SearchControlaufrufe, wie zuvor in Listing 1 gezeigt.

Als nächstes rufe ich die search()Methode auf DirContext, die (objectclass=person)als Wert des Filters übergeben wird. Die search()Methode gibt ein NamingEnumerationObjekt zurück, das alle Einträge im Teilbaum von enthält Context, wobei objectclassgleich ist person. Nachdem ich ein NamingEnumerationObjekt als Ergebnis erhalten habe, durchlaufe ich es und drucke für jedes PersonObjekt ein cn- Attribut .

Damit ist meine Erklärung des JNDI-Client-Codes abgeschlossen. Wenn Sie sich SimpleLDAPClient.java in Listing 1 ansehen, können Sie leicht erkennen, dass mehr als die Hälfte des Codes zum Öffnen und Schließen von Ressourcen verwendet wird. Ein weiteres Problem mit der JNDI-API besteht darin, dass die meisten ihrer Methoden im NamingExceptionFehlerfall eine oder eine ihrer Unterklassen auslösen. Da NamingExceptiones sich um eine aktivierte Ausnahme handelt, müssen Sie sie behandeln, wenn sie ausgelöst wird. Können Sie sich jedoch wirklich von einer Ausnahme erholen, wenn Ihr LDAP-Server nicht verfügbar ist? Nein, das kannst du nicht.

Die meisten Entwickler umgehen JNDIs, NamingExceptionindem sie sie einfach fangen und nichts tun. Das Problem mit dieser Lösung ist, dass Sie wichtige Informationen verlieren können.