feat(client): add http basic auth

add http basic auth

ref tobyxdd/hysteria#15

Signed-off-by: mritd <mritd@linux.com>
This commit is contained in:
mritd 2020-08-07 14:12:01 +08:00
parent 7257ce746e
commit ca1f1fdcab
No known key found for this signature in database
GPG Key ID: 98C41327E6D3E645
3 changed files with 47 additions and 8 deletions

View File

@ -3,6 +3,14 @@ package main
import ( import (
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/base64"
"io/ioutil"
"net"
"net/http"
"strings"
"time"
"github.com/elazarl/goproxy"
"github.com/lucas-clemente/quic-go" "github.com/lucas-clemente/quic-go"
"github.com/lucas-clemente/quic-go/congestion" "github.com/lucas-clemente/quic-go/congestion"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -12,10 +20,6 @@ import (
hyHTTP "github.com/tobyxdd/hysteria/pkg/http" hyHTTP "github.com/tobyxdd/hysteria/pkg/http"
"github.com/tobyxdd/hysteria/pkg/obfs" "github.com/tobyxdd/hysteria/pkg/obfs"
"github.com/tobyxdd/hysteria/pkg/socks5" "github.com/tobyxdd/hysteria/pkg/socks5"
"io/ioutil"
"net"
"net/http"
"time"
) )
func proxyClient(args []string) { func proxyClient(args []string) {
@ -152,6 +156,36 @@ func proxyClient(args []string) {
"action": actionToString(action, arg), "action": actionToString(action, arg),
"dst": reqAddr, "dst": reqAddr,
}).Debug("New HTTP request") }).Debug("New HTTP request")
},
func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
if config.HTTPUser == "" || config.HTTPPassword == "" {
return req, nil
}
resp := goproxy.NewResponse(req, goproxy.ContentTypeText, http.StatusUnauthorized, "401 - Forbidden: Unauthorized")
// RFC7617 section 2.1
pa := req.Header.Get("Proxy-Authorization")
if pa == "" {
return req, resp
}
authStr := strings.Fields(pa)
if len(authStr) != 2 || authStr[0] != "Basic" {
return req, resp
}
decodeBytes, err := base64.StdEncoding.DecodeString(authStr[1])
if err != nil {
logrus.WithField("error", err).Fatal("Failed to decode base64 auth string")
return req, resp
}
userAndPassword := strings.Split(string(decodeBytes), ":")
if len(userAndPassword) != 2 {
return req, resp
}
if userAndPassword[0] != config.HTTPUser || userAndPassword[1] != config.HTTPPassword {
return req, resp
}
return req, nil
}) })
if err != nil { if err != nil {
logrus.WithField("error", err).Fatal("HTTP server initialization failed") logrus.WithField("error", err).Fatal("HTTP server initialization failed")

View File

@ -13,6 +13,8 @@ type proxyClientConfig struct {
SOCKS5DisableUDP bool `json:"socks5_disable_udp" desc:"Disable SOCKS5 UDP support"` SOCKS5DisableUDP bool `json:"socks5_disable_udp" desc:"Disable SOCKS5 UDP support"`
HTTPAddr string `json:"http_addr" desc:"HTTP listen address"` HTTPAddr string `json:"http_addr" desc:"HTTP listen address"`
HTTPTimeout int `json:"http_timeout" desc:"HTTP connection timeout in seconds"` HTTPTimeout int `json:"http_timeout" desc:"HTTP connection timeout in seconds"`
HTTPUser string `json:"http_user" desc:"HTTP basic auth username"`
HTTPPassword string `json:"http_password" desc:"HTTP basic auth password"`
ACLFile string `json:"acl" desc:"Access control list"` ACLFile string `json:"acl" desc:"Access control list"`
ServerAddr string `json:"server" desc:"Server address"` ServerAddr string `json:"server" desc:"Server address"`
Username string `json:"username" desc:"Authentication username"` Username string `json:"username" desc:"Authentication username"`

View File

@ -3,19 +3,22 @@ package http
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/elazarl/goproxy"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core"
"net" "net"
"net/http" "net/http"
"time" "time"
"github.com/elazarl/goproxy"
"github.com/tobyxdd/hysteria/pkg/acl"
"github.com/tobyxdd/hysteria/pkg/core"
) )
func NewProxyHTTPServer(hyClient core.Client, idleTimeout time.Duration, aclEngine *acl.Engine, func NewProxyHTTPServer(hyClient core.Client, idleTimeout time.Duration, aclEngine *acl.Engine,
newDialFunc func(reqAddr string, action acl.Action, arg string)) (*goproxy.ProxyHttpServer, error) { newDialFunc func(reqAddr string, action acl.Action, arg string),
basicAuthFunc func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response)) (*goproxy.ProxyHttpServer, error) {
proxy := goproxy.NewProxyHttpServer() proxy := goproxy.NewProxyHttpServer()
proxy.Logger = &nopLogger{} proxy.Logger = &nopLogger{}
proxy.NonproxyHandler = http.NotFoundHandler() proxy.NonproxyHandler = http.NotFoundHandler()
proxy.OnRequest().DoFunc(basicAuthFunc)
proxy.Tr = &http.Transport{ proxy.Tr = &http.Transport{
Dial: func(network, addr string) (net.Conn, error) { Dial: func(network, addr string) (net.Conn, error) {
// Parse addr string // Parse addr string