Rust LDAP解析库ldap-parser的使用,高效处理轻量目录访问协议数据解析与操作

Rust LDAP解析库ldap-parser的使用,高效处理轻量目录访问协议数据解析与操作

License: MIT Apache License 2.0 docs.rs crates.io Github CI Minimum rustc version

LDAP解析器

这是一个轻量级目录访问协议(LDAP)(RFC4511)解析器,使用nom解析器组合框架实现。

它采用纯Rust编写,性能高效,并广泛使用零拷贝技术。该库在设计(递归限制、防御性编程)、测试和模糊测试等方面都特别注意安全性和可靠性。它还力求避免panic。

示例

解析LDAP消息(BER格式):

use ldap_parser::parse_ldap_message;
use ldap_parser::ldap::{MessageID, ProtocolOp, ProtocolOpTag};

static DATA: &[u8] = include_bytes!("../assets/message-search-request-01.bin");

let res = parse_ldap_message(DATA);
match res {
    Ok((rem, msg)) => {
        assert!(rem.is_empty());
        //
        assert_eq!(msg.message_id, MessageID(4));
        assert_eq!(msg.protocol_op.tag(), ProtocolOpTag::SearchRequest);
        match msg.protocol_op {
            ProtocolOp::SearchRequest(req) => {
                assert_eq!(req.base_object.0, "dc=rccad,dc=net");
            },
            _ => panic!("Unexpected message type"),
        }
    },
    _ => panic!("LDAP parsing failed: {:?}", res),
}

完整示例代码

// 导入必要的库
use ldap_parser::parse_ldap_message;
use ldap_parser::ldap::{MessageID, ProtocolOp, ProtocolOpTag};

fn main() {
    // 示例LDAP搜索请求的二进制数据
    static DATA: &[u8] = &[
        0x30, 0x3e, 0x02, 0x01, 0x04, 0x63, 0x39, 0x04, 
        0x0f, 0x64, 0x63, 0x3d, 0x72, 0x63, 0x63, 0x61, 
        0x64, 0x2c, 0x64, 0x63, 0x3d, 0x6e, 0x65, 0x74, 
        0x0a, 0x01, 0x02, 0x0a, 0x01, 0x00, 0x02, 0x01, 
        0x00, 0x02, 0x01, 0x00, 0x01, 0x01, 0x00, 0xa0, 
        0x1a, 0x30, 0x18, 0x04, 0x03, 0x63, 0x6f, 0x6d, 
        0x04, 0x11, 0x4f, 0x3d, 0x4e, 0x65, 0x74, 0x20, 
        0x4c, 0x6d, 0x20, 0x50, 0x3d, 0x4d, 0x20, 0x44, 
        0x3d, 0x43
    ];

    // 解析LDAP消息
    let res = parse_ldap_message(DATA);
    
    // 处理解析结果
    match res {
        Ok((rem, msg)) => {
            // 确保所有数据都被解析
            assert!(rem.is_empty());
            
            // 验证消息ID
            println!("Message ID: {}", msg.message_id.0);
            assert_eq!(msg.message_id, MessageID(4));
            
            // 检查协议操作类型
            println!("Operation type: {:?}", msg.protocol_op.tag());
            assert_eq!(msg.protocol_op.tag(), ProtocolOpTag::SearchRequest);
            
            // 处理具体的搜索请求
            match msg.protocol_op {
                ProtocolOp::SearchRequest(req) => {
                    println!("Search base: {}", req.base_object.0);
                    assert_eq!(req.base_object.0, "dc=rccad,dc=net");
                    
                    // 可以在这里进一步处理搜索请求的其他字段
                    println!("Scope: {:?}", req.scope);
                    println!("Filter: {:?}", req.filter);
                },
                _ => panic!("Unexpected message type"),
            }
        },
        Err(e) => {
            eprintln!("LDAP parsing failed: {:?}", e);
        }
    }
}

许可证

采用以下任一种许可证:

  • Apache License, Version 2.0
  • MIT license

贡献

除非您明确声明,否则任何有意提交用于包含在作品中的贡献,如Apache-2.0许可证中所定义,均应如上所述获得双重许可,而无需任何其他条款或条件。


1 回复

Rust LDAP解析库ldap-parser使用指南

介绍

ldap-parser是一个用于解析和操作LDAP(轻量目录访问协议)数据的Rust库。它提供了高效的方式来处理LDAP协议数据单元(PDU),支持BER编码解析,并允许开发者轻松地构建和解析LDAP消息。

主要特性

  • 完整的LDAP协议支持(v3)
  • BER/DER编码解析器
  • 零拷贝解析
  • 支持构建LDAP请求和响应
  • 完善的错误处理

安装

在Cargo.toml中添加依赖:

[dependencies]
ldap-parser = "0.6"

基本使用方法

解析LDAP消息

use ldap_parser::{parse_ldap_message, LdapMessage};

// 解码十六进制格式的LDAP消息
let data = hex::decode("3020020101640b0a01310a01320a01330a0134").unwrap();
// 解析LDAP消息
let (rem, msg) = parse_ldap_message(&data).unwrap();

// 匹配不同类型的LDAP消息
match msg {
    LdapMessage::SearchRequest(sr) => {
        println!("Got search request: {:?}", sr);
    }
    _ => println!("Got other LDAP message: {:?}", msg),
}

构建LDAP消息

use ldap_parser::{
    ldap::LdapMessage,
    search::{SearchRequest, Scope},
    FromBer, ToDer,
};

