Skip to content

Commit 2212f8f

Browse files
authored
Merge pull request #7 from gobuffalo/better-error-handling
better error handling once more
2 parents a78e58d + 7c1520f commit 2212f8f

File tree

7 files changed

+143
-350
lines changed

7 files changed

+143
-350
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
<p align="center"><img src="https://github.com/gobuffalo/buffalo/blob/master/logo.svg" width="360"></p>
1+
# mw-basicauth
22

3-
<p align="center">
4-
<a href="https://godoc.org/github.com/gobuffalo/mw-basicauth"><img src="https://godoc.org/github.com/gobuffalo/mw-basicauth?status.svg" alt="GoDoc"></a>
5-
<a href="https://travis-ci.org/gobuffalo/mw-basicauth"><img src="https://travis-ci.org/gobuffalo/mw-basicauth.svg?branch=master" alt="Build Status"></a>
6-
<a href="https://goreportcard.com/report/github.com/gobuffalo/mw-basicauth"><img src="https://goreportcard.com/badge/github.com/gobuffalo/mw-basicauth" alt="Go Report Card" /></a>
7-
</p>
3+
[![Standard Test](https://github.com/gobuffalo/mw-basicauth/actions/workflows/standard-go-test.yml/badge.svg)](https://github.com/gobuffalo/mw-basicauth/actions/workflows/standard-go-test.yml)
4+
[![Go Reference](https://pkg.go.dev/badge/github.com/gobuffalo/mw-basicauth.svg)](https://pkg.go.dev/github.com/gobuffalo/mw-basicauth)
5+
[![Go Report Card](https://goreportcard.com/badge/github.com/gobuffalo/mw-basicauth)](https://goreportcard.com/report/github.com/gobuffalo/mw-basicauth)
86

9-
# [Basic HTTP Authentication](https://tools.ietf.org/html/rfc7617) Middleware for [Buffalo](https://github.com/gobuffalo/buffalo)
7+
[Basic HTTP Authentication](https://tools.ietf.org/html/rfc7617) Middleware
8+
for [Buffalo](https://github.com/gobuffalo/buffalo)
109

1110
## Installation
1211

13-
```bash
14-
$ go get -u github.com/gobuffalo/mw-basicauth
12+
```console
13+
$ go get github.com/gobuffalo/mw-basicauth
1514
```
1615

1716
## Usage
@@ -20,6 +19,7 @@ $ go get -u github.com/gobuffalo/mw-basicauth
2019
auth := func(c buffalo.Context, u, p string) (bool, error) {
2120
return (u == "username" && p == "password"), nil
2221
}
22+
2323
app.Use(basicauth.Middleware(auth))
2424
```
2525

SHOULDERS.md

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,19 @@ mw-basicauth does not try to reinvent the wheel! Instead, it uses the already gr
55
Thank you to the following **GIANTS**:
66

77
* [github.com/BurntSushi/toml](https://godoc.org/github.com/BurntSushi/toml)
8-
* [github.com/Masterminds/semver/v3](https://godoc.org/github.com/Masterminds/semver/v3)
98
* [github.com/aymerick/douceur](https://godoc.org/github.com/aymerick/douceur)
10-
* [github.com/cockroachdb/apd](https://godoc.org/github.com/cockroachdb/apd)
11-
* [github.com/coreos/go-systemd](https://godoc.org/github.com/coreos/go-systemd)
129
* [github.com/cpuguy83/go-md2man/v2](https://godoc.org/github.com/cpuguy83/go-md2man/v2)
13-
* [github.com/creack/pty](https://godoc.org/github.com/creack/pty)
1410
* [github.com/davecgh/go-spew](https://godoc.org/github.com/davecgh/go-spew)
1511
* [github.com/dustin/go-humanize](https://godoc.org/github.com/dustin/go-humanize)
1612
* [github.com/fatih/color](https://godoc.org/github.com/fatih/color)
1713
* [github.com/fatih/structs](https://godoc.org/github.com/fatih/structs)
1814
* [github.com/felixge/httpsnoop](https://godoc.org/github.com/felixge/httpsnoop)
1915
* [github.com/fsnotify/fsnotify](https://godoc.org/github.com/fsnotify/fsnotify)
20-
* [github.com/go-kit/log](https://godoc.org/github.com/go-kit/log)
21-
* [github.com/go-logfmt/logfmt](https://godoc.org/github.com/go-logfmt/logfmt)
2216
* [github.com/go-sql-driver/mysql](https://godoc.org/github.com/go-sql-driver/mysql)
23-
* [github.com/go-stack/stack](https://godoc.org/github.com/go-stack/stack)
24-
* [github.com/gobuffalo/attrs](https://godoc.org/github.com/gobuffalo/attrs)
2517
* [github.com/gobuffalo/buffalo](https://godoc.org/github.com/gobuffalo/buffalo)
2618
* [github.com/gobuffalo/envy](https://godoc.org/github.com/gobuffalo/envy)
2719
* [github.com/gobuffalo/events](https://godoc.org/github.com/gobuffalo/events)
28-
* [github.com/gobuffalo/fizz](https://godoc.org/github.com/gobuffalo/fizz)
2920
* [github.com/gobuffalo/flect](https://godoc.org/github.com/gobuffalo/flect)
30-
* [github.com/gobuffalo/genny/v2](https://godoc.org/github.com/gobuffalo/genny/v2)
3121
* [github.com/gobuffalo/github_flavored_markdown](https://godoc.org/github.com/gobuffalo/github_flavored_markdown)
3222
* [github.com/gobuffalo/grift](https://godoc.org/github.com/gobuffalo/grift)
3323
* [github.com/gobuffalo/helpers](https://godoc.org/github.com/gobuffalo/helpers)
@@ -36,60 +26,36 @@ Thank you to the following **GIANTS**:
3626
* [github.com/gobuffalo/logger](https://godoc.org/github.com/gobuffalo/logger)
3727
* [github.com/gobuffalo/meta](https://godoc.org/github.com/gobuffalo/meta)
3828
* [github.com/gobuffalo/nulls](https://godoc.org/github.com/gobuffalo/nulls)
39-
* [github.com/gobuffalo/packd](https://godoc.org/github.com/gobuffalo/packd)
4029
* [github.com/gobuffalo/plush/v4](https://godoc.org/github.com/gobuffalo/plush/v4)
41-
* [github.com/gobuffalo/pop/v6](https://godoc.org/github.com/gobuffalo/pop/v6)
4230
* [github.com/gobuffalo/refresh](https://godoc.org/github.com/gobuffalo/refresh)
4331
* [github.com/gobuffalo/tags/v3](https://godoc.org/github.com/gobuffalo/tags/v3)
4432
* [github.com/gobuffalo/validate/v3](https://godoc.org/github.com/gobuffalo/validate/v3)
4533
* [github.com/gofrs/uuid](https://godoc.org/github.com/gofrs/uuid)
4634
* [github.com/google/go-cmp](https://godoc.org/github.com/google/go-cmp)
47-
* [github.com/google/renameio](https://godoc.org/github.com/google/renameio)
4835
* [github.com/gorilla/css](https://godoc.org/github.com/gorilla/css)
4936
* [github.com/gorilla/handlers](https://godoc.org/github.com/gorilla/handlers)
5037
* [github.com/gorilla/mux](https://godoc.org/github.com/gorilla/mux)
5138
* [github.com/gorilla/securecookie](https://godoc.org/github.com/gorilla/securecookie)
5239
* [github.com/gorilla/sessions](https://godoc.org/github.com/gorilla/sessions)
5340
* [github.com/inconshreveable/mousetrap](https://godoc.org/github.com/inconshreveable/mousetrap)
54-
* [github.com/jackc/chunkreader](https://godoc.org/github.com/jackc/chunkreader)
55-
* [github.com/jackc/chunkreader/v2](https://godoc.org/github.com/jackc/chunkreader/v2)
56-
* [github.com/jackc/pgconn](https://godoc.org/github.com/jackc/pgconn)
57-
* [github.com/jackc/pgio](https://godoc.org/github.com/jackc/pgio)
58-
* [github.com/jackc/pgmock](https://godoc.org/github.com/jackc/pgmock)
59-
* [github.com/jackc/pgpassfile](https://godoc.org/github.com/jackc/pgpassfile)
60-
* [github.com/jackc/pgproto3](https://godoc.org/github.com/jackc/pgproto3)
61-
* [github.com/jackc/pgproto3/v2](https://godoc.org/github.com/jackc/pgproto3/v2)
62-
* [github.com/jackc/pgservicefile](https://godoc.org/github.com/jackc/pgservicefile)
63-
* [github.com/jackc/pgtype](https://godoc.org/github.com/jackc/pgtype)
64-
* [github.com/jackc/pgx/v4](https://godoc.org/github.com/jackc/pgx/v4)
65-
* [github.com/jackc/puddle](https://godoc.org/github.com/jackc/puddle)
6641
* [github.com/jmoiron/sqlx](https://godoc.org/github.com/jmoiron/sqlx)
6742
* [github.com/joho/godotenv](https://godoc.org/github.com/joho/godotenv)
68-
* [github.com/kballard/go-shellquote](https://godoc.org/github.com/kballard/go-shellquote)
69-
* [github.com/kisielk/gotool](https://godoc.org/github.com/kisielk/gotool)
70-
* [github.com/konsorten/go-windows-terminal-sequences](https://godoc.org/github.com/konsorten/go-windows-terminal-sequences)
7143
* [github.com/kr/pretty](https://godoc.org/github.com/kr/pretty)
7244
* [github.com/kr/pty](https://godoc.org/github.com/kr/pty)
7345
* [github.com/kr/text](https://godoc.org/github.com/kr/text)
7446
* [github.com/lib/pq](https://godoc.org/github.com/lib/pq)
75-
* [github.com/luna-duclos/instrumentedsql](https://godoc.org/github.com/luna-duclos/instrumentedsql)
7647
* [github.com/mattn/go-colorable](https://godoc.org/github.com/mattn/go-colorable)
7748
* [github.com/mattn/go-isatty](https://godoc.org/github.com/mattn/go-isatty)
7849
* [github.com/mattn/go-sqlite3](https://godoc.org/github.com/mattn/go-sqlite3)
7950
* [github.com/microcosm-cc/bluemonday](https://godoc.org/github.com/microcosm-cc/bluemonday)
8051
* [github.com/mitchellh/go-homedir](https://godoc.org/github.com/mitchellh/go-homedir)
8152
* [github.com/monoculum/formam](https://godoc.org/github.com/monoculum/formam)
8253
* [github.com/pkg/diff](https://godoc.org/github.com/pkg/diff)
83-
* [github.com/pkg/errors](https://godoc.org/github.com/pkg/errors)
8454
* [github.com/pmezard/go-difflib](https://godoc.org/github.com/pmezard/go-difflib)
8555
* [github.com/psanford/memfs](https://godoc.org/github.com/psanford/memfs)
8656
* [github.com/rogpeppe/go-internal](https://godoc.org/github.com/rogpeppe/go-internal)
87-
* [github.com/rs/xid](https://godoc.org/github.com/rs/xid)
88-
* [github.com/rs/zerolog](https://godoc.org/github.com/rs/zerolog)
8957
* [github.com/russross/blackfriday/v2](https://godoc.org/github.com/russross/blackfriday/v2)
90-
* [github.com/satori/go.uuid](https://godoc.org/github.com/satori/go.uuid)
9158
* [github.com/sergi/go-diff](https://godoc.org/github.com/sergi/go-diff)
92-
* [github.com/shopspring/decimal](https://godoc.org/github.com/shopspring/decimal)
9359
* [github.com/sirupsen/logrus](https://godoc.org/github.com/sirupsen/logrus)
9460
* [github.com/sourcegraph/annotate](https://godoc.org/github.com/sourcegraph/annotate)
9561
* [github.com/sourcegraph/syntaxhighlight](https://godoc.org/github.com/sourcegraph/syntaxhighlight)
@@ -98,13 +64,7 @@ Thank you to the following **GIANTS**:
9864
* [github.com/stretchr/objx](https://godoc.org/github.com/stretchr/objx)
9965
* [github.com/stretchr/testify](https://godoc.org/github.com/stretchr/testify)
10066
* [github.com/yuin/goldmark](https://godoc.org/github.com/yuin/goldmark)
101-
* [github.com/zenazn/goji](https://godoc.org/github.com/zenazn/goji)
102-
* [go.uber.org/atomic](https://godoc.org/go.uber.org/atomic)
103-
* [go.uber.org/multierr](https://godoc.org/go.uber.org/multierr)
104-
* [go.uber.org/tools](https://godoc.org/go.uber.org/tools)
105-
* [go.uber.org/zap](https://godoc.org/go.uber.org/zap)
10667
* [golang.org/x/crypto](https://godoc.org/golang.org/x/crypto)
107-
* [golang.org/x/lint](https://godoc.org/golang.org/x/lint)
10868
* [golang.org/x/mod](https://godoc.org/golang.org/x/mod)
10969
* [golang.org/x/net](https://godoc.org/golang.org/x/net)
11070
* [golang.org/x/sync](https://godoc.org/golang.org/x/sync)
@@ -114,8 +74,5 @@ Thank you to the following **GIANTS**:
11474
* [golang.org/x/tools](https://godoc.org/golang.org/x/tools)
11575
* [golang.org/x/xerrors](https://godoc.org/golang.org/x/xerrors)
11676
* [gopkg.in/check.v1](https://godoc.org/gopkg.in/check.v1)
117-
* [gopkg.in/errgo.v2](https://godoc.org/gopkg.in/errgo.v2)
118-
* [gopkg.in/inconshreveable/log15.v2](https://godoc.org/gopkg.in/inconshreveable/log15.v2)
11977
* [gopkg.in/yaml.v2](https://godoc.org/gopkg.in/yaml.v2)
12078
* [gopkg.in/yaml.v3](https://godoc.org/gopkg.in/yaml.v3)
121-
* [honnef.co/go/tools](https://godoc.org/honnef.co/go/tools)

basicauth.go

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

33
import (
44
"encoding/base64"
5+
"errors"
56
"net/http"
67
"strings"
78

89
"github.com/gobuffalo/buffalo"
9-
"github.com/pkg/errors"
1010
)
1111

1212
var (
13+
// These errors are internal and will not be seen in production mode
14+
1315
// ErrNoCreds is returned when no basic auth credentials are defined
1416
ErrNoCreds = errors.New("no basic auth credentials defined")
1517

@@ -30,25 +32,36 @@ func Middleware(auth Authorizer) buffalo.MiddlewareFunc {
3032
return func(c buffalo.Context) error {
3133
token := strings.SplitN(c.Request().Header.Get("Authorization"), " ", 2)
3234
if len(token) != 2 {
33-
c.Response().Header().Set("WWW-Authenticate", `Basic realm="Basic Authentication"`)
34-
return c.Error(http.StatusUnauthorized, ErrUnauthorized)
35+
return responseUnauthorized(c, ErrNoCreds)
3536
}
3637
b, err := base64.StdEncoding.DecodeString(token[1])
3738
if err != nil {
38-
return c.Error(http.StatusUnauthorized, ErrUnauthorized)
39+
return responseUnauthorized(c, ErrNoCreds)
3940
}
41+
4042
pair := strings.SplitN(string(b), ":", 2)
4143
if len(pair) != 2 {
42-
return c.Error(http.StatusUnauthorized, ErrUnauthorized)
44+
return responseUnauthorized(c, ErrUnauthorized)
4345
}
46+
4447
success, err := auth(c, pair[0], pair[1])
4548
if err != nil {
46-
return errors.WithStack(err)
49+
// log only this situation since it is an internal error
50+
c.Logger().Errorf("authorizer error: %v", err)
51+
return responseUnauthorized(c, ErrUnauthorized)
4752
}
4853
if !success {
49-
return c.Error(http.StatusUnauthorized, ErrUnauthorized)
54+
return responseUnauthorized(c, ErrAuthFail)
5055
}
56+
5157
return next(c)
5258
}
5359
}
5460
}
61+
62+
func responseUnauthorized(c buffalo.Context, err error) error {
63+
// Always uses status 401 but internally propagate the original error.
64+
// The error could be used in error handlers to handle extra steps.
65+
c.Response().Header().Set("WWW-Authenticate", `Basic realm="Basic Authentication"`)
66+
return c.Error(http.StatusUnauthorized, err)
67+
}

basicauth_test.go

Lines changed: 35 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@ package basicauth_test
22

33
import (
44
"encoding/base64"
5-
"fmt"
5+
"net/http"
66
"testing"
77

88
"github.com/gobuffalo/buffalo"
9+
"github.com/gobuffalo/buffalo/render"
910
"github.com/gobuffalo/httptest"
1011
basicauth "github.com/gobuffalo/mw-basicauth"
1112
"github.com/stretchr/testify/require"
1213
)
1314

1415
func app() *buffalo.App {
1516
h := func(c buffalo.Context) error {
16-
return c.Render(200, nil)
17+
return c.Render(200, render.String("Welcome"))
1718
}
1819
auth := func(c buffalo.Context, u, p string) (bool, error) {
1920
return (u == "tester" && p == "pass123"), nil
@@ -25,50 +26,37 @@ func app() *buffalo.App {
2526
}
2627

2728
func TestBasicAuth(t *testing.T) {
28-
r := require.New(t)
29-
30-
w := httptest.New(app())
31-
32-
// missing authorization
33-
res := w.HTML("/").Get()
34-
r.Equal(401, res.Code)
35-
r.Contains(res.Header().Get("WWW-Authenticate"), `Basic realm="Basic Authentication"`)
36-
r.Contains(res.Body.String(), "Unauthorized")
37-
38-
// bad header value, not Basic
39-
req := w.HTML("/")
40-
req.Headers["Authorization"] = "badcreds"
41-
res = req.Get()
42-
r.Equal(401, res.Code)
43-
r.Contains(res.Body.String(), "Unauthorized")
44-
45-
// bad cred values
46-
req = w.HTML("/")
47-
req.Headers["Authorization"] = "bad creds"
48-
res = req.Get()
49-
r.Equal(401, res.Code)
50-
r.Contains(res.Body.String(), "Unauthorized")
51-
52-
// invalid cred values in authorization
53-
creds := base64.StdEncoding.EncodeToString([]byte("badcredvalue"))
54-
req = w.HTML("/")
55-
req.Headers["Authorization"] = fmt.Sprintf("Basic %s", creds)
56-
res = req.Get()
57-
r.Equal(401, res.Code)
58-
r.Contains(res.Body.String(), "Unauthorized")
59-
60-
// wrong cred values in authorization
61-
creds = base64.StdEncoding.EncodeToString([]byte("foo:bar"))
62-
req = w.HTML("/")
63-
req.Headers["Authorization"] = fmt.Sprintf("Basic %s", creds)
64-
res = req.Get()
65-
r.Equal(401, res.Code)
66-
r.Contains(res.Body.String(), "Unauthorized")
29+
tests := []struct {
30+
status int
31+
name string
32+
auth string
33+
message string
34+
}{
35+
{http.StatusUnauthorized, "missing", "MISSING", "no basic auth credentials defined"},
36+
{http.StatusUnauthorized, "empty", "", "no basic auth credentials defined"},
37+
{http.StatusUnauthorized, "badcreds", "badcreds", "no basic auth credentials defined"},
38+
{http.StatusUnauthorized, "bad creds", "bad creds", "no basic auth credentials defined"},
39+
{http.StatusUnauthorized, "invalid", "Basic " + base64.StdEncoding.EncodeToString([]byte("badcredvalue")), "Unauthorized"},
40+
{http.StatusUnauthorized, "wrong", "Basic " + base64.StdEncoding.EncodeToString([]byte("foo:bar")), "invalid basic auth username"},
41+
{http.StatusOK, "valid", "Basic " + base64.StdEncoding.EncodeToString([]byte("tester:pass123")), "Welcome"},
42+
}
6743

68-
// valid cred values
69-
creds = base64.StdEncoding.EncodeToString([]byte("tester:pass123"))
70-
req = w.HTML("/")
71-
req.Headers["Authorization"] = fmt.Sprintf("Basic %s", creds)
72-
res = req.Get()
73-
r.Equal(200, res.Code)
44+
for _, tt := range tests {
45+
t.Run(tt.name, func(t *testing.T) {
46+
r := require.New(t)
47+
w := httptest.New(app())
48+
49+
// missing authorization
50+
req := w.HTML("/")
51+
if tt.auth != "MISSING" {
52+
req.Headers["Authorization"] = tt.auth
53+
}
54+
res := req.Get()
55+
r.Equal(tt.status, res.Code)
56+
if tt.status == http.StatusUnauthorized {
57+
r.Contains(res.Header().Get("WWW-Authenticate"), `Basic realm="Basic Authentication"`)
58+
}
59+
r.Contains(res.Body.String(), tt.message)
60+
})
61+
}
7462
}

go.mod

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ module github.com/gobuffalo/mw-basicauth
33
go 1.16
44

55
require (
6-
github.com/gobuffalo/buffalo v0.18.9
7-
github.com/gobuffalo/httptest v1.5.1
8-
github.com/pkg/errors v0.9.1
9-
github.com/stretchr/testify v1.8.0
6+
github.com/gobuffalo/buffalo v1.1.0
7+
github.com/gobuffalo/httptest v1.5.2
8+
github.com/stretchr/testify v1.8.1
109
)

0 commit comments

Comments
 (0)