RPM build fix (reverted CI changes which will need to be un-reverted or made conditional) and vendor Rust dependencies to make builds much faster in any CI system.

This commit is contained in:
Adam Ierymenko
2022-06-08 07:32:16 -04:00
parent 373ca30269
commit d5ca4e5f52
12611 changed files with 2898014 additions and 284 deletions

View File

@@ -0,0 +1 @@
{"files":{"Cargo.lock":"a2f539608f97d8f98e5b296c19d06515481949b1f031517dcf1c62cb38c70ea2","Cargo.toml":"a0f66e02db1107ce5f882d63cd0b48241f39f31988a8b59d61f9c2f15e0c7634","LICENSE":"6863634a792d36121f9e9c5ad6093c26520c97fb3e6396b354545c3f58969d4e","README.md":"f7b0fc2ad58d744d4dad9d149fe4ba89f2ae48091ebbaf691237405040e16dbd","examples/custom_claims.rs":"54afdafdd6eb9d014ffa574386dda173cd5bb064aae66d41411fd18df9a26265","examples/hs256.rs":"62a847c9d455f0d0d5c9ad95be06707ae40496c94a669e37d33adaf01f5fcf0c","src/algorithm/mod.rs":"83d779fabf3e5c8b1dd507d51c7b1abc0e6724eae4bf2b9341b9f1321d361108","src/algorithm/openssl.rs":"45d5252a5a02d9a6e6198e682d59bcdd7624f2d6dc9d16ede5f9774e17deb74d","src/algorithm/rust_crypto.rs":"e518c754d19d3f4cb62fe5c78d3fa673699d8501cf0225cecb49fe4ead68138c","src/algorithm/store.rs":"da6af6dafb6f223020dece153d69d985a9061480e6170b6bb155a2d59bbdf73e","src/claims.rs":"2ab2ac2341a33068e6fb0d5ee57db315caf85cef2eff7fabc91a095a9e5411da","src/error.rs":"ff3f5eda3390d0e53d5241961808fce7fa154d319d7f0bfde6a279ce87865a1f","src/header.rs":"bc542f3355da24d49443b6a82f843a0af78c6bfe236a8ed1c0e0659a4b44eeef","src/lib.rs":"fb17cbadb6c1fc2d4897edc289521ced9c07e6055c373177727067ce7ba384cd","src/token/mod.rs":"afaf57a53d317b026ab0ff9bccede79962a7ac26f06840bbda6b4a5b56e1185e","src/token/signed.rs":"48cba5ae1fae99ba369dfc0414c0d3a8f9c7ad489f0c1875959e6b8dc962c8e4","src/token/verified.rs":"88258dec2a31b5edf1e76d6d985ca5324e1b04ed31033966ea3f203937d69723","test/es256-private.pem":"e78044d6a7e87ebfd6e929e435ffe260bd728a1397b9d7906c8316b08a2bcd91","test/es256-public.pem":"4aa69dafd976d669e58e08734621e84d5248611b61dcdea8c2301f13a897d632","test/rs256-private.pem":"9f0b1cde761836bade73e1dcacc7f59abf361a5a9077c2495549dd78d93827fd","test/rs256-public-2.pem":"1c350b92548ade1a0696678257f95b0f5e96ae006fa794d9781627e92283bb4b","test/rs256-public.pem":"2d2f53a127944dc169e102ef0bf077808211fa26cb750d1272235cdac78aa8c4"},"package":"6204285f77fe7d9784db3fdc449ecce1a0114927a51d5a41c4c7a292011c015f"}

