1.活動目錄(AD)
Active Directory 是用於 Windows Server 的目錄服務。
它存儲着網絡上各種對象的有關信息,並使該信息易於管理員和用戶查找及使用。
Active Directory 目錄服務使用結構化的數據存儲作為目錄信息的邏輯層次結構的基礎。
通過登錄驗證以及目錄中對象的訪問控制,將安全性集成到 Active Directory 中。
目錄服務,如 Active Directory,提供了用於存儲目錄數據並使該數據可由網絡用戶和管理員使用的方法。
例如,Active Directory 存儲了有關用戶帳戶的信息,如名稱、密碼、電話號碼等,並允許相同網絡上的其他已授權用戶訪問該信息。
2.LDAP
LDAP是輕量目錄訪問協議,英文全稱是Lightweight Directory Access Protocol。
LDAP是基於X.500標准的。
LDAP 僅通過使用原始 X.500目錄存取協議 (DAP) 的功能子集而減少了所需的系統資源消耗。
與X.500不同,LDAP支持TCP/IP,這對訪問Internet是必須的。
LDAP和關系數據庫是兩種不同層次的概念,后者是存貯方式(同一層次如網格數據庫,對象數據庫),前者是存貯模式和訪問協議。
LDAP是一個比關系數據庫抽象層次更高的存貯概念,與關系數據庫的查詢語言SQL屬同一級別。
3.ADSI
在Delphi中可以使用微軟的ADSI(活動目錄服務接口)來訪問活動目錄。
ADSI是一組以COM接口的形式提供目錄服務的,是為基於目錄服務提供的通用接口。
一些標准的ADSI提供者(Provider)有WinNT、IIS、LDAP和NDS。
可以通過ADSI存取四種網絡目錄結構:
WinNT (Microsoft SAM 數據庫)、LDAP (輕量目錄存取協議)、NDS (NetWare目錄服務)和NWCOMPAT(Novell NetWare 3.x)。
ADSI可以使Windows NT 管理員的工作變得輕松。
ADSI支持管理員執行一些一般的管理任務,比如添加新用戶、管理打印機、安全設定和控制NT域。
因為ADSI使用COM接口,任何支持COM的編程語言像Delphi、BCB、VB、VC等都可以調用ADSI。
如在Delphi中調用ADSI,則需要引入活動目錄類型庫。
操作如下:
在IDE中,Project--->Import Type Library。
選擇“Active Ds Type Library(Version 1.0)”,單擊“Create Unit”。
Delphi會做相應的封裝,生成ActiveDs_TLB.pas文件。
Uses ActiveDs_TLB,就可以在Delphi程序中使用ADSI了。
4.JAVA+LDAP訪問Window 2000 Server AD。
package ADOper;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.NamingEnumeration;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import java.util.Enumeration;
public class ADOperTest {
public ADOperTest() {
}
public void GetADInfo() {
Hashtable HashEnv = new Hashtable();
String LDAP_URL = "ldap://192.168.100.3:389"; //LDAP訪問地址
//String adminName = "CN=OAWebUser,CN=Users,DC=Hebmc,DC=com";//AD的用戶名
String adminName = "Hebmc\\OAWebUser"; //注意用戶名的寫法:domain\User 或 User@domain.com
adminName = "OAWebUser@Hebmc.com"; //注意用戶名的寫法:domain\User 或 User@domain.com
String adminPassword = "chenzuooaup02"; //密碼
HashEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); //LDAP訪問安全級別
HashEnv.put(Context.SECURITY_PRINCIPAL, adminName); //AD User
HashEnv.put(Context.SECURITY_CREDENTIALS, adminPassword); //AD Password
HashEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); //LDAP工廠類
HashEnv.put(Context.PROVIDER_URL, LDAP_URL);
try {
LdapContext ctx = new InitialLdapContext(HashEnv, null);
SearchControls searchCtls = new SearchControls(); //Create the search controls
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); //Specify the search scope
String searchFilter = "objectClass=User"; //specify the LDAP search filter
//String searchFilter = "objectClass=organizationalUnit";//specify the LDAP search filter
String searchBase = "DC=Hebmc,DC=com"; //Specify the Base for the search//搜索域節點
int totalResults = 0;
//Specify the attributes to return
//String returnedAtts[] = {"memberOf"};//定制返回屬性
String returnedAtts[] = {
"url", "whenChanged", "employeeID", "name", "userPrincipalName",
"physicalDeliveryOfficeName", "departmentNumber", "telephoneNumber",
"homePhone", "mobile", "department", "sAMAccountName", "whenChanged",
"mail"}; //定制返回屬性
searchCtls.setReturningAttributes(returnedAtts); //設置返回屬性集
//Search for objects using the filter
NamingEnumeration answer = ctx.search(searchBase, searchFilter,searchCtls);
while (answer.hasMoreElements()) {
SearchResult sr = (SearchResult) answer.next();
System.out.println("************************************************");
System.out.println(sr.getName());
Attributes Attrs = sr.getAttributes();
if (Attrs != null) {
try {
for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore(); ) {
Attribute Attr = (Attribute) ne.next();
System.out.println(" AttributeID=" + Attr.getID().toString());
//讀取屬性值
for (NamingEnumeration e = Attr.getAll(); e.hasMore();totalResults++) {
System.out.println(" AttributeValues=" + e.next().toString());
}
System.out.println(" ---------------");
//讀取屬性值
Enumeration values = Attr.getAll();
if (values != null) { // 迭代
while (values.hasMoreElements()) {
System.out.println(" AttributeValues=" + values.nextElement());
}
}
System.out.println(" ---------------");
}
}
catch (NamingException e) {
System.err.println("Throw Exception : " + e);
}
}
}
System.out.println("Number: " + totalResults);
ctx.close();
}
catch (NamingException e) {
e.printStackTrace();
System.err.println("Throw Exception : " + e);
}
}
public static void main(String args[]) {
ADOperTest ad = new ADOperTest();
ad.GetADInfo();
}
}
備注:
使用LADP訪問AD,注意用戶名的寫法:domain\User 或 User@domain.com。
如用戶名不正確,則可能會出現如下異常:
javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 525, vece
5.Delphi7使用WinNT Provider訪問Window 2000 Server AD。
unit Unt_AD;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ActiveDs_TLB, ActiveX, ComObj;
type
TMainFrm = class(TForm)
grp1: TGroupBox;
cbUseLogin: TCheckBox;
lbl1: TLabel;
ADSIUsername: TEdit;
lbl2: TLabel;
ADSIPassword: TEdit;
ADSIDomainName: TEdit;
btn1: TButton;
lbl3: TLabel;
GroupListView: TListView;
ComputerListView: TListView;
SeverListView: TListView;
UserListView: TListView;
lbl4: TLabel;
lbl5: TLabel;
Label1: TLabel;
lbl6: TLabel;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
procedure GetDomainInformation(Domain: IADsContainer);
procedure AddUserToList(ADsObj:IADs);
procedure AddGroupToList(ADsObj:IADs);
procedure AddComputerToList(ADsObj:IADs);
public
{ Public declarations }
end;
//連接 Win NT 目錄服務就是找到域控制器然后綁定到相應的對象上。
//綁定可以通過 ADsGetObject 或 ADsOpenObject 函數來實現。
//第一個函數使用登錄用戶缺省的信任級別,
//第二個函數允許開發者指定特殊的安全信任機制來綁定 ADSI 對象。
//缺省條件下,ADsGetObject函數根據當前用戶進行安全認證。
function ADsGetObject(lpszPathName: PWideChar; //第一個參數是對象的路徑名
const riid: TIID; //第二個參數是對象的接口標識符
out obj): HResult; stdcall; external 'activeds.dll';// 第三個參數用於返回得到的被請求的接口指針
//ADsOpenObject 函數在不同的安全認證機制下綁定 ADSI 對象,
//它主要是通過調用參數返回的用戶名和口令來認證的
function ADsOpenObject(lpszPathName: PWideChar; //第一個參數是對象的路徑名
lpszUserName: PWideChar; //第二個參數是調用者提供的用戶名
lpszPassword: PWideChar; //第三個參數是調用者提供的口令
dwReserved: LongInt; //第四個參數是一個保留的 provider 標識,用來確定綁定的認證方法
const riid: TIID; //第五個參數是請求接口的接口標識符,
out obj): HResult; stdcall; external 'activeds.dll'; //最后一個參數用來返回請求的接口指針。
var
MainFrm: TMainFrm;
implementation
{$R *.dfm}
// 獲取域信息
procedure TMainFrm.GetDomainInformation(Domain: IADsContainer);
var
Enum: IEnumVariant;
ADsTempObj: OLEVariant;
ADsObj: IADs;
Value: LongWord;
begin
//清空用戶、組和計算機列表
UserListView.Items.Clear;
GroupListView.Items.Clear;
ComputerListView.Items.Clear;
//獲取枚舉對象,並賦值給 Enum 變量
Enum := (Domain._NewEnum) as IEnumVariant;
//利用枚舉對象查找,把每個子對象賦值給臨時的 OLEVariant 對象
while (Enum.Next(1, ADsTempObj, Value) = S_OK) do
begin
ADsObj := IUnknown(ADsTempObj) as IADs; //獲得臨時對象:OLEVariant 變量賦值給 ADSI 對象
if AdsObj.Class_ = 'User' then //如果是用戶對象
AddUserToList(ADsObj);
if AdsObj.Class_ = 'Group' then //如果是組對象
AddGroupToList(ADsObj);
if AdsObj.Class_ = 'Computer' then //如果是計算機對象
AddComputerToList(ADsObj);
ADsTempObj:=Null; //釋放OLEVariant
end;
end;
procedure TMainFrm.AddUserToList(ADsObj:IADs);
var aListItem:TListItem;
begin
aListItem:=UserListView.Items.Add;
aListItem.Caption:=ADsObj.Name;
aListItem.SubItems.Add(ADsObj.Class_);
aListItem.SubItems.Add(ADsObj.ADsPath);
aListItem.SubItems.Add(ADsObj.Parent);
// aListItem.SubItems.Add(ADsObj.Get('sAMAccountName'));
end;
procedure TMainFrm.AddGroupToList(ADsObj:IADs);
var aListItem:TListItem;
begin
aListItem:=GroupListView.Items.Add;
aListItem.Caption:=ADsObj.Name;
aListItem.SubItems.Add(ADsObj.Class_);
aListItem.SubItems.Add(ADsObj.ADsPath);
end;
procedure TMainFrm.AddComputerToList(ADsObj:IADs);
var aListItem:TListItem;
begin
aListItem:=ComputerListView.Items.Add;
aListItem.Caption:=ADsObj.Name;
aListItem.SubItems.Add(ADsObj.Class_);
aListItem.SubItems.Add(ADsObj.ADsPath);
end;
procedure TMainFrm.btn1Click(Sender: TObject);
var
UnknownObject: IUnknown;
DomainPath,ADUser,ADPass: WideString;
Domain: IADsContainer;
begin
// 指定域路徑
DomainPath := 'WinNT://' + ADSIDomainName.Text;
ADUser:= ADSIUsername.Text;
ADPass:= ADSIPassword.Text;
DomainPath := 'WinNT://Hebmc.com';
ADUser: ADUser:= 'Hebmc\OAWebUser'; //注意用戶名稱的寫法:domain\User 或 User@domain.com
ADUser:= 'OAWebUser@Hebmc.com'; //注意用戶名稱的寫法:domain\User 或 User@domain.com
ADPass:= 'chenzuooaup02';
// 如果使用用戶登錄了信息
if cbUseLogin.Checked then // 使用用戶登錄的信息創建域對象
OleCheck(AdsOpenObject(PWideChar(DomainPath),
PWideChar(ADUser),
PWideChar(ADPass),
0,
IID_IADsContainer,
UnknownObject))
else
OleCheck(ADsGetObject(PWideChar(DomainPath),
IID_IADsContainer,
UnknownObject));
// 設定域對象
Domain := UnknownObject as IADsContainer;
// 從域中獲得信息列表
GetDomainInformation(Domain);
end;
end.
備注:
*.注意用戶名的寫法:domain\User 或 User@domain.com。
*.Delphi使用WinNT Provider方式訪問AD,在使用ADsObj.Get('屬性')時,會有一個報錯:“高速緩存中找不到目錄屬性。” (The directory property cannot be found in the cache)。
目前該問題還不知如何解決。
*.資料參考《Delphi深度探索-活動目錄開發》。
作者:陳省(Hubdog)。 http://hubdog.csdn.net/。
6.Delphi7使用LDAP訪問Window 2000 Server AD。
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ActiveDs_TLB, ActiveX, ComObj;
type
TMainFrm = class(TForm)
Button1: TButton;
ObjMemo: TMemo;
OUMemo: TMemo;
UserMemo: TMemo;
cbUseLogin: TCheckBox;
Obj_Label: TLabel;
OU_Label: TLabel;
Users_Label: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure GetADInfo(aUser,aPass,aDomainPath: WideString);
end;
//連接 Win NT 目錄服務就是找到域控制器然后綁定到相應的對象上。
//綁定可以通過 ADsGetObject 或 ADsOpenObject 函數來實現。
//第一個函數使用登錄用戶缺省的信任級別,
//第二個函數允許開發者指定特殊的安全信任機制來綁定 ADSI 對象。
//缺省條件下,ADsGetObject函數根據當前用戶進行安全認證。
function ADsGetObject(lpszPathName: PWideChar; //第一個參數是對象的路徑名
const riid: TIID; //第二個參數是對象的接口標識符
out obj): HResult; stdcall; external 'activeds.dll';// 第三個參數用於返回得到的被請求的接口指針
//ADsOpenObject 函數在不同的安全認證機制下綁定 ADSI 對象,
//它主要是通過調用參數返回的用戶名和口令來認證的
function ADsOpenObject(lpszPathName: PWideChar; //第一個參數是對象的路徑名
lpszUserName: PWideChar; //第二個參數是調用者提供的用戶名
lpszPassword: PWideChar; //第三個參數是調用者提供的口令
dwReserved: LongInt; //第四個參數是一個保留的 provider 標識,用來確定綁定的認證方法
const riid: TIID; //第五個參數是請求接口的接口標識符,
out obj): HResult; stdcall; external 'activeds.dll'; //最后一個參數用來返回請求的接口指針。
var
MainFrm: TMainFrm;
implementation
{$R *.dfm}
procedure TMainFrm.Button1Click(Sender: TObject);
var DomainPath,ADUser,ADPass: WideString;
begin
DomainPath := 'LDAP://192.168.100.3/OU=省公司,OU=組織架構,DC=Hebmc,DC=com';//LDAP訪問AD的路徑。
ADUser:='Hebmc\OAWebUser'; //注意用戶名稱的寫法:域名稱 + 用戶名稱 或 User@domain.com
ADUser:='OAWebUser@Hebmc.com'; //注意用戶名稱的寫法:域名稱 + 用戶名稱 或 User@domain.com
ADPass:='chenzuooaup02'; //用戶密碼。
GetADInfo(ADUser,ADPass,DomainPath);
end;
procedure TMainFrm.GetADInfo(aUser,aPass,aDomainPath: WideString);
var
UnknownObject: IUnknown;
Enum: IEnumVariant;
ADsTempObj: OLEVariant;
Domain: IADsContainer;
ADsObj: IADs;
Value: LongWord;
begin
// 如果使用AD用戶信息登錄
if cbUseLogin.Checked then // 使用用戶登錄的信息創建域對象
OleCheck(AdsOpenObject(PWideChar(aDomainPath),
PWideChar(aUser),
PWideChar(aPass),
0,
IID_IADsContainer,
UnknownObject))
else
OleCheck(ADsGetObject(PWideChar(aDomainPath),
IID_IADsContainer,
UnknownObject));
// 設定域對象
Domain := UnknownObject as IADsContainer;
//獲取枚舉對象,並賦值給 Enum 變量
Enum := (Domain._NewEnum) as IEnumVariant;
//利用枚舉對象查找,把每個子對象賦值給臨時的 OLEVariant 對象
while (Enum.Next(1, ADsTempObj, Value) = S_OK) do
begin
ADsObj := IUnknown(ADsTempObj) as IADs; //獲得臨時對象:OLEVariant 變量賦值給 ADSI 對象
ObjMemo.Lines.Add(AdsObj.Class_); //對象類型
if AdsObj.Class_ = 'organizationalUnit' then //如果是組織單元對象
OUMemo.Lines.Add(ADsObj.Name) ;
if AdsObj.Class_ = 'user' then //如果是用戶對象
UserMemo.Lines.Add(ADsObj.Name+'(用戶代碼='+ADsObj.Get('sAMAccountName')+')');
//遞歸。得到組內相關用戶。
GetADInfo(aUser,aPass,ADsObj.ADsPath);
ADsTempObj:=Null; //釋放OLEVariant
end;
end;
end.
備注:
*. 注意用戶名的寫法:domain\User 或 User@domain.com
*. Delphi使用LDAP方式訪問AD,可以使用ADsObj.Get('屬性')時得到相關屬性值。
屬性的取值域可以通過JAVA程序得到。
Directory Services(目錄服務)
我們知道,當局域網的規模變的越來越大時,為了方便主機管理,我們使用DHCP來實現IP地址、以太網地址、主機名和拓撲結構等的集中管理和統一分配。同樣,如果一個局域網內有許多的其它資源時,如打印機、共享文件夾等等,為了方便的定位及查找它們,一種集中定位管理的方式或許是較好的選擇,DNS和NIS都是用來實現類似管理的方法。
對於局域網內的一個用戶來講,工作等其它應用需要,我們必須憑帳號登錄主機、用帳號收發E-mail,甚至為了管理需要公司還需要維護一個電子號碼簿來存儲員工的姓名、地址、電話號碼等信息。隨着時間的增長,我們會為這些越來越多的帳號和密碼弄的頭暈腦脹。同時,如果一個員工離開,管理員就不得不翻遍所有的記錄帳號信息的文件把離職員工的信息刪除。這些將是一個繁瑣而效率低下的工作。那么,如果能將此些帳號信息等統一到一個文件中進行管理,無疑會大大提高員工及管理員的工作效率。目錄服務(LDAP是其實現的一種)正是基於這些應用實現的。
LDAP
LDAP是Lightweight Directory Access Protocol的縮寫,顧名思義,它是指輕量級目錄訪問協議(這個主要是相對另一目錄訪問協議X.500而言的;LDAP略去了x.500中許多不太常用的功能,且以TCP/IP協議為基礎)。目錄服務和數據庫很類似,但又有着很大的不同之處。數據庫設計為方便讀寫,但目錄服務專門進行了讀優化的設計,因此不太適合於經常有寫操作的數據存儲。同時,LDAP只是一個協議,它沒有涉及到如何存儲這些信息,因此還需要一個后端數據庫組件來實現。這些后端可以 是bdb(BerkeleyDB)、ldbm、shell和passwd等。
LDAP目錄以樹狀的層次結構來存儲數據(這很類同於DNS),最頂層即根部稱作“基准DN”,形如"dc=mydomain,dc=org"或者"o= mydomain.org",前一種方式更為靈活也是Windows AD中使用的方式。在根目錄的下面有很多的文件和目錄,為了把這些大量的數據從邏輯上分開,LDAP像其它的目錄服務協議一樣使用OU (Organization Unit),可以用來表示公司內部機構,如部門等,也可以用來表示設備、人員等。同時OU還可以有子OU,用來表示更為細致的分類。
LDAP中每一條記錄都有一個唯一的區別於其它記錄的名字DN(Distinguished Name),其處在“葉子”位置的部分稱作RDN;如dn:cn=tom,ou=animals,dc=mydomain,dc=org中tom即為 RDN;RDN在一個OU中必須是唯一的。
因為LDAP數據是“樹”狀的,而且這棵樹是可以無限延伸的,假設你要樹上的一個蘋果(一條記錄),你怎么告訴園丁它的位置呢?當然首先要說明是哪一棵樹(dc,相當於MYSQL的DB),然后是從樹根到那個蘋果所經過的所有“分叉”(ou,呵呵MYSQL里面好象沒有這 DD),最后就是這個蘋果的名字(uid,記得我們設計MYSQL或其它數據庫表時,通常為了方便管理而加上一個‘id’字段嗎?)。好了!這時我們可以清晰的指明這個蘋果的位置了,就是那棵“歪脖樹”的東邊那個分叉上的靠西邊那個分叉的再靠北邊的分叉上的半紅半綠的……,暈了!你直接爬上去吧!我還是說說LDAP里要怎么定義一個字段的位置吧,樹(dc=waibo,dc=com),分叉(ou=bei,ou=xi,ou= dong),蘋果(cn=honglv),好了!位置出來了:
dn:cn=honglv,ou=bei,ou=xi,ou=dong,dc=waibo,dc=com
LDAP的 可擴展性和靈活性
LDAP 協議既是跨平台的也是基於標准的。這意味着幾乎在任何計算機平台上運行的任何應用程序都可以從LDAP目錄獲取信息。另外,無論什么服務器操作系統、文件系統或平台對於客戶機都是無關緊要的。
LDAP目錄幾乎可以存儲所有類型的數據:電子郵件地址、DNS 信息、NIS 映射、安全性密鑰、聯系人信息列表和計算機名等。如果需要專門的組織單元或項,則可以根據具體實現來定制控制給定字段可以保存哪種信息的規則(稱為模式,稍后將詳細討論)。
大多數 LDAP 服務器的安裝和配置相對比較簡單,並且可以在很少或沒有維護的情況下運行多年,而且很容易為特定類型的訪問而進行最優化。
可以容易地配置 LDAP 目錄來復制部分或所有目錄樹(使用推(push)或拉(pull)方法)。這可以使系統管理員不必擔心出現單點故障的情況。
可以通過 ACL(訪問控制表,Access Control List)來控制對目錄的訪問。例如,管理員可以根據給定組或位置中的成員資格來限制誰可以看到哪些內容,或者給予特殊用戶在其自己記錄中修改所選字段的能力。ACL 提供極其細粒度的訪問控制,而且 ACL 將這種控制與 LDAP 安裝結合在一起,而不是與請求信息的客戶機結合在一起。此外,可以容易地將 LDAP 與大多數現有的安全性層和/或認證系統(例如 SSL、Kerberos 和 PAM 等)集成在一起。
LDIF
LDIF(LDAP Interchange Format)是指存儲LDAP配置信息及目錄內容的標准文本文件格式,之所以使用文本文件來格式來存儲這些信息是為了方便讀取和修改,這也是其它大多數 服務配置文件所采取的格式。LDIF文件常用來向目錄導入或更改記錄信息,這些信息需要按照LDAP中schema的格式進行組織,並會接受schema 的檢查,如果不符合其要求的格式將會出現報錯信息。LDIF文件樣例如下:
dn:cn=stan,ou=linux,ou=computer,dc=ourschool,dc=org
objectClass:organizationalPerson
cn:stan
cn:czm
sn:czm
其中,以“#”號開頭的為注釋行;第二行起的行中,冒號左邊為屬性,右邊是屬性的值,這類同於編程中的變量及為其所賦的值,但屬性可以被重復賦值。
注意:同一個屬性可以有一個或者多個值,ldap在尋址時,可以根據同一個屬性的不同值進行尋址,例如上例中可以根據cn屬性的stan和czm進行尋址,這樣速度更快。
objectClass
對象類由 LDAP 目錄使用來定義給定類型的對象可以有哪些屬性。對象類還定義項必須有什么屬性,以及項可以有什么屬性。所有對象類都從其父對象類繼承需求,然后添加它們自己的需求。
對象類有五個組件:OID(對象標識)、唯一名稱、父對象(SUP)、任何需要的屬性(MUST)和允許的屬性列表(MAY)。OID是由LDAP目錄的內部數據庫機制使用的數據標識符。從概念上講,它們與IP地址相似,因為每個對象類都必須有一個唯一數字。並且象DNS和IP之間的關系那樣,由創建它們的個人進行注冊,並由這些人“擁有”。
在LDAP中objectClass分為三種:Abstract,Structural,AUXIALIARY。要定義一個Entry必須包含一個Structural類型的ObjectClass,
其他兩個類型可包括0或多個。其中Top是一個頂級ObjectClass,里面定義了一個MUST Attribute:ObjectClass,於是也就決定了必須有
一個其它的Structural ObjectClass才能定義一個Entry.其中ObjectClass又可以存在繼承關系,子ObjectClass會繼承父ObjectClass中的
全部Attribute.該繼承關系於Java中有點相似.
在LDAP中每一個ObjectClass都定義了一些Attribute,其Attribute仍然可以是ObjectClass。在這些Attriubte中分為兩種類型MUST,MAY, MUST表示這個Entry必須包括的屬性,MAY為可選。一個ObjectClass的Attribute也包括所有繼承自父ObjectClass和自身定義的ObjectClass。
下面用一個類型進行說明:
objectclass ( 2.5.6.0 NAME 'top' ABSTRACT
MUST objectClass )
objectclass ( 1.3.6.1.4.1.1466.344 NAME 'dcObject'
DESC 'RFC2247: domain component object'
SUP top AUXILIARY
MUST dc )
上面是兩個objectclass的定義,其中top為ABSTRACT,dcObject為AUXILIARY,這兩個類型都不能定義Entry.
下面這個LDIF文件在導入到LDAP時會出錯:
dn: dc=java,dc=com
objectClass:dcObject
dc: java.com
要定義這個Entry必須找到一個STRUCTURAL類型的ObjectClass。
objectClasses: ( 2.5.6.4 NAME 'organization'
DESC 'RFC2256: an organization' SUP top STRUCTURAL
MUST o
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory
$ x121Address $ registeredAddress $ destinationIndicator
$ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier
$ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber
$ street $ postOfficeBox $ postalCode $ postalAddress
$ physicalDeliveryOfficeName $ st $ l $ description ) )
這個objectClass的類型為STRUCTURAL,因此可以用來定義Entry.具體定義如下
dn: dc=java,dc=com
objectClass:dcObject
objectClass:organization
dc: java.com
o: java.com
Attribute
Attribute類同於編程語言中的變量,它可以被賦值,就像是可以存放一個單一類型信息的容器。官方聲明了許多常用的 Attribute,如果其中沒有你所需要的,你可以自己定義,但要避免重名。objectClass是一種特殊的Attribute,它包含其它用到的 Attribute以及它自身。常見的Attribute如下:

