Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/njaremko/samael
A SAML2 library for Rust
https://github.com/njaremko/samael
Last synced: 3 months ago
JSON representation
A SAML2 library for Rust
- Host: GitHub
- URL: https://github.com/njaremko/samael
- Owner: njaremko
- License: mit
- Created: 2020-02-22T21:47:24.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2024-06-24T01:44:16.000Z (5 months ago)
- Last Synced: 2024-06-24T18:02:11.569Z (5 months ago)
- Language: Rust
- Size: 261 KB
- Stars: 68
- Watchers: 5
- Forks: 38
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
- awesome-saml - samael
README
## Samael
[![Crates.io][crates-badge]][crates-url]
[![MIT licensed][mit-badge]][mit-url][crates-badge]: https://img.shields.io/crates/v/samael.svg
[crates-url]: https://crates.io/crates/samael
[mit-badge]: https://img.shields.io/crates/l/samael
[mit-url]: https://github.com/njaremko/samael/blob/master/LICENSEThis is a SAML2 library for rust.
This is a work in progress. Pull Requests are welcome.
Current Features:
- Serializing and Deserializing SAML messages
- IDP-initiated SSO
- SP-initiated SSO Redirect-POST binding
- Helpers for validating SAML assertions
- Encrypted assertions aren't supported yet
- Verify SAMLRequest (AuthnRequest) message signatures
- Create signed SAMLResponse (Response) messagesThe `"xmlsec"` feature flag adds basic support for verifying and signing SAML messages. We're using a modified copy of [rust-xmlsec](https://github.com/voipir/rust-xmlsec) library (bindings to xmlsec1 library).
If you want to use the `"xmlsec"` feature, you'll need to install the following C libs:
- libiconv
- libtool
- libxml2
- libxslt
- libclang
- openssl
- pkg-config
- xmlsec1# Build instructions
We use [nix](https://nixos.org) 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.1. [Install nix](https://github.com/DeterminateSystems/nix-installer)
1. Install [direnv](https://direnv.net/) and [cachix](https://docs.cachix.org)
```
# Add ~/.nix-profile/bin to your path first
nix profile install nixpkgs#direnv
nix profile install nixpkgs#cachix
```
1. Run `cachix use nix-community` to enable a binary cache for the rust toolchain (otherwise you'll build the rust toolchain from scratch)
1. `cd` into this repo and run `direnv allow` and `nix-direnv-reload`
1. Install the [direnv VS Code extension](https://marketplace.visualstudio.com/items?itemName=mkhl.direnv)## Building the library
Just run `nix build`
## Entering a dev environment
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:
```sh
cargo build --features xmlsec
cargo test --features xmlsec
```# How do I use this library?
You'll need these dependencies for this example
```toml
[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:
```rust
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> {
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| {
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(())
}
```