283
zeroidc/vendor/jwt/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,283 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block-buffer"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95"
dependencies = [
"generic-array",
]
[[package]]
name = "cc"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cpufeatures"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0"
dependencies = [
"generic-array",
]
[[package]]
name = "digest"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b"
dependencies = [
"block-buffer",
"crypto-common",
"generic-array",
"subtle",
]
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "hmac"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddca131f3e7f2ce2df364b57949a9d47915cfbd35e46cfee355ccebbf794d6a2"
dependencies = [
"digest",
]
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "jwt"
version = "0.16.0"
dependencies = [
"base64",
"crypto-common",
"digest",
"doc-comment",
"hmac",
"openssl",
"serde",
"serde_json",
"sha2",
]
[[package]]
name = "libc"
version = "0.2.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "openssl"
version = "0.10.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-sys",
]
[[package]]
name = "openssl-sys"
version = "0.9.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82"
dependencies = [
"autocfg",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "pkg-config"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "proc-macro2"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "serde"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha2"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "typenum"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"

54
zeroidc/vendor/jwt/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,54 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
edition = "2018"
name = "jwt"
version = "0.16.0"
authors = ["Michael Yang <mikkyangg@gmail.com>"]
description = "JSON Web Token library"
homepage = "http://github.com/mikkyang/rust-jwt"
documentation = "https://docs.rs/jwt"
readme = "README.md"
keywords = ["JWT", "token", "web"]
license = "MIT"
repository = "http://github.com/mikkyang/rust-jwt"
[package.metadata.docs.rs]
features = ["openssl"]
[dependencies.base64]
version = "0.13"
[dependencies.crypto-common]
version = "0.1"
[dependencies.digest]
version = "0.10"
[dependencies.hmac]
version = "0.12"
features = ["reset"]
[dependencies.openssl]
version = "0.10"
optional = true
[dependencies.serde]
version = "1.0"
features = ["derive"]
[dependencies.serde_json]
version = "1.0"
[dependencies.sha2]
version = "0.10"
[dev-dependencies.doc-comment]
version = "0.3"

22
zeroidc/vendor/jwt/LICENSE vendored Normal file
View File

@@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2015 Michael Yang <mikkyangg@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

150
zeroidc/vendor/jwt/README.md vendored Normal file
View File

@@ -0,0 +1,150 @@
# JWT [![Build Status]][Github Actions] [![Latest Version]][crates.io] [![Documentation]][docs.rs]
[Build Status]: https://github.com/mikkyang/rust-jwt/actions/workflows/rust.yml/badge.svg?branch=master
[Github Actions]: https://github.com/mikkyang/rust-jwt/actions/workflows/rust.yml?query=branch%3Amaster
[Latest Version]: https://img.shields.io/crates/v/jwt.svg
[crates.io]: https://crates.io/crates/jwt
[Documentation]: https://img.shields.io/badge/rust-documentation-blue.svg
[docs.rs]: https://docs.rs/jwt
A JSON Web Token library.
### Only Claims
If you don't care about that header as long as the header is verified, signing
and verification can be done with just a few traits.
#### Signing
Claims can be any `serde::Serialize` type, usually derived with
`serde_derive`.
```rust
use hmac::{Hmac, Mac};
use jwt::SignWithKey;
use sha2::Sha256;
use std::collections::BTreeMap;
let key: Hmac<Sha256> = Hmac::new_from_slice(b"some-secret").unwrap();
let mut claims = BTreeMap::new();
claims.insert("sub", "someone");
let token_str = claims.sign_with_key(&key).unwrap();
assert_eq!(token_str, "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lb25lIn0.5wwE1sBrs-vftww_BGIuTVDeHtc1Jsjo-fiHhDwR8m0");
```
#### Verification
Claims can be any `serde::Deserialize` type, usually derived with
`serde_derive`.
```rust
use hmac::{Hmac, Mac};
use jwt::VerifyWithKey;
use sha2::Sha256;
use std::collections::BTreeMap;
let key: Hmac<Sha256> = Hmac::new_from_slice(b"some-secret").unwrap();
let token_str = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lb25lIn0.5wwE1sBrs-vftww_BGIuTVDeHtc1Jsjo-fiHhDwR8m0";
let claims: BTreeMap<String, String> = token_str.verify_with_key(&key).unwrap();
assert_eq!(claims["sub"], "someone");
```
### Header and Claims
If you need to customize the header, you can use the `Token` struct. For
convenience, a `Header` struct is provided for all of the commonly defined
fields, but any type that implements `JoseHeader` can be used.
#### Signing
Both header and claims have to implement `serde::Serialize`.
```rust
use hmac::{Hmac, Mac};
use jwt::{AlgorithmType, Header, SignWithKey, Token};
use sha2::Sha384;
use std::collections::BTreeMap;
let key: Hmac<Sha384> = Hmac::new_from_slice(b"some-secret").unwrap();
let header = Header {
algorithm: AlgorithmType::Hs384,
..Default::default()
};
let mut claims = BTreeMap::new();
claims.insert("sub", "someone");
let token = Token::new(header, claims).sign_with_key(&key).unwrap();
assert_eq!(token.as_str(), "eyJhbGciOiJIUzM4NCJ9.eyJzdWIiOiJzb21lb25lIn0.WM_WnPUkHK6zm6Wz7zk1kmIxz990Te7nlDjQ3vzcye29szZ-Sj47rLNSTJNzpQd_");
```
#### Verification
Both header and claims have to implement `serde::Deserialize`.
```rust
use hmac::{Hmac, Mac};
use jwt::{AlgorithmType, Header, Token, VerifyWithKey};
use sha2::Sha384;
use std::collections::BTreeMap;
let key: Hmac<Sha384> = Hmac::new_from_slice(b"some-secret").unwrap();
let token_str = "eyJhbGciOiJIUzM4NCJ9.eyJzdWIiOiJzb21lb25lIn0.WM_WnPUkHK6zm6Wz7zk1kmIxz990Te7nlDjQ3vzcye29szZ-Sj47rLNSTJNzpQd_";
let token: Token<Header, BTreeMap<String, String>, _> = VerifyWithKey::verify_with_key(token_str, &key).unwrap();
let header = token.header();
let claims = token.claims();
assert_eq!(header.algorithm, AlgorithmType::Hs384);
assert_eq!(claims["sub"], "someone");
```
### Store
A `Store` can be used to represent a collection of keys indexed by key id. Right now, this is only automatically implemented for `BTreeMap` and `HashMap` with `Borrow<str>` keys. If specialization lands then it will be implemented for all `Index<&str>` traits as it was before.
For the trait `SignWithStore`, the key id will be automatically added to the header for bare claims.
Because claims do not have a way to specify key id, a tuple of key id and claims is necessary. For
tokens, the header's key id will be used to get the key.
For the trait `VerifyWithStore`, the key id from the deserialized header will be used to choose the key
to use.
```rust
use hmac::{Hmac, Mac};
use jwt::{Header, SignWithStore, Token, VerifyWithStore};
use sha2::Sha512;
use std::collections::BTreeMap;
let mut store: BTreeMap<_, Hmac<Sha512>> = BTreeMap::new();
store.insert("first_key", Hmac::new_from_slice(b"first").unwrap());
store.insert("second_key", Hmac::new_from_slice(b"second").unwrap());
let mut claims = BTreeMap::new();
claims.insert("sub", "someone");
let token_str = ("second_key", claims).sign_with_store(&store).unwrap();
assert_eq!(token_str, "eyJhbGciOiJIUzUxMiIsImtpZCI6InNlY29uZF9rZXkifQ.eyJzdWIiOiJzb21lb25lIn0.9gALQon5Mk8r4BjOZ2SJQlauGmT4WUhpN152x9dfKvkPON1VwEN09Id8vjQ0ABlfLJUTVNP36dsdrpYEZDLUcw");
let verified_token: Token<Header, BTreeMap<String, String>, _> = token_str.verify_with_store(&store).unwrap();
assert_eq!(verified_token.claims()["sub"], "someone");
assert_eq!(verified_token.header().key_id.as_ref().unwrap(), "second_key");
```
## Supported Algorithms
Pure Rust HMAC is supported through [RustCrypto](https://github.com/RustCrypto). Implementations of RSA and ECDSA signatures are supported through OpenSSL, which is not enabled by default. OpenSSL types must be wrapped in the [`PKeyWithDigest`](http://mikkyang.github.io/rust-jwt/doc/jwt/algorithm/openssl/struct.PKeyWithDigest.html) struct.
* HS256
* HS384
* HS512
* RS256
* RS384
* RS512
* ES256
* ES384
* ES512

View File

@@ -0,0 +1,50 @@
use hmac::{Hmac, Mac};
use jwt::{Header, SignWithKey, Token, VerifyWithKey};
use serde::{Deserialize, Serialize};
use sha2::Sha256;
#[derive(Default, Deserialize, Serialize)]
struct Custom {
sub: String,
rhino: bool,
}
fn new_token(user_id: &str, password: &str) -> Result<String, &'static str> {
// Dummy auth
if password != "password" {
return Err("Wrong password");
}
let header: Header = Default::default();
let claims = Custom {
sub: user_id.into(),
rhino: true,
};
let unsigned_token = Token::new(header, claims);
let key: Hmac<Sha256> = Hmac::new_from_slice(b"secret_key").map_err(|_e| "Invalid key")?;
let signed_token = unsigned_token
.sign_with_key(&key)
.map_err(|_e| "Sign error")?;
Ok(signed_token.into())
}
fn login(token: &str) -> Result<String, &'static str> {
let key: Hmac<Sha256> = Hmac::new_from_slice(b"secret_key").map_err(|_e| "Invalid key")?;
let token: Token<Header, Custom, _> =
VerifyWithKey::verify_with_key(token, &key).map_err(|_e| "Verification failed")?;
let (_, claims) = token.into();
Ok(claims.sub)
}
fn main() -> Result<(), &'static str> {
let token = new_token("Michael Yang", "password")?;
let logged_in_user = login(&*token)?;
assert_eq!(logged_in_user, "Michael Yang");
Ok(())
}

39
zeroidc/vendor/jwt/examples/hs256.rs vendored Normal file
View File

@@ -0,0 +1,39 @@
use hmac::{Hmac, Mac};
use jwt::{RegisteredClaims, SignWithKey, VerifyWithKey};
use sha2::Sha256;
fn new_token(user_id: &str, password: &str) -> Result<String, &'static str> {
// Dummy auth
if password != "password" {
return Err("Wrong password");
}
let claims = RegisteredClaims {
issuer: Some("mikkyang.com".into()),
subject: Some(user_id.into()),
..Default::default()
};
let key: Hmac<Sha256> = Hmac::new_from_slice(b"secret_key").map_err(|_e| "Invalid key")?;
let signed_token = claims.sign_with_key(&key).map_err(|_e| "Sign failed")?;
Ok(signed_token)
}
fn login(token: &str) -> Result<String, &'static str> {
let key: Hmac<Sha256> = Hmac::new_from_slice(b"secret_key").map_err(|_e| "Invalid key")?;
let claims: RegisteredClaims =
VerifyWithKey::verify_with_key(token, &key).map_err(|_e| "Parse failed")?;
claims.subject.ok_or("Missing subject")
}
fn main() -> Result<(), &'static str> {
let token = new_token("Michael Yang", "password")?;
let logged_in_user = login(&*token)?;
assert_eq!(logged_in_user, "Michael Yang");
Ok(())
}

88
zeroidc/vendor/jwt/src/algorithm/mod.rs vendored Normal file
View File

@@ -0,0 +1,88 @@
//! Algorithms capable of signing and verifying tokens. By default only the
//! `hmac` crate's `Hmac` type is supported. For more algorithms, enable the
//! feature `openssl` and see the [openssl](openssl/index.html)
//! module. The `none` algorithm is explicitly not supported.
//! ## Examples
//! ```
//! use hmac::{Hmac, Mac};
//! use sha2::Sha256;
//!
//! let hs256_key: Hmac<Sha256> = Hmac::new_from_slice(b"some-secret").unwrap();
//! ```
use serde::{Deserialize, Serialize};
use crate::error::Error;
#[cfg(feature = "openssl")]
pub mod openssl;
pub mod rust_crypto;
pub mod store;
/// The type of an algorithm, corresponding to the
/// [JWA](https://tools.ietf.org/html/rfc7518) specification.
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum AlgorithmType {
Hs256,
Hs384,
Hs512,
Rs256,
Rs384,
Rs512,
Es256,
Es384,
Es512,
Ps256,
Ps384,
Ps512,
#[serde(rename = "none")]
None,
}
impl Default for AlgorithmType {
fn default() -> Self {
AlgorithmType::Hs256
}
}
/// An algorithm capable of signing base64 encoded header and claims strings.
/// strings.
pub trait SigningAlgorithm {
fn algorithm_type(&self) -> AlgorithmType;
fn sign(&self, header: &str, claims: &str) -> Result<String, Error>;
}
/// An algorithm capable of verifying base64 encoded header and claims strings.
pub trait VerifyingAlgorithm {
fn algorithm_type(&self) -> AlgorithmType;
fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error>;
fn verify(&self, header: &str, claims: &str, signature: &str) -> Result<bool, Error> {
let signature_bytes = base64::decode_config(signature, base64::URL_SAFE_NO_PAD)?;
self.verify_bytes(header, claims, &*signature_bytes)
}
}
// TODO: investigate if these AsRef impls are necessary
impl<T: AsRef<dyn VerifyingAlgorithm>> VerifyingAlgorithm for T {
fn algorithm_type(&self) -> AlgorithmType {
self.as_ref().algorithm_type()
}
fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
self.as_ref().verify_bytes(header, claims, signature)
}
}
impl<T: AsRef<dyn SigningAlgorithm>> SigningAlgorithm for T {
fn algorithm_type(&self) -> AlgorithmType {
self.as_ref().algorithm_type()
}
fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
self.as_ref().sign(header, claims)
}
}

