oxide-auth icon indicating copy to clipboard operation
oxide-auth copied to clipboard

Gate dependencies behind feature flags

Open aumetra opened this issue 1 year ago • 10 comments

This PR gates the following dependencies behind feature flags:

  • rust-argon2
  • rmp-serde

These dependencies are less common dependencies for some web services, since:

a) not everyone uses rust-argon2 (personally, I use the RustCrypto argon2 crate for pretty much all my projects) b) not everyone uses MessagePack in their projects

In total, this makes the dependency tree 16 dependencies lighter with all features disabled.
Whether these features should be enabled by default or not can definitely be discussed.

All the features are documented on docs.rs using the unstable doc_auto_cfg feature


I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.

aumetra avatar Nov 27 '23 09:11 aumetra

screenshot_docs

aumetra avatar Nov 27 '23 10:11 aumetra

Makes sense. Will try to refactor towards generalizing the implementations over different inner implementations.

aumetra avatar Nov 27 '23 10:11 aumetra

Okay, the abstraction over different de-/serializers is.. a mess. Unless we pull in erased_serde to erase the actual types of the machinery inside using some dynamic dispatch and a box.

aumetra avatar Nov 27 '23 12:11 aumetra

The dispatch need not be byte-compatible with previous version, imo, since in-memory data should be treated as ephemeral. Well, any new design could be validated by trying to swap the current encoding scheme for something like BER or even JWT but those can always live as separate implementations as well. This opens the possibility of having a public wrapper type (with private fields, implementing Serialize) which the policy is to turn into a byte vector. Or rather two methods since there are two different instances of encoding happening. The AssertGrant type codifies essentially already one of those two, the other is currently ad-hoc tuples. Both could be public types, without public constructors.

HeroicKatora avatar Nov 27 '23 13:11 HeroicKatora

Something like that? @HeroicKatora

That's a fully opaque representation that publicly implements Deserialize and Serialize and doesn't expose any other information to the outside.
Explicitly adds a disclaimer to the documentation that the internal representation is unstable and might change at any time.

The internal representation at the moment is just an enum.

aumetra avatar Nov 27 '23 16:11 aumetra

The only problem here are auto-traits, i.e. Send and Sync should still work for the Assertion

Rewrote the internals to dynamically dispatch instead. Works fine, added the auto traits as a requirement to the trait itself, so that's still fine.

aumetra avatar Nov 28 '23 06:11 aumetra

Fyi, the bulk of this PR looks good. But, from the perspective of secure defaults, I don't yet feel comfortable with an interface doesnt provide some secure configuration of all interfaces for users by default. That means, there should be an easy choice and that one should be secure. In particular, new with a parameter seems off. It's congruent with that idiom if the new interface is not available in all configurations so long as it is available in the default one.

The serializer is not as relevant but still I'm not sold on the idea of making it more difficult to most people (I'm basing this on the fact that this is the first time that issue came up) and not having at least an optional dependency that fully implements the trait. Or, at the very least, there should be good guidance within the trait documentation on how to bind it to a generic serialization library.

Just some thoughts here, and why I'm not convinced yet that this PR is ready.

HeroicKatora avatar Dec 03 '23 00:12 HeroicKatora

@HeroicKatora Well, do you think it would be sufficient if we provided a Default implementation (even if gated behind a cfg flag) that uses these secure defaults?

Such as the interfaces that use the argon2 password policy, they get a default impl.

And, of course, the Encoder also gets a default impl gated behind something like messagepack.

And all these features could be enabled by default to make the default experience secure by default.

aumetra avatar Dec 03 '23 03:12 aumetra

@HeroicKatora Hey, sorry for the delay, I wanted to ask if what I proposed in the previous comment would be fine?
Meaning an API where the default features expose these secure defaults?

aumetra avatar Feb 16 '24 10:02 aumetra

The approach is decent with the trait factoring, but I can't quite get over the modification to new and other constructors instead of a with_ method and new being dependent on (non-default) features. In particular note how that introduces an apparently necessity for (or maybe draw to) an improper implementation of the password store in tests and associated churn. Knowing users, this might well be the place used as a template for customized versions. And if this is motivated by being 'just simple' then I can definitely see real cases of it happening in Production where it is a huge security hole. The changes you've made since the initial version do contribute to security-by-default but I'm not fully convinced that the PR overall is positive. It's close though.

Do note that tests can have a dev-dependency on the encoding / hashing crates, maybe that is a direction to use?

HeroicKatora avatar Feb 23 '24 19:02 HeroicKatora