schema
LDAP中,schema用來指定一個目錄中所包含的objects的類型 (objectClass)以及每一個objectClass中的各個必備(mandatory)和可選(optional)的屬性 (attribute)。因此,Schema是一個數據模型,它被用來決定數據怎樣被存儲,被跟蹤的數據的是什么類型,存儲在不同的Entry下的數據之間的關系。schema 需要在主配置文件slapd.conf中指定,以用來決定本目錄中使用到的objectClass。管理員可以自己設計制定schema,一般包括屬性定 義(AttributeDefinition)、類定義(ClassDefinition)以及語法定義(SyntaxDefinition)等部分。
LDAP V3中在x.500標准的基礎上定義了一個包含了網絡中大多常見對象的schema,這些對象包括國家、所在地、組織、人員、小組以及設備等。同時,LDAP V3中可以很方便的從目錄中提取出schema,它正是一條記錄中關於屬性的聲明部分。
對象標識符
對象標識符( Object Identifiers )是被LDAP內部數據庫引用的數字標識。Attribute的名字是設計為方便人們讀取的,但為了方便計算機的處理,通常使用一組數字來標識這些對象,這類同於SNMP中的MIB2。例如,當計算機接收到dc這個Attribute時,它會將這個名字轉換為對應的OID: 1.3.6.1.4.1.1466.115.121.1.26。
幾點體會
重大誤解
很多所謂基於LDAP實現的認證都是使用目錄來存儲加密(多數是MD5)后的密碼而已.但是這種密碼很好被暴力破解.於是你的系統的安全狀態有退回到未 shadow過的/etc/passwd時代.在介紹目錄服務的書籍中提到/etc/passwd也算是一種目錄.我們不能說一個文本文件是用來做認證的吧?
很多LDAP的實現和應用都不使用LDAP來作驗證.如微軟的活動目錄.還有斯坦福大學的目錄都使用了kerberos.配置好的Windows域控制器本身就是一個Kerberos KDC.而斯坦福的目錄也采用了Hedimal的Kerberos實現來做KDC和一個Windows 的KDC.這樣的理由很明顯的.如果要通過過LDAP目錄來實現一個十分安全的認證信息的存儲要借助大量的外圍協議.還不如直接使用這些協議本身.長話短說,我們應該讓目錄存儲它改存儲的東西.
產品選擇
產品的選擇取決於你部署目錄服務的目的以及內容.如果活動目錄提供給你的那些的功能足夠你的需要.那么采用活動目錄好了.因為他一開始就將安全實現的很好(操作系統安全不在討論之列).而且配置簡單.而且和客戶端(windows)兼容的較好.
如果你想在深入研究LDAP協議.或者要實現一個高度自定義的目錄.那么選擇OpenLDAP吧!
安全措施.
盡量少將安全敏感的信息存儲在目錄中.如果非存不可.一定要編輯ACL嚴格的控制訪問權限如userPassword等.多數情況下目錄服務還要主要是給其他的服務提供數據存儲.這樣的話應該讓每個服務器綁定到不通的DN,同時在ACL中賦予他們較高的權限.而不能讓所有的服務都使用rootdn來綁定.
目錄結構的設計
雖然目錄結構的設計可以比較靈活.但比較有經驗的設計可以使你的目錄結構更加合理,而且可以給你帶來意想不到的好處.盡量參照前人實現的產品一吸收好的思想.分析微軟的設計,在目錄中建立分組的目錄樹是明智的做法.這樣每個帳戶的memberof屬性的值他所屬的組的DN,這樣就可以方便的將基於組的訪問控制列表也實現在目錄結構中.相象如果活動目錄中用戶的memberof屬性是"Aministrators"而不是"CN= Administrators,CN=Builtin,DC=example,DC=edu,DC=cn"的話會給微軟帶來多少麻煩?盡量的將更多的數據以樹的形式組織,同時在字段中使用更多的DN代替單一的數值,可以最大限度的發揮目錄服務的潛力.
AD和LDAP的關系
參考至:http://doc.linuxpk.com/2293.html
http://doc.linuxpk.com/2583.html
http://doc.linuxpk.com/2586.html
http://doc.linuxpk.com/28400.html
http://bbs.chinaunix.net/thread-889055-1-1.html
http://hi.baidu.com/dongyuejiang/item/d2af278125f05d5d26ebd9a0
http://linux.chinaitlab.com/special/ldap/Index.html
Directory Services(目錄服務)
我們知道,當局域網的規模變的越來越大時,為了方便主機管理,我們使用DHCP來實現IP地址、以太網地址、主機名和拓撲結構等的集中管理和統一分配。同樣,如果一個局域網內有許多的其它資源時,如打印機、共享文件夾等等,為了方便的定位及查找它們,一種集中定位管理的方式或許是較好的選擇,DNS和NIS都是用來實現類似管理的方法。
對於局域網內的一個用戶來講,工作等其它應用需要,我們必須憑帳號登錄主機、用帳號收發E-mail,甚至為了管理需要公司還需要維護一個電子號碼簿來存儲員工的姓名、地址、電話號碼等信息。隨着時間的增長,我們會為這些越來越多的帳號和密碼弄的頭暈腦脹。同時,如果一個員工離開,管理員就不得不翻遍所有的記錄帳號信息的文件把離職員工的信息刪除。這些將是一個繁瑣而效率低下的工作。那么,如果能將此些帳號信息等統一到一個文件中進行管理,無疑會大大提高員工及管理員的工作效率。目錄服務(LDAP是其實現的一種)正是基於這些應用實現的。
LDAP
LDAP是Lightweight Directory Access Protocol的縮寫,顧名思義,它是指輕量級目錄訪問協議(這個主要是相對另一目錄訪問協議X.500而言的;LDAP略去了x.500中許多不太常用的功能,且以TCP/IP協議為基礎)。目錄服務和數據庫很類似,但又有着很大的不同之處。數據庫設計為方便讀寫,但目錄服務專門進行了讀優化的設計,因此不太適合於經常有寫操作的數據存儲。同時,LDAP只是一個協議,它沒有涉及到如何存儲這些信息,因此還需要一個后端數據庫組件來實現。這些后端可以 是bdb(BerkeleyDB)、ldbm、shell和passwd等。
LDAP目錄以樹狀的層次結構來存儲數據(這很類同於DNS),最頂層即根部稱作“基准DN”,形如"dc=mydomain,dc=org"或者"o= mydomain.org",前一種方式更為靈活也是Windows AD中使用的方式。在根目錄的下面有很多的文件和目錄,為了把這些大量的數據從邏輯上分開,LDAP像其它的目錄服務協議一樣使用OU (Organization Unit),可以用來表示公司內部機構,如部門等,也可以用來表示設備、人員等。同時OU還可以有子OU,用來表示更為細致的分類。
LDAP中每一條記錄都有一個唯一的區別於其它記錄的名字DN(Distinguished Name),其處在“葉子”位置的部分稱作RDN;如dn:cn=tom,ou=animals,dc=mydomain,dc=org中tom即為 RDN;RDN在一個OU中必須是唯一的。
因為LDAP數據是“樹”狀的,而且這棵樹是可以無限延伸的,假設你要樹上的一個蘋果(一條記錄),你怎么告訴園丁它的位置呢?當然首先要說明是哪一棵樹(dc,相當於MYSQL的DB),然后是從樹根到那個蘋果所經過的所有“分叉”(ou,呵呵MYSQL里面好象沒有這 DD),最后就是這個蘋果的名字(uid,記得我們設計MYSQL或其它數據庫表時,通常為了方便管理而加上一個‘id’字段嗎?)。好了!這時我們可以清晰的指明這個蘋果的位置了,就是那棵“歪脖樹”的東邊那個分叉上的靠西邊那個分叉的再靠北邊的分叉上的半紅半綠的……,暈了!你直接爬上去吧!我還是說說LDAP里要怎么定義一個字段的位置吧,樹(dc=waibo,dc=com),分叉(ou=bei,ou=xi,ou= dong),蘋果(cn=honglv),好了!位置出來了:
dn:cn=honglv,ou=bei,ou=xi,ou=dong,dc=waibo,dc=com
LDAP的 可擴展性和靈活性
LDAP 協議既是跨平台的也是基於標准的。這意味着幾乎在任何計算機平台上運行的任何應用程序都可以從LDAP目錄獲取信息。另外,無論什么服務器操作系統、文件系統或平台對於客戶機都是無關緊要的。
LDAP目錄幾乎可以存儲所有類型的數據:電子郵件地址、DNS 信息、NIS 映射、安全性密鑰、聯系人信息列表和計算機名等。如果需要專門的組織單元或項,則可以根據具體實現來定制控制給定字段可以保存哪種信息的規則(稱為模式,稍后將詳細討論)。
大多數 LDAP 服務器的安裝和配置相對比較簡單,並且可以在很少或沒有維護的情況下運行多年,而且很容易為特定類型的訪問而進行最優化。
可以容易地配置 LDAP 目錄來復制部分或所有目錄樹(使用推(push)或拉(pull)方法)。這可以使系統管理員不必擔心出現單點故障的情況。
可以通過 ACL(訪問控制表,Access Control List)來控制對目錄的訪問。例如,管理員可以根據給定組或位置中的成員資格來限制誰可以看到哪些內容,或者給予特殊用戶在其自己記錄中修改所選字段的能力。ACL 提供極其細粒度的訪問控制,而且 ACL 將這種控制與 LDAP 安裝結合在一起,而不是與請求信息的客戶機結合在一起。此外,可以容易地將 LDAP 與大多數現有的安全性層和/或認證系統(例如 SSL、Kerberos 和 PAM 等)集成在一起。
LDIF
LDIF(LDAP Interchange Format)是指存儲LDAP配置信息及目錄內容的標准文本文件格式,之所以使用文本文件來格式來存儲這些信息是為了方便讀取和修改,這也是其它大多數 服務配置文件所采取的格式。LDIF文件常用來向目錄導入或更改記錄信息,這些信息需要按照LDAP中schema的格式進行組織,並會接受schema 的檢查,如果不符合其要求的格式將會出現報錯信息。LDIF文件樣例如下:
dn:cn=stan,ou=linux,ou=computer,dc=ourschool,dc=org
objectClass:organizationalPerson
cn:stan
cn:czm
sn:czm
其中,以“#”號開頭的為注釋行;第二行起的行中,冒號左邊為屬性,右邊是屬性的值,這類同於編程中的變量及為其所賦的值,但屬性可以被重復賦值。
注意:同一個屬性可以有一個或者多個值,ldap在尋址時,可以根據同一個屬性的不同值進行尋址,例如上例中可以根據cn屬性的stan和czm進行尋址,這樣速度更快。
objectClass
對象類由 LDAP 目錄使用來定義給定類型的對象可以有哪些屬性。對象類還定義項必須有什么屬性,以及項可以有什么屬性。所有對象類都從其父對象類繼承需求,然后添加它們自己的需求。
對象類有五個組件:OID(對象標識)、唯一名稱、父對象(SUP)、任何需要的屬性(MUST)和允許的屬性列表(MAY)。OID是由LDAP目錄的內部數據庫機制使用的數據標識符。從概念上講,它們與IP地址相似,因為每個對象類都必須有一個唯一數字。並且象DNS和IP之間的關系那樣,由創建它們的個人進行注冊,並由這些人“擁有”。
在LDAP中objectClass分為三種:Abstract,Structural,AUXIALIARY。要定義一個Entry必須包含一個Structural類型的ObjectClass,
其他兩個類型可包括0或多個。其中Top是一個頂級ObjectClass,里面定義了一個MUST Attribute:ObjectClass,於是也就決定了必須有
一個其它的Structural ObjectClass才能定義一個Entry.其中ObjectClass又可以存在繼承關系,子ObjectClass會繼承父ObjectClass中的
全部Attribute.該繼承關系於Java中有點相似.
在LDAP中每一個ObjectClass都定義了一些Attribute,其Attribute仍然可以是ObjectClass。在這些Attriubte中分為兩種類型MUST,MAY, MUST表示這個Entry必須包括的屬性,MAY為可選。一個ObjectClass的Attribute也包括所有繼承自父ObjectClass和自身定義的ObjectClass。
下面用一個類型進行說明:
objectclass ( 2.5.6.0 NAME 'top' ABSTRACT
MUST objectClass )
objectclass ( 1.3.6.1.4.1.1466.344 NAME 'dcObject'
DESC 'RFC2247: domain component object'
SUP top AUXILIARY
MUST dc )
上面是兩個objectclass的定義,其中top為ABSTRACT,dcObject為AUXILIARY,這兩個類型都不能定義Entry.
下面這個LDIF文件在導入到LDAP時會出錯:
dn: dc=java,dc=com
objectClass:dcObject
dc: java.com
要定義這個Entry必須找到一個STRUCTURAL類型的ObjectClass。
objectClasses: ( 2.5.6.4 NAME 'organization'
DESC 'RFC2256: an organization' SUP top STRUCTURAL
MUST o
MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory
$ x121Address $ registeredAddress $ destinationIndicator
$ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier
$ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber
$ street $ postOfficeBox $ postalCode $ postalAddress
$ physicalDeliveryOfficeName $ st $ l $ description ) )
這個objectClass的類型為STRUCTURAL,因此可以用來定義Entry.具體定義如下
dn: dc=java,dc=com
objectClass:dcObject
objectClass:organization
dc: java.com
o: java.com
Attribute
Attribute類同於編程語言中的變量,它可以被賦值,就像是可以存放一個單一類型信息的容器。官方聲明了許多常用的 Attribute,如果其中沒有你所需要的,你可以自己定義,但要避免重名。objectClass是一種特殊的Attribute,它包含其它用到的 Attribute以及它自身。常見的Attribute如下:

