فهرست منبع

basic auth in http server

Darien Raymond 8 سال پیش
والد
کامیت
1d3c8098e9
5فایلهای تغییر یافته به همراه128 افزوده شده و 12 حذف شده
  1. 12 0
      proxy/http/config.go
  2. 22 10
      proxy/http/config.pb.go
  3. 2 1
      proxy/http/config.proto
  4. 9 0
      proxy/http/server.go
  5. 83 1
      testing/scenarios/http_test.go

+ 12 - 0
proxy/http/config.go

@@ -1 +1,13 @@
 package http
+
+func (sc *ServerConfig) HasAccount(username, password string) bool {
+	if sc.Accounts == nil {
+		return false
+	}
+
+	p, found := sc.Accounts[username]
+	if !found {
+		return false
+	}
+	return p == password
+}

+ 22 - 10
proxy/http/config.pb.go

@@ -17,7 +17,8 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
 
 // Config for HTTP proxy server.
 type ServerConfig struct {
-	Timeout uint32 `protobuf:"varint,1,opt,name=timeout" json:"timeout,omitempty"`
+	Timeout  uint32            `protobuf:"varint,1,opt,name=timeout" json:"timeout,omitempty"`
+	Accounts map[string]string `protobuf:"bytes,2,rep,name=accounts" json:"accounts,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
 }
 
 func (m *ServerConfig) Reset()                    { *m = ServerConfig{} }
@@ -32,6 +33,13 @@ func (m *ServerConfig) GetTimeout() uint32 {
 	return 0
 }
 
+func (m *ServerConfig) GetAccounts() map[string]string {
+	if m != nil {
+		return m.Accounts
+	}
+	return nil
+}
+
 // ClientConfig for HTTP proxy client.
 type ClientConfig struct {
 }
@@ -49,16 +57,20 @@ func init() {
 func init() { proto.RegisterFile("v2ray.com/core/proxy/http/config.proto", fileDescriptor0) }
 
 var fileDescriptor0 = []byte{
-	// 161 bytes of a gzipped FileDescriptorProto
+	// 238 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2b, 0x33, 0x2a, 0x4a,
 	0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x28, 0xca, 0xaf, 0xa8,
 	0xd4, 0xcf, 0x28, 0x29, 0x29, 0xd0, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28, 0xca,
-	0x2f, 0xc9, 0x17, 0x12, 0x85, 0xa9, 0x2b, 0x4a, 0xd5, 0x03, 0xab, 0xd1, 0x03, 0xa9, 0x51, 0xd2,
-	0xe0, 0xe2, 0x09, 0x4e, 0x2d, 0x2a, 0x4b, 0x2d, 0x72, 0x06, 0x2b, 0x16, 0x92, 0xe0, 0x62, 0x2f,
-	0xc9, 0xcc, 0x4d, 0xcd, 0x2f, 0x2d, 0x91, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0d, 0x82, 0x71, 0x95,
-	0xf8, 0xb8, 0x78, 0x9c, 0x73, 0x32, 0x53, 0xf3, 0x4a, 0x20, 0x2a, 0x9d, 0xac, 0xb9, 0x24, 0x93,
-	0xf3, 0x73, 0xf5, 0xb0, 0x1a, 0x1b, 0xc0, 0x18, 0xc5, 0x02, 0xa2, 0x57, 0x31, 0x89, 0x86, 0x19,
-	0x05, 0x25, 0x56, 0xea, 0x39, 0x83, 0xe4, 0x03, 0xc0, 0xf2, 0x1e, 0x25, 0x25, 0x05, 0x49, 0x6c,
-	0x60, 0x47, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xc9, 0xae, 0x86, 0xab, 0xbe, 0x00, 0x00,
-	0x00,
+	0x2f, 0xc9, 0x17, 0x12, 0x85, 0xa9, 0x2b, 0x4a, 0xd5, 0x03, 0xab, 0xd1, 0x03, 0xa9, 0x51, 0xda,
+	0xc2, 0xc8, 0xc5, 0x13, 0x9c, 0x5a, 0x54, 0x96, 0x5a, 0xe4, 0x0c, 0x56, 0x2d, 0x24, 0xc1, 0xc5,
+	0x5e, 0x92, 0x99, 0x9b, 0x9a, 0x5f, 0x5a, 0x22, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x1b, 0x04, 0xe3,
+	0x0a, 0xf9, 0x72, 0x71, 0x24, 0x26, 0x27, 0xe7, 0x97, 0xe6, 0x95, 0x14, 0x4b, 0x30, 0x29, 0x30,
+	0x6b, 0x70, 0x1b, 0x19, 0xea, 0x61, 0x35, 0x54, 0x0f, 0xd9, 0x40, 0x3d, 0x47, 0xa8, 0x1e, 0xd7,
+	0xbc, 0x92, 0xa2, 0xca, 0x20, 0xb8, 0x11, 0x52, 0xd6, 0x5c, 0xbc, 0x28, 0x52, 0x42, 0x02, 0x5c,
+	0xcc, 0xd9, 0xa9, 0x95, 0x60, 0x5b, 0x39, 0x83, 0x40, 0x4c, 0x21, 0x11, 0x2e, 0xd6, 0xb2, 0xc4,
+	0x9c, 0xd2, 0x54, 0x09, 0x26, 0xb0, 0x18, 0x84, 0x63, 0xc5, 0x64, 0xc1, 0xa8, 0xc4, 0xc7, 0xc5,
+	0xe3, 0x9c, 0x93, 0x99, 0x9a, 0x57, 0x02, 0xb1, 0xc4, 0xc9, 0x9a, 0x4b, 0x32, 0x39, 0x3f, 0x17,
+	0xbb, 0x73, 0x02, 0x18, 0xa3, 0x58, 0x40, 0xf4, 0x2a, 0x26, 0xd1, 0x30, 0xa3, 0xa0, 0xc4, 0x4a,
+	0x3d, 0x67, 0x90, 0x7c, 0x00, 0x58, 0xde, 0xa3, 0xa4, 0xa4, 0x20, 0x89, 0x0d, 0x1c, 0x42, 0xc6,
+	0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, 0x0a, 0xdd, 0xc0, 0x4b, 0x01, 0x00, 0x00,
 }

+ 2 - 1
proxy/http/config.proto

@@ -9,9 +9,10 @@ option java_multiple_files = true;
 // Config for HTTP proxy server.
 message ServerConfig {
   uint32 timeout = 1;
+  map<string, string> accounts = 2;
 }
 
 // ClientConfig for HTTP proxy client.
 message ClientConfig {
 
-}
+}

+ 9 - 0
proxy/http/server.go

@@ -83,6 +83,15 @@ Start:
 		}
 		return trace
 	}
+
+	if len(s.config.Accounts) > 0 {
+		user, pass, ok := request.BasicAuth()
+		if !ok || !s.config.HasAccount(user, pass) {
+			_, err := conn.Write([]byte("HTTP/1.1 401 UNAUTHORIZED\r\n\r\n"))
+			return err
+		}
+	}
+
 	log.Trace(newError("request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]"))
 	conn.SetReadDeadline(time.Time{})
 

+ 83 - 1
testing/scenarios/http_test.go

@@ -12,8 +12,8 @@ import (
 	"v2ray.com/core/common/serial"
 	"v2ray.com/core/proxy/freedom"
 	v2http "v2ray.com/core/proxy/http"
-	. "v2ray.com/ext/assert"
 	v2httptest "v2ray.com/core/testing/servers/http"
+	. "v2ray.com/ext/assert"
 )
 
 func TestHttpConformance(t *testing.T) {
@@ -72,3 +72,85 @@ func TestHttpConformance(t *testing.T) {
 
 	CloseAllServers(servers)
 }
+
+func TestHttpBasicAuth(t *testing.T) {
+	assert := With(t)
+
+	httpServerPort := pickPort()
+	httpServer := &v2httptest.Server{
+		Port:        httpServerPort,
+		PathHandler: make(map[string]http.HandlerFunc),
+	}
+	_, err := httpServer.Start()
+	assert(err, IsNil)
+	defer httpServer.Close()
+
+	serverPort := pickPort()
+	serverConfig := &core.Config{
+		Inbound: []*proxyman.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: net.SinglePortRange(serverPort),
+					Listen:    net.NewIPOrDomain(net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{
+					Accounts: map[string]string{
+						"a": "b",
+					},
+				}),
+			},
+		},
+		Outbound: []*proxyman.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
+			},
+		},
+	}
+
+	servers, err := InitializeServerConfigs(serverConfig)
+	assert(err, IsNil)
+
+	{
+		transport := &http.Transport{
+			Proxy: func(req *http.Request) (*url.URL, error) {
+				return url.Parse("http://127.0.0.1:" + serverPort.String())
+			},
+		}
+
+		client := &http.Client{
+			Transport: transport,
+		}
+
+		{
+			resp, err := client.Get("http://127.0.0.1:" + httpServerPort.String())
+			assert(err, IsNil)
+			assert(resp.StatusCode, Equals, 401)
+		}
+
+		{
+			req, err := http.NewRequest("GET", "http://127.0.0.1:"+httpServerPort.String(), nil)
+			assert(err, IsNil)
+
+			req.SetBasicAuth("a", "c")
+			resp, err := client.Do(req)
+			assert(err, IsNil)
+			assert(resp.StatusCode, Equals, 401)
+		}
+
+		{
+			req, err := http.NewRequest("GET", "http://127.0.0.1:"+httpServerPort.String(), nil)
+			assert(err, IsNil)
+
+			req.SetBasicAuth("a", "b")
+			resp, err := client.Do(req)
+			assert(err, IsNil)
+			assert(resp.StatusCode, Equals, 200)
+
+			content, err := ioutil.ReadAll(resp.Body)
+			assert(err, IsNil)
+			assert(string(content), Equals, "Home")
+		}
+	}
+
+	CloseAllServers(servers)
+}