Golang net/http/httptest error crypto/x509.unknownauthorityerror - go

I am trying to mock out a response from a HTTPS web service responding to my Golang package.
In my unit test I am using net/http/httptest.
My function is
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello")
}))
defer ts.Close()
tr := &http.Transport{TLSClientConfig: &TLS.Config{InsecureSkipVerify: true}}
client := ts.Client()
client= &http.Client{Transport:tr}
res, err := client.Get(ts.URL)
When I step through the code and my package makes the call to the mock service, it errors with error (crypto/x509.UnknownAuthorityError)
I thought the skip verify is meant ignore verifying any certificates? Yes, I am mocking out certificates when my package is instantiated, but for the purpose of the test, I am not interested in the certificates all I want to do is verify the response coming back and the code after.
What am I doing wrong with mocking a HTTPS request response?

Related

OAuth Authorization in Golang CLI Applications

I've been using the code from the OAuth2 package documentation to add authorization to my CLI application, but I've run into a bit of a snag.
package main
import (
"context"
"fmt"
"log"
"golang.org/x/oauth2"
)
func main() {
ctx := context.Background()
conf := &oauth2.Config{
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
Scopes: []string{"SCOPE1", "SCOPE2"},
Endpoint: oauth2.Endpoint{
AuthURL: "https://provider.com/o/oauth2/auth",
TokenURL: "https://provider.com/o/oauth2/token",
},
}
// Redirect user to consent page to ask for permission
// for the scopes specified above.
url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline)
fmt.Printf("Visit the URL for the auth dialog: %v", url)
// Use the authorization code that is pushed to the redirect
// URL. Exchange will do the handshake to retrieve the
// initial access token. The HTTP Client returned by
// conf.Client will refresh the token as necessary.
var code string
if _, err := fmt.Scan(&code); err != nil {
log.Fatal(err)
}
tok, err := conf.Exchange(ctx, code)
if err != nil {
log.Fatal(err)
}
client := conf.Client(ctx, tok)
client.Get("...")
}
I'm using StackOverflow as the authorization server and api.stackexchange.com doc says the following. But I'm not sure what it means.
Desktop applications cannot participate directly in OAuth 2.0 flows, however the embeddable browser controls available in most frameworks make it possible to work around this limitation.
The issue is that when I use the method described in the documentation, I have to manually click the URL generated in the CLI and manually copy the access token to continue.
Do you happen to know of a way to automate these two steps in Golang or a different approach I could take for authorization in CLI applications?
What I'm hoping for is something like what you see in the heroku-cli but with OAuth 2.0 - it would be awesome if my app could handle authorization in a similar way. Thanks for your help!
I'd really appreciate any help or advice you can offer. Thanks!

GRPC over HTTPS proper client initialization in Go

I'm interfacing from my code certain 3rd party software (particularly chirpstack v4) which provides API via GPRC. When deployed locally, it answers via HTTP and I get the response all right.
However in cluster we have the same server deployed with HTTPS (with letsencrypt certificate, not something private) so I'm trying to add corresponding transport layer security settings, but to my surprise I got then
rpc error: code = Internal desc = unexpected HTTP status code received from server: 400 (Bad Request); malformed header: missing HTTP content-type
I tried adding SetHeader to context with content-type: application/grpc but this won't change anything so I'm not sure it is really about header (moreover that it works with plain HTTP). So I wonder, perhaps anyone can point me some mistake in initialization of transport layer security?
// this is used with plain HTTP
//opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
// this for case of working via HTTPS
opts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))}
// also tried NewClientTLSFromCert(x509.SystemCertPool()) - the same
serverAddr := "our-public-address:443"
ctx := context.Background()
conn, err := grpc.Dial(serverAddr, opts...)
if err != nil {
println("Dial error:", err.Error())
return
}
cli := api.NewInternalServiceClient(conn)
req := &api.LoginRequest{Email: "admin", Password: "admin"}
resp, err := cli.Login(ctx, req) // error arises here
if err != nil {
println("login failed", err.Error())
}
Thanks in advance for hints and suggestions!

AWS API Gateway WebSockets [POST]#connections Returning 404 NotFound

