Active Directory kullanıcılarını bir tablodan SELECT etmek:


Oracle veri tabanından domain sunucunuza erişip kullanıcıları görme konusunu detaylı örneklerle anlatan sayısız doküman var.

Bu örnekler genel anlamda DBMS_LDAP paketini kullanarak domain sunucunuza nasıl erişeceğinizi, eriştikten sonra nasıl browse edeceğinizi gösteriyor.

Test etmek için domain sunucunuzun adres ve port bilgilerini edinmelisiniz. Tabii bir de username/password.

Ben bu örneklerde tarif edilen yöntemi kendi tablomu doldurmasını sağlayacak şekilde biraz değiştirdim. Bunu yaparken de neredeyse tamamen Billy~Verreynne ‘in https://community.oracle.com/thread/4064849 adresindeki önerilerini kullandım.

Eklediğim bir kaç küçük şey oldu:

  • ldap_host, ldap_user, ldap_passw gibi değişkenleri plain-text göndermek yerine encrypt etmek istedim.
  • bu örnek attribute_name ve attribute_value isimli iki kolonda alt alta sıralıyordu oysa ben isim, email, departman, title, telefon gibi bilgileri de içeren bir tablom olsun, bu tablo ben her sorguladığımda canlı olarak LDAP üzerinden beslensin istiyordum.

Yaptıklarımsa şunlar;

  • önce objelerimi hazırladım.
    • TLDAPATTR için kullandığım kolonları özelleştirebilirsiniz. Ama tabii bu durumda DBMS_LDAP kullandığımız fonksiyonda da uygun değişiklikler yapmamız gerekecek.
CREATE OR REPLACE TYPE tstrings IS TABLE OF VARCHAR2(4000);
 
CREATE OR REPLACE TYPE tldapattr IS object 
(
attribute_name VARCHAR2(50), 
attribute_value VARCHAR2(4000), 
dispname VARCHAR2(255), 
email VARCHAR2(255), 
department VARCHAR2(255), 
memberof VARCHAR2(255), 
manager VARCHAR2(255), 
extension VARCHAR2(255
);
 
CREATE OR REPLACE TYPE tldapattrlist IS TABLE OF tldapattr;
  • sonra type objemde görmek istediğim kolonları besleyecek şekilde değiştirerek fonksiyonumu create ettim.
CREATE OR REPLACE FUNCTION ldapattr (filter VARCHAR2, attributes tstrings DEFAULT NULL) 
RETURN tldapattrlist pipelined AUTHID definer IS
 
ldap_host    VARCHAR2(256);
ldap_port    VARCHAR2(256) := '389';
ldap_user    VARCHAR2(256); 
ldap_passw   VARCHAR2(256);
ldap_base    VARCHAR2(256) := 'OU=buraya_Organization_Unit_bilgisi_yaz,dc=sizin_domain_controlleriniz,dc=muhtemelen_com'; 
LDAP_ATTR    CONSTANT tstrings := NEW tstrings('displayname' ,'mail', 'department', 'memberof', 'manager','telephonenumber');
 
retVal          INTEGER;  
ldapSession     DBMS_LDAP.SESSION;  
attrList        DBMS_LDAP.string_collection;  
valList         DBMS_LDAP.string_collection;  
ldapMessage     DBMS_LDAP.message;  
berElement      DBMS_LDAP.ber_element;  
ldapTimeout     DBMS_LDAP.timeval;  
 
attrName        VARCHAR2(256);  
attrDisplay     VARCHAR2(4000);  
name            VARCHAR2(256);  
attrNum         INTEGER;  
i               INTEGER; 
 
v_dispname     VARCHAR2(255);
v_email        VARCHAR2(255);  
v_department   VARCHAR2(255);
v_memberof     VARCHAR2(255);
v_manager      VARCHAR2(255);
v_extension    VARCHAR2(255);
BEGIN
SELECT 'foo' INTO ldap_host FROM dual;
SELECT 'goo' INTO ldap_user FROM dual;
SELECT 'hoo' INTO ldap_passw FROM dual;
 
pipe ROW(TLDAPATTR('PARAM.<filter>', filter, v_dispname, v_email, v_department, v_memberof, v_manager, v_extension));  
         DBMS_LDAP.USE_EXCEPTION := TRUE;
 
-- create LDAP session  
         ldapSession := DBMS_LDAP.init(hostname => LDAP_HOST, portnum  => LDAP_PORT);  
         retval := DBMS_LDAP.simple_bind_s(ld=> ldapSession,dn=> LDAP_USER,passwd=> LDAP_PASSW);  
 
-- build a distinct ordered list of attributes  
         i := 0;  
         FOR c IN (SELECT DISTINCT column_value AS ATTR FROM TABLE(NVL(attributes,LDAP_ATTR)) ORDER BY 1) LOOP  
                 i := i + 1;  
                 attrList(i) := c.attr;  
                 attrDisplay := attrDisplay || c.attr || ' ';  
         END LOOP;  
pipe ROW(TLDAPATTR('PARAM:<attribute list>', TRIM(attrDisplay), v_dispname, v_email, v_department, v_memberof, v_manager, v_extension));  
 
-- use supplied filter to search  
        ldapTimeout.seconds := 5;  
        ldapTimeout.useconds := 0;
 
        retval := DBMS_LDAP.search_st(
		ld => ldapSession,
		base => ldap_base,
		scope => DBMS_LDAP.SCOPE_SUBTREE,
		filter => filter,
		attrs => attrList,
		attronly => 0,
		tv => ldapTimeout,
		res => ldapMessage);
 
-- is the search successful?  
        retval := DBMS_LDAP.count_entries(ld => ldapSession, msg => ldapMessage);  
        IF retval = 0 THEN  
pipe ROW(TLDAPATTR('Error', 'No matches found for filter ['||filter||'].',v_dispname, v_email, v_department, v_memberof, v_manager, v_extension));  
retVal := DBMS_LDAP.unbind_s(ld => ldapSession);  
RETURN;  
        END IF;  
-- Get all the entries returned by our search.  
        ldapMessage := DBMS_LDAP.first_entry(ld  => ldapSession, msg => ldapMessage);  
 
        WHILE ldapMessage IS NOT NULL  
        LOOP  
-- Get all the attributes for this entry.  
        attrName := DBMS_LDAP.first_attribute(ld => ldapSession, ldapentry => ldapMessage, ber_elem  => berElement);  
--degerleri her defasinda resetle
v_dispname   := NULL;
v_email      := NULL;
v_department := NULL;
v_memberof   := NULL;
v_manager 	 := NULL;
v_extension  := NULL;
-- output a null row for formatting an empty line between records  
                pipe ROW( NULL );  
-- output DN as unique record identifier  
                pipe ROW(TLDAPATTR('distinguishedName', DBMS_LDAP.get_dn(ldapSession, ldapMessage), v_dispname, v_email, v_department, v_memberof, v_manager, v_extension));   
-- now output attribute name-values found for the DN  
attrNum := 1;
		LOOP  
		EXIT WHEN attrName IS NULL;
		EXIT WHEN attrNum > attrList.COUNT;   
-- Get all the values for this attribute.  
		valList := DBMS_LDAP.get_values (ld => ldapSession, ldapentry => ldapMessage, attr => attrName);
			FOR i IN valList.FIRST .. valList.LAST
			LOOP
				IF attrName    = 'displayName' THEN v_dispname := SUBSTR(valList(i),1,200);
				ELSIF attrName = 'mail' THEN v_email := SUBSTR(valList(i),1,200);
				ELSIF attrName = 'department' THEN v_department := SUBSTR(valList(i),1,200);
				ELSIF attrName = 'memberOf' THEN v_memberof := SUBSTR(valList(i),1,200);
				ELSIF attrName = 'manager' THEN v_manager := SUBSTR(valList(i),1,200);
				ELSIF attrName = 'telephoneNumber' THEN v_extension := SUBSTR(valList(i),1,200);
				END IF ;
			END LOOP values_loop;
name := valList.FIRST;  
WHILE name IS NOT NULL LOOP  
pipe ROW(TLDAPATTR(attrName,valList(name),v_dispname, v_email, v_department, v_memberof, v_manager, v_extension));  
name := valList.Next(name);  
END LOOP;  
 
attrName := DBMS_LDAP.next_attribute(ld => ldapSession, ldapentry => ldapMessage, ber_elem  => berElement);
attrNum := attrNum + 1;  
END LOOP;  
 
ldapMessage := DBMS_LDAP.next_entry(ld  => ldapSession, msg => ldapMessage);  
END LOOP;  
 
-- Disconnect from the LDAP server.  
retVal := DBMS_LDAP.unbind_s(ld => ldapSession);  
RETURN;  
END;

bunları yaptıktan sonra şöyle test edebiliyor olmalısınız:

SELECT * 
FROM TABLE(ldapattr(filter => '(&(objectclass=user) (!(useraccountcontrol=514)))'))

514 pasif kullanıcıları dışarıda bırakmak için. Search stringi kendi ihtiyaçlarınıza göre değiştirebilirsiniz. Son olarak datayı derli toplu görmek için bir VIEW oluşturun.

Böylece a/d kullanıcılarınız, bu kullanıcıların bağlı olduğu yöneticiler, departmanları, masa telefonları gibi bilgilere dilediğiniz zaman gerçek zamanlı olarak erişebilirsiniz.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.