Commit Graph

271 Commits

Author SHA1 Message Date
Glenn Griffin
8f84553769 Use a bloom filter to track scopes.
Each token is stored along with a 64bit bloom filter that is created
from the set of scopes associated with that token. When retrieving
tokens for a set of scopes a new bloom filter is calculated for the
requested scopes and compared to the filters of all previously fetched
scopes. The bloom filter allows for efficiently skipping entries that
are definitely not a superset.
2019-12-18 09:07:45 -08:00
Glenn Griffin
7c1664142c Don't serialize the scope hash.
Seahash is a stable hash, but there isn't any value in serializing it's
value. Instead calculate the value of the hash when deserializing and
only serialize the scopes and tokens. This provides flexibility to
change the hash value in the future without breaking the on-disk format.
2019-12-18 09:07:45 -08:00
Glenn Griffin
5be2eadeca Use the storage token hash more effectively.
Use a BTreeMap to key the tokens by the hash value. On retrieval first
look for a matching hash value and return it if it exists. Only if it
does not exist does it fallback to the subset matching. This makes the
common case where an application uses a consistent set of scopes more
efficient without detrimentally impacting the less common cases.
2019-12-18 09:07:45 -08:00
Glenn Griffin
089c6ba212 Use seahash rather that DefaultHasher.
DefaultHasher is not documented as being consistent. It's best to not
trust that the resulting hash value is consistent even across different
executions of the same binary and even more so across different
versions.
2019-12-18 09:06:33 -08:00
Glenn Griffin
baa8d56653 JSONToken should always contain scopes.
This is already the case when writing a token file. Presumably the only
reason it was an Option was for backwards compatibility, but we're
already breaking compatibility with the change to the hash value so this
seems like an appropriate time to make the change.

This change also highlights how unused the hash value has been
previously. Future changes plan to use the hash value for more efficient
handling.
2019-12-18 09:03:35 -08:00
Glenn Griffin
b70d07aac2 storage set method should just accept a Token rather than Option<Token>.
No caller ever provided a None value. Presumably a None value should
delete the token, but it didn't do that and that would be more clearly
done with a remove or delete method.
2019-12-18 09:03:35 -08:00
Glenn Griffin
4b4b2fe3f4 refactor storage get and set methods.
These previously accepted a hash and scopes. The hash was required to be
a hash of the provided scopes but that wasn't enforced by the compiler.
We now have the compiler enforce that by creating a HashedScopes type
that ties the scopes and the hash together and pass that into the
storage methods.
2019-12-18 09:03:34 -08:00
Glenn Griffin
f76dea5dbd Add header styling to the AuthenticatorBuilder rustdoc 2019-12-18 08:59:43 -08:00
Glenn Griffin
d17c760276 Remove an obsolete todo. 2019-12-18 08:59:43 -08:00
Glenn Griffin
68a30ea0fe Tidy up tests. 2019-12-18 08:59:43 -08:00
Glenn Griffin
ca453c056c Improve documentation 2019-12-18 08:59:43 -08:00
Glenn Griffin
e5aa32b3cf Tidy up some imports.
No more need to macro_use serde. Order the imports consistently (albeit
somewhat arbitrary), starting with items from this crate, followed by
std, followed by external crates.
2019-12-18 08:59:43 -08:00
Glenn Griffin
ba0b8f366a Rename RequestError to Error
RequestError is the error value that encompasses all errors from the
authenticators. Their is an established convention of using Error as the
name for those types.
2019-12-18 08:57:24 -08:00
Glenn Griffin
0fe66619dd Minimize the number of items on the rustdoc landing page.
Restructure the modules and imports to increase the signal to noise
ration on the cargo doc landing page. This includes exposing some
modules as public so that they can contain things that need to be public
but that users will rarely need to interact with. Most items from
types.rs were moved into an error.rs module that is now exposed
publicly.
2019-12-18 08:57:24 -08:00
Glenn Griffin
3aadc6b0ef Major refactor of the public API.
1) Remove the GetToken trait. The trait seemed to be organically
designed. It appeared to be mostly tailored for simplifying the
implementation since there was no way for users to provide their own
implementation to Authenticator. It sadly seemed to get in the way of
implementations more than it helped. An enum representing the known
implementations is a more straightforward way to accomplish the goal and
also has the benefit of not requiring Boxing when returning features
(which admittedly is a minor concern for this use case).

2) Reduce the number of type parameters by using trait object for
delegates. This simplifies the code considerably and the performance
impact of virtual dispatch for the delegate calls is a non-factor.

