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

feat(sql/auth): base authentication storage implementation #1095

Merged
merged 14 commits into from
Oct 28, 2022

Conversation

GeorgeMac
Copy link
Contributor

@GeorgeMac GeorgeMac commented Oct 25, 2022

Fixes: FLI-36

Initial implementation for storing Authentication instances into the backing relational DBs.
This PR:

  1. Creates a new package internal/storage/sql/auth.
  2. Creates an *auth.Store implementation specifically for Authentication associated state.
  3. Adds the necessary migrations for each DB driver.
  4. Implements CreateAuthentication.
  5. Implements GetAuthenticationByClientToken.
  6. Create and Get both perform client token hashing using SHA256.
  7. Adds create and read tests for Authentication instances.

@GeorgeMac GeorgeMac changed the base branch from authentication to gm/authentication-protobuf October 25, 2022 13:42
@codecov-commenter
Copy link

codecov-commenter commented Oct 25, 2022

Codecov Report

Merging #1095 (28b9a6d) into authentication (57da7f2) will increase coverage by 0.42%.
The diff coverage is 84.29%.

❗ Current head 28b9a6d differs from pull request most recent head afd9f67. Consider uploading reports for the commit afd9f67 to get more accurate results

@@                Coverage Diff                 @@
##           authentication    #1095      +/-   ##
==================================================
+ Coverage           80.52%   80.94%   +0.42%     
==================================================
  Files                  26       29       +3     
  Lines                1884     2125     +241     
==================================================
+ Hits                 1517     1720     +203     
- Misses                287      318      +31     
- Partials               80       87       +7     
Impacted Files Coverage Δ
internal/storage/sql/migrator.go 23.45% <10.00%> (-2.94%) ⬇️
internal/storage/sql/auth/fields.go 69.44% <69.44%> (ø)
internal/storage/sql/auth/store.go 87.76% <87.76%> (ø)
internal/storage/sql/errors.go 98.24% <98.24%> (ø)

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@GeorgeMac GeorgeMac changed the title WIP: storage implementation WIP: authentication storage implementation Oct 26, 2022
Base automatically changed from gm/authentication-protobuf to authentication October 26, 2022 13:52
@GeorgeMac GeorgeMac changed the title WIP: authentication storage implementation feat(sql/auth): base authentication storage implementation Oct 26, 2022
@GeorgeMac GeorgeMac marked this pull request as ready for review October 27, 2022 13:02
cmd/flipt/import.go Show resolved Hide resolved
internal/storage/sql/auth/fields.go Outdated Show resolved Hide resolved
builder: builder,
now: timestamppb.Now,
generateID: func() string {
return uuid.Must(uuid.NewV4()).String()
Copy link
Collaborator

Choose a reason for hiding this comment

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

are we worried about (highly unlikely) potential for panic here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the only case uuid panics occur is when your system runs out of entropy (I could be mistaken).
I believe the advice in this situation is to panic for reals. So, I wouldn't be too worried about not capturing this.

internal/storage/sql/auth/fields.go Outdated Show resolved Hide resolved
&authentication.Id,
&hashedToken,
ptr(method(authentication.Method)),
&jsonField[map[string]string]{authentication.Metadata},
Copy link
Collaborator

Choose a reason for hiding this comment

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

for variant.attachment I think we just represented it as a string and compacted it before saving, ie:

if attachment != nil {

is there a reason to do it this way instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The jsonField container just marshals which type it contains to and from a string to make that operations a one-liner. I could definitely use json.Compact in the Driver implementation too. But this is the same thing.

Copy link
Collaborator

Choose a reason for hiding this comment

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

cool, i wonder if we should move to be consistent everywhere

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me see if I can drop Attachment in, and it just works...
I just moved JSONField to the sql package, so it is reachable now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahh I see, Attachment moves around as a string in the protobuf itself. My mistake.

Whereas, Metadata is actually a map<string, string> in protobuf:

map<string, string> metadata = 6;

Here, JSONField allows for the one-lining of (un)marshalling to and from arbitrary Go types like this to string for persistence.

Whereas, Attachment using json.Compact to first unmarshal a string which assumed to contain JSON and back into a compact JSON form.

Seems these are two relatively different concepts, and I see why they're both different.
With Attachments, the data's schema is controlled by the end user.
We don't need to know the structure of the JSON document.
It is compacted to keep storage cost minimized.

With Metadata, the data's schema is strictly map<string, string>.
We use that structure internally to allow each auth method to populate the map in their respective ways (e.g. static tokens store their name and description under controlled keys).
JSON is merely a convenient serialization form to stash the structured object in a TEXT field.

)

// AdaptError converts specific known-driver errors into wrapped storage errors.
func (d Driver) AdaptError(err error) error {
Copy link
Collaborator

Choose a reason for hiding this comment

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

oh i like this. is the idea to replace the specific sql/x subpackages that override the common implementation with this for existing flag/segment/etc CRUD operations?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, 💯 I think we might be able to do away with having to add adaptors for each driver.
I can port the rest of Flipt to it in a later PR too if we like how it works.

Copy link
Collaborator

@markphelps markphelps left a comment

Choose a reason for hiding this comment

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

heyooooo 🚀

}
}

func FuzzHashClientToken(f *testing.F) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

ooo love the fuzz

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Honestly, first time I have given it a proper go. It is really neat.
I ran a long fuzz of this function. Roughly ~7M calls.

It is mostly just base64 and sha256, so not testing much.
However, it was nice to get some confidence it was producing base64 encoded non-zero length tokens.

@GeorgeMac GeorgeMac merged commit 979b1c5 into authentication Oct 28, 2022
@GeorgeMac GeorgeMac deleted the gm/authentication-storage branch October 28, 2022 08:35
GeorgeMac added a commit that referenced this pull request Nov 8, 2022
fix(sql/auth): use crypto/rand.Reader in place of math/rand.New

fix(sql/auth): capture test parameters in loop-body variables

chore(migrations): drop index before dropping authentications table

fix(import): run down migrations on --drop

fix(migrations/sqlite3): syntax error in uniqueness constraint on temp table in down

test(sql/auth): fuzz hashClientToken

chore(sql/auth): more fuzzing seeds

fix(sql/auth): map driver constraint errors to internal error representation

chore(sql/auth): remove underscore from Fuzz test name

chore(storage/sql): remove dead code

refactor(migrations): change authentications method from string to integer

refactor(storage/sql): move common field utilities into sql package

chore(storage/sql): use keyed field in struct literals
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