I connect a client (or a couple of clients) to the websockets endpoint in API Gateway.
Then, I try to post a message back to the client using these guidelines: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html
// Send sends a message to a connection ID.
func Send(domain, stage, connectionID, message string) (events.APIGatewayProxyResponse, error) {
session := session.Must(session.NewSession())
endpoint := fmt.Sprintf("https://%s/%s/#connections/%s", domain, stage, connectionID)
apiClient := apigatewaymanagementapi.New(session, aws.NewConfig().WithEndpoint(endpoint))
connectionInput := apigatewaymanagementapi.PostToConnectionInput{
ConnectionId: aws.String(connectionID),
Data: []byte(message),
}
_, err := apiClient.PostToConnection(&connectionInput)
if err != nil {
fmt.Println(err.Error())
return events.APIGatewayProxyResponse{StatusCode: 500}, err
}
return events.APIGatewayProxyResponse{StatusCode: 200}, nil
}
It doesn't matter whether I invoke the Send function locally or a client sends a message and API Gateway invokes my publish Lambda where I loop through the connections and invoke Send for each of them.
The result is always the same.
NotFoundException:
status code: 404, request id: 7bb1546a-c2a7-4e98-92a0-fcc7ae175d7c
Things I've tried:
Escaped #connections and the actual connectionID
Made sure the client connection hasn't timed out
Made sure I have the correct AWS credentials in my environment variables
Made sure my Lambda has permissions to invoke API Gateway
Made sure the endpoint is in the correct format: https://{api-id}.execute-api.{region}.amazonaws.com/{stage}/#connections/{connection_id}
How can I successfully send messages to the clients?
Turns out this line
endpoint := fmt.Sprintf("https://%s/%s/#connections/%s", domain, stage, connectionID)
needs to turn into this
endpoint := fmt.Sprintf("https://%s/%s/", domain, stage)

How to create HTTP Session in Go

I am currently using fasthttp for sending my requests my question is, is there a way to have a persistent session? I need the cookies and data to stick.
c := fasthttp.Client{ Name: "Add To Cart",}
store, err := session.Start() // ?????
args := fasthttp.AcquireArgs()
defer fasthttp.ReleaseArgs(args)
args.Add("pid", sizepid)
args.Add("options", "[]")
args.Add("quantity", "1")
statusCode, body, err := c.Post(nil, "URL", args)
if err != nil {
panic(err)
}`
Based on your question I think this is already clear to you, but just in case:
Sessions aren't started on the client, they are started on the server. The server checks to see if a specific cookie exists; if it does it resumes the session that the cookie identifies; if it doesn't it creates a new session and sends the identifier back to the client as a cookie. All the client needs to do is send the correct cookie to the server.
So, you need to read and write cookies. The fasthttp.Client.Post() interface doesn't allow you to do that. So instead of that nice interface, things become rather ugly.
You need to ask fasthttp for both a Request and Response object before you do the request. Once you've done the initial request, you need to either look all cookies, or read out a specific cookie. You can now use those values for your next request.
I've written a short example of how you would do this.
func main() {
c := fasthttp.Client{}
// Create a request
req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)
req.SetRequestURI(`https://www.google.com/`)
// Create a response
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)
// Execute the request, writing to the response object
err := c.Do(req, resp)
if err != nil {
panic(err)
}
// Loop over all cookies; usefull if you want to just send everything back on consecutive requests
resp.Header.VisitAllCookie(func(key, value []byte) {
log.Printf("Cookie %s: %s\n", key, value)
})
// Read a specific cookie
nid := fasthttp.AcquireCookie()
defer fasthttp.ReleaseCookie(nid)
nid.SetKey(`NID`)
if resp.Header.Cookie(nid) {
log.Println("Value for NID Cookie: " + string(nid.Value()))
// Create a second request and set the cookie from the first
req2 := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req2)
req2.SetRequestURI(`https://www.google.com/`)
req2.Header.SetCookie(`NID`, string(nid.Value()))
// Now you can execute this request again using c.Do() - don't forget to acquire a new Response!
}
}
Note: you can chose to skip the fasthttp.AcquireXXX() and defer fasthttp.ReleaseXXX(yyy) steps - but that would negate much (maybe most) of the performance benefits over using standard net/http, so if you go that route maybe just ditch fasthttp all together.

How to test http.Redirect target URL in golang

I have set up a http redirect in the go handler, and I'm trying to verify if the target URL is composed as expected.
I'm currently using httptest for relevant unit test.
In the handler:
url := fmt.Sprintf("%s%s?token=%s", domain, someURL, token)
http.Redirect(w, r, url, 302)
The current unit test can only verify the respond code but not the target URL:
resp := httptest.NewRecorder()
router.ServeHTTP(resp, req)
assert.Equal(t, 302, resp.Code)
I'm expecting something like
assert.Equal(t, expectedURL, resp.redirectURL)
Assert that the Location header is as expected:
assert.Equal(t, expectedURL, resp.HeaderMap.Get("Location"))

Resources