簡體   English   中英

如何將參數傳遞給 ldapjs exop() function?

[英]How do I pass parameters to the ldapjs exop() function?

我正在嘗試使用“更改用戶密碼”擴展操作,如本 RFC中所定義,它聲明它采用三個可選參數的序列。 但是,ldapjs 的 client.exop() function 似乎只允許我為它提供一個字符串或緩沖區。

這是我的嘗試:

const dn = `uid=${username},ou=People,dc=${orginization},dc=com`
client.exop('1.3.6.1.4.1.4203.1.11.1', [dn, null, newPassword], (err, value, res) => {
  // ...
})

這是由此產生的錯誤:

TypeError: options.requestValue must be a buffer or a string

我應該如何將這些值編碼成一個字符串? ldapjs 文檔提供的有關將參數傳遞給擴展操作的信息非常少。

長話短說:博士; 擴展操作參數需要是使用 BER 標准編碼的 ASN.1 值。 這不是一項簡單的任務,因此您可能需要一個額外的 npm 庫,例如asn1來幫助完成此過程。

在梳理了 ldapjs 的代碼,閱讀了一堆關於 ASN.1 的內容以及 LDAP 如何使用 ASN.1 標准,以及一些反復試驗之后,我終於能夠解決這個問題。 由於明顯缺乏這方面的文檔,我想我會分享我在 stackoverflow 上學到的東西,這樣其他人就不需要 go 像我一樣經歷那么多麻煩。

一個工作示例

這使用asn1 npm庫對發送的數據進行編碼。

const { Ber } = require('asn1')

// ...

const CTX_SPECIFIC_CLASS = 0b10 << 6
const writer = new Ber.Writer()
writer.startSequence()
writer.writeString(dn, CTX_SPECIFIC_CLASS | 0) // sequence item number 0
// I'm choosing to omit the optional sequence item number 1
writer.writeString(newPassword, CTX_SPECIFIC_CLASS | 2) // sequence item number 2
writer.endSequence()
client.exop('1.3.6.1.4.1.4203.1.11.1', writer.buffer, (err, value, res) => {
  // ...
})

什么是 ASN.1?

ASN.1 是一種用於描述 object 接口的語言。這些接口的特殊之處在於它們與語言無關 - 即 javascript 可以創建符合這些接口之一的 object,對其進行編碼,並將其發送到 python服務器然后根據同一接口解碼和驗證 object。 ASN.1 的大部分內容與我們試圖完成的事情無關,但重要的是要注意我們正在嘗試做的是制作一個符合這些 ASN.1 接口之一的 object(LDAP 是圍繞他們)。

什么是誤碼率?

BER 描述了一種表示符合 ASN.1 接口的 object 的標准方法。 使用 BER 標准,我們可以將 javascript 數據編碼到 LDAP 服務器可以理解的緩沖區中。

BER 基礎知識

BER 被設計成一個非常緊湊的編碼標准。 我將在這里介紹 go 基礎知識,但如果您想了解有關 BER 二進制表示的更多詳細信息(它專為 LDAP 用戶量身定制),我強烈推薦這篇文章 A Layman's Guide to a Subset of ASN.1、BER 和 DER是另一個很好的資源。

ASN.1 描述了一些基本的 object 類型,例如字符串和數字,它描述了結構化的 object 類型,例如序列或集合。 它還為用戶提供了使用他們自己的自定義類型的能力。

在 BER 中,每條數據都以兩個字節(通常)為前綴:一個標識符字節和一個數據長度字節。 標識符字節用關於它包含的數據類型的信息標記數據(字符串?序列?自定義類型?)。 標簽有四種“類別”:通用(例如字符串)、應用(LDAP 定義了一些您可能會遇到的應用標簽)、上下文特定(請參閱下面的“BER 序列”部分)和私有(不太可能適用這里)。 字符串標記的位序列將始終被解釋為字符串標記,但自定義標記的位序列的含義可能因環境而異,甚至在請求中也不同。

在asn1 npm庫中,可以寫出一個字符串元素,如下:

writer.writeString('text')

為了找到所有可用的函數,該庫的作者要求您查看源代碼

BER 序列

序列用於描述具有特定形狀的 object(一組鍵值對)。 有些元素可能是可選的,而其他元素是必需的。 我遵循的RFC對其參數進行了以下描述。 我們需要符合這個序列的接口,以便將我們的密碼重置參數發送到 LDAP。

PasswdModifyRequestValue ::= SEQUENCE {
  userIdentity    [0]  OCTET STRING OPTIONAL
  oldPasswd       [1]  OCTET STRING OPTIONAL
  newPasswd       [2]  OCTET STRING OPTIONAL }

[0][1][2]都指的是特定於上下文的標記號。 標記有上下文特定標記 1 的值將被解釋為 oldPasswd 參數的值。 我們不需要使用全局字符串標記來指示我們的值是字符串類型 - LDAP 已經可以使用我們符合的接口推斷出該信息。 這意味着當按此序列寫入字符串時,必須像以前那樣執行writer.writeString('text') (自動使用全局字符串標簽),必須提供標簽編號,如下所示:

const CTX_SPECIFIC_CLASS = 0b10 << 6
writer.writeString(newPassword, CTX_SPECIFIC_CLASS | 2) // The second optional parameter allows you to set a custom tag on the data being set (instead of the default string tag).

標記字節的前兩位保留用於指定標記 class(在這種情況下,它是上下文特定的 class,或位“10”)。 所以, CTX_SPECIFIC_CLASS | 2 CTX_SPECIFIC_CLASS | 2指RFC描述的newPasswd序列項。 請注意,如果我想省略一個可選的序列條目,我只是不寫出標有該序列 ID 的值。

結束語

希望這應該為讀者提供足夠的信息,以便能夠為擴展的 LDAP 操作格式化和發送 BER 編碼參數。 我確實想指出,我不是 ASN.1/BER 專家——以上所有這些信息只是我在過去幾天從自己的研究中理解這些概念的方式。 因此,這篇文章中可能有一些錯誤解釋的地方。 如果您碰巧比我更了解這個主題,請隨意編輯它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM