Skip to content

Commit ed62451

Browse files
maweckhacdias
authored andcommitted
feat: proxy auth support (filebrowser#485)
* Change the order of commands to be able to cache more layers in case of multiple builds triggered in a row * Fix filebrowser#471 * Format Code * Revert "Change the order of commands to be able to cache more layers in case of multiple builds triggered in a row" This reverts commit 01362f3. * Adjustment based on the review * Rename "login-header" to "loginHeader" and prepare auth.method to accept "none" as a value * Fixed line break * Readd "lumberjack.v2" import which was removed by gofmt Sorry - I do my tests and run "gofmt" before comitting the changes - It sadly seems like it is messing up the imports over and over again.
1 parent b90e7b8 commit ed62451

File tree

4 files changed

+77
-21
lines changed

4 files changed

+77
-21
lines changed

cmd/filebrowser/main.go

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,22 @@ package main
22

33
import (
44
"fmt"
5-
"io/ioutil"
6-
"log"
7-
"net"
8-
"net/http"
9-
"os"
10-
"path/filepath"
11-
"strings"
12-
135
"github.com/asdine/storm"
14-
15-
"gopkg.in/natefinch/lumberjack.v2"
16-
176
"github.com/filebrowser/filebrowser"
187
"github.com/filebrowser/filebrowser/bolt"
198
h "github.com/filebrowser/filebrowser/http"
209
"github.com/filebrowser/filebrowser/staticgen"
2110
"github.com/hacdias/fileutils"
2211
flag "github.com/spf13/pflag"
2312
"github.com/spf13/viper"
24-
)
13+
"gopkg.in/natefinch/lumberjack.v2"
14+
"io/ioutil"
15+
"log"
16+
"net"
17+
"net/http"
18+
"os"
19+
"path/filepath"
20+
"strings")
2521