// 构建搜索请求
let sr = SearchRequest {
    base_object: "dc=example,dc=com".into(),  // 搜索基础DN
    scope: Scope::WholeSubtree,  // 搜索范围为整个子树
    deref_aliases: 0,  // 不解除别名引用
    size_limit: 0,  // 无大小限制
    time_limit: 0,  // 无时间限制
    types_only: false,  // 返回条目和属性值
    filter: ldap_parser::Filter::Present("objectClass".into()),  // 过滤条件:存在objectClass属性
    attributes: vec!["cn".into(), "sn".into()],  // 返回的属性列表
};

// 构建完整的LDAP消息
let msg = LdapMessage {
    msg_id: 1,  // 消息ID
    op: ldap_parser::LdapOp::SearchRequest(sr),  // 操作类型为搜索请求
    ctrl: vec![],  // 控制项为空
};

// 序列化为DER编码
let der = msg.to_der().unwrap();
println!("Serialized: {:?}", hex::encode(&der));

处理LDAP过滤器

use ldap_parser::Filter;

// 解析过滤器
let filter_data = hex::decode("a317040f6f626a656374436c6173733004").unwrap();
let (_, filter) = Filter::from_ber(&filter_data).unwrap();

// 匹配不同类型的过滤器
match filter {
    Filter::Present(attr) => {
        println!("Filter for attribute presence: {}", attr);
    }
    _ => println!("Other filter type"),
}

// 构建复杂过滤器
let complex_filter = Filter::And(vec![
    Filter::Equality("objectClass".into(), "person".into()),  // 与条件1:objectClass=person
    Filter::Or(vec![
        Filter::Equality("sn".into(), "Doe".into()),  // 或条件1:sn=Doe
        Filter::Equality("givenName".into(), "John".into()),  // 或条件2:givenName=John
    ]),
]);

高级用法

处理控制项

use ldap_parser::{
    controls::{Control, PagedResults},
    LdapMessage,
};

// 添加分页控制项
let paged_control = Control {
    ctrl_type: "1.2.840.113556.1.4.319".into(),  // 分页结果的OID
    criticality: true,  // 设置为关键控制项
    ctrl_value: Some(PagedResults {
        size: 100,  // 每页大小
        cookie: vec![],  // 初始cookie为空
    }
    .to_der()
    .unwrap()),
};

let mut msg = LdapMessage {
    msg_id: 2,
    op: ldap_parser::LdapOp::SearchRequest(/* ... */),
    ctrl: vec![],
};

// 添加控制项到消息中
msg.ctrl.push(paged_control);

错误处理

use ldap_parser::{parse_ldap_message, LdapError};

let invalid_data = vec![0x30, 0x20, 0x02]; // 不完整的LDAP消息

// 处理解析可能出现的错误
match parse_ldap_message(&invalid_data) {
    Ok((_, msg)) => println!("Parsed message: {:?}", msg),
    Err(e) => match e {
        LdapError::Ber(e) => println!("BER parsing error: {:?}", e),  // BER解析错误
        LdapError::InvalidMessage => println!("Invalid LDAP message"),  // 无效的LDAP消息
        _ => println!("Other error"),  // 其他错误
    },
}

完整示例Demo

下面是一个完整的LDAP客户端搜索示例,结合了上述多个功能:

use ldap_parser::{
    controls::{Control, PagedResults},
    ldap::LdapMessage,
    search::{SearchRequest, Scope},
    FromBer, ToDer, Filter,
    parse_ldap_message,
};

fn main() {
    // 1. 构建搜索请求
    let search_request = SearchRequest {
        base_object: "dc=example,dc=com".into(),
        scope: Scope::WholeSubtree,
        deref_aliases: 0,
        size_limit: 100,
        time_limit: 30,
        types_only: false,
        filter: Filter::And(vec![
            Filter::Equality("objectClass".into(), "person".into()),
            Filter::Present("cn".into()),
        ]),
        attributes: vec!["cn".into(), "mail".into(), "uid".into()],
    };

    // 2. 添加分页控制
    let paged_control = Control {
        ctrl_type: "1.2.840.113556.1.4.319".into(),
        criticality: true,
        ctrl_value: Some(PagedResults {
            size: 50,
            cookie: vec![],
        }.to_der().unwrap()),
    };

    // 3. 构建完整的LDAP消息
    let mut ldap_message = LdapMessage {
        msg_id: 1,
        op: ldap_parser::LdapOp::SearchRequest(search_request),
        ctrl: vec![paged_control],
    };

    // 4. 序列化为DER编码
    let der_data = ldap_message.to_der().unwrap();
    println!("Serialized LDAP search request: {:?}", hex::encode(&der_data));

    // 5. 模拟接收到响应后的处理
    let response_data = hex::decode("...").unwrap(); // 这里应该是实际的响应数据
    match parse_ldap_message(&response_data) {
        Ok((remaining, message)) => {
            println!("Successfully parsed LDAP message: {:?}", message);
            // 处理分页控制响应
            for control in message.ctrl {
                if control.ctrl_type == "1.2.840.113556.1.4.319" {
                    if let Some(value) = control.ctrl_value {
                        if let Ok((_, paged)) = PagedResults::from_ber(&value) {
                            println!("Paged results control: size={}, cookie={:?}", 
                                   paged.size, hex::encode(&paged.cookie));
                        }
                    }
                }
            }
        }
        Err(e) => {
            println!("Failed to parse LDAP response: {:?}", e);
        }
    }
}

性能提示

  1. 对于高性能场景,尽量重用缓冲区
  2. 使用零拷贝解析方法处理大型LDAP响应
  3. 考虑使用流式解析处理非常大的LDAP消息

总结

ldap-parser库为Rust开发者提供了处理LDAP协议数据的强大工具,无论是构建LDAP客户端、服务器还是中间件,都能从中受益。其类型安全的API和高效的解析器使其成为Rust生态中处理LDAP协议的首选库。

回到顶部