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 身份验证
15,779 每月下载量
260KB
6K SLoC
Samael
这是一个 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
的可重复构建。它将确保您以不会影响您系统其他部分的方式安装所需的库。如果您想利用这一点,您需要做一点工作。
- 安装 nix
- 安装 direnv 和 cachix
# Add ~/.nix-profile/bin to your path first nix profile install nixpkgs/release-23.11#direnv nix profile install nixpkgs/release-23.11#cachix
- 运行
cachix use nix-community
以启用 rust 工具链的二进制缓存(否则您将从头开始构建 rust 工具链) cd
进入此仓库并运行direnv allow
- 安装 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