2622
var (
2723
addr string
@@ -38,13 +34,17 @@ var (
3834
recaptchakey string
3935
recaptchasecret string
4036
port int
41-
noAuth bool
42-
allowCommands bool
43-
allowEdit bool
44-
allowNew bool
45-
allowPublish bool
46-
showVer bool
47-
alterRecaptcha bool
37+
auth struct {
38+
method string
39+
loginHeader string
40+
}
41+
noAuth bool
42+
allowCommands bool
43+
allowEdit bool
44+
allowNew bool
45+
allowPublish bool
46+
showVer bool
47+
alterRecaptcha bool
4848
)
4949

5050
func init() {
@@ -63,6 +63,8 @@ func init() {
6363
flag.BoolVar(&allowCommands, "allow-commands", true, "Default allow commands option for new users")
6464
flag.BoolVar(&allowEdit, "allow-edit", true, "Default allow edit option for new users")
6565
flag.BoolVar(&allowPublish, "allow-publish", true, "Default allow publish option for new users")
66+
flag.StringVar(&auth.method, "auth.method", "default", "Switch between 'none', 'default' and 'proxy' authentication.")
67+
flag.StringVar(&auth.loginHeader, "auth.loginHeader", "X-Forwarded-User", "The header name used for proxy authentication.")
6668
flag.BoolVar(&allowNew, "allow-new", true, "Default allow new option for new users")
6769
flag.BoolVar(&noAuth, "no-auth", false, "Disables authentication")
6870
flag.BoolVar(&alterRecaptcha, "alternative-recaptcha", false, "Use recaptcha.net for serving and handling, useful in China")
@@ -84,6 +86,8 @@ func setupViper() {
8486
viper.SetDefault("AllowPublish", true)
8587
viper.SetDefault("StaticGen", "")
8688
viper.SetDefault("Locale", "")
89+
viper.SetDefault("AuthMethod", "default")
90+
viper.SetDefault("LoginHeader", "X-Fowarded-User")
8791
viper.SetDefault("NoAuth", false)
8892
viper.SetDefault("BaseURL", "")
8993
viper.SetDefault("PrefixURL", "")
@@ -104,6 +108,8 @@ func setupViper() {
104108
viper.BindPFlag("AllowPublish", flag.Lookup("allow-publish"))
105109
viper.BindPFlag("Locale", flag.Lookup("locale"))
106110
viper.BindPFlag("StaticGen", flag.Lookup("staticgen"))
111+
viper.BindPFlag("AuthMethod", flag.Lookup("auth.method"))
112+
viper.BindPFlag("LoginHeader", flag.Lookup("auth.loginHeader"))
107113
viper.BindPFlag("NoAuth", flag.Lookup("no-auth"))
108114
viper.BindPFlag("BaseURL", flag.Lookup("baseurl"))
109115
viper.BindPFlag("PrefixURL", flag.Lookup("prefixurl"))
@@ -168,6 +174,18 @@ func main() {
168174
})
169175
}
170176

177+
// Validate the provided config before moving forward
178+
if viper.GetString("AuthMethod") != "none" && viper.GetString("AuthMethod") != "default" && viper.GetString("AuthMethod") != "proxy" {
179+
log.Fatal("The property 'auth.method' needs to be set to 'default' or 'proxy'.")
180+
}
181+
182+
if viper.GetString("AuthMethod") == "proxy" {
183+
if viper.GetString("LoginHeader") == "" {
184+
log.Fatal("The 'loginHeader' needs to be specified when 'proxy' authentication is used.")
185+
}
186+
log.Println("[WARN] Filebrowser authentication is configured to 'proxy' authentication. This can cause a huge security issue if the infrastructure is not configured correctly.")
187+
}
188+
171189
// Builds the address and a listener.
172190
laddr := viper.GetString("Address") + ":" + viper.GetString("Port")
173191
listener, err := net.Listen("tcp", laddr)
@@ -196,6 +214,8 @@ func handler() http.Handler {
196214
}
197215

198216
fm := &filebrowser.FileBrowser{
217+
AuthMethod: viper.GetString("AuthMethod"),
218+
LoginHeader: viper.GetString("LoginHeader"),
199219
NoAuth: viper.GetBool("NoAuth"),
200220
BaseURL: viper.GetString("BaseURL"),
201221
PrefixURL: viper.GetString("PrefixURL"),

doc.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ to import "github.com/filebrowser/filebrowser/bolt".
1616
1717
m := &fm.FileBrowser{
1818
NoAuth: false,
19+
Auth: {
20+
Method: "default",
21+
LoginHeader: "X-Fowarded-User"
22+
},
1923
DefaultUser: &fm.User{
2024
AllowCommands: true,
2125
AllowEdit: true,

filebrowser.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ type FileBrowser struct {
7171
// there will only exist one user, called "admin".
7272
NoAuth bool
7373

74+
// Define if which of the following authentication mechansims should be used:
75+
// - 'default', which requires a user and a password.
76+
// - 'proxy', which requires a valid user and the user name has to be provided through an
77+
// http header.
78+
// - 'none', which allows anyone to access the filebrowser instance.
79+
AuthMethod string
80+
81+
// When 'AuthMethod' is set to 'proxy' the header configured below is used to identify the user.
82+
LoginHeader string
83+
7484
// ReCaptcha host, key and secret.
7585
ReCaptchaHost string
7686
ReCaptchaKey string

http/auth.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,32 @@ func reCaptcha(host, secret, response string) (bool, error) {
5151

5252
// authHandler processes the authentication for the user.
5353
func authHandler(c *fb.Context, w http.ResponseWriter, r *http.Request) (int, error) {
54-
// NoAuth instances shouldn't call this method.
5554
if c.NoAuth {
55+
// NoAuth instances shouldn't call this method.
5656
return 0, nil
5757
}
5858

59+
if c.AuthMethod == "proxy" {
60+
// Receive the Username from the Header and check if it exists.
61+
u, err := c.Store.Users.GetByUsername(r.Header.Get(c.LoginHeader), c.NewFS)
62+
if err != nil {
63+
return http.StatusForbidden, nil
64+
}
65+
66+
c.User = u
67+
return printToken(c, w)
68+
}
69+
5970
// Receive the credentials from the request and unmarshal them.
6071
var cred cred
72+
6173
if r.Body == nil {
6274
return http.StatusForbidden, nil
6375
}
6476

6577
err := json.NewDecoder(r.Body).Decode(&cred)
6678
if err != nil {
67-
return http.StatusForbidden, nil
79+
return http.StatusForbidden, err
6880
}
6981

7082
// If ReCaptcha is enabled, check the code.
@@ -171,6 +183,16 @@ func validateAuth(c *fb.Context, r *http.Request) (bool, *fb.User) {
171183
return true, c.User
172184
}
173185

186+
// If proxy auth is used do not verify the JWT token if the header is provided.
187+
if c.AuthMethod == "proxy" {
188+
u, err := c.Store.Users.GetByUsername(r.Header.Get(c.LoginHeader), c.NewFS)
189+
if err != nil {
190+
return false, nil
191+
}
192+
c.User = u
193+
return true, c.User
194+
}
195+
174196
keyFunc := func(token *jwt.Token) (interface{}, error) {
175197
return c.Key, nil
176198
}

0 commit comments

Comments
 (0)