schema
LDAP中,schema用來指定一個目錄中所包含的objects的類型 (objectClass)以及每一個objectClass中的各個必備(mandatory)和可選(optional)的屬性 (attribute)。因此,Schema是一個數據模型,它被用來決定數據怎樣被存儲,被跟蹤的數據的是什么類型,存儲在不同的Entry下的數據之間的關系。schema 需要在主配置文件slapd.conf中指定,以用來決定本目錄中使用到的objectClass。管理員可以自己設計制定schema,一般包括屬性定 義(AttributeDefinition)、類定義(ClassDefinition)以及語法定義(SyntaxDefinition)等部分。
LDAP V3中在x.500標准的基礎上定義了一個包含了網絡中大多常見對象的schema,這些對象包括國家、所在地、組織、人員、小組以及設備等。同時,LDAP V3中可以很方便的從目錄中提取出schema,它正是一條記錄中關於屬性的聲明部分。
對象標識符
對象標識符( Object Identifiers )是被LDAP內部數據庫引用的數字標識。Attribute的名字是設計為方便人們讀取的,但為了方便計算機的處理,通常使用一組數字來標識這些對象,這類同於SNMP中的MIB2。例如,當計算機接收到dc這個Attribute時,它會將這個名字轉換為對應的OID: 1.3.6.1.4.1.1466.115.121.1.26。
幾點體會
重大誤解
很多所謂基於LDAP實現的認證都是使用目錄來存儲加密(多數是MD5)后的密碼而已.但是這種密碼很好被暴力破解.於是你的系統的安全狀態有退回到未 shadow過的/etc/passwd時代.在介紹目錄服務的書籍中提到/etc/passwd也算是一種目錄.我們不能說一個文本文件是用來做認證的吧?
很多LDAP的實現和應用都不使用LDAP來作驗證.如微軟的活動目錄.還有斯坦福大學的目錄都使用了kerberos.配置好的Windows域控制器本身就是一個Kerberos KDC.而斯坦福的目錄也采用了Hedimal的Kerberos實現來做KDC和一個Windows 的KDC.這樣的理由很明顯的.如果要通過過LDAP目錄來實現一個十分安全的認證信息的存儲要借助大量的外圍協議.還不如直接使用這些協議本身.長話短說,我們應該讓目錄存儲它改存儲的東西.
產品選擇
產品的選擇取決於你部署目錄服務的目的以及內容.如果活動目錄提供給你的那些的功能足夠你的需要.那么采用活動目錄好了.因為他一開始就將安全實現的很好(操作系統安全不在討論之列).而且配置簡單.而且和客戶端(windows)兼容的較好.
如果你想在深入研究LDAP協議.或者要實現一個高度自定義的目錄.那么選擇OpenLDAP吧!
安全措施.
盡量少將安全敏感的信息存儲在目錄中.如果非存不可.一定要編輯ACL嚴格的控制訪問權限如userPassword等.多數情況下目錄服務還要主要是給其他的服務提供數據存儲.這樣的話應該讓每個服務器綁定到不通的DN,同時在ACL中賦予他們較高的權限.而不能讓所有的服務都使用rootdn來綁定.
目錄結構的設計
雖然目錄結構的設計可以比較靈活.但比較有經驗的設計可以使你的目錄結構更加合理,而且可以給你帶來意想不到的好處.盡量參照前人實現的產品一吸收好的思想.分析微軟的設計,在目錄中建立分組的目錄樹是明智的做法.這樣每個帳戶的memberof屬性的值他所屬的組的DN,這樣就可以方便的將基於組的訪問控制列表也實現在目錄結構中.相象如果活動目錄中用戶的memberof屬性是"Aministrators"而不是"CN= Administrators,CN=Builtin,DC=example,DC=edu,DC=cn"的話會給微軟帶來多少麻煩?盡量的將更多的數據以樹的形式組織,同時在字段中使用更多的DN代替單一的數值,可以最大限度的發揮目錄服務的潛力.
AD和LDAP的關系
參考至:http://doc.linuxpk.com/2293.html
http://doc.linuxpk.com/2583.html
http://doc.linuxpk.com/2586.html
http://doc.linuxpk.com/28400.html
http://bbs.chinaunix.net/thread-889055-1-1.html
http://hi.baidu.com/dongyuejiang/item/d2af278125f05d5d26ebd9a0
http://linux.chinaitlab.com/special/ldap/Index.html
