// eccaProxy: proxy the user requests and authenticate with the credentials we know. func eccaProxy(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { //log.Println("\n\n\nRequest is ", req.Method, req.URL.String()) ctx.Logf("Start-of-eccaProxy handler") for _, c := range req.Cookies() { ctx.Logf("Cookie send by the client is: %#v", c.Name) } // set the scheme to https so we connect upstream securely if req.URL.Scheme == "http" { req.URL.Scheme = "https" } // Copy the body because we need it untouched. But we also need to parse // the POST parameters and that eats the original buffer with the body body, err := ioutil.ReadAll(req.Body) check(err) req.Body.Close() // close it before replacing. Prevents leaking file descriptors. // give the data back immedeately. req.Body = ioutil.NopCloser(bytes.NewReader(body)) // Read the parameters req.ParseForm() // eats req.Body req.Body = ioutil.NopCloser(bytes.NewReader(body)) // copy back in again // Check for POST method with 'encrypt', 'sign' or 'initiate-direct-connection' parameter. if req.Method == "POST" { if req.Form.Get("initiate-direct-connection") == "required" { // create a direct connection listener, awaiting reply return initiateDirectConnection(req) } else if req.Form.Get("encrypt") == "required" { // transparantly encrypt and sign for a private message return encryptMessage(req) } else if req.Form.Get("sign") == "required" || req.Form.Get("sign") == "optional" { // transparently sign the message before publication return signMessage(req, ctx) } } // Fetch the request from upstream resp, err := fetchRequest(req, ctx) if err != nil { ctx.Warnf("There was an error fetching the users' request: %v", err) return req, goproxy.NewResponse(req, goproxy.ContentTypeText, http.StatusInternalServerError, "Some server error!") } ctx.Logf("response is %#v", resp) for _, c := range resp.Cookies() { ctx.Logf("Cookie send by the server is: %#v\n", c.Name) } ctx.Logf("End-of-eccaProxy handler") //log.Printf("Sleeping for 10 seconds...\n") //time.Sleep(10 * time.Second) return nil, resp // let goproxy send our response }
// fetchRequest fetches the original users' request. // adds client certificate to authenticate func fetchRequest(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Response, error) { // clean up the recycled header we got from the user ctx.Logf("OldRequestURI is %s", req.RequestURI) req.RequestURI = "" client, err := makeClient(req.URL.Host) if err != nil { return nil, err } ctx.Logf("Connecting to: %s", req.URL.String()) resp, err := client.Do(req) if err != nil { return nil, err } // The rest of this function should go in a separate Response handler.. // test if we need to authenticate. if resp.StatusCode != 401 { // nope, we're done. Exit here. return resp, nil } ctx.Logf("status code is 401") // We have an 401-authorization failed // Test for a WWW-Authenticate: Ecca .... header. auth := ParseWWWAuthHeader(resp.Header.Get("Www-Authenticate")) if auth == nil { // No Ecca-authentication required. We're done. Exit here. log.Printf("No WWW-Authenticate: Ecca header, sending 401 response to client") return resp, nil } ctx.Logf("WWW-Authenticate: Ecca header found: %#v", auth) // remember registerURL for the signup-phase registerURLmap[req.Host] = auth["register"] // redirect to Ecca-Proxy user agent (ourself) to log in or sign up resp.Body.Close() resp = redirectToSelector(req) return resp, nil }