Skip to content

Commit 251195b

Browse files
committed
feat(auth): add cli option to enable auth for specified users
1 parent 7cba61b commit 251195b

File tree

8 files changed

+144
-64
lines changed

8 files changed

+144
-64
lines changed

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,6 @@ ghfs [options]
226226
--cors-dir <fs-path> ...
227227
Allow CORS requests for specific file system paths(and sub paths).
228228
229-
--global-auth
230-
Use Basic Auth for all url path.
231-
--auth <url-path> ...
232-
Use Basic Auth for specific url paths(and sub paths).
233-
--auth-dir <fs-path> ...
234-
Use Basic Auth for specific file system paths(and sub paths).
235229
--user [<username>]:[<password>] ...
236230
Specify users for current virtual host for Basic Auth, empty username and/or password is allowed.
237231
--user-base64 [<username>]:[<base64-password>] ...
@@ -241,6 +235,15 @@ ghfs [options]
241235
--user-sha512 [<username>]:<sha512-password> ...
242236
Specify users for Basic Auth, with encoded password.
243237
238+
--global-auth
239+
Use Basic Auth for all url path.
240+
--auth <url-path> ...
241+
--auth-user <separator><url-path>[<separator><allowed-username>...] ...
242+
Use Basic Auth for specific url paths(and sub paths).
243+
--auth-dir <fs-path> ...
244+
--auth-dir-user <separator><fs-path>[<separator><allowed-username>...] ...
245+
Use Basic Auth for specific file system paths(and sub paths).
246+
244247
-c|--cert <file> ...
245248
Specify TLS certificate file.
246249

README.zh-CN.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,6 @@ ghfs [选项]
216216
--cors-dir <文件系统路径> ...
217217
接受指定文件系统路径(及子路径)的CORS跨域请求。
218218
219-
--global-auth
220-
对所有URL路径启用http基本验证(Basic Auth)。
221-
--auth <URL路径> ...
222-
对指定URL路径(及子路径)启用http基本验证。
223-
--auth-dir <文件系统路径> ...
224-
对指定文件系统路径(及子路径)启用http基本验证。
225219
--user [<用户名>]:[<密码>] ...
226220
为当前虚拟主机指定用于http基本验证的用户,允许空的用户名和/或密码。
227221
--user-base64 [<用户名>]:[<base64密码>] ...
@@ -231,6 +225,15 @@ ghfs [选项]
231225
--user-sha512 [<用户名>]:<sha512密码> ...
232226
指定http基本验证的用户,对密码使用特定的编码。
233227
228+
--global-auth
229+
对所有URL路径启用http基本验证(Basic Auth)。
230+
--auth <URL路径> ...
231+
--auth-user <分隔符><URL路径>[<分隔符><允许的用户名>...] ...
232+
对指定URL路径(及子路径)启用http基本验证。
233+
--auth-dir <文件系统路径> ...
234+
--auth-dir-user <分隔符><文件系统路径>[<分隔符><允许的用户名>...] ...
235+
对指定文件系统路径(及子路径)启用http基本验证。
236+
234237
-c|--cert <证书文件> ...
235238
指定TLS证书文件。
236239

