-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Allow OAuth::Consumer to take TLS context #4382
base: master
Are you sure you want to change the base?
Allow OAuth::Consumer to take TLS context #4382
Conversation
9cbb1ca
to
98e265e
Compare
Please ensure that your changes compile before you send a pull request. |
@RX14: They do, in the context of a shard anyway, as i exported the OAuth namespace into an OAuthmp namespace in my project, it compiles and runs, though i've had to make other changes to adjust for the slightly non-standard OAuth service in use. Compiling Crystal itself on Arch with grsecurity and a bunch of other changes can get nasty - PAX needs to be off or carefully exempted. |
@sempervictus You shouldn't need the compile crystal itself to run the standard library test suite. Just use |
As for the compile error, it does look weird. It might be a compiler bug. You'll probably have to extract it out into a field in the constructor, like |
Ah, cool, thank you for the tip - will take a bit to get spun up with the language specific idiosyncrasies (I miss interactive introspection in a REPL like you wouldn't believe, ICR ain't quite it).
Will run in my project to test as you suggested this evening, but if you'd like I can just move the resolution of the ivar into the method body since that seems to be what's causing Travis to fail spec.
Also, is the project convention not to use Travis as a testbed for PRs?
Lastly, the oauth header generated as a hash with a string embedded seems to be getting rejected by our python2 oauth provider. Works with python oauth client, so I'm thinking something is off in the param builder here, or the python service.
…-------- Original Message --------
From: Chris Hobbs <notifications@github.com>
Sent: Friday, May 5, 2017 11:37 AM
To: crystal-lang/crystal <crystal@noreply.github.com>
Subject: Re: [crystal-lang/crystal] Allow OAuth::Consumer to take TLS context (#4382)
CC: RageLtMan <rageltman@sempervictus.com>,Mention <mention@noreply.github.com>
@sempervictus You shouldn't need the compile crystal itself to run the standard library test suite. Just use `make std_spec` with the latest compiler release and it should be fine.
--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#4382 (comment)
|
@sempervictus Sure you can use travis but it's easier for most people to run the specs locally if they have crystal already checked out. A lot of people don't bother to check the travis status after they make their PR and need a nudge. |
@RX14: So i'm thinking this is actually a compiler bug:
where @scheme, only capable of being a String, and having a default value provided, or taking any other potential value passed, would still be a String, is compared to the String "https." In my limited understanding of compiler safety, this should be a "safe" operation since we must be comparing the same data types, even if they're empty. What i find a bit more troubling, is that by setting up @tls as a union of Nil | Bool | OpenSSL::SSL::Context::Client during initialization of the Consumer as discussed above, we're breaking a later call passing @tls to HTTP::Client.new as seen in:
Smells (to me anyway) of the instance variable @tls being a different type of union than the one expected by the HTTP::Client. The following code compiles and runs the spec just fine:
though i'm assuming a bit of Ruby-ish inferential behavior in that snippet, of which i'm not yet sure. Specifically the notion that @tls being a Union is "truthy," or will evaluate to True in the case of being passed true or an OpenSSL::SSL::Context::Client object, but not false. The actual commit i just pushed takes the approach of using #is_a?(OpenSSL::SSL::Context::Client), which seems less "elegant" than the snippet above. |
Your code doesn't allow passing tls: false when scheme is https. I'm not sure why you'd want to do that but I think it should be possible. Simply don't use the |
src/oauth/consumer.cr
Outdated
@@ -63,7 +63,8 @@ class OAuth::Consumer | |||
@request_token_uri : String = "/oauth/request_token", | |||
@authorize_uri : String = "/oauth/authorize", | |||
@access_token_uri : String = "/oauth/access_token", | |||
@tls : Bool | OpenSSL::SSL::Context::Client = @scheme == "https") | |||
@tls : Bool | OpenSSL::SSL::Context::Client = false) | |||
@tls = @scheme == "https" unless @tls.is_a?(OpenSSL::SSL::Context::Client) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest positive check instead in the vein of @scheme == "https" if @tls.is_a?(Bool)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still incorrect as per my comment above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@RX14: Check the commit log, i specifically explain that the logic here is not sound because of the Union handling problem when calling HTTP::Client.new using the three member Union of Nil | Bool | OpenSSL::SSL::Context::Client since HTTP::Client's constructor expects a Union with only Bool | OpenSSL::SSL::Context::Client members. I'm pretty sure this is a compiler level error - my original implementation was clean and retained logic consistency for assigning @tls. I will note that today you simply cant set @tls to false, so while the condition we both noticed is problematic for good programmers (this is how bugs and security flaws are born), it doesn't cause a functional regression, and should be fixed by allowing the original design of this PR to work in the initializer's arg processing stack.
@Sija: This is a positive check, for the OpenSSL::SSL::Context::Client member in the Union.
@ALL: So the hack here would be something like
...
@tls_ctx : Nil | OpenSSL::SSL::Context::Client = nil)
@tls = @tls_ctx.nil? ? @scheme == "https" : @tlx_ctx
...
Sorry for the eye sore, but given the logic constraint, union type check, and initializer arg misbehavior, this might have to be the "safe until required functionality is in place lower in the stack" approach
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sempervictus The hack you mentioned is much better written as
tls : Nil | OpenSSL::SSL::Context::Client | Bool = nil)
@tls = tls.nil? ? @scheme == "https" : tls
and that's what I'd send in as my fix, at least until this compiler bug gets fixed.
@RX14: We cant add a nil to the union, its passed to another initializer in http client which can't take the altered passed argument - union type check succeeds, or we could potentially pass a nil to http client which should fault..
|
@sempervictus You absolutely can if you remove nil from the union before it's set to |
That's a strange nuance, implicitly changing the type of a variable during conditional evaluation.
I'll test your version this evening. Thanks for the enlightening insight, will take me a few cycles to get up to speed, but having read through the tracker and stdlib, it looks like there's a good deal of work I can tackle...
|
Just noticed the one character difference... local variables and instance variables can share names. Grand. Still prevents passing a boolean option for the tls setting, which is counter to the normal logic, but probably the lesser of evils available to us. |
@sempervictus if you just add |
feab217
to
cc0508a
Compare
Sorry for the lag, got lost in the churn :(. Implemented as you requested @RX14. Thanks for prodding me through this.
|
Looks like the build is failing because of formatting. Would run |
CI failure on the last commit is unrelated - OSX seems to not have been able to acquire LLVM:
|
Addresses issue crystal-lang#4381 Oauth consumer objects determine their TLS configuration strictly as a boolean, then pass it to HTTP clients which are capable of more complex configuration for use cases such as ignoring peer certificate validation, client certificate configuration, etc. Add a tls parameter of Nil | Bool | OpenSSL::SSL::Context::Client, checking for its presence to determine whether or not to fall back to resolving the boolean value from the value of @scheme when assigning the value for @tls, which remains a union of Bool | OpenSSL::SSL::Context::Client which can be passed to the HTTP client safely.
eb12a03
to
280c318
Compare
@RX14: seems to be passing CI, any blockers remaining? |
There are couple of things from my point of view:
|
@mverzilli We do a similar thing in HTTP::Client so the change to accept a TLS context isn't without precedent. Personally, I think we should design some sort of openssl-agnostic TLS api and only expose that in the stdlib. We then implement a openssl-backed version of that API and extract the old openssl module to a shard which people who need advanced features can use. Then, everywhere we use TLS, we can have a nice crystally options class which people can pass in. Obviously beyond the scope of this PR. |
Agreed. Still we would need at least one test to exercise the new option (even more important considering that eventually we'll have to break backwards compatibility to "agnosticize" the design). |
Windows's built in SSL would probably be a good test of that. Windows support will likely be here in some fashion by the time fiddling with SSL apis is at the top of the todo list. |
Wholly agreed on abstraction of TLS functions to a shim lib for interface with the multiple back ends available (win, libre, etc). |
@sempervictus are you still working on the specs? ;) |
Addresses issue #4381
Oauth consumer objects determine their TLS configuration strictly
as a boolean, then pass it to HTTP clients which are capable of
more complex configuration for use cases such as ignoring peer
certificate validation, client certificate configuration, etc.
Remove the strict Bool typecasting for the @tls instance variable
in OAuth::Consumer, replacing it with initializer functionality
which encapsulates the scheme resolution for default value setting
or takes explicit Bool | OpenSSL::SSL::Context::Client parameters.