Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup #47

Merged
merged 4 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- markdownlint-disable blanks-around-headings blanks-around-lists no-duplicate-heading -->

# Changelog
All notable changes to this project will be documented in this file.

Expand All @@ -6,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

<!-- next-header -->
## [Unreleased] - ReleaseDate
### Changed
- [PR#47](https://github.com/EmbarkStudios/tame-oauth/pull/47) removed the dependency upon `chrono` as it was overkill and brought in multiple security advisories and is only lightly maintained.

## [0.6.0] - 2021-08-07
### Added
- [PR#40](https://github.com/EmbarkStudios/tame-oauth/pull/40) added support for [`Metadata Server Auth`](https://cloud.google.com/compute/docs/instances/verifying-instance-identity) so that you can obtain oauth tokens when running inside GCP. Thanks [@boulos](https://github.com/boulos)!
Expand All @@ -17,7 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [0.5.1] - 2021-06-05
### Removed
- Removed unused depdendency on `lock_api`, which was lingering after [PR#21](https://github.com/EmbarkStudios/tame-oauth/pull/21).
- Removed unused dependency on `lock_api`, which was lingering after [PR#21](https://github.com/EmbarkStudios/tame-oauth/pull/21).

## [0.5.0] - 2021-06-05
### Added
Expand Down
14 changes: 9 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
[package]
name = "tame-oauth"
version = "0.6.0"
authors = ["Embark <[email protected]>", "Jake Shadle <[email protected]>"]
authors = [
"Embark <[email protected]>",
"Jake Shadle <[email protected]>",
]
edition = "2018"
description = "A (very) simple oauth 2.0 library"
license = "MIT OR Apache-2.0"
documentation = "https://docs.rs/tame-oauth"
homepage = "https://github.com/EmbarkStudios/tame-oauth"
repository = "https://github.com/EmbarkStudios/tame-oauth"
keywords = ["oauth", "tame", "sans-io", "gcp"]
categories = ["authentication"]
readme = "README.md"

[badges]
Expand All @@ -29,14 +33,14 @@ jwt = ["ring"]
# This enables features in chrono and ring that are necessary to use this library
# in a wasm32 web (browser) context. If you are using wasm outside the browser
# you will need to target wasm32-wasi for the requisite functionality (time and random)
wasm-web = ["chrono/wasmbind", "ring/wasm32_c"]
wasm-web = ["ring/wasm32_c"]

[dependencies]
base64 = "0.13" # Keep aligned with rustls
chrono = "0.4"
# Keep aligned with rustls
base64 = "0.13"
http = "0.2"
ring = { version = "0.16", optional = true }
serde = { version = "1.0", features = [ "derive" ] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
twox-hash = { version = "1.5.0", default-features = false }
url = { version = "2.2", optional = true }
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# 🔐 tame-oauth
<div align="center">

# `🔐 tame-oauth`

[![Embark](https://img.shields.io/badge/embark-open%20source-blueviolet.svg)](http://embark.games)
[![Embark](https://img.shields.io/badge/discord-ark-%237289da.svg?logo=discord)](https://discord.gg/dAuKfZS)
Expand All @@ -9,6 +11,8 @@

`tame-oauth` is a small oauth crate that follows the [sans-io](https://sans-io.readthedocs.io/) approach.

</div>

## Why?

* You want to control how you actually make oauth HTTP requests
Expand All @@ -22,7 +26,7 @@
## Features

* `gcp` (default) - Support for [GCP oauth2](https://developers.google.com/identity/protocols/oauth2)
* `wasm-web` - Enables wasm features in `chrono` and `ring` needed for `tame-oauth` to be used in a wasm browser context. Note this feature should not be used when targetting wasm outside the browser context, in which case you would likely need to target `wasm32-wasi`.
* `wasm-web` - Enables wasm features in `ring` needed for `tame-oauth` to be used in a wasm browser context. Note this feature should not be used when targeting wasm outside the browser context, in which case you would likely need to target `wasm32-wasi`.
* `jwt` (default) - Support for [JSON Web Tokens](https://jwt.io/), required for `gcp`
* `url` (default) - Url parsing, required for `gcp`

Expand Down
14 changes: 10 additions & 4 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ targets = [

[advisories]
unmaintained = "deny"
ignore = [
]
ignore = []

[bans]
multiple-versions = "deny"
Expand All @@ -17,9 +16,10 @@ deny = [
{ name = "openssl-sys" },
]
skip = [
# hyper uses this old version
{ name = "itoa", version = "=0.4.8" },
]
skip-tree = [
]
skip-tree = []

[licenses]
unlicensed = "deny"
Expand All @@ -28,6 +28,7 @@ confidence-threshold = 0.92
allow = [
"Apache-2.0",
"MIT",
"BSD-3-Clause",
]
exceptions = [
{ allow = ["MPL-2.0"], name = "webpki-roots" },
Expand All @@ -51,6 +52,11 @@ license-files = [
{ path = "LICENSE", hash = 0xbd0eed23 },
]

[[licenses.clarify]]
name = "encoding_rs"
expression = "(Apache-2.0 OR MIT) AND BSD-3-Clause"
license-files = [{ path = "COPYRIGHT", hash = 0x39f8ad31 }]

[[licenses.clarify]]
name = "webpki"
expression = "ISC"
Expand Down
27 changes: 14 additions & 13 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ pub enum Error {
file: std::path::PathBuf,
error: Box<Error>,
},
/// An error occured due to [`SystemTime`](std::time::SystemTime)
SystemTime(std::time::SystemTimeError),
}

impl fmt::Display for Error {
Expand All @@ -60,31 +62,24 @@ impl fmt::Display for Error {
InvalidCredentials { file, error } => {
write!(f, "Invalid credentials in '{}': {}", file.display(), error)
}
SystemTime(te) => {
write!(f, "System Time error: {}", te)
}
}
}
}

impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn Err> {
use Error::{Auth, Base64Decode, Http, Json};

match self {
Base64Decode(err) => Some(err as &dyn Err),
Http(err) => Some(err as &dyn Err),
Json(err) => Some(err as &dyn Err),
Auth(err) => Some(err as &dyn Err),
_ => None,
}
}

fn source(&self) -> Option<&(dyn Err + 'static)> {
use Error::{Auth, Base64Decode, Http, Json};
#![allow(clippy::enum_glob_use)]
use Error::*;

match self {
Base64Decode(err) => Some(err as &dyn Err),
Http(err) => Some(err as &dyn Err),
Json(err) => Some(err as &dyn Err),
Auth(err) => Some(err as &dyn Err),
SystemTime(err) => Some(err as &dyn Err),
_ => None,
}
}
Expand All @@ -108,6 +103,12 @@ impl From<serde_json::Error> for Error {
}
}

impl From<std::time::SystemTimeError> for Error {
fn from(e: std::time::SystemTimeError) -> Self {
Error::SystemTime(e)
}
}

#[derive(serde::Deserialize, Debug)]
pub struct AuthError {
/// Top level error type
Expand Down
5 changes: 2 additions & 3 deletions src/gcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,13 @@ impl TokenProvider for TokenProviderWrapper {

impl From<TokenResponse> for Token {
fn from(tr: TokenResponse) -> Self {
let expires_ts = chrono::Utc::now().timestamp() + tr.expires_in;

Self {
access_token: tr.access_token,
token_type: tr.token_type,
refresh_token: String::new(),
expires_in: Some(tr.expires_in),
expires_in_timestamp: Some(expires_ts),
expires_in_timestamp: std::time::SystemTime::now()
.checked_add(std::time::Duration::from_secs(tr.expires_in as u64)),
}
}
}
9 changes: 5 additions & 4 deletions src/gcp/service_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,16 @@ impl TokenProvider for ServiceAccountProvider {
}
};

let issued = chrono::Utc::now().timestamp();
let expiry = issued + 3600 - 5; // Give us some wiggle room near the hour mark
let issued_at = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)?
.as_secs() as i64;

let claims = jwt::Claims {
issuer: self.info.client_email.clone(),
scope: scopes,
audience: self.info.token_uri.clone(),
expiration: expiry,
issued_at: issued,
expiration: issued_at + 3600 - 5, // Give us some wiggle room near the hour mark
issued_at,
subject: subject.map(|s| s.into()),
};

Expand Down
16 changes: 13 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![doc = include_str!("../README.md")]
// BEGIN - Embark standard lints v0.4
// BEGIN - Embark standard lints v5 for Rust 1.55+
// do not change or add/remove here, but one can add exceptions after this section
// for more info see: <https://github.com/EmbarkStudios/rust-ecosystem/issues/59>
#![deny(unsafe_code)]
Expand All @@ -10,6 +10,8 @@
clippy::checked_conversions,
clippy::dbg_macro,
clippy::debug_assert_with_mut_call,
clippy::disallowed_method,
clippy::disallowed_type,
clippy::doc_markdown,
clippy::empty_enum,
clippy::enum_glob_use,
Expand All @@ -19,13 +21,17 @@
clippy::explicit_into_iter_loop,
clippy::fallible_impl_from,
clippy::filter_map_next,
clippy::flat_map_option,
clippy::float_cmp_const,
clippy::fn_params_excessive_bools,
clippy::from_iter_instead_of_collect,
clippy::if_let_mutex,
clippy::implicit_clone,
clippy::imprecise_flops,
clippy::inefficient_to_string,
clippy::invalid_upcast_comparisons,
clippy::large_digit_groups,
clippy::large_stack_arrays,
clippy::large_types_passed_by_value,
clippy::let_unit_value,
clippy::linkedlist,
Expand All @@ -37,20 +43,25 @@
clippy::map_unwrap_or,
clippy::match_on_vec_items,
clippy::match_same_arms,
clippy::match_wild_err_arm,
clippy::match_wildcard_for_single_variants,
clippy::mem_forget,
clippy::mismatched_target_os,
clippy::missing_enforced_import_renames,
clippy::mut_mut,
clippy::mutex_integer,
clippy::needless_borrow,
clippy::needless_continue,
clippy::needless_for_each,
clippy::option_option,
clippy::path_buf_push_overwrite,
clippy::ptr_as_ptr,
clippy::rc_mutex,
clippy::ref_option_ref,
clippy::rest_pat_in_fully_bound_structs,
clippy::same_functions_in_if_condition,
clippy::semicolon_if_nothing_returned,
clippy::single_match_else,
clippy::string_add_assign,
clippy::string_add,
clippy::string_lit_as_bytes,
Expand All @@ -67,9 +78,8 @@
nonstandard_style,
rust_2018_idioms
)]
// END - Embark standard lints v0.4
// END - Embark standard lints v0.5 for Rust 1.55+
// crate-specific exceptions:
#![allow()]

#[cfg(feature = "gcp")]
pub mod gcp;
Expand Down
20 changes: 9 additions & 11 deletions src/token.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::Error;
use chrono::{offset::TimeZone, DateTime, Utc};
use std::time::SystemTime;

/// Represents a token as returned by `OAuth2` servers.
///
Expand All @@ -23,23 +23,21 @@ pub struct Token {
/// Prefer using expiry_date()
pub expires_in: Option<i64>,
/// timestamp is seconds since epoch indicating when the token will expire
/// in absolute terms. use [`Self::expiry_date`] to convert to DateTime.
pub expires_in_timestamp: Option<i64>,
/// in absolute terms.
pub expires_in_timestamp: Option<SystemTime>,
}

impl Token {
/// Returns true if we are expired.
#[inline]
pub fn has_expired(&self) -> bool {
self.access_token.is_empty() || self.expiry_date() <= Utc::now()
}

/// Returns a [`chrono::DateTime`] object representing our expiry date.
pub fn expiry_date(&self) -> DateTime<Utc> {
match self.expires_in_timestamp {
Some(ts) => Utc.timestamp(ts, 0),
None => Utc::now(),
if self.access_token.is_empty() {
return true;
}

let expiry = self.expires_in_timestamp.unwrap_or_else(SystemTime::now);

expiry <= SystemTime::now()
}
}

Expand Down