Merge pull request #74 from se77en/master

Add basic auth to dashboard
This commit is contained in:
fatedier 2016-08-14 13:55:13 +08:00 committed by GitHub
commit 47c1a3e52c
5 changed files with 86 additions and 23 deletions

View File

@ -6,7 +6,7 @@
## What is frp? ## What is frp?
frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.Now, it supports tcp, http and https protocol when requests can be forwarded by domains to backward web services. frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet. Now, it supports tcp, http and https protocol when requests can be forwarded by domains to backward web services.
## Catalog ## Catalog
@ -37,9 +37,9 @@ frp is a fast reverse proxy to help you expose a local server behind a NAT or fi
## Status ## Status
frp is under development and you can try it with latest release version.Master branch for releasing stable version when dev branch for developing. frp is under development and you can try it with latest release version. Master branch for releasing stable version when dev branch for developing.
**We may change any protocol and can't promise backward compatible.Please check the release log when upgrading.** **We may change any protocol and can't promise backward compatible. Please check the release log when upgrading.**
## Architecture ## Architecture
@ -149,9 +149,12 @@ Configure a port for dashboard to enable this feature:
```ini ```ini
[common] [common]
dashboard_port = 7500 dashboard_port = 7500
# dashboard's username and password are both optionalif not set, default is admin.
dashboard_username = abc
dashboard_password = abc
``` ```
Then visit `http://[server_addr]:7500` to see dashboard. Then visit `http://[server_addr]:7500` to see dashboard, default username and password are both `admin`.
![dashboard](/doc/pic/dashboard.png) ![dashboard](/doc/pic/dashboard.png)

View File

@ -146,9 +146,12 @@ frp 目前正在前期开发阶段master 分支用于发布稳定版本dev
```ini ```ini
[common] [common]
dashboard_port = 7500 dashboard_port = 7500
# dashboard 用户名密码可选,默认都为 admin
dashboard_username = abc
dashboard_password = abc
``` ```
打开浏览器通过 `http://[server_addr]:7500` 访问 dashboard 界面。 打开浏览器通过 `http://[server_addr]:7500` 访问 dashboard 界面,用户名密码默认为 `admin`
![dashboard](/doc/pic/dashboard.png) ![dashboard](/doc/pic/dashboard.png)

View File

@ -9,6 +9,9 @@ vhost_http_port = 80
vhost_https_port = 443 vhost_https_port = 443
# if you want to configure or reload frps by dashboard, dashboard_port must be set # if you want to configure or reload frps by dashboard, dashboard_port must be set
dashboard_port = 7500 dashboard_port = 7500
# dashboard username and password for basic protect, if not set, both default value is admin
dashboard_username = abc
dashboard_password = abc
# dashboard assets directory(only for debug mode) # dashboard assets directory(only for debug mode)
# assets_dir = ./static # assets_dir = ./static
# console or real logFile path like ./frps.log # console or real logFile path like ./frps.log

View File

@ -30,19 +30,21 @@ import (
// common config // common config
var ( var (
ConfigFile string = "./frps.ini" ConfigFile string = "./frps.ini"
BindAddr string = "0.0.0.0" BindAddr string = "0.0.0.0"
BindPort int64 = 7000 BindPort int64 = 7000
VhostHttpPort int64 = 0 // if VhostHttpPort equals 0, don't listen a public port for http protocol VhostHttpPort int64 = 0 // if VhostHttpPort equals 0, don't listen a public port for http protocol
VhostHttpsPort int64 = 0 // if VhostHttpsPort equals 0, don't listen a public port for https protocol VhostHttpsPort int64 = 0 // if VhostHttpsPort equals 0, don't listen a public port for https protocol
DashboardPort int64 = 0 // if DashboardPort equals 0, dashboard is not available DashboardPort int64 = 0 // if DashboardPort equals 0, dashboard is not available
AssetsDir string = "" DashboardUsername string = "admin"
LogFile string = "console" DashboardPassword string = "admin"
LogWay string = "console" // console or file AssetsDir string = ""
LogLevel string = "info" LogFile string = "console"
LogMaxDays int64 = 3 LogWay string = "console" // console or file
PrivilegeMode bool = false LogLevel string = "info"
PrivilegeToken string = "" LogMaxDays int64 = 3
PrivilegeMode bool = false
PrivilegeToken string = ""
// if PrivilegeAllowPorts is not nil, tcp proxies which remote port exist in this map can be connected // if PrivilegeAllowPorts is not nil, tcp proxies which remote port exist in this map can be connected
PrivilegeAllowPorts map[int64]struct{} PrivilegeAllowPorts map[int64]struct{}
@ -119,6 +121,16 @@ func loadCommonConf(confFile string) error {
DashboardPort = 0 DashboardPort = 0
} }
tmpStr, ok = conf.Get("common", "dashboard_username")
if ok {
DashboardUsername = tmpStr
}
tmpStr, ok = conf.Get("common", "dashboard_password")
if ok {
DashboardPassword = tmpStr
}
tmpStr, ok = conf.Get("common", "assets_dir") tmpStr, ok = conf.Get("common", "assets_dir")
if ok { if ok {
AssetsDir = tmpStr AssetsDir = tmpStr

View File

@ -15,9 +15,11 @@
package server package server
import ( import (
"encoding/base64"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"strings"
"time" "time"
"github.com/fatedier/frp/src/assets" "github.com/fatedier/frp/src/assets"
@ -38,7 +40,7 @@ func RunDashboardServer(addr string, port int64) (err error) {
// view, see dashboard_view.go // view, see dashboard_view.go
mux.Handle("/favicon.ico", http.FileServer(assets.FileSystem)) mux.Handle("/favicon.ico", http.FileServer(assets.FileSystem))
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(assets.FileSystem))) mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(assets.FileSystem)))
mux.HandleFunc("/", viewDashboard) mux.HandleFunc("/", use(viewDashboard, basicAuth))
address := fmt.Sprintf("%s:%d", addr, port) address := fmt.Sprintf("%s:%d", addr, port)
server := &http.Server{ server := &http.Server{
@ -58,3 +60,43 @@ func RunDashboardServer(addr string, port int64) (err error) {
go server.Serve(ln) go server.Serve(ln)
return return
} }
func use(h http.HandlerFunc, middleware ...func(http.HandlerFunc) http.HandlerFunc) http.HandlerFunc {
for _, m := range middleware {
h = m(h)
}
return h
}
func basicAuth(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
if len(s) != 2 {
http.Error(w, "Not authorized", 401)
return
}
b, err := base64.StdEncoding.DecodeString(s[1])
if err != nil {
http.Error(w, err.Error(), 401)
return
}
pair := strings.SplitN(string(b), ":", 2)
if len(pair) != 2 {
http.Error(w, "Not authorized", 401)
return
}
if pair[0] != DashboardUsername || pair[1] != DashboardPassword {
http.Error(w, "Not authorized", 401)
return
}
h.ServeHTTP(w, r)
}
}