Опростете достъпа до директории с Spring LDAP

Spring LDAP е Spring базирана рамка, която опростява LDAP програмирането на платформата Java. В това ръководство стъпка по стъпка за използване на Spring LDAP ще научите как рамката се справя с кодирането на ниско ниво, изисквано от повечето LDAP клиенти, за да можете да се съсредоточите върху разработването на бизнес логиката на вашето приложение. Също така ще практикувате прости CRUD операции, използвайки Spring LDAP и ще научите за по-усъвършенствани операции като създаване на динамични филтри и преобразуване на LDAP записи в Java зърна.

Лекият протокол за достъп до директории е съществен компонент на повечето широкомащабни корпоративни внедрявания на приложения днес. LDAP се използва предимно за съхраняване на информация, свързана с идентичността на потребителя, като потребителско име, парола и имейл адрес. Той се използва и в изпълнения на сигурността, където е необходимо да се съхраняват правата за достъп на потребителите за целите на удостоверяване и упълномощаване.

Java Naming and Directory Interface (JDNI) е API, използван за LDAP програмиране на платформата Java. Той определя стандартен интерфейс, който може да се използва във вашето приложение за взаимодействие с всеки LDAP сървър. За съжаление използването на JNDI обикновено включва писане на много повтарящи се кодове на ниско ниво. JNDI прекалено много работи с прости процедури, като например да гарантира правилното отваряне и затваряне на ресурсите. В допълнение, повечето JNDI методи хвърлят проверени изключения, които отнемат много време за обработка. При внимателна проверка изглежда, че 50 до 60 процента от времето, прекарано в програмиране на JNDI, се губи за обработка на повтарящи се задачи.

Spring LDAP е Java библиотека с отворен код, предназначена да опрости LDAP програмирането на платформата Java. Точно както Spring Framework отнема голяма част от програмирането на ниско ниво от разработването на корпоративни приложения на Java, Spring LDAP ви освобождава от инфраструктурните подробности за използването на LDAP. Вместо да се притеснявате за NamingExceptions и да получите InitialContexts, вие сте свободни да се концентрирате върху бизнес логиката на вашето приложение. Spring LDAP също дефинира изчерпателна непроверена йерархия на изключения и предоставя помощни класове за изграждане на LDAP филтри и отличени имена.

Пролетни LDAP и JNDI

Имайте предвид, че Spring LDAP рамката не замества JNDI. По-скоро осигурява класове на обвивки и помощни програми през JNDI, за да опрости LDAP програмирането на платформата Java.

В тази статия, ръководство за начинаещи за използване на Spring LDAP, ще започна с разработването на проста програма JNDI за изпълнение на LDAP търсене. След това ще покажа колко по-лесно е да се направи същото, използвайки Spring LDAP framework. Ще ви покажа как да използвате Spring LDAP's AttributeMapper, за да съпоставите LDAP атрибутите на Java зърна и как да използвате динамичните му филтри за изграждане на заявки. И накрая, ще предоставя стъпка по стъпка въведение в използването на Spring LDAP рамката за добавяне, изтриване и модифициране на данни във вашия LDAP сървър.

Имайте предвид, че тази статия предполага, че сте запознати с концепциите и терминологията на Spring Framework. Вижте раздела Ресурси, за да научите повече за Spring Framework, LDAP и JNDI, както и да изтеглите примерното приложение.

Прост JNDI клиент

Листинг 1 показва проста програма JNDI, която ще отпечата атрибутите cn на всички Personтипови обекти на вашата конзола.

Листинг 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) { } } } } }

Първото нещо, което направих в Листинг 1, е да създам InitialDirContextобект, който след това да се използва като контекст за следните операции в директорията. Когато създавам нов Contextобект, конфигурирам свойства като потребителско име, парола и механизъм за удостоверяване, които могат да се използват за свързване към LDAP сървъра. Успях с това, като създадох Hashtableобект, настроих всички тези свойства като двойки ключ / стойност в Hashtableи предадох Hashtableна InitialDirContextконструктора.

Непосредственият проблем с този подход е, че съм кодирал твърдо всички конфигурационни параметри във файл .java. Това работи добре за моя пример, но не и за реално приложение. В приложение от реалния свят бих искал да съхранявам свойствата на връзката във файл jndi.properties и да го поставя в пътя на класа на моя проект или в папката / lib. При създаването на нов InitialDirContextобект, JNDI API ще търси и на двете места файла jndi.properties, след което ще го използва за създаване на връзка с LDAP сървъра.

JNDI конфигурационни параметри

Листинг 2 показва конфигурационните параметри на JNDI за свързване с моя LDAP сървър. Обяснявам значението на параметрите по-долу.

Листинг 2. JNDI конфигурационни параметри за 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) трябва да бъде равен на напълно квалифицираното име на класа, което ще се използва за създаване на нов първоначален контекст. Ако не е посочена стойност, тогава NoInitialContextExceptionсе изхвърля.
  2. Context.PROVIDER_URL ( java.naming.provider.url) трябва да бъде равен на URL адреса на LDAP сървъра, с който искате да се свържете. Трябва да е във формата ldap://:.
  3. Context.SECURITY_AUTHENTICATION ( java.naming.security.authentication) представлява вида на механизма за удостоверяване, който искате да използвате. Използвал съм потребителско име и парола за удостоверяване в моя пример, така че стойността на това свойство е проста .
  4. Context.SECURITY_PRINCIPAL ( java.naming.security.principal) представлява отличеното потребителско име (DN), което трябва да се използва за установяване на връзка.
  5. Context.SECURITY_CREDENTIALS ( java.naming.security.credentials) представлява паролата на потребителя.

Клиентският код на JNDI

След получаване на Contextобекта следващата ми стъпка е да създам SearchControlобект, който капсулира факторите, които определят обхвата на търсенето ми и какво ще бъде върнато. Искам да търся цялото поддърво, вкоренено в контекста, затова зададох обхвата на търсене, SUBTREE_SCOPEкато извиках setSearchScope()метода на SearchControl, както беше показано по-рано в Листинг 1.

След това извиквам search()метода на DirContext, предавайки (objectclass=person)като стойност на филтъра. В search()метода ще върне NamingEnumerationобект съдържа всички вписвания в поддървото на Context, където objectclassе равно person. След NamingEnumerationкато получа обект като резултат, прелиствам през него и отпечатвам атрибут cn за всеки Personобект.

Това завършва моето обяснение за клиентския код на JNDI. Разглеждайки SimpleLDAPClient.java, показан в Листинг 1, можете лесно да видите, че повече от половината код отива към отваряне и затваряне на ресурси. Друг проблем с JNDI API е, че повечето от неговите методи ще изхвърлят един NamingExceptionили един от неговите подкласове в случай на грешка. Тъй като NamingExceptionе проверено изключение, трябва да се справите с него, ако е хвърлено, но наистина ли можете да се възстановите от изключение, ако вашият LDAP сървър не работи? Не, не можеш.

Повечето разработчици заобикалят JNDI NamingException, като просто ги хващат и не правят нищо. Проблемът с това решение е, че може да загубите важна информация.