17 个版本

0.0.17 2024 年 7 月 3 日
0.0.15 2024 年 4 月 4 日
0.0.14 2023 年 11 月 7 日
0.0.12 2023 年 5 月 11 日
0.0.7 2020 年 3 月 14 日

#40 in 身份验证

Download history 1994/week @ 2024-05-04 3114/week @ 2024-05-11 2198/week @ 2024-05-18 1897/week @ 2024-05-25 1610/week @ 2024-06-01 1502/week @ 2024-06-08 1806/week @ 2024-06-15 2838/week @ 2024-06-22 1845/week @ 2024-06-29 2786/week @ 2024-07-06 3245/week @ 2024-07-13 2447/week @ 2024-07-20 3282/week @ 2024-07-27 3838/week @ 2024-08-03 4510/week @ 2024-08-10 3796/week @ 2024-08-17

15,779 每月下载量

MIT 许可证

260KB
6K SLoC

Samael

Crates.io MIT licensed

这是一个 Rust 的 SAML2 库。

这是一个正在进行中的项目。欢迎 Pull Requests。

当前功能

  • 序列化和反序列化 SAML 消息
  • IDP 启动的 SSO
  • SP 启动的 SSO Redirect-POST 绑定
  • 验证 SAML 断言的辅助工具
    • 不支持加密断言
  • 验证 SAMLRequest (AuthnRequest) 消息签名
  • 创建签名的 SAMLResponse (Response) 消息

启用 "xmlsec" 功能标志可添加对验证和签名 SAML 消息的基本支持。我们使用 rust-xmlsec 库(xmlsec1 库的绑定)的修改版本。

如果您想使用 "xmlsec" 功能,您需要安装以下 C 库

  • libiconv
  • libtool
  • libxml2
  • libxslt
  • libclang
  • openssl
  • pkg-config
  • xmlsec1

构建说明

我们使用 nix 来促进 samael 的可重复构建。它将确保您以不会影响您系统其他部分的方式安装所需的库。如果您想利用这一点,您需要做一点工作。

  1. 安装 nix
  2. 安装 direnvcachix
    # Add ~/.nix-profile/bin to your path first
    nix profile install nixpkgs/release-23.11#direnv
    nix profile install nixpkgs/release-23.11#cachix
    
  3. 运行 cachix use nix-community 以启用 rust 工具链的二进制缓存(否则您将从头开始构建 rust 工具链)
  4. cd 进入此仓库并运行 direnv allow
  5. 安装 direnv VS Code 扩展

构建库

只需运行 nix build

进入开发环境

如果您遵循了上面的说明,只需将 cd 进入目录即可设置可重复的开发环境,但如果您不想安装 direnv,则只需运行 nix develop

从那里您可以像平常一样构建

cargo build --features xmlsec
cargo test --features xmlsec

我如何使用这个库?

您需要以下依赖项来使用此示例

[dependencies]
tokio = { version = "1.28.1", features = ["full"] }
samael = { version = "0.0.12", features = ["xmlsec"] }
warp = "0.3.5"
reqwest = "0.11.18"
openssl = "0.10.52"
openssl-probe = "0.1.5"

以下是一些使用此库的示例代码

use samael::metadata::{ContactPerson, ContactType, EntityDescriptor};
use samael::service_provider::ServiceProviderBuilder;
use std::collections::HashMap;
use std::fs;
use warp::Filter;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    openssl_probe::init_ssl_cert_env_vars();

    let resp = reqwest::get("https://samltest.id/saml/idp")
        .await?
        .text()
        .await?;
    let idp_metadata: EntityDescriptor = samael::metadata::de::from_str(&resp)?;

    let pub_key = openssl::x509::X509::from_pem(&fs::read("./publickey.cer")?)?;
    let private_key = openssl::rsa::Rsa::private_key_from_pem(&fs::read("./privatekey.pem")?)?;

    let sp = ServiceProviderBuilder::default()
        .entity_id("".to_string())
        .key(private_key)
        .certificate(pub_key)
        .allow_idp_initiated(true)
        .contact_person(ContactPerson {
            sur_name: Some("Bob".to_string()),
            contact_type: Some(ContactType::Technical.value().to_string()),
            ..ContactPerson::default()
        })
        .idp_metadata(idp_metadata)
        .acs_url("https://127.0.0.1:8080/saml/acs".to_string())
        .slo_url("https://127.0.0.1:8080/saml/slo".to_string())
        .build()?;

    let metadata = sp.metadata()?.to_string()?;

    let metadata_route = warp::get()
        .and(warp::path("metadata"))
        .map(move || metadata.clone());

    let acs_route = warp::post()
        .and(warp::path("acs"))
        .and(warp::body::form())
        .map(move |s: HashMap<String, String>| {
            if let Some(encoded_resp) = s.get("SAMLResponse") {
                let t = sp
                    .parse_base64_response(encoded_resp, Some(&["a_possible_request_id"]))
                    .unwrap();
                return format!("{:?}", t);
            }
            format!("")
        });

    let saml_routes = warp::path("saml").and(acs_route.or(metadata_route));
    warp::serve(saml_routes).run(([127, 0, 0, 1], 8080)).await;
    Ok(())
}

依赖项

~7–10MB
~219K SLoC