Crates.io | samael |
lib.rs | samael |
version | 0.0.17 |
source | src |
created_at | 2020-02-23 20:48:21.465107 |
updated_at | 2024-07-03 16:39:24.102874 |
description | A SAML2 library for Rust |
homepage | |
repository | https://github.com/njaremko/samael |
max_upload_size | |
id | 211847 |
size | 333,987 |
This is a SAML2 library for rust.
This is a work in progress. Pull Requests are welcome.
Current Features:
The "xmlsec"
feature flag adds basic support for verifying and signing SAML messages. We're using a modified copy of rust-xmlsec library (bindings to xmlsec1 library).
If you want to use the "xmlsec"
feature, you'll need to install the following C libs:
We use nix to faciliate reproducible builds of samael
.
It will ensure you have the required libraries installed in a way that won't cause any issues with the rest of your system.
If you want to take advantage of this, you'll need to put in a little bit of work.
# 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
to enable a binary cache for the rust toolchain (otherwise you'll build the rust toolchain from scratch)cd
into this repo and run direnv allow
Just run nix build
If you followed the above instructions, just cd
-ing into the directory will setup a reproducible dev environment,
but if you don't want to install direnv
, then just run nix develop
.
From their you can build as normal:
cargo build --features xmlsec
cargo test --features xmlsec
You'll need these dependencies for this example
[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"
Here is some sample code using this library:
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("http://localhost:8080/saml/acs".to_string())
.slo_url("http://localhost: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(())
}