View File

@@ -0,0 +1,179 @@
//! OpenSSL support through the openssl crate.
//! Note that private keys can only be used for signing and that public keys
//! can only be used for verification.
//! ## Examples
//! ```
//! use jwt::PKeyWithDigest;
//! use openssl::hash::MessageDigest;
//! use openssl::pkey::PKey;
//! let pem = include_bytes!("../../test/rs256-public.pem");
//! let rs256_public_key = PKeyWithDigest {
//! digest: MessageDigest::sha256(),
//! key: PKey::public_key_from_pem(pem).unwrap(),
//! };
//! ```
use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
use crate::error::Error;
use crate::SEPARATOR;
use openssl::bn::BigNum;
use openssl::ecdsa::EcdsaSig;
use openssl::hash::MessageDigest;
use openssl::nid::Nid;
use openssl::pkey::{Id, PKey, Private, Public};
use openssl::sign::{Signer, Verifier};
/// A wrapper class around [PKey](../../../openssl/pkey/struct.PKey.html) that
/// associates the key with a
/// [MessageDigest](../../../openssl/hash/struct.MessageDigest.html).
pub struct PKeyWithDigest<T> {
pub digest: MessageDigest,
pub key: PKey<T>,
}
impl<T> PKeyWithDigest<T> {
fn algorithm_type(&self) -> AlgorithmType {
match (self.key.id(), self.digest.type_()) {
(Id::RSA, Nid::SHA256) => AlgorithmType::Rs256,
(Id::RSA, Nid::SHA384) => AlgorithmType::Rs384,
(Id::RSA, Nid::SHA512) => AlgorithmType::Rs512,
(Id::EC, Nid::SHA256) => AlgorithmType::Es256,
(Id::EC, Nid::SHA384) => AlgorithmType::Es384,
(Id::EC, Nid::SHA512) => AlgorithmType::Es512,
_ => panic!("Invalid algorithm type"),
}
}
}
impl SigningAlgorithm for PKeyWithDigest<Private> {
fn algorithm_type(&self) -> AlgorithmType {
PKeyWithDigest::algorithm_type(self)
}
fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
let mut signer = Signer::new(self.digest.clone(), &self.key)?;
signer.update(header.as_bytes())?;
signer.update(SEPARATOR.as_bytes())?;
signer.update(claims.as_bytes())?;
let signer_signature = signer.sign_to_vec()?;
let signature = if self.key.id() == Id::EC {
der_to_jose(&signer_signature)?
} else {
signer_signature
};
Ok(base64::encode_config(&signature, base64::URL_SAFE_NO_PAD))
}
}
impl VerifyingAlgorithm for PKeyWithDigest<Public> {
fn algorithm_type(&self) -> AlgorithmType {
PKeyWithDigest::algorithm_type(self)
}
fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
let mut verifier = Verifier::new(self.digest.clone(), &self.key)?;
verifier.update(header.as_bytes())?;
verifier.update(SEPARATOR.as_bytes())?;
verifier.update(claims.as_bytes())?;
let verified = if self.key.id() == Id::EC {
let der = jose_to_der(signature)?;
verifier.verify(&der)?
} else {
verifier.verify(signature)?
};
Ok(verified)
}
}
/// OpenSSL by default signs ECDSA in DER, but JOSE expects them in a concatenated (R, S) format
fn der_to_jose(der: &[u8]) -> Result<Vec<u8>, Error> {
let signature = EcdsaSig::from_der(&der)?;
let r = signature.r().to_vec();
let s = signature.s().to_vec();
Ok([r, s].concat())
}
/// OpenSSL by default verifies ECDSA in DER, but JOSE parses out a concatenated (R, S) format
fn jose_to_der(jose: &[u8]) -> Result<Vec<u8>, Error> {
let (r, s) = jose.split_at(jose.len() / 2);
let ecdsa_signature =
EcdsaSig::from_private_components(BigNum::from_slice(r)?, BigNum::from_slice(s)?)?;
Ok(ecdsa_signature.to_der()?)
}
#[cfg(test)]
mod tests {
use crate::algorithm::openssl::PKeyWithDigest;
use crate::algorithm::AlgorithmType::*;
use crate::algorithm::{SigningAlgorithm, VerifyingAlgorithm};
use crate::error::Error;
use crate::header::PrecomputedAlgorithmOnlyHeader as AlgOnly;
use crate::ToBase64;
use openssl::hash::MessageDigest;
use openssl::pkey::PKey;
// {"sub":"1234567890","name":"John Doe","admin":true}
const CLAIMS: &'static str =
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
const RS256_SIGNATURE: &'static str =
"cQsAHF2jHvPGFP5zTD8BgoJrnzEx6JNQCpupebWLFnOc2r_punDDTylI6Ia4JZNkvy2dQP-7W-DEbFQ3oaarHsDndqUgwf9iYlDQxz4Rr2nEZX1FX0-FMEgFPeQpdwveCgjtTYUbVy37ijUySN_rW-xZTrsh_Ug-ica8t-zHRIw";
#[test]
fn rs256_sign() -> Result<(), Error> {
let pem = include_bytes!("../../test/rs256-private.pem");
let algorithm = PKeyWithDigest {
digest: MessageDigest::sha256(),
key: PKey::private_key_from_pem(pem)?,
};
let result = algorithm.sign(&AlgOnly(Rs256).to_base64()?, CLAIMS)?;
assert_eq!(result, RS256_SIGNATURE);
Ok(())
}
#[test]
fn rs256_verify() -> Result<(), Error> {
let pem = include_bytes!("../../test/rs256-public.pem");
let algorithm = PKeyWithDigest {
digest: MessageDigest::sha256(),
key: PKey::public_key_from_pem(pem)?,
};
let verification_result =
algorithm.verify(&AlgOnly(Rs256).to_base64()?, CLAIMS, RS256_SIGNATURE)?;
assert!(verification_result);
Ok(())
}
#[test]
fn es256() -> Result<(), Error> {
let private_pem = include_bytes!("../../test/es256-private.pem");
let private_key = PKeyWithDigest {
digest: MessageDigest::sha256(),
key: PKey::private_key_from_pem(private_pem)?,
};
let signature = private_key.sign(&AlgOnly(Es256).to_base64()?, CLAIMS)?;
let public_pem = include_bytes!("../../test/es256-public.pem");
let public_key = PKeyWithDigest {
digest: MessageDigest::sha256(),
key: PKey::public_key_from_pem(public_pem)?,
};
let verification_result =
public_key.verify(&AlgOnly(Es256).to_base64()?, CLAIMS, &*signature)?;
assert!(verification_result);
Ok(())
}
}

View File

