1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! This is a rust library for generating and validating ASAP tokens. It provides
//! options for doing so that are compliant with the [ASAP specification](https://s2sauth.bitbucket.io/spec/).
//!
//! ASAP is a protocol that extends JWT. It does this so resource servers can be
//! confident that incoming requests with signed ASAP tokens are indeed coming
//! from the intended client. If you want to know more, see [the specification](https://s2sauth.bitbucket.io/spec/).
//!
//! Things to note about this ASAP library:
//!
//! * This library is *awesome*. If you use Rust and want ASAP, you should use this!
//! * At the moment it only supports the `RS256` algorithm. This is the most used
//! algorithm that ASAP uses, so there's been no need to implement any others.
//! * The ASAP `Validator` struct can optionally detect duplicate `jti` nonces.
//!
//! This library aims to be fully compliant with the ASAP specification [found here](https://s2sauth.bitbucket.io/spec/).
//! If you notice anything out of the ordinary, please don't hesitate to make a Issue
//! or PR stating where it doesn't comply.
//!
//! This library also aims to be really simple to use! You should concentrate
//! less on ASAP, and more on writing your client or service. If you spend too
//! much time working with this library, then it's failed its purpose. Please
//! make an Issue/PR telling us why, and we'll do our best to make it better.
//!
//! Here's a quick example of how you can generate tokens using this library:
//!
//! ```rust
//! # extern crate asap;
//! # extern crate serde;
//! # #[macro_use] extern crate serde_json;
//! #
//! use asap::claims::Aud;
//! use asap::generator::Generator;
//!
//! // The identifier of the service that issues the token (`iss`).
//! let iss = "service01".to_string();
//! // The key id (`kid`) of the public key in your keyserver.
//! let kid = "service01/my-key-id".to_string();
//! // The `private_key` used to sign each token.
//! let private_key = include_bytes!("../support/keys/service01/1530402390-private.der").to_vec();
//!
//! // Here's your generator! 🎉
//! let generator = Generator::new(iss, kid, private_key);
//!
//! // Generate tokens, etc...
//! # let aud = Aud::One("aud".to_string());
//! # let extra_claims = None;
//! let token = generator.token(aud, extra_claims).unwrap();
//! ```
//!
//! And here's another example of how you can validate tokens. This example
//! requires the default `validator` feature:
//!
//! ```rust
//! # extern crate asap;
//! # extern crate serde;
//! # #[macro_use] extern crate serde_json;
//! #
//! # #[cfg(feature = "validator")]
//! # async fn validator_example() {
//! # use serde::de::DeserializeOwned;
//! use asap::claims::Claims;
//! use asap::validator::Validator;
//!
//! let asap_token = "<your-asap-token>";
//!
//! // The keyserver(s) which hosts your public keys.
//! let primary_keyserver = "http://my-keyserver/".to_string();
//! let fallback_keyserver = "http://my-fallback-keyserver/".to_string();
//! // The audience of the server/resource that validates the incoming tokens.
//! let resource_server_audience = "my-server".to_string();
//!
//! // Build the ASAP validator:
//! let validator = Validator::builder(primary_keyserver, resource_server_audience)
//! .fallback_keyserver(fallback_keyserver)
//! .build();
//!
//! // A list of issuers that are allowed to access this server/resource.
//! let whitelisted_issuers = vec!["list", "of", "whitelisted", "issuers"];
//! match validator.decode(asap_token, &whitelisted_issuers).await {
//! Ok(token_data) => {
//! // Here you have a successfully verified and accepted access token!
//! //
//! // Remember the directions from the ASAP spec:
//! // If the resource server successfully verifies and accepts the
//! // access token, then it MUST process the request and it MUST assume
//! // that the request was issued by the issuer.
//! println!("claims {:?}", token_data.claims);
//! },
//! Err(e) => {
//! // Oh boo, there was an error decoding and validating the ASAP token.
//! //
//! // Remember the directions from the ASAP spec:
//! // If the resource server rejects the access token, then it MUST
//! // reply with a status code of 401 UNAUTHORIZED and MUST include a
//! // WWW-Authenticate header field as per the HTTP specification.
//! eprintln!("{:?}", e);
//! }
//! }
//! # }
//! ```
//!
//! That's really it! It should be simple - that's the goal.
compile_error!;
extern crate chrono;
extern crate anyhow;
extern crate jsonwebtoken as jwt;
extern crate jsonwebtoken_aws_lc as jwt;
extern crate lru_time_cache;
extern crate pem;
extern crate rand;
extern crate reqwest;
extern crate serde;
extern crate thiserror;
extern crate serde_derive;
extern crate serde_json;