Skip to content
This repository was archived by the owner on Sep 3, 2025. It is now read-only.

Commit 0a65d0a

Browse files
committed
bundle-server: introduce '--auth-config' web server option
Add an '--auth-config' flag to specify the path to a JSON file containing information used to configure bundle server auth, as well as a function for parsing the config. For now, no modes are configured, so attempting to pass a value to the option will fail. Update the 'git-bundle-web-server' manpage to describe the auth config and its usage. Also add 'auth-config.md' technical documentation with more detail around the schema of the auth config file. These will be updated as new modes are introduced. Signed-off-by: Victoria Dye <vdye@github.com>
1 parent 26d21f5 commit 0a65d0a

7 files changed

Lines changed: 131 additions & 1 deletion

File tree

cmd/git-bundle-server/web-server.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,11 @@ func (w *webServerCmd) startServer(ctx context.Context, args []string) error {
7777
parser.Visit(func(f *flag.Flag) {
7878
if webServerFlags.Lookup(f.Name) != nil {
7979
value := f.Value.String()
80-
if f.Name == "cert" || f.Name == "key" || f.Name == "client-ca" {
80+
if f.Name == "cert" ||
81+
f.Name == "key" ||
82+
f.Name == "client-ca" ||
83+
f.Name == "auth-config" {
84+
8185
// Need the absolute value of the path
8286
value, err = filepath.Abs(value)
8387
if err != nil {

cmd/git-bundle-web-server/main.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,43 @@ package main
22

33
import (
44
"context"
5+
"encoding/json"
56
"flag"
67
"fmt"
78
"os"
9+
"strings"
810

911
"github.com/git-ecosystem/git-bundle-server/cmd/utils"
1012
"github.com/git-ecosystem/git-bundle-server/internal/argparse"
1113
"github.com/git-ecosystem/git-bundle-server/internal/log"
14+
"github.com/git-ecosystem/git-bundle-server/pkg/auth"
1215
)
1316

17+
func parseAuthConfig(configPath string) (auth.AuthMiddleware, error) {
18+
var config authConfig
19+
fileBytes, err := os.ReadFile(configPath)
20+
if err != nil {
21+
return nil, err
22+
}
23+
24+
err = json.Unmarshal(fileBytes, &config)
25+
if err != nil {
26+
return nil, err
27+
}
28+
29+
switch strings.ToLower(config.AuthMode) {
30+
default:
31+
return nil, fmt.Errorf("unrecognized auth mode '%s'", config.AuthMode)
32+
}
33+
}
34+
35+
type authConfig struct {
36+
AuthMode string `json:"mode"`
37+
38+
// Per-middleware custom config
39+
Parameters json.RawMessage `json:"parameters,omitempty"`
40+
}
41+
1442
func main() {
1543
log.WithTraceLogger(context.Background(), func(ctx context.Context, logger log.TraceLogger) {
1644
parser := argparse.NewArgParser(logger, "git-bundle-web-server [--port <port>] [--cert <filename> --key <filename>]")
@@ -28,9 +56,27 @@ func main() {
2856
key := utils.GetFlagValue[string](parser, "key")
2957
tlsMinVersion := utils.GetFlagValue[uint16](parser, "tls-version")
3058
clientCA := utils.GetFlagValue[string](parser, "client-ca")
59+
authConfig := utils.GetFlagValue[string](parser, "auth-config")
3160

3261
// Configure auth
62+
var err error
3363
middlewareAuthorize := authFunc(nil)
64+
if authConfig != "" {
65+
middleware, err := parseAuthConfig(authConfig)
66+
if err != nil {
67+
logger.Fatalf(ctx, "Invalid auth config: %w", err)
68+
}
69+
if middleware == nil {
70+
// Up until this point, everything indicates that a user intends
71+
// to use - and has properly configured - custom auth. However,
72+
// despite there being no error from the initializer, the
73+
// middleware was empty. This is almost certainly incorrect, so
74+
// we exit.
75+
logger.Fatalf(ctx, "Middleware is nil, but no error was returned from initializer. "+
76+
"If no middleware is desired, remove the --auth-config option.")
77+
}
78+
middlewareAuthorize = middleware.Authorize
79+
}
3480

3581
// Configure the server
3682
bundleServer, err := NewBundleWebServer(logger,

cmd/utils/common-args.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ func WebServerFlags(parser argParser) (*flag.FlagSet, func(context.Context)) {
8686
tlsVersion := tlsVersionValue(tls.VersionTLS12)
8787
f.Var(&tlsVersion, "tls-version", "The minimum TLS version the server will accept")
8888
f.String("client-ca", "", "The path to the client authentication certificate authority PEM")
89+
f.String("auth-config", "", "File containing the configuration for server auth middleware")
8990

9091
// Function to call for additional arg validation (may exit with 'Usage()')
9192
validationFunc := func(ctx context.Context) {

docs/man/git-bundle-web-server.adoc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ web-server* for managing the web server process on their systems.
2727

2828
include::server-options.asc[]
2929

30+
== CONFIGURING AUTH
31+
32+
The *--auth-config* option configures authentication middleware for the server,
33+
either using a built-in mode or with a custom plugin. The auth config specified
34+
by that option is a JSON file that identifies the type of access control
35+
requested and information needed to configure it.
36+
37+
=== Schema
38+
39+
The auth config JSON contains the following fields:
40+
41+
*mode* (string)::
42+
The auth mode to use. Not case-sensitive.
43+
44+
*parameters* (object)::
45+
A structure containing mode-specific key-value configuration fields, if
46+
applicable. May be optional, depending on *mode*.
47+
3048
== SEE ALSO
3149

3250
man:git-bundle-server[1], man:git-bundle[1], man:git-fetch[1]

docs/man/server-options.asc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ configured for TLS, this option is a no-op.
2929
Require that requests to the bundle server include a client certificate that
3030
can be validated by the certificate authority file at the specified _path_.
3131
No-op if *--cert* and *--key* are not configured.
32+
33+
*--auth-config* _path_:::
34+
Use the JSON contents of the specified file to configure
35+
authentication/authorization for requests to the web server.

docs/technical/auth-config.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Configuring access control
2+
3+
User access to web server endpoints on the bundle server is configured via the
4+
`--auth-config` option to `git-bundle-web-server` and/or `git-bundle-server
5+
web-server`. The auth config is a JSON file that identifies the type of access
6+
control requested and information needed to configure it.
7+
8+
## Schema
9+
10+
The JSON file contains the following fields:
11+
12+
<table>
13+
<thead>
14+
<tr>
15+
<th>Field</th>
16+
<th>Type</th>
17+
<th>Description</th>
18+
</tr>
19+
</thead>
20+
<tbody>
21+
<tr>
22+
<td><code>mode</code></td>
23+
<td>string</td>
24+
<td>
25+
The auth mode to use. Not case-sensitive.
26+
</td>
27+
</tr>
28+
<tr>
29+
<td><code>parameters</code></td>
30+
<td>object</td>
31+
<td>
32+
A structure containing mode-specific key-value configuration
33+
fields, if applicable.
34+
</td>
35+
</tr>
36+
</tbody>
37+
</table>

pkg/auth/middleware.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package auth
2+
3+
import (
4+
"net/http"
5+
)
6+
7+
// AuthMiddleware provides custom authN/authZ functionality to validate requests
8+
// to the bundle web server.
9+
//
10+
// BE CAREFUL! Accesses to the loaded AuthMiddleware instance will *not* be
11+
// thread-safe. Custom implementations should ensure any writes to any common
12+
// state are properly locked.
13+
type AuthMiddleware interface {
14+
// Authorize interprets the contents of a bundle server request of a valid
15+
// format (i.e., /<owner>/<repo>[/<bundle>]) and returns an AuthResult
16+
// indicating whether the request should be allowed or denied. If the
17+
// AuthResult is invalid (not created with Allow() or Deny()), the server
18+
// will respond with a 500 status.
19+
Authorize(r *http.Request, owner string, repo string) AuthResult
20+
}

0 commit comments

Comments
 (0)