@@ -0,0 +1,138 @@
//! RustCrypto implementations of signing and verifying algorithms.
//! According to that organization, only hmac is safely implemented at the
//! moment.
use digest::{
block_buffer::Eager,
consts::U256,
core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore},
generic_array::typenum::{IsLess, Le, NonZero},
HashMarker,
};
use hmac::{Hmac, Mac};
use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
use crate::error::Error;
use crate::SEPARATOR;
/// A trait used to make the implementation of `SigningAlgorithm` and
/// `VerifyingAlgorithm` easier.
/// RustCrypto crates tend to have algorithm types defined at the type level,
/// so they cannot accept a self argument.
pub trait TypeLevelAlgorithmType {
fn algorithm_type() -> AlgorithmType;
}
macro_rules! type_level_algorithm_type {
($rust_crypto_type: ty, $algorithm_type: expr) => {
impl TypeLevelAlgorithmType for $rust_crypto_type {
fn algorithm_type() -> AlgorithmType {
$algorithm_type
}
}
};
}
type_level_algorithm_type!(sha2::Sha256, AlgorithmType::Hs256);
type_level_algorithm_type!(sha2::Sha384, AlgorithmType::Hs384);
type_level_algorithm_type!(sha2::Sha512, AlgorithmType::Hs512);
impl<D> SigningAlgorithm for Hmac<D>
where
D: CoreProxy + TypeLevelAlgorithmType,
D::Core: HashMarker
+ BufferKindUser<BufferKind = Eager>
+ FixedOutputCore
+ digest::Reset
+ Default
+ Clone,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn algorithm_type(&self) -> AlgorithmType {
D::algorithm_type()
}
fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
let hmac = get_hmac_with_data(self, header, claims);
let mac_result = hmac.finalize();
let code = mac_result.into_bytes();
Ok(base64::encode_config(&code, base64::URL_SAFE_NO_PAD))
}
}
impl<D> VerifyingAlgorithm for Hmac<D>
where
D: CoreProxy + TypeLevelAlgorithmType,
D::Core: HashMarker
+ BufferKindUser<BufferKind = Eager>
+ FixedOutputCore
+ digest::Reset
+ Default
+ Clone,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn algorithm_type(&self) -> AlgorithmType {
D::algorithm_type()
}
fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
let hmac = get_hmac_with_data(self, header, claims);
hmac.verify_slice(signature)?;
Ok(true)
}
}
fn get_hmac_with_data<D>(hmac: &Hmac<D>, header: &str, claims: &str) -> Hmac<D>
where
D: CoreProxy,
D::Core: HashMarker
+ BufferKindUser<BufferKind = Eager>
+ FixedOutputCore
+ digest::Reset
+ Default
+ Clone,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let mut hmac = hmac.clone();
hmac.reset();
hmac.update(header.as_bytes());
hmac.update(SEPARATOR.as_bytes());
hmac.update(claims.as_bytes());
hmac
}
#[cfg(test)]
mod tests {
use crate::algorithm::{SigningAlgorithm, VerifyingAlgorithm};
use crate::error::Error;
use hmac::{Hmac, Mac};
use sha2::Sha256;
#[test]
pub fn sign() -> Result<(), Error> {
let header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
let claims = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
let expected_signature = "TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
let signer: Hmac<Sha256> = Hmac::new_from_slice(b"secret")?;
let computed_signature = SigningAlgorithm::sign(&signer, header, claims)?;
assert_eq!(computed_signature, expected_signature);
Ok(())
}
#[test]
pub fn verify() -> Result<(), Error> {
let header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
let claims = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
let signature = "TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
let verifier: Hmac<Sha256> = Hmac::new_from_slice(b"secret")?;
assert!(VerifyingAlgorithm::verify(
&verifier, header, claims, signature
)?);
Ok(())
}
}

View File

@@ -0,0 +1,32 @@
use std::borrow::Borrow;
use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
/// A store of keys that can be retrieved by key id.
pub trait Store {
type Algorithm: ?Sized;
fn get(&self, key_id: &str) -> Option<&Self::Algorithm>;
}
impl<K, A> Store for BTreeMap<K, A>
where
K: Borrow<str> + Ord,
{
type Algorithm = A;
fn get(&self, key_id: &str) -> Option<&A> {
BTreeMap::get(self, key_id)
}
}
impl<K, A> Store for HashMap<K, A>
where
K: Borrow<str> + Ord + Hash,
{
type Algorithm = A;
fn get(&self, key_id: &str) -> Option<&A> {
HashMap::get(self, key_id)
}
}

92
zeroidc/vendor/jwt/src/claims.rs vendored Normal file
View File

@@ -0,0 +1,92 @@
//! Convenience structs for commonly defined fields in claims.
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
/// Generic [JWT claims](https://tools.ietf.org/html/rfc7519#page-8) with
/// defined fields for registered and private claims.
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Claims {
#[serde(flatten)]
pub registered: RegisteredClaims,
#[serde(flatten)]
pub private: BTreeMap<String, serde_json::Value>,
}
impl Claims {
pub fn new(registered: RegisteredClaims) -> Self {
Claims {
registered,
private: BTreeMap::new(),
}
}
}
pub type SecondsSinceEpoch = u64;
/// Registered claims according to the
/// [JWT specification](https://tools.ietf.org/html/rfc7519#page-9).
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct RegisteredClaims {
#[serde(rename = "iss", skip_serializing_if = "Option::is_none")]
pub issuer: Option<String>,
#[serde(rename = "sub", skip_serializing_if = "Option::is_none")]
pub subject: Option<String>,
#[serde(rename = "aud", skip_serializing_if = "Option::is_none")]
pub audience: Option<String>,
#[serde(rename = "exp", skip_serializing_if = "Option::is_none")]
pub expiration: Option<SecondsSinceEpoch>,
#[serde(rename = "nbf", skip_serializing_if = "Option::is_none")]
pub not_before: Option<SecondsSinceEpoch>,
#[serde(rename = "iat", skip_serializing_if = "Option::is_none")]
pub issued_at: Option<SecondsSinceEpoch>,
#[serde(rename = "jti", skip_serializing_if = "Option::is_none")]
pub json_web_token_id: Option<String>,
}
#[cfg(test)]
mod tests {
use crate::claims::Claims;
use crate::error::Error;
use crate::{FromBase64, ToBase64};
use serde_json::Value;
use std::default::Default;
// {"iss":"mikkyang.com","exp":1302319100,"custom_claim":true}
const ENCODED_PAYLOAD: &str =
"eyJpc3MiOiJtaWtreWFuZy5jb20iLCJleHAiOjEzMDIzMTkxMDAsImN1c3RvbV9jbGFpbSI6dHJ1ZX0K";
#[test]
fn registered_claims() -> Result<(), Error> {
let claims = Claims::from_base64(ENCODED_PAYLOAD)?;
assert_eq!(claims.registered.issuer.unwrap(), "mikkyang.com");
assert_eq!(claims.registered.expiration.unwrap(), 1302319100);
Ok(())
}
#[test]
fn private_claims() -> Result<(), Error> {
let claims = Claims::from_base64(ENCODED_PAYLOAD)?;
assert_eq!(claims.private["custom_claim"], Value::Bool(true));
Ok(())
}
#[test]
fn roundtrip() -> Result<(), Error> {
let mut claims: Claims = Default::default();
claims.registered.issuer = Some("mikkyang.com".into());
claims.registered.expiration = Some(1302319100);
let enc = claims.to_base64()?;
assert_eq!(claims, Claims::from_base64(&*enc)?);
Ok(())
}
}

75
zeroidc/vendor/jwt/src/error.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
use std::fmt;
use std::string::FromUtf8Error;
use base64::DecodeError;
use crypto_common::InvalidLength;
use digest::MacError;
use serde_json::Error as JsonError;
use self::Error::*;
use crate::algorithm::AlgorithmType;
#[derive(Debug)]
pub enum Error {
AlgorithmMismatch(AlgorithmType, AlgorithmType),
Base64(DecodeError),
Format,
InvalidSignature,
Json(JsonError),
NoClaimsComponent,
NoHeaderComponent,
NoKeyId,
NoKeyWithKeyId(String),
NoSignatureComponent,
RustCryptoMac(MacError),
RustCryptoMacKeyLength(InvalidLength),
TooManyComponents,
Utf8(FromUtf8Error),
#[cfg(feature = "openssl")]
OpenSsl(openssl::error::ErrorStack),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
AlgorithmMismatch(a, b) => {
write!(f, "Expected algorithm type {:?} but found {:?}", a, b)
}
NoKeyId => write!(f, "No key id found"),
NoKeyWithKeyId(ref kid) => write!(f, "Key with key id {} not found", kid),
NoHeaderComponent => write!(f, "No header component found in token string"),
NoClaimsComponent => write!(f, "No claims component found in token string"),
NoSignatureComponent => write!(f, "No signature component found in token string"),
TooManyComponents => write!(f, "Too many components found in token string"),
Format => write!(f, "Format"),
InvalidSignature => write!(f, "Invalid signature"),
Base64(ref x) => write!(f, "{}", x),
Json(ref x) => write!(f, "{}", x),
Utf8(ref x) => write!(f, "{}", x),
RustCryptoMac(ref x) => write!(f, "{}", x),
RustCryptoMacKeyLength(ref x) => write!(f, "{}", x),
#[cfg(feature = "openssl")]
OpenSsl(ref x) => write!(f, "{}", x),
}
}
}
impl std::error::Error for Error {}
macro_rules! error_wrap {
($f:ty, $e:expr) => {
impl From<$f> for Error {
fn from(f: $f) -> Error {
$e(f)
}
}
};
}
error_wrap!(DecodeError, Base64);
error_wrap!(JsonError, Json);
error_wrap!(FromUtf8Error, Utf8);
error_wrap!(MacError, RustCryptoMac);
error_wrap!(InvalidLength, RustCryptoMacKeyLength);
#[cfg(feature = "openssl")]
error_wrap!(openssl::error::ErrorStack, Error::OpenSsl);