src/param/cli.go

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,46 @@ func NewCliCmd() *goNixArgParser.Command {
4242
err = options.AddFlagsValues("dirindexes", []string{"-I", "--dir-index"}, "GHFS_DIR_INDEX", nil, "default index page for directory")
4343
serverError.CheckFatal(err)
4444

45+
err = options.AddFlagValues("users", "--user", "", nil, "user info: <username>:<password>")
46+
serverError.CheckFatal(err)
47+
48+
err = options.AddFlagValues("usersbase64", "--user-base64", "", nil, "user info: <username>:<base64-password>")
49+
serverError.CheckFatal(err)
50+
51+
err = options.AddFlagValues("usersmd5", "--user-md5", "", nil, "user info: <username>:<md5-password>")
52+
serverError.CheckFatal(err)
53+
54+
err = options.AddFlagValues("userssha1", "--user-sha1", "", nil, "user info: <username>:<sha1-password>")
55+
serverError.CheckFatal(err)
56+
57+
err = options.AddFlagValues("userssha256", "--user-sha256", "", nil, "user info: <username>:<sha256-password>")
58+
serverError.CheckFatal(err)
59+
60+
err = options.AddFlagValues("userssha512", "--user-sha512", "", nil, "user info: <username>:<sha512-password>")
61+
serverError.CheckFatal(err)
62+
63+
err = options.AddFlag("globalauth", "--global-auth", "GHFS_GLOBAL_AUTH", "require Basic Auth for all directories")
64+
serverError.CheckFatal(err)
65+
66+
err = options.AddFlagValues("authurls", "--auth", "", nil, "url path that require Basic Auth")
67+
serverError.CheckFatal(err)
68+
69+
err = options.AddFlagValues("authurlsusers", "--auth-user", "", nil, "url path that require Basic Auth for specific users, <sep><url-path>[<sep><user>...]")
70+
serverError.CheckFatal(err)
71+
72+
err = options.AddFlagValues("authdirs", "--auth-dir", "", nil, "file system path that require Basic Auth")
73+
serverError.CheckFatal(err)
74+
75+
err = options.AddFlagValues("authdirsusers", "--auth-dir-user", "", nil, "file system path that require Basic Auth for specific users, <sep><fs-path>[<sep><user>...]")
76+
serverError.CheckFatal(err)
77+
4578
err = options.AddFlagValues("globalrestrictaccess", "--global-restrict-access", "GHFS_GLOBAL_RESTRICT_ACCESS", []string{}, "restrict access to all url paths from current host, with optional extra allow list")
4679
serverError.CheckFatal(err)
4780

48-
err = options.AddFlagValues("restrictaccessurls", "--restrict-access", "", []string{}, "restrict access to specific url paths from current host, with optional extra allow list")
81+
err = options.AddFlagValues("restrictaccessurls", "--restrict-access", "", []string{}, "restrict access to specific url paths from current host, with optional extra allow list, <sep><url-path>[<sep><allowed-host>...]")
4982
serverError.CheckFatal(err)
5083

51-
err = options.AddFlagValues("restrictaccessdirs", "--restrict-access-dir", "", []string{}, "restrict access to specific file system paths from current host, with optional extra allow list")
84+
err = options.AddFlagValues("restrictaccessdirs", "--restrict-access-dir", "", []string{}, "restrict access to specific file system paths from current host, with optional extra allow list, <sep><fs-path>[<sep><allowed-host>...]")
5285
serverError.CheckFatal(err)
5386

5487
err = options.AddFlagValues("globalheaders", "--global-header", "GHFS_GLOBAL_HEADER", []string{}, "custom headers for all url paths, e.g. <name>:<value>")
@@ -105,33 +138,6 @@ func NewCliCmd() *goNixArgParser.Command {
105138
err = options.AddFlagValues("corsdirs", "--cors-dir", "", nil, "file system path that enable CORS headers")
106139
serverError.CheckFatal(err)
107140

108-
err = options.AddFlag("globalauth", "--global-auth", "GHFS_GLOBAL_AUTH", "require Basic Auth for all directories")
109-
serverError.CheckFatal(err)
110-
111-
err = options.AddFlagValues("authurls", "--auth", "", nil, "url path that require Basic Auth")
112-
serverError.CheckFatal(err)
113-
114-
err = options.AddFlagValues("authdirs", "--auth-dir", "", nil, "file system path that require Basic Auth")
115-
serverError.CheckFatal(err)
116-
117-
err = options.AddFlagValues("users", "--user", "", nil, "user info: <username>:<password>")
118-
serverError.CheckFatal(err)
119-
120-
err = options.AddFlagValues("usersbase64", "--user-base64", "", nil, "user info: <username>:<base64-password>")
121-
serverError.CheckFatal(err)
122-
123-
err = options.AddFlagValues("usersmd5", "--user-md5", "", nil, "user info: <username>:<md5-password>")
124-
serverError.CheckFatal(err)
125-
126-
err = options.AddFlagValues("userssha1", "--user-sha1", "", nil, "user info: <username>:<sha1-password>")
127-
serverError.CheckFatal(err)
128-
129-
err = options.AddFlagValues("userssha256", "--user-sha256", "", nil, "user info: <username>:<sha256-password>")
130-
serverError.CheckFatal(err)
131-
132-
err = options.AddFlagValues("userssha512", "--user-sha512", "", nil, "user info: <username>:<sha512-password>")
133-
serverError.CheckFatal(err)
134-
135141
err = options.AddFlagsValues("certs", []string{"-c", "--cert"}, "GHFS_CERT", nil, "TLS certificate path")
136142
serverError.CheckFatal(err)
137143

@@ -366,6 +372,12 @@ func CmdResultsToParams(results []*goNixArgParser.ParseResult) (params Params, e
366372
param.GlobalAuth = result.HasKey("globalauth")
367373
param.AuthUrls, _ = result.GetStrings("authurls")
368374
param.AuthDirs, _ = result.GetStrings("authdirs")
375+
// auth urls users
376+
authUrlsUsers, _ := result.GetStrings("authurlsusers")
377+
param.AuthUrlsUsers = SplitAllKeyValues(authUrlsUsers)
378+
// auth dirs users
379+
authDirsUsers, _ := result.GetStrings("authdirsusers")
380+
param.AuthDirsUsers = SplitAllKeyValues(authDirsUsers)
369381

370382
// users
371383
arrUsersPlain, _ := result.GetStrings("users")

src/param/main.go

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,29 @@ type Param struct {
1818

1919
DefaultSort string
2020
DirIndexes []string
21-
// value: [url-path, fs-path]
22-
Aliases [][2]string
21+
Aliases [][2]string // [][url-path, fs-path]
22+
23+
// [][username, password]
24+
UsersPlain [][2]string
25+
UsersBase64 [][2]string
26+
UsersMd5 [][2]string
27+
UsersSha1 [][2]string
28+
UsersSha256 [][2]string
29+
UsersSha512 [][2]string
30+
31+
GlobalAuth bool
32+
AuthUrls []string
33+
AuthUrlsUsers [][]string // [][path, user...]
34+
AuthDirs []string
35+
AuthDirsUsers [][]string // [][path, user...]
2336

2437
GlobalRestrictAccess []string
25-
// value: [restrict-path, allow-hosts...]
38+
// [][restrict-path, allow-hosts...]
2639
RestrictAccessUrls [][]string
2740
RestrictAccessDirs [][]string
2841

29-
// value: [name, value]
30-
GlobalHeaders [][2]string
31-
// value: [path, (name, value)...]
42+
GlobalHeaders [][2]string // [][name, value]
43+
// [][path, (name, value)...]
3244
HeadersUrls [][]string
3345
HeadersDirs [][]string
3446

@@ -52,17 +64,6 @@ type Param struct {
5264
CorsUrls []string
5365
CorsDirs []string
5466

55-
GlobalAuth bool
56-
AuthUrls []string
57-
AuthDirs []string
58-
// value: [username, password]
59-
UsersPlain [][2]string
60-
UsersBase64 [][2]string
61-
UsersMd5 [][2]string
62-
UsersSha1 [][2]string
63-
UsersSha256 [][2]string
64-
UsersSha512 [][2]string
65-
6667
Certificates []tls.Certificate
6768
Listens []string
6869
ListensPlain []string
@@ -138,6 +139,21 @@ func (param *Param) normalize() (errs []error) {
138139
// dir indexes
139140
param.DirIndexes = normalizeFilenames(param.DirIndexes)
140141

142+
// auth users
143+
param.AuthUrlsUsers, es = normalizeAllPathValues(param.AuthUrlsUsers, true, util.NormalizeUrlPath, nil)
144+
if len(es) == 0 {
145+
dedupAllPathValues(param.AuthUrlsUsers)
146+
} else {
147+
errs = append(errs, es...)
148+
}
149+
150+
param.AuthDirsUsers, es = normalizeAllPathValues(param.AuthDirsUsers, true, filepath.Abs, nil)
151+
if len(es) == 0 {
152+
dedupAllPathValues(param.AuthDirsUsers)
153+
} else {
154+
errs = append(errs, es...)
155+
}
156+
141157
// global restrict access, nil to disable, non-nil to enable with allowed hosts
142158
if param.GlobalRestrictAccess != nil {
143159
param.GlobalRestrictAccess = util.ExtractHostsFromUrls(param.GlobalRestrictAccess)

src/serverHandler/aliasHandler.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,11 @@ func newAliasHandler(
212212
dirIndexes: p.DirIndexes,
213213
aliases: allAliases.filterSuccessor(currentAlias.url),
214214

215-
globalAuth: p.GlobalAuth || prefixMatched(p.AuthUrls, util.HasUrlPrefixDir, currentAlias.url) || prefixMatched(p.AuthDirs, util.HasFsPrefixDir, currentAlias.fs),
216-
authUrls: filterSuccessor(p.AuthUrls, util.HasUrlPrefixDir, currentAlias.url),
217-
authDirs: filterSuccessor(p.AuthDirs, util.HasFsPrefixDir, currentAlias.fs),
215+
globalAuth: p.GlobalAuth || prefixMatched(p.AuthUrls, util.HasUrlPrefixDir, currentAlias.url) || prefixMatched(p.AuthDirs, util.HasFsPrefixDir, currentAlias.fs),
216+
authUrls: filterSuccessor(p.AuthUrls, util.HasUrlPrefixDir, currentAlias.url),
217+
authUrlsUsers: vhostCtx.authUrlsUsers.filterSuccessor(util.HasUrlPrefixDir, currentAlias.url),
218+
authDirs: filterSuccessor(p.AuthDirs, util.HasFsPrefixDir, currentAlias.fs),
219+
authDirsUsers: vhostCtx.authDirsUsers.filterSuccessor(util.HasFsPrefixDir, currentAlias.fs),
218220

219221
globalRestrictAccess: globalRestrictAccess,
220222
restrictAccessUrls: vhostCtx.restrictAccessUrls.filterSuccessor(util.HasUrlPrefixDir, currentAlias.url),

src/serverHandler/util.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package serverHandler
22

33
import (
4+
"mjpclab.dev/ghfs/src/user"
45
"mjpclab.dev/ghfs/src/util"
56
"net/http"
67
"os"
@@ -9,6 +10,27 @@ import (
910
"strings"
1011
)
1112

13+
func pathUsernamesToPathUids(users *user.List, pathsUsernames [][]string) pathIntsList {
14+
list := make(pathIntsList, 0, len(pathsUsernames))
15+
for _, pathUsernames := range pathsUsernames {
16+
if len(pathUsernames) < 1 {
17+
continue
18+
}
19+
pathIds := pathInts{
20+
path: pathUsernames[0],
21+
ints: make([]int, 0, len(pathUsernames)-1),
22+
}
23+
for _, username := range pathUsernames[1:] {
24+
uid := users.FindIndex(username)
25+
if uid >= 0 {
26+
pathIds.ints = append(pathIds.ints, uid)
27+
}
28+
}
29+
list = append(list, pathIds)
30+
}
31+
return list
32+
}
33+
1234
func wildcardToRegexp(wildcards []string) (*regexp.Regexp, error) {
1335
if len(wildcards) == 0 {
1436
return nil, nil

src/serverHandler/vhostHandler.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ type vhostContext struct {
2222
hideDirs *regexp.Regexp
2323
hideFiles *regexp.Regexp
2424

25+
authUrlsUsers pathIntsList
26+
authDirsUsers pathIntsList
27+
2528
restrictAccessUrls pathStringsList
2629
restrictAccessDirs pathStringsList
2730

@@ -75,6 +78,10 @@ func NewVhostHandler(
7578
return nil, errs
7679
}
7780

81+
// auth urls users
82+
authUrlsUsers := pathUsernamesToPathUids(users, p.AuthUrlsUsers)
83+
authDirsUsers := pathUsernamesToPathUids(users, p.AuthDirsUsers)
84+
7885
// restrict access
7986
restrictAccessUrls := newRestrictAccesses(p.RestrictAccessUrls)
8087
restrictAccessDirs := newRestrictAccesses(p.RestrictAccessDirs)
@@ -84,10 +91,13 @@ func NewVhostHandler(
8491

8592
// alias param
8693
vhostCtx := &vhostContext{
87-
users: users,
8894
theme: theme,
8995
logger: logger,
9096

97+
users: users,
98+
authUrlsUsers: authUrlsUsers,
99+
authDirsUsers: authDirsUsers,
100+
91101
shows: shows,
92102
showDirs: showDirs,
93103
showFiles: showFiles,

test/case/007.auth.bash

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
source "$root"/lib.bash
44

5-
"$ghfs" -l 3003 -r "$fs"/vhost1 --auth /hello --user alice:AliceSecret -E '' &
5+
"$ghfs" -l 3003 -r "$fs"/vhost1 --auth /hello --auth-user :/world:bob --user alice:AliceSecret --user bob:BobSecret -E '' &
66
sleep 0.05 # wait server ready
77

88
status=$(curl_get_status http://127.0.0.1:3003/yes/)
@@ -17,10 +17,22 @@ assert "$status" '200'
1717
status=$(curl_head_status http://alice:AliceSecret@127.0.0.1:3003/hello/)
1818
assert "$status" '200'
1919

20+
status=$(curl_get_status http://alice:AliceSecret@127.0.0.1:3003/world/)
21+
assert "$status" '401'
22+
23+
status=$(curl_head_status http://alice:AliceSecret@127.0.0.1:3003/world/)
24+
assert "$status" '401'
25+
26+
status=$(curl_get_status http://bob:BobSecret@127.0.0.1:3003/world/)
27+
assert "$status" '200'
28+
29+
status=$(curl_head_status http://bob:BobSecret@127.0.0.1:3003/world/)
30+
assert "$status" '200'
31+
2032
status=$(curl_get_status http://127.0.0.1:3003/yes/?auth)
2133
assert "$status" '401'
2234

23-
status=$(curl_get_status http://bob:BobSecret@127.0.0.1:3003/yes/)
35+
status=$(curl_get_status http://eve:EveSecret@127.0.0.1:3003/yes/)
2436
assert "$status" '200'
2537

2638
status=$(curl_get_status http://alice:AliceSecret@127.0.0.1:3003/yes/?auth)

0 commit comments

Comments
 (0)