3) With the above two simplifications it became easier to unify the
public interface for building an authenticator. See the examples for how
InstalledFlow, DeviceFlow, and ServiceAccount authenticators are now created.
2019-12-18 08:57:24 -08:00
Glenn Griffin
911fec82f1 Make FlowDelegate object safe. 2019-12-18 08:57:24 -08:00
Glenn Griffin
c0919bee86 allow setting grant_type for device code 2019-12-18 08:57:24 -08:00
Glenn Griffin
88a8f74406 Refactor token storage.
The current code uses standard blocking i/o operations (std::fs::*) this
is problematic as it would block the entire futures executor waiting for
i/o.

This change is a major refactoring to make the token storage mechansim
async i/o friendly. The first major decision was to abandon the GetToken
trait. The trait is only implemented internally and there was no
mechanism for users to provide their own, but async fn's are not
currently supported in trait impls so keeping the trait would have
required Boxing futures. This probably would have been fine, but seemed
unnecessary. Instead of a trait the storage mechanism is just an enum
with a choice between Memory and Disk storage.

The DiskStorage works primarily as it did before, rewriting the entire
contents of the file on every set() invocation. The only difference is
that we now defer the actual writing to a separate task so that it does
not block the return of the Token to the user. If disk i/o is too slow
to keep up with the rate of incoming writes it will push back and
will eventually block the return of tokens, this is to prevent a buildup
of in-flight requests. One major drawback to this approach is that any
errors that happen on write are simply logged and no delegate function
is invoked on error because the delegate no longer has the ability to
say to sleep, retry, etc.
2019-12-18 08:57:24 -08:00
Glenn Griffin
e1f0819156 Authenticator should handle the server not returning a refresh_token.
Currently the authenticator will panic when trying to refresh an expired
token that does not have a refresh token. This change handles it so that
the authenticator will only attempt a refresh when a refresh_token
exists, and otherwise will attempt to retrieve a fresh token.
2019-12-18 08:53:22 -08:00
Glenn Griffin
060eb92bf7 Refactor JWT handling in ServiceAccountAccess.
Avoid reading and parsing the private key file on every invocation of
token() in favor or reading it once when the ServiceAccountAccess is
built. Also avoid unnecessary allocations when signing JWT tokens and
renamed sub to subject to avoid any confusion with the std::ops::Sub
trait.
2019-12-18 08:53:22 -08:00
Glenn Griffin
05f7c10533 Remove unnecessary 'static bounds 2019-12-18 08:53:22 -08:00
Glenn Griffin
e8675fa1da Refactor retrieve_device_token.
wait_for_device_token polls indefinitely at the specified intervals.
Use tokio::timer::Timeout to bound the time it will poll for.
2019-12-18 08:53:22 -08:00
Glenn Griffin
ef23eef31d Remove more unnecessary clones. 2019-12-18 08:53:22 -08:00
Glenn Griffin
b6affacbf0 Unify trait bounds on Authenticator::build 2019-12-18 08:53:22 -08:00
Glenn Griffin
fa121d41b2 Delegates no longer need to implement Clone. 2019-12-18 08:53:22 -08:00
Glenn Griffin
7446200421 Remove unnecessary trait bounds on hyper connector.
Send+Sync is implied by the trait, and Clone is no longer necessary.
2019-12-18 08:53:22 -08:00
Glenn Griffin
0e9cf512ba Remove the HTTPRedirectEphemeral variant.
In favor of making it the default and removing the option to specify a
port to listen on. If needed a variant can be added to specify a port
explicitly, but most users should want an ephemeral port chosen so
making it the default makes sense while other breaking changes are in
flight.
2019-12-18 08:53:22 -08:00
Glenn Griffin
8489f470a4 cargo clippy fixes 2019-12-18 08:53:22 -08:00
Glenn Griffin
4bd81c3263 cargo fmt 2019-12-18 08:53:22 -08:00
Glenn Griffin
2cf2e465d1 Add JsonErrorOr enum to make json error handling more concise/consistent.
JsonErrorOr is an untagged enum that is generic over arbitrary data.
This means that when deserializing JsonErrorOr<T> it will first check
the json field for an 'error' attribute. If one exists it will
deserialize into the JsonErrorOr::Err variant that contains a JsonError.
If the message doesn't contain an 'error' field it will attempt to
deserialize T into he JsonErrorOr::Data variant.
2019-12-18 08:53:22 -08:00
Glenn Griffin
29f800ba7f Some more improvements to reduce unnecessary allocations. 2019-12-18 08:53:22 -08:00
Glenn Griffin
bf0136067f Make some of the helpers a bit more idiomatic. 2019-12-18 08:53:22 -08:00
Glenn Griffin
e9b2a3a076 The inner GetToken on Authenticator no longer needs to be reference counted. 2019-12-18 08:53:22 -08:00
Glenn Griffin
a0c73d6087 No need to clone the hyper::Client
The ownership behavior is straightforward and more clear when not
cloning arbitrary handles.
2019-12-18 08:53:22 -08:00
Glenn Griffin
916aaa84e9 Authenticator.store no longer needs to be reference counted. 2019-12-18 08:53:22 -08:00
Glenn Griffin
9542e3a9f1 Remove instances of cloning ApplicationSecret
ApplicationSecret is not a small struct. This removes the instances
where it's cloned in favor of passing a shared reference.
2019-12-18 08:53:22 -08:00
Glenn Griffin
696577aa01 Accept scopes as a slice of anything that can produce a &str.
Along with the public facing change the implementation has been modified
to no longer clone the scopes instead using the pointer to the scopes
the user provided. This greatly reduces the number of allocations on
each token() call.

Note that this also changes the hashing method used for token storage in
an incompatible way with the previous implementation. The previous
implementation pre-sorted the vector and hashed the contents to make the
result independent of the ordering of the scopes. Instead we now combine
the hash values of each scope together with XOR, thus producing a hash
value that does not depend on order without needing to allocate another
vector and sort.
2019-12-18 08:53:22 -08:00
Glenn Griffin
7e210a22c5 Have TokenStorage take scopes by iterator rather than Vec.
This reduces the number of allocations needed.
2019-12-18 08:53:22 -08:00
Glenn Griffin
0f29c258c6 FlowType isn't used for anything. Remove it. 2019-12-18 08:53:22 -08:00
Glenn Griffin
a4c9b6034e Require trait implementations to be Send + Sync.
Tidy up some of the trait bounds on types and methods.
2019-12-18 08:53:22 -08:00
Glenn Griffin
93cbd91341 Move to std::futures to support async/await. 2019-12-18 08:53:22 -08:00
Murph Murphy
a52625a071 fix(storage): storage clears all matching tokens
Change Storage to clear all existing JSONTokens with the current `hash` on set if at least one exists.

Fixes #117 if it's a real issue.
2019-12-16 14:50:24 -07:00
Cameron Taggart
d9bb9b7232 cargo fmt --all 2019-11-12 15:58:31 +01:00
Cameron Taggart
cce1a03f76 unwrap options in asert_eq 2019-11-12 14:41:40 +00:00
Cameron Taggart
b7703d40b4 make refresh_token an option 2019-11-11 22:44:31 +00:00
Lewin Bormann
09af50132a chore(fmt): rustfmt 2019-09-29 09:41:19 +02:00
Lewin Bormann
fbd38002fa chore(lint): Make clippy happy 2019-09-29 08:45:12 +02:00
Lewin Bormann
778e5afa8f Merge pull request #106 from ggriffiniii/master
Make RequestError Sync
2019-08-31 19:38:08 +02:00
Glenn Griffin
c33d0b8481 Make RequestError Sync
This requires enforcing that errors returned from TokenStorage
implementations are Send, which the ones in this crate are, but is a
breaking change because any external implementations may be returning
errors that are !Sync currently.

The motivation for this change is that Box<dyn Error + Send> is not as fully
supported within the rust stdlib as Box<dyn Error + Send + Sync>. In
particular there exists these two From impls:

impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a>
impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a>

but no corresponding impl for

impl<'a, E: Error + Send + 'a> From<E> for Box<dyn Error + Send + 'a>

This may just be an oversight in the rust stdlib that could be fixed,
but in practice it means that dealing with 'Error + Send' types is not
the most ergonomic because the '?' operator can't be used to convert
from a Box<dyn Error + Send> to a Box<dyn Error>.

Since the current implementations (not counting any external ones that
may exist) implement Sync this seems like a good tradeoff to make it a
little easier to use in an ergonomic way.
2019-08-30 11:53:45 -07:00
Glenn Griffin
fbb8c69efb Change the name of TokenGetterBuilder to AuthFlow.
I believe AuthFlow more succinctly describes the purpose of the type to
users reading documentation.
2019-08-29 11:48:29 -07:00