191
zeroidc/vendor/jwt/src/header.rs vendored Normal file
View File

@@ -0,0 +1,191 @@
//! Convenience structs for commonly defined fields in headers.
use std::borrow::Cow;
use serde::{Deserialize, Serialize};
use crate::algorithm::AlgorithmType;
use crate::error::Error;
use crate::ToBase64;
/// A trait for any header than can conform to the
/// [JWT specification](https://tools.ietf.org/html/rfc7519#page-11).
pub trait JoseHeader {
fn algorithm_type(&self) -> AlgorithmType;
fn key_id(&self) -> Option<&str> {
None
}
fn type_(&self) -> Option<HeaderType> {
None
}
fn content_type(&self) -> Option<HeaderContentType> {
None
}
}
/// Generic [JWT header](https://tools.ietf.org/html/rfc7519#page-11) with
/// defined fields for common fields.
#[derive(Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct Header {
#[serde(rename = "alg")]
pub algorithm: AlgorithmType,
#[serde(rename = "kid", skip_serializing_if = "Option::is_none")]
pub key_id: Option<String>,
#[serde(rename = "typ", skip_serializing_if = "Option::is_none")]
pub type_: Option<HeaderType>,
#[serde(rename = "cty", skip_serializing_if = "Option::is_none")]
pub content_type: Option<HeaderContentType>,
}
impl JoseHeader for Header {
fn algorithm_type(&self) -> AlgorithmType {
self.algorithm
}
fn key_id(&self) -> Option<&str> {
self.key_id.as_deref()
}
fn type_(&self) -> Option<HeaderType> {
self.type_
}
fn content_type(&self) -> Option<HeaderContentType> {
self.content_type
}
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum HeaderType {
#[serde(rename = "JWT")]
JsonWebToken,
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum HeaderContentType {
#[serde(rename = "JWT")]
JsonWebToken,
}
/// A header that only contains the algorithm type. The `ToBase64`
/// implementation uses static strings for faster serialization.
pub struct PrecomputedAlgorithmOnlyHeader(pub AlgorithmType);
impl JoseHeader for PrecomputedAlgorithmOnlyHeader {
fn algorithm_type(&self) -> AlgorithmType {
let PrecomputedAlgorithmOnlyHeader(algorithm_type) = *self;
algorithm_type
}
}
impl ToBase64 for PrecomputedAlgorithmOnlyHeader {
fn to_base64(&self) -> Result<Cow<'static, str>, Error> {
let precomputed_str = match self.algorithm_type() {
AlgorithmType::Hs256 => "eyJhbGciOiAiSFMyNTYifQ",
AlgorithmType::Hs384 => "eyJhbGciOiAiSFMzODQifQ",
AlgorithmType::Hs512 => "eyJhbGciOiAiSFM1MTIifQ",
AlgorithmType::Rs256 => "eyJhbGciOiAiUlMyNTYifQ",
AlgorithmType::Rs384 => "eyJhbGciOiAiUlMzODQifQ",
AlgorithmType::Rs512 => "eyJhbGciOiAiUlM1MTIifQ",
AlgorithmType::Es256 => "eyJhbGciOiAiRVMyNTYifQ",
AlgorithmType::Es384 => "eyJhbGciOiAiRVMzODQifQ",
AlgorithmType::Es512 => "eyJhbGciOiAiRVM1MTIifQ",
AlgorithmType::Ps256 => "eyJhbGciOiAiUFMyNTYifQ",
AlgorithmType::Ps384 => "eyJhbGciOiAiUFMzODQifQ",
AlgorithmType::Ps512 => "eyJhbGciOiAiUFM1MTIifQ",
AlgorithmType::None => "eyJhbGciOiAibm9uZSJ9Cg",
};
Ok(Cow::Borrowed(precomputed_str))
}
}
/// A header with a borrowed key. Used for signing claims with a Store
/// conveniently.
#[derive(Serialize)]
pub(crate) struct BorrowedKeyHeader<'a> {
#[serde(rename = "alg")]
pub algorithm: AlgorithmType,
#[serde(rename = "kid")]
pub key_id: &'a str,
}
impl<'a> JoseHeader for BorrowedKeyHeader<'a> {
fn algorithm_type(&self) -> AlgorithmType {
self.algorithm
}
fn key_id(&self) -> Option<&str> {
Some(self.key_id)
}
}
#[cfg(test)]
mod tests {
use crate::algorithm::AlgorithmType;
use crate::error::Error;
use crate::header::{Header, HeaderType, PrecomputedAlgorithmOnlyHeader};
use crate::{FromBase64, ToBase64};
#[test]
fn from_base64() -> Result<(), Error> {
let enc = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
let header = Header::from_base64(enc)?;
assert_eq!(header.type_.unwrap(), HeaderType::JsonWebToken);
assert_eq!(header.algorithm, AlgorithmType::Hs256);
let enc = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFLU0YzZyJ9";
let header = Header::from_base64(enc)?;
assert_eq!(header.key_id.unwrap(), "1KSF3g".to_string());
assert_eq!(header.algorithm, AlgorithmType::Rs256);
Ok(())
}
#[test]
fn roundtrip() -> Result<(), Error> {
let header: Header = Default::default();
let enc = header.to_base64()?;
assert_eq!(header, Header::from_base64(&*enc)?);
Ok(())
}
#[test]
fn precomputed_headers() -> Result<(), Error> {
let algorithms = [
AlgorithmType::Hs256,
AlgorithmType::Hs384,
AlgorithmType::Hs512,
AlgorithmType::Rs256,
AlgorithmType::Rs384,
AlgorithmType::Rs512,
AlgorithmType::Es256,
AlgorithmType::Es384,
AlgorithmType::Es512,
AlgorithmType::Ps256,
AlgorithmType::Ps384,
AlgorithmType::Ps512,
AlgorithmType::None,
];
for algorithm in algorithms.iter() {
let precomputed = PrecomputedAlgorithmOnlyHeader(*algorithm);
let precomputed_str = precomputed.to_base64()?;
let header = Header::from_base64(&*precomputed_str)?;
assert_eq!(*algorithm, header.algorithm);
}
Ok(())
}
}

