Loading...
Loading...
### Terraform Version ```shell Terraform 1.13.5 ``` ### Terraform Configuration Files Configuration is not relevant to this report. ### Debug Output n/a ### Expected Behavior During the OAuth process for [the Terraform Login Protocol](https://developer.hashicorp.com/terraform/internals/login-protocol), the `terraform login` process temporarily starts an HTTP server running on localhost, and asks the OAuth provider to redirect the user's browser back to an endpoint on that server once the interactive consent flow has completed. After handling that request, the temporary HTTP server ought to return an HTML page including the following message so that the user understands that they should return to their terminal to continue: ```html The login server has returned an authentication code to Terraform. Now close this page and return to the terminal where terraform login is running to see the result of the login process. ``` ### Actual Behavior Sometimes the browser's connection to that temporary server is closed abruptly without returning a response, causing the browser to display a generic error message. Although Terraform does still save the new auth token to disk as expected, the user is currently looking at the browser rather than the terminal and so gets no indication that the process has succeeded. ### Steps to Reproduce This behavior is nondeterministic (see "Additional Context" below) but it can potentially happen for any `terraform login` to a hostname that supports the `login.v1` protocol. After approving the issuance of the token in the OAuth provider's web UI, their OAuth provider implementation will redirect back to Terraform's server. At that point Terraform will either return the expected success message or will abruptly terminate the connection. Unfortunately because this behavior can only be triggered as part of an interaction with an external service run by a third-party, I cannot provide a ready-to-run reproduction process but I have instead attempted to explain the apparent cause of the problem below. ### Additional Context I actually found this problem while working on another codebase that has some code in common with Terraform, but in closed-box testing I observed it in Terraform to and so I'm reporting it here in case it's helpful, since I believe I implemented this bug way back in 6bba3ceb4208c470f82b2985747329fbcabbc8f2! 😞 Unfortunately due to my relationship with that other codebase I'm not allowed to look at any Terraform code that is not under an open source license, but this problem appears to have existed in the older MPL-licenced releases too and so I'm going to use code from those older releases as context here. I don't know if the code I'm linking to here is still the same in current Terraform, but even if not the behavior I've described still seems to occur in some form. I believe the cause of this problem is a nondeterministic order of operations across two goroutines in the `terraform login` implementation. The temporary HTTP server serves each incoming request in a new goroutine, with the following handler: https://github.com/hashicorp/terraform/blob/325d18262e9eeb20546e0d27ef002a14fbc21118/internal/command/login.go#L420-L455 Notice that when it receives an acceptable request that suggests completion of the OAuth flow it sends the "code" to the `codeCh` channel. The main goroutine awaits a message on that channel before proceeding: https://github.com/hashicorp/terraform/blob/325d18262e9eeb20546e0d27ef002a14fbc21118/internal/command/login.go#L505-L516 Notice that immediately after receiving the code the main goroutine closes the HTTP server. That code is running concurrently with the code at the end of the HTTP handler that returns the response, and so it's unpredictable whether the handler will finish writing its response before the main goroutine terminates the server. If the main goroutine wins this race then the connection to the user's browser is terminated too soon and the browser renders an error message. A relatively straightforward quick patch for this is to use [`Server.Shutdown`](https://pkg.go.dev/net/http#Server.Shutdown) instead of [`Server.Close`](https://pkg.go.dev/net/http#Server.Close) so that any active connections are allowed to run to completion. However, that's still not a completely robust solution since of course not long afterwards the `terraform login` process will completely exit anyway and so in principle it's possible (though less likely) that the process exit happens before the handler finishes sending the response and thus the same symptom occurs. Either sending the response _before_ sending the code to the channel, or alternatively making the HTTP handler send an explicit signal to the main goroutine that it's finished sending the response, would be a more robust approach. ### References The temporary HTTP server described in this issue is handling the "Redirection Endpoint" as defined in [RFC 6749 section 3.1.2](https://datatracker.ietf.org/doc/html/rfc6749#section-3.1.2). ### Generative AI / LLM assisted development? None
Click on a version to see all relevant bugs
Terraform Integration
Learn more about where this data comes from
BugZero Plan
Streamline upgrades with automated vendor bug scrubs
BugZero Prevent
Wish you caught this bug sooner? Get proactive today.