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

ssl: only set "sslrootcert" once #573

Merged
merged 1 commit into from
Mar 9, 2017
Merged

ssl: only set "sslrootcert" once #573

merged 1 commit into from
Mar 9, 2017

Conversation

tamird
Copy link
Collaborator

@tamird tamird commented Mar 6, 2017

Fixes #570, though I have not been able to write a test for this.

Remove methods on values. These methods are not a useful abstraction
and only serve to obscure that the underlying structure is a map. Their
presence is particularly inconvenient in that they promote confusing
empty values with the lack of value.


This change is Reviewable

@tamird tamird requested a review from maddyblue March 6, 2017 17:35
@tamird tamird changed the title Remove methods on values ssl: only set "sslrootcert" once Mar 6, 2017
@cbandy
Copy link
Contributor

cbandy commented Mar 6, 2017

I can't tell if it's appropriate to treat o.Get(...) != "" the same as _, ok := o[...]; ok.

ssl.go Outdated
errorf("couldn't parse pem in sslrootcert")
}
} else {
delete(o, "sslrootcert")
Copy link
Contributor

Choose a reason for hiding this comment

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

iiuc, this has the same problem described in #570. We shouldn't be writing to o.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think so, because it's now guarded by the presence of a non-empty value, which should only happen once at Dial and not during cancellation.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree that this is safe and fixes the bug there because when this function is re-invoked during cancel, sslrootcert will have been deleted, and so this branch will not be entered.

ssl.go Outdated
case "disable":
return nil
default:
errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
}

sslClientCertificates(&tlsConf, o)
sslCertificateAuthority(&tlsConf, o)
Copy link
Contributor

Choose a reason for hiding this comment

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

This function (or its contents) still need to be invoked when sslmode is verify-ca or verify-full.

Copy link
Contributor

Choose a reason for hiding this comment

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

See failing tests TestSSLVerifyCA and TestSSLVerifyFull.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

@tamird
Copy link
Collaborator Author

tamird commented Mar 6, 2017 via email

@tamird
Copy link
Collaborator Author

tamird commented Mar 7, 2017

@cbandy addressed your concrete comments; anything else you'd like to see done before merging?

Copy link
Contributor

@cbandy cbandy left a comment

Choose a reason for hiding this comment

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

The logic/fix for #570 looks sound.

However, I'm convinced we should not change the conditionals that test for empty string. I found (unless I'm mistaken) that the SSL options in this PR are affected negatively, and I suspect other options are affected similarly.

ssl.go Outdated
verifyCaOnly = true
} else {
o.Set("sslrootcert", "")
// From http://www.postgresql.org/docs/current/static/libpq- ssl.html:
Copy link
Contributor

Choose a reason for hiding this comment

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

Spaces have appeared after some of the dashes in this paragraph. On this line, it broke this link.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

ssl.go Outdated

var cinfo, kinfo os.FileInfo
var err error

if sslcert != "" && sslkey != "" {
if sslkeyOK && sslcertOK {
Copy link
Contributor

Choose a reason for hiding this comment

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

As I understand it, this change breaks compatibility with libpq connection strings.

If I'm reading libpq source correctly, these settings fallback to the user/home paths when the supplied value is blank:

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The old code is also incompatible with that libpq logic in that libpq allows either the certificate or the key to be blank, while this only does the right thing if both are blank.

I'm inclined to "break" compatibility in this way until someone reports that they need it, at which time we should add tests and implement the actual libpq behaviour.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed this, I think, though I think tests are going to break and I've not yet explicitly tested the empty string case.

ssl.go Outdated
@@ -105,16 109,15 @@ func sslClientCertificates(tlsConf *tls.Config, o values) {

// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
func sslCertificateAuthority(tlsConf *tls.Config, o values) {
if sslrootcert := o.Get("sslrootcert"); sslrootcert != "" {
if sslrootcert, ok := o["sslrootcert"]; ok {
Copy link
Contributor

Choose a reason for hiding this comment

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

As I understand it, this change breaks compatibility with libpq connection strings.

If I'm reading libpq source correctly, the CA certificate is only loaded when this setting is not blank:

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think you're right, but as mentioned above, I think this is OK until we get a report of someone relying on this behaviour. WDYT?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed and added a test.

@cbandy
Copy link
Contributor

cbandy commented Mar 7, 2017

If compatibility with libpq connection strings is a goal, then maybe we should also support the home directory fallback for sslrootcert, ~/.postgresql/root.crt.

Copy link
Collaborator Author

@tamird tamird left a comment

Choose a reason for hiding this comment

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

I do think compatibility with libpq connection strings is a goal of this library, but not of this particular PR.

ssl.go Outdated
verifyCaOnly = true
} else {
o.Set("sslrootcert", "")
// From http://www.postgresql.org/docs/current/static/libpq- ssl.html:
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

ssl.go Outdated

var cinfo, kinfo os.FileInfo
var err error

if sslcert != "" && sslkey != "" {
if sslkeyOK && sslcertOK {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The old code is also incompatible with that libpq logic in that libpq allows either the certificate or the key to be blank, while this only does the right thing if both are blank.

I'm inclined to "break" compatibility in this way until someone reports that they need it, at which time we should add tests and implement the actual libpq behaviour.

ssl.go Outdated
@@ -105,16 109,15 @@ func sslClientCertificates(tlsConf *tls.Config, o values) {

// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
func sslCertificateAuthority(tlsConf *tls.Config, o values) {
if sslrootcert := o.Get("sslrootcert"); sslrootcert != "" {
if sslrootcert, ok := o["sslrootcert"]; ok {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think you're right, but as mentioned above, I think this is OK until we get a report of someone relying on this behaviour. WDYT?

@cbandy
Copy link
Contributor

cbandy commented Mar 7, 2017

I do think compatibility with libpq connection strings is a goal of this library, but not of this particular PR.

I didn't mean to imply that we should improve compatibility in this PR. I mean that we should not regress compatibility.

I'm inclined to "break" compatibility in this way until someone reports that they need it, at which time we should add tests and implement the actual libpq behaviour.

I'm not sure what you're trying to imply with the quotes here. I think I sufficiently (?) demonstrated that the behavior of SSL options should be based on blank values rather than the presence of keys in the map.

I think this is OK until we get a report of someone relying on this behaviour. WDYT?

🤔 I'm still not convinced... Maybe you see some other benefits to these values changes that I do not. Why these changes?

@tamird
Copy link
Collaborator Author

tamird commented Mar 7, 2017

Well, in general, values definitely promotes bad practices. That said, fixing the regressions you pointed out and adding tests.

@tamird
Copy link
Collaborator Author

tamird commented Mar 8, 2017

@cbandy OK, I think this is good to go with new tests exercising the treatment of empty sslcert and sslkey options.

Fixes #570, though I have not been able to write a test for this.

Remove methods on `values`. These methods are not a useful abstraction
and only serve to obscure that the underlying structure is a map. Their
presence is particularly inconvenient in that they promote confusing
empty values with the lack of value.

While I'm here, also improve conformance with libpq's treatment of
blank sslcert and sslkey option values. See the test changes for
specific changes.
@maddyblue
Copy link
Collaborator

Review status: 0 of 6 files reviewed at latest revision, 1 unresolved discussion.


ssl_test.go, line 44 at r1 (raw file):

func checkSSLSetup(t *testing.T, conninfo string) {
	_, err := openSSLConn(t, conninfo)

Why don't we need to close the db here?


Comments from Reviewable

@tamird
Copy link
Collaborator Author

tamird commented Mar 8, 2017

Review status: 0 of 6 files reviewed at latest revision, 1 unresolved discussion.


ssl_test.go, line 44 at r1 (raw file):

Previously, mjibson (Matt Jibson) wrote…

Why don't we need to close the db here?

I mean, we do, but it doesn't really matter since a nil error will result in a test failure, and the leaked database handle won't turn up anywhere.


Comments from Reviewable

@maddyblue
Copy link
Collaborator

Review status: 0 of 6 files reviewed at latest revision, 1 unresolved discussion.


ssl_test.go, line 44 at r1 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

I mean, we do, but it doesn't really matter since a nil error will result in a test failure, and the leaked database handle won't turn up anywhere.

Will it remain open on the server until a timeout? When running go test -count 100 -race trying to find race conditions I've had the pg server complain about too many connections, so I want to make sure we're closing things correctly.


Comments from Reviewable

@tamird
Copy link
Collaborator Author

tamird commented Mar 8, 2017

Review status: 0 of 6 files reviewed at latest revision, 1 unresolved discussion.


ssl_test.go, line 44 at r1 (raw file):

Previously, mjibson (Matt Jibson) wrote…

Will it remain open on the server until a timeout? When running go test -count 100 -race trying to find race conditions I've had the pg server complain about too many connections, so I want to make sure we're closing things correctly.

There will never be a non-nil connection here in a passing test run.


Comments from Reviewable

@maddyblue
Copy link
Collaborator

Well then LGTM, again. I agree that there is (was?) a problem since empty strings had their meaning changed in this PR. It seems like this code handles those in at least a well documented way, and if there are missing combinations we can add those as test cases.

@tamird
Copy link
Collaborator Author

tamird commented Mar 8, 2017

Thanks, @mjibson. I'll wait for final approval from @cbandy or else merge this tomorrow.

Copy link
Contributor

@cbandy cbandy left a comment

Choose a reason for hiding this comment

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

🎈

@tamird tamird merged commit a6140c9 into lib:master Mar 9, 2017
@tamird tamird deleted the remove-values-methods branch March 9, 2017 16:48
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