228
zeroidc/vendor/jwt/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,228 @@
//! ### Only Claims
//! If you don't care about that header as long as the header is verified, signing
//! and verification can be done with just a few traits.
//! #### Signing
//! Claims can be any `serde::Serialize` type, usually derived with
//! `serde_derive`.
//! ```rust
//! use hmac::{Hmac, Mac};
//! use jwt::SignWithKey;
//! use sha2::Sha256;
//! use std::collections::BTreeMap;
//!
//! # use jwt::Error;
//! # fn try_main() -> Result<(), Error> {
//! let key: Hmac<Sha256> = Hmac::new_from_slice(b"some-secret")?;
//! let mut claims = BTreeMap::new();
//! claims.insert("sub", "someone");
//! let token_str = claims.sign_with_key(&key)?;
//! assert_eq!(token_str, "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lb25lIn0.5wwE1sBrs-vftww_BGIuTVDeHtc1Jsjo-fiHhDwR8m0");
//! # Ok(())
//! # }
//! # try_main().unwrap()
//! ```
//! #### Verification
//! Claims can be any `serde::Deserialize` type, usually derived with
//! `serde_derive`.
//! ```rust
//! use hmac::{Hmac, Mac};
//! use jwt::VerifyWithKey;
//! use sha2::Sha256;
//! use std::collections::BTreeMap;
//!
//! # use jwt::Error;
//! # fn try_main() -> Result<(), Error> {
//! let key: Hmac<Sha256> = Hmac::new_from_slice(b"some-secret")?;
//! let token_str = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lb25lIn0.5wwE1sBrs-vftww_BGIuTVDeHtc1Jsjo-fiHhDwR8m0";
//! let claims: BTreeMap<String, String> = token_str.verify_with_key(&key)?;
//! assert_eq!(claims["sub"], "someone");
//! # Ok(())
//! # }
//! # try_main().unwrap()
//! ```
//! ### Header and Claims
//! If you need to customize the header, you can use the `Token` struct. For
//! convenience, a `Header` struct is provided for all of the commonly defined
//! fields, but any type that implements `JoseHeader` can be used.
//! #### Signing
//! Both header and claims have to implement `serde::Serialize`.
//! ```rust
//! use hmac::{Hmac, Mac};
//! use jwt::{AlgorithmType, Header, SignWithKey, Token};
//! use sha2::Sha384;
//! use std::collections::BTreeMap;
//!
//! # use jwt::Error;
//! # fn try_main() -> Result<(), Error> {
//! let key: Hmac<Sha384> = Hmac::new_from_slice(b"some-secret")?;
//! let header = Header {
//! algorithm: AlgorithmType::Hs384,
//! ..Default::default()
//! };
//! let mut claims = BTreeMap::new();
//! claims.insert("sub", "someone");
//! let token = Token::new(header, claims).sign_with_key(&key)?;
//! assert_eq!(token.as_str(), "eyJhbGciOiJIUzM4NCJ9.eyJzdWIiOiJzb21lb25lIn0.WM_WnPUkHK6zm6Wz7zk1kmIxz990Te7nlDjQ3vzcye29szZ-Sj47rLNSTJNzpQd_");
//! # Ok(())
//! # }
//! # try_main().unwrap()
//! ```
//! #### Verification
//! Both header and claims have to implement `serde::Deserialize`.
//! ```rust
//! use hmac::{Hmac, Mac};
//! use jwt::{AlgorithmType, Header, Token, VerifyWithKey};
//! use sha2::Sha384;
//! use std::collections::BTreeMap;
//!
//! # use jwt::Error;
//! # fn try_main() -> Result<(), Error> {
//! let key: Hmac<Sha384> = Hmac::new_from_slice(b"some-secret")?;
//! let token_str = "eyJhbGciOiJIUzM4NCJ9.eyJzdWIiOiJzb21lb25lIn0.WM_WnPUkHK6zm6Wz7zk1kmIxz990Te7nlDjQ3vzcye29szZ-Sj47rLNSTJNzpQd_";
//! let token: Token<Header, BTreeMap<String, String>, _> = token_str.verify_with_key(&key)?;
//! let header = token.header();
//! let claims = token.claims();
//! assert_eq!(header.algorithm, AlgorithmType::Hs384);
//! assert_eq!(claims["sub"], "someone");
//! # Ok(())
//! # }
//! # try_main().unwrap()
//! ```
#[cfg(doctest)]
doctest!("../README.md");
use std::borrow::Cow;
#[cfg(doctest)]
use doc_comment::doctest;
use serde::{Deserialize, Serialize};
#[cfg(feature = "openssl")]
pub use crate::algorithm::openssl::PKeyWithDigest;
pub use crate::algorithm::store::Store;
pub use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
pub use crate::claims::Claims;
pub use crate::claims::RegisteredClaims;
pub use crate::error::Error;
pub use crate::header::{Header, JoseHeader};
pub use crate::token::signed::{SignWithKey, SignWithStore};
pub use crate::token::verified::{VerifyWithKey, VerifyWithStore};
pub use crate::token::{Unsigned, Unverified, Verified};
pub mod algorithm;
pub mod claims;
pub mod error;
pub mod header;
pub mod token;
const SEPARATOR: &str = ".";
/// Representation of a structured JWT. Methods vary based on the signature
/// type `S`.
pub struct Token<H, C, S> {
header: H,
claims: C,
signature: S,
}
impl<H, C, S> Token<H, C, S> {
pub fn header(&self) -> &H {
&self.header
}
pub fn claims(&self) -> &C {
&self.claims
}
pub fn remove_signature(self) -> Token<H, C, Unsigned> {
Token {
header: self.header,
claims: self.claims,
signature: Unsigned,
}
}
}
impl<H, C, S> From<Token<H, C, S>> for (H, C) {
fn from(token: Token<H, C, S>) -> Self {
(token.header, token.claims)
}
}
/// A trait used to convert objects in base64 encoding. The return type can
/// be either owned if the header is dynamic, or it can be borrowed if the
/// header is a static, pre-computed value. It is implemented automatically
/// for every type that implements
/// [Serialize](../../serde/trait.Serialize.html). as a base64 encoding of
/// the object's JSON representation.
pub trait ToBase64 {
fn to_base64(&self) -> Result<Cow<str>, Error>;
}
impl<T: Serialize> ToBase64 for T {
fn to_base64(&self) -> Result<Cow<str>, Error> {
let json_bytes = serde_json::to_vec(&self)?;
let encoded_json_bytes = base64::encode_config(&json_bytes, base64::URL_SAFE_NO_PAD);
Ok(Cow::Owned(encoded_json_bytes))
}
}
/// A trait used to parse objects from base64 encoding. The return type can
/// be either owned if the header is dynamic, or it can be borrowed if the
/// header is a static, pre-computed value. It is implemented automatically
/// for every type that implements
/// [DeserializeOwned](../../serde/trait.Deserialize.html) for
/// the base64 encoded JSON representation.
pub trait FromBase64: Sized {
fn from_base64<Input: ?Sized + AsRef<[u8]>>(raw: &Input) -> Result<Self, Error>;
}
impl<T: for<'de> Deserialize<'de> + Sized> FromBase64 for T {
fn from_base64<Input: ?Sized + AsRef<[u8]>>(raw: &Input) -> Result<Self, Error> {
let json_bytes = base64::decode_config(raw, base64::URL_SAFE_NO_PAD)?;
Ok(serde_json::from_slice(&json_bytes)?)
}
}
#[cfg(test)]
mod tests {
use crate::algorithm::AlgorithmType::Hs256;
use crate::error::Error;
use crate::header::Header;
use crate::token::signed::SignWithKey;
use crate::token::verified::VerifyWithKey;
use crate::Claims;
use crate::Token;
use hmac::Hmac;
use hmac::Mac;
use sha2::Sha256;
#[test]
pub fn raw_data() -> Result<(), Error> {
let raw = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
let token: Token<Header, Claims, _> = Token::parse_unverified(raw)?;
assert_eq!(token.header.algorithm, Hs256);
let verifier: Hmac<Sha256> = Hmac::new_from_slice(b"secret")?;
assert!(token.verify_with_key(&verifier).is_ok());
Ok(())
}
#[test]
pub fn roundtrip() -> Result<(), Error> {
let token: Token<Header, Claims, _> = Default::default();
let key: Hmac<Sha256> = Hmac::new_from_slice(b"secret")?;
let signed_token = token.sign_with_key(&key)?;
let signed_token_str = signed_token.as_str();
let recreated_token: Token<Header, Claims, _> = Token::parse_unverified(signed_token_str)?;
assert_eq!(signed_token.header(), recreated_token.header());
assert_eq!(signed_token.claims(), recreated_token.claims());
recreated_token.verify_with_key(&key)?;
Ok(())
}
}

18
zeroidc/vendor/jwt/src/token/mod.rs vendored Normal file
View File

@@ -0,0 +1,18 @@
//! A structured representation of a JWT.
pub mod signed;
pub mod verified;
pub struct Unsigned;
pub struct Signed {
pub token_string: String,
}
pub struct Verified;
pub struct Unverified<'a> {
pub header_str: &'a str,
pub claims_str: &'a str,
pub signature_str: &'a str,
}

190
zeroidc/vendor/jwt/src/token/signed.rs vendored Normal file
View File

