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

Configurable Nonces #45

Merged
merged 4 commits into from
Oct 11, 2020
Merged

Configurable Nonces #45

merged 4 commits into from
Oct 11, 2020

Conversation

andrewmostello
Copy link
Contributor

We're working with a service that uses OAuth 1.0 for authentication, but does not accept non-alphanumeric characters in the nonce. That's peculiar to this service, but by exporting the existing Noncer interface and adding a Noncer field to the Config, it's easy to enable configuration for this situation. Because this is a general change, other peculiar cases can now also be covered.

The existing behavior is part of an exported DefaultNoncer, which is the default used when no custom Noncer is specified. DefaultNoncer is a Base64Noncer with Length 32.

If anyone else needs a noncer that excludes non-alphanumeric characters, a new HexNoncer is also included. HexNoncer works just like Base64Noncer, but encodes in hexadecimal instead of base64.

Export the Noncer interface, and add a Noncer field to Config to
provide custom nonce creation. Create a DefaultNoncer Noncer that
formalizes the existing functionality, which is used by default. Add
a new HexNoncer as an alternative option.
noncer.go Outdated
// DefaultNoncer is the default Noncer. It reads 32
// bytes from crypto/rand and returns those bytes as a
// base64 encoded string.
DefaultNoncer Noncer = Base64Noncer{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what another exported type for this really gains. DefaultNoncer isn't something abstracting the real noncer in a way we'd be able to change it in future, your use case shows servers are sensitive to the details.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds good to me. I added this to have a designated default for package consumers who don't want to customize have a handy option, but it's redundant.

noncer.go Outdated
// returns those bytes as a base64 encoded string. If
// Length is 0, 32 bytes are read.
type Base64Noncer struct {
Length int
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a true need for altering the length? Every exported type and field is a library commitment.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or if someone sets it below 32 there may be some concern about lack of uniqueness among nonces. The spec doesn't provide a hard requirement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds good to me. I'm not invested either way.

noncer.go Outdated
// HexNoncer reads Length bytes from crypto/rand and
// returns those bytes as a base64 encoded string. If
// Length is 0, 32 bytes are read.
type HexNoncer struct {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be here? Those users who have special nonce needs can implement their own. Not sure hex is special or just your preferred variant.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose, go ahead and keep it. If we're going to export an interface, there should be two concrete types that implement it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't need to be there, and I'm good either way. I know what I need to use and I tossed it in here as an alternative option. I'll keep it in per your second comment, but I'm fine either way.

auther.go Outdated
@@ -137,12 +129,11 @@ func (a *auther) commonOAuthParams() map[string]string {

// Returns a base64 encoded random 32 byte string.
func (a *auther) nonce() string {
if a.noncer != nil {
return a.noncer.Nonce()
noncer := DefaultNoncer
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this defaulting logic would more commonly belong in newAuther, retaining the field that was there?

The test changes in this PR have to do with this choice, and not testing the actual noncer details it seems.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. I was thinking about the pattern I use when the struct is exported and you're not sure whether it could be nil, but that doesn't apply here.

noncer.go Outdated
// ordinary functions as Noncers. If f is a function
// with the appropriate signature, NoncerFunc(f) is a
// Noncer that calls f.
type NoncerFunc func() string
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not needed, folks can write a struct. And most should never need to alter the noncer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in there because it's how I originally implemented the Noncers (I didn't bother with separate types and just used NoncerFuncs).

andrewmostello and others added 2 commits October 2, 2020 11:45
Remove redundant "DefaultNoncer" var (just refer to Base64Noncer).
Remove NoncerFunc. Remove Length field from two provided Noncers and
instead set length to 32 bytes.
@dghubble dghubble merged commit e32d262 into dghubble:master Oct 11, 2020
@ikari-pl
Copy link

ikari-pl commented Jan 5, 2021

Awesome, I needed exactly this, for similar reasons (ended up doing dirty hacks on the module to just test my code). Can it get released as a new version? :) (as you can tell, i'm totally new to golang, found a way to pull the merged version after I typed this)

bvuong pushed a commit to fuse-inventory/oauth1 that referenced this pull request Sep 16, 2021
* Add a Noncer interface to allow custom noncers
* Default to Base64Noncer (no change, recommended)
* Add HexNoncer for providers that don't accept non-alphanumeric nonces
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants