func (runCommand *RunCommand) Execute(configLoader ConfigLoader) error { config, err := configLoader() if err != nil { return err } proxy := goproxy.NewProxyHttpServer() //Verbose if either config or RunCommand is set to verbose proxy.Verbose = config.Verbose || runCommand.IsVerbose var matchCondition = goproxy.ReqConditionFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) bool { _, ok := config.Rewrites[req.URL.String()] log.Printf("Trying to match %s", req.URL.String()) if ok { log.Printf("Matched %s", req.URL.String()) } return ok }) proxy.OnRequest(matchCondition).DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { dstFile, _ := config.Rewrites[req.URL.Path] fileBytes, err := ioutil.ReadFile(dstFile) if err == nil { return req, goproxy.NewResponse(req, "text/css", 200, string(fileBytes[:])) } else { log.Printf("Error reading file %s", dstFile) return req, nil } }) configChan := proxyconfig.StartWatching(proxyconfig.DefaultConfigFile) go func() { for { config = <-configChan proxy.Verbose = config.Verbose } }() log.Printf("Starting proxyserver localhost:8080 with config %+v", *config) log.Fatal(http.ListenAndServe(":8080", proxy)) return nil }
func serve(ctx *cli.Context) error { clientID := ctx.String("client-id") clientSecret := ctx.String("client-secret") var config settings.Config var err error if ctx.String("config") != "" { config, err = settings.Parse(ctx.String("config")) if err != nil { logs.Error(err) } } if config.Debug() { logs.Level(logs.DebugLevel) } redisSettings, err := config.Redis() client := redis.NewClient(&redis.Options{Addr: redisSettings.String()}) if _, err := client.Ping().Result(); err != nil { return err } logs.Debug("Connected to Redis at %s", redisSettings.String()) store := components.NewRedisStore(client) proxy := goproxy.NewProxyHttpServer() if config.Debug() { proxy.Verbose = true } // Treat only requests with an SID cookie or POSTing username and password. var session = goproxy.ReqConditionFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) bool { _, err := req.Cookie("SID") return err == nil || (req.Method == "POST" && req.FormValue("username") != "" && req.FormValue("password") != "") // The form is already parsed. }) proxy.NonproxyHandler = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { dump, _ := httputil.DumpRequest(req, true) fmt.Println(string(dump)) req.URL.Scheme = req.Header.Get("X-Scheme") req.URL.Host = req.Host proxy.ServeHTTP(w, req) }) proxy.OnRequest(session).DoFunc( func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { //dump, _ := httputil.DumpRequest(req, true) //fmt.Println(string(dump)) cookie, err := req.Cookie("SID") if err == nil { session, err := store.Load(cookie.Value) if err != nil { return req, goproxy.NewResponse(req, "text/plain", http.StatusForbidden, "Invalid cookie") } req.Header.Del("Cookie") req.Header.Add("Authorization", "Bearer "+session.AccessToken) return req, nil } // Perform an OAuth "Resource Owner Password Credentials Grant" req.Form.Add("grant_type", "password") req.SetBasicAuth(clientID, clientSecret) // We must update the body and the content size for our new post value. var buffer io.Reader = strings.NewReader(req.Form.Encode()) req.Body = ioutil.NopCloser(buffer) switch v := buffer.(type) { case *bytes.Buffer: req.ContentLength = int64(v.Len()) case *bytes.Reader: req.ContentLength = int64(v.Len()) case *strings.Reader: req.ContentLength = int64(v.Len()) } //req.RequestURI = "" // Must be removed for client requests client := &http.Client{} resp, err := client.Do(req) if err != nil { return req, nil } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return req, nil } // TODO: Check http status for errors access := new(components.AccessData) if err := json.Unmarshal(body, access); err != nil { return req, nil } session := &components.Session{ ID: strings.TrimRight(base64.StdEncoding.EncodeToString(uuid.NewRandom()), "="), AccessToken: access.AccessToken, RefreshToken: access.RefreshToken, ExpiresIn: access.ExpiresIn, } if err := store.Save(session); err != nil { return req, nil } // TODO: Give a json response to clients resp = goproxy.NewResponse(req, "text/plain", http.StatusOK, "") cookie = &http.Cookie{Name: "SID", Value: session.ID} resp.Header.Add("Set-Cookie", cookie.String()) return req, resp }, ) server, err := config.Server() if err != nil { logs.Critical(err) os.Exit(1) } logs.Info("Listening on %s", server.String()) return http.ListenAndServe(server.String(), proxy) }