@@ -0,0 +1,190 @@
use crate::algorithm::store::Store;
use crate::algorithm::SigningAlgorithm;
use crate::error::Error;
use crate::header::{BorrowedKeyHeader, Header, JoseHeader};
use crate::token::{Signed, Unsigned};
use crate::{ToBase64, Token, SEPARATOR};
/// Allow objects to be signed with a key.
pub trait SignWithKey<T> {
fn sign_with_key(self, key: &impl SigningAlgorithm) -> Result<T, Error>;
}
/// Allow objects to be signed with a store.
pub trait SignWithStore<T> {
fn sign_with_store<S, A>(self, store: &S) -> Result<T, Error>
where
S: Store<Algorithm = A>,
A: SigningAlgorithm;
}
impl<H, C> Token<H, C, Unsigned> {
/// Create a new unsigned token, with mutable headers and claims.
pub fn new(header: H, claims: C) -> Self {
Token {
header,
claims,
signature: Unsigned,
}
}
pub fn header_mut(&mut self) -> &mut H {
&mut self.header
}
pub fn claims_mut(&mut self) -> &mut C {
&mut self.claims
}
}
impl<H, C> Default for Token<H, C, Unsigned>
where
H: Default,
C: Default,
{
fn default() -> Self {
Token::new(H::default(), C::default())
}
}
impl<C: ToBase64> SignWithKey<String> for C {
fn sign_with_key(self, key: &impl SigningAlgorithm) -> Result<String, Error> {
let header = Header {
algorithm: key.algorithm_type(),
..Default::default()
};
let token = Token::new(header, self).sign_with_key(key)?;
Ok(token.signature.token_string)
}
}
impl<'a, C: ToBase64> SignWithStore<String> for (&'a str, C) {
fn sign_with_store<S, A>(self, store: &S) -> Result<String, Error>
where
S: Store<Algorithm = A>,
A: SigningAlgorithm,
{
let (key_id, claims) = self;
let key = store
.get(key_id)
.ok_or_else(|| Error::NoKeyWithKeyId(key_id.to_owned()))?;
let header = BorrowedKeyHeader {
algorithm: key.algorithm_type(),
key_id,
};
let token = Token::new(header, claims).sign_with_key(key)?;
Ok(token.signature.token_string)
}
}
impl<H, C> SignWithKey<Token<H, C, Signed>> for Token<H, C, Unsigned>
where
H: ToBase64 + JoseHeader,
C: ToBase64,
{
fn sign_with_key(self, key: &impl SigningAlgorithm) -> Result<Token<H, C, Signed>, Error> {
let header_algorithm = self.header.algorithm_type();
let key_algorithm = key.algorithm_type();
if header_algorithm != key_algorithm {
return Err(Error::AlgorithmMismatch(header_algorithm, key_algorithm));
}
let header = self.header.to_base64()?;
let claims = self.claims.to_base64()?;
let signature = key.sign(&header, &claims)?;
let token_string = [&*header, &*claims, &signature].join(SEPARATOR);
Ok(Token {
header: self.header,
claims: self.claims,
signature: Signed { token_string },
})
}
}
impl<H, C> SignWithStore<Token<H, C, Signed>> for Token<H, C, Unsigned>
where
H: ToBase64 + JoseHeader,
C: ToBase64,
{
fn sign_with_store<S, A>(self, store: &S) -> Result<Token<H, C, Signed>, Error>
where
S: Store<Algorithm = A>,
A: SigningAlgorithm,
{
let key_id = self.header.key_id().ok_or(Error::NoKeyId)?;
let key = store
.get(key_id)
.ok_or_else(|| Error::NoKeyWithKeyId(key_id.to_owned()))?;
self.sign_with_key(key)
}
}
impl<'a, H, C> Token<H, C, Signed> {
/// Get the string representation of the token.
pub fn as_str(&self) -> &str {
&self.signature.token_string
}
}
impl<H, C> From<Token<H, C, Signed>> for String {
fn from(token: Token<H, C, Signed>) -> Self {
token.signature.token_string
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use hmac::{Hmac, Mac};
use serde::Serialize;
use sha2::{Sha256, Sha512};
use crate::algorithm::AlgorithmType;
use crate::error::Error;
use crate::header::Header;
use crate::token::signed::{SignWithKey, SignWithStore};
use crate::Token;
#[derive(Serialize)]
struct Claims<'a> {
name: &'a str,
}
#[test]
pub fn sign_claims() -> Result<(), Error> {
let claims = Claims { name: "John Doe" };
let key: Hmac<Sha256> = Hmac::new_from_slice(b"secret")?;
let signed_token = claims.sign_with_key(&key)?;
assert_eq!(signed_token, "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiSm9obiBEb2UifQ.LlTGHPZRXbci-y349jXXN0byQniQQqwKGybzQCFIgY0");
Ok(())
}
#[test]
pub fn sign_unsigned_with_store() -> Result<(), Error> {
let mut key_store = BTreeMap::new();
let key1: Hmac<Sha512> = Hmac::new_from_slice(b"first")?;
let key2: Hmac<Sha512> = Hmac::new_from_slice(b"second")?;
key_store.insert("first_key".to_owned(), key1);
key_store.insert("second_key".to_owned(), key2);
let header = Header {
algorithm: AlgorithmType::Hs512,
key_id: Some(String::from("second_key")),
..Default::default()
};
let claims = Claims { name: "Jane Doe" };
let token = Token::new(header, claims);
let signed_token = token.sign_with_store(&key_store)?;
assert_eq!(signed_token.as_str(), "eyJhbGciOiJIUzUxMiIsImtpZCI6InNlY29uZF9rZXkifQ.eyJuYW1lIjoiSmFuZSBEb2UifQ.t2ON5s8DDb2hefBIWAe0jaEcp-T7b2Wevmj0kKJ8BFxKNQURHpdh4IA-wbmBmqtiCnqTGoRdqK45hhW0AOtz0A");
Ok(())
}
}

289
zeroidc/vendor/jwt/src/token/verified.rs vendored Normal file
View File

@@ -0,0 +1,289 @@
use crate::algorithm::store::Store;
use crate::algorithm::VerifyingAlgorithm;
use crate::error::Error;
use crate::header::{Header, JoseHeader};
use crate::token::{Unverified, Verified};
use crate::{FromBase64, Token, SEPARATOR};
/// Allow objects to be verified with a key.
pub trait VerifyWithKey<T> {
fn verify_with_key(self, key: &impl VerifyingAlgorithm) -> Result<T, Error>;
}
/// Allow objects to be verified with a store.
pub trait VerifyWithStore<T> {
fn verify_with_store<S, A>(self, store: &S) -> Result<T, Error>
where
S: Store<Algorithm = A>,
A: VerifyingAlgorithm;
}
impl<'a, H: JoseHeader, C> VerifyWithKey<Token<H, C, Verified>> for Token<H, C, Unverified<'a>> {
fn verify_with_key(
self,
key: &impl VerifyingAlgorithm,
) -> Result<Token<H, C, Verified>, Error> {
let header = self.header();
let header_algorithm = header.algorithm_type();
let key_algorithm = key.algorithm_type();
if header_algorithm != key_algorithm {
return Err(Error::AlgorithmMismatch(header_algorithm, key_algorithm));
}
let Unverified {
header_str,
claims_str,
signature_str,
} = self.signature;
if key.verify(header_str, claims_str, signature_str)? {
Ok(Token {
header: self.header,
claims: self.claims,
signature: Verified,
})
} else {
Err(Error::InvalidSignature)
}
}
}
impl<'a, H: JoseHeader, C> VerifyWithStore<Token<H, C, Verified>> for Token<H, C, Unverified<'a>> {
fn verify_with_store<S, A>(self, store: &S) -> Result<Token<H, C, Verified>, Error>
where
S: Store<Algorithm = A>,
A: VerifyingAlgorithm,
{
let header = self.header();
let key_id = header.key_id().ok_or(Error::NoKeyId)?;
let key = store
.get(key_id)
.ok_or_else(|| Error::NoKeyWithKeyId(key_id.to_owned()))?;
self.verify_with_key(key)
}
}
impl<'a, H, C> VerifyWithKey<Token<H, C, Verified>> for &'a str
where
H: FromBase64 + JoseHeader,
C: FromBase64,
{
fn verify_with_key(
self,
key: &impl VerifyingAlgorithm,
) -> Result<Token<H, C, Verified>, Error> {
let unverified = Token::parse_unverified(self)?;
unverified.verify_with_key(key)
}
}
impl<'a, H, C> VerifyWithStore<Token<H, C, Verified>> for &'a str
where
H: FromBase64 + JoseHeader,
C: FromBase64,
{
fn verify_with_store<S, A>(self, store: &S) -> Result<Token<H, C, Verified>, Error>
where
S: Store<Algorithm = A>,
A: VerifyingAlgorithm,
{
let unverified: Token<H, C, _> = Token::parse_unverified(self)?;
unverified.verify_with_store(store)
}
}
impl<'a, C: FromBase64> VerifyWithKey<C> for &'a str {
fn verify_with_key(self, key: &impl VerifyingAlgorithm) -> Result<C, Error> {
let token: Token<Header, C, _> = self.verify_with_key(key)?;
Ok(token.claims)
}
}
impl<'a, C: FromBase64> VerifyWithStore<C> for &'a str {
fn verify_with_store<S, A>(self, store: &S) -> Result<C, Error>
where
S: Store<Algorithm = A>,
A: VerifyingAlgorithm,
{
let token: Token<Header, C, _> = self.verify_with_store(store)?;
Ok(token.claims)
}
}
impl<'a, H: FromBase64, C: FromBase64> Token<H, C, Unverified<'a>> {
/// Not recommended. Parse the header and claims without checking the validity of the signature.
pub fn parse_unverified(token_str: &str) -> Result<Token<H, C, Unverified>, Error> {
let [header_str, claims_str, signature_str] = split_components(token_str)?;
let header = H::from_base64(header_str)?;
let claims = C::from_base64(claims_str)?;
let signature = Unverified {
header_str,
claims_str,
signature_str,
};
Ok(Token {
header,
claims,
signature,
})
}
}
pub(crate) fn split_components(token: &str) -> Result<[&str; 3], Error> {
let mut components = token.split(SEPARATOR);
let header = components.next().ok_or(Error::NoHeaderComponent)?;
let claims = components.next().ok_or(Error::NoClaimsComponent)?;
let signature = components.next().ok_or(Error::NoSignatureComponent)?;
if components.next().is_some() {
return Err(Error::TooManyComponents);
}
Ok([header, claims, signature])
}
#[cfg(test)]
mod tests {
use std::collections::{BTreeMap, HashMap};
use std::iter::FromIterator;
use hmac::{Hmac, Mac};
use serde::Deserialize;
use sha2::{Sha256, Sha512};
use crate::algorithm::VerifyingAlgorithm;
use crate::error::Error;
use crate::token::verified::{VerifyWithKey, VerifyWithStore};
#[derive(Debug, Deserialize)]
struct Claims {
name: String,
}
#[test]
#[cfg(feature = "openssl")]
pub fn token_can_not_be_verified_with_a_wrong_key() -> Result<(), Error> {
use crate::{token::signed::SignWithKey, AlgorithmType, Header, PKeyWithDigest, Token};
use openssl::{hash::MessageDigest, pkey::PKey};
let private_pem = include_bytes!("../../test/rs256-private.pem");
let public_pem = include_bytes!("../../test/rs256-public-2.pem");
let rs256_private_key = PKeyWithDigest {
digest: MessageDigest::sha256(),
key: PKey::private_key_from_pem(private_pem).unwrap(),
};
let rs256_public_key = PKeyWithDigest {
digest: MessageDigest::sha256(),
key: PKey::public_key_from_pem(public_pem).unwrap(),
};
let header = Header {
algorithm: AlgorithmType::Rs256,
..Default::default()
};
let mut claims = BTreeMap::new();
claims.insert("sub", "someone");
let signed_token = Token::new(header, claims).sign_with_key(&rs256_private_key)?;
let token_str = signed_token.as_str();
let unverified_token: Token<Header, BTreeMap<String, String>, _> =
Token::parse_unverified(token_str)?;
let verified_token_result = unverified_token.verify_with_key(&rs256_public_key);
assert!(verified_token_result.is_err());
match verified_token_result.err().unwrap() {
Error::InvalidSignature => Ok(()),
other => panic!("Wrong error type: {:?}", other),
}
}
#[test]
pub fn component_errors() {
let key: Hmac<Sha256> = Hmac::new_from_slice(b"first").unwrap();
let no_claims = "header";
match VerifyWithKey::<String>::verify_with_key(no_claims, &key) {
Err(Error::NoClaimsComponent) => (),
Ok(s) => panic!("Verify should not have succeeded with output {:?}", s),
x => panic!("Incorrect error type {:?}", x),
}
let no_signature = "header.claims";
match VerifyWithKey::<String>::verify_with_key(no_signature, &key) {
Err(Error::NoSignatureComponent) => (),
Ok(s) => panic!("Verify should not have succeeded with output {:?}", s),
x => panic!("Incorrect error type {:?}", x),
}
let too_many = "header.claims.signature.";
match VerifyWithKey::<String>::verify_with_key(too_many, &key) {
Err(Error::TooManyComponents) => (),
Ok(s) => panic!("Verify should not have succeeded with output {:?}", s),
x => panic!("Incorrect error type {:?}", x),
}
}
// Test stores
fn create_test_data<T>() -> Result<T, Error>
where
T: FromIterator<(&'static str, Box<dyn VerifyingAlgorithm>)>,
{
// Test two different algorithms in the same store
let key1: Hmac<Sha256> = Hmac::new_from_slice(b"first")?;
let key2: Hmac<Sha512> = Hmac::new_from_slice(b"second")?;
let name_to_key_tuples = vec![
("first_key", Box::new(key1) as Box<dyn VerifyingAlgorithm>),
("second_key", Box::new(key2) as Box<dyn VerifyingAlgorithm>),
]
.into_iter()
.collect();
Ok(name_to_key_tuples)
}
// Header {"alg":"HS512","kid":"second_key"}
// Claims {"name":"Jane Doe"}
const JANE_DOE_SECOND_KEY_TOKEN: &str = "eyJhbGciOiJIUzUxMiIsImtpZCI6InNlY29uZF9rZXkifQ.eyJuYW1lIjoiSmFuZSBEb2UifQ.t2ON5s8DDb2hefBIWAe0jaEcp-T7b2Wevmj0kKJ8BFxKNQURHpdh4IA-wbmBmqtiCnqTGoRdqK45hhW0AOtz0A";
#[test]
pub fn verify_claims_with_b_tree_map() -> Result<(), Error> {
let key_store: BTreeMap<_, _> = create_test_data()?;
let claims: Claims = JANE_DOE_SECOND_KEY_TOKEN.verify_with_store(&key_store)?;
assert_eq!(claims.name, "Jane Doe");
Ok(())
}
#[test]
pub fn verify_claims_with_hash_map() -> Result<(), Error> {
let key_store: HashMap<_, _> = create_test_data()?;
let claims: Claims = JANE_DOE_SECOND_KEY_TOKEN.verify_with_store(&key_store)?;
assert_eq!(claims.name, "Jane Doe");
Ok(())
}
#[test]
pub fn verify_claims_with_missing_key() -> Result<(), Error> {
let key_store: BTreeMap<_, _> = create_test_data()?;
let missing_key_token = "eyJhbGciOiJIUzUxMiIsImtpZCI6Im1pc3Npbmdfa2V5In0.eyJuYW1lIjoiSmFuZSBEb2UifQ.MC9hmBjv9OABdv5bsjVdwUgPOhvpe6a924KU-U7PjVWF2N-f_HXa1PVWtDVJ-dqt1GKutVwixrz7hgVvE_G5_w";
let should_fail_claims: Result<Claims, _> = missing_key_token.verify_with_store(&key_store);
match should_fail_claims {
Err(Error::NoKeyWithKeyId(key_id)) => assert_eq!(key_id, "missing_key"),
_ => panic!(
"Missing key should have triggered specific error but returned {:?}",
should_fail_claims
),
}
Ok(())
}
}

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDaCNjB5eSARlkILmSrpnfoI8TYi7tJ7xzpy4Bb1D6HVoAoGCCqGSM49
AwEHoUQDQgAEU9PK2chNDTNdJygt1lkhLwuhLOkcuG90J5kHbnHNC/PG9ww1D7q0
d9dWWzfRfZfx3Duw+3j8NnBt6zBgnUG5Uw==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEU9PK2chNDTNdJygt1lkhLwuhLOkc
uG90J5kHbnHNC/PG9ww1D7q0d9dWWzfRfZfx3Duw+3j8NnBt6zBgnUG5Uw==
-----END PUBLIC KEY-----

View File

@@ -0,0 +1,3 @@
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQABAoGAD+onAtVye4ic7VR7V50DF9bOnwRwNXrARcDhq9LWNRrRGElESYYTQ6EbatXS3MCyjjX2eMhu/aF5YhXBwkppwxg+EOmXeh+MzL7Zh284OuPbkglAaGhV9bb6/5CpuGb1esyPbYW+Ty2PC0GSZfIXkXs76jXAu9TOBvD0ybc2YlkCQQDywg2R/7t3Q2OE2+yo382CLJdrlSLVROWKwb4tb2PjhY4XAwV8d1vy0RenxTB+K5Mu57uVSTHtrMK0GAtFr833AkEA6avx20OHo61Yela/4k5kQDtjEf1N0LfI+BcWZtxsS3jDM3i1Hp0KSu5rsCPb8acJo5RO26gGVrfAsDcIXKC+bQJAZZ2XIpsitLyPpuiMOvBbzPavd4gY6Z8KWrfYzJoI/Q9FuBo6rKwl4BFoToD7WIUS+hpkagwWiz+6zLoX1dbOZwJACmH5fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aPFaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw==
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,6 @@
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3rAEiYZsc3E8FUGiBCt8e4dkt
qc77U8lnpAfi8DaGSoYu9jelD8/za7XIqFD99EgBA+DXbR01jzSU+ILsfG21jS2B
pPE39zuJYj5X7sQvKg1wRGVS0pi+DVLNEJUhTP8B3fUf1TD72t4aYJh4t8ZrgD90
9VQglfyJZ7wuuHYHqQIDAQAB
-----END PUBLIC KEY-----

View File

@@ -0,0 +1,3 @@
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB
-----END PUBLIC KEY-----