Skip to content

Commit dcc60fb

Browse files
committed
Attempt to add HTTP authentication for #40
1 parent 9dc6ad8 commit dcc60fb

File tree

6 files changed

+100
-2
lines changed

6 files changed

+100
-2
lines changed

Diff for: Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION=0.1.7
1+
VERSION=0.2.0
22

33
all: deps fmt combined
44

@@ -25,7 +25,7 @@ deps:
2525
go get labix.org/v2/mgo
2626
# added to fix travis issues
2727
go get code.google.com/p/go-uuid/uuid
28-
go get code.google.com/p/go.crypto/bcrypt
28+
go get golang.org/x/crypto/bcrypt
2929

3030
test-deps:
3131
go get github.com/smartystreets/goconvey

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ MailHog is an email testing tool for developers:
4141
* See [Introduction to Jim](/docs/JIM.md) for more information
4242
* HTTP API to list, retrieve and delete messages
4343
* See [APIv1](/docs/APIv1.md) and [APIv2](/docs/APIv2.md) documentation for more information
44+
* [HTTP basic authentication](docs/Auth.md) for MailHog UI and API
4445
* Multipart MIME support
4546
* Download individual MIME parts
4647
* In-memory message storage

Diff for: config/config.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package config
2+
3+
import (
4+
"flag"
5+
6+
"github.com/ian-kent/envconf"
7+
)
8+
9+
func DefaultConfig() *Config {
10+
return &Config{
11+
AuthFile: "",
12+
}
13+
}
14+
15+
type Config struct {
16+
AuthFile string
17+
}
18+
19+
var cfg = DefaultConfig()
20+
21+
func Configure() *Config {
22+
return cfg
23+
}
24+
25+
func RegisterFlags() {
26+
flag.StringVar(&cfg.AuthFile, "auth-file", envconf.FromEnvP("MH_AUTH_FILE", "").(string), "A username:bcryptpw mapping file")
27+
}

Diff for: docs/Auth.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
Authentication
2+
==============
3+
4+
HTTP basic authentication is supported using a password file.
5+
6+
See [example-auth](example-auth) for an example.
7+
8+
Authentication applies to all HTTP requests, including static content
9+
and API endpoints.
10+
11+
### Password file format
12+
13+
The password file format is:
14+
15+
* One user per line
16+
* `username:password`
17+
* Password is bcrypted
18+
19+
By default, a bcrypt difficulty of 4 is used to reduce page load times.
20+
21+
### Generating a bcrypted password
22+
23+
You can use a MailHog shortcut to generate a bcrypted password:
24+
25+
MailHog bcrypt <password>
26+
27+
### Enabling HTTP authentication
28+
29+
To enable authentication, pass an `-auth-file` flag to MailHog:
30+
31+
MailHog -auth-file=docs/example-auth
32+
33+
This also works if you're running MailHog-UI and MailHog-Server separately:
34+
35+
MailHog-Server -auth-file=docs/example-auth
36+
MailHog-UI -auth-file=docs/example-auth
37+
38+
## Future compatibility
39+
40+
Authentication has been a bit of an experiment.
41+
42+
The exact implementation may change over time, e.g. using sessions in the UI
43+
and tokens for the API to avoid frequently bcrypting passwords.

Diff for: docs/example-auth

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test:$2a$04$qxRo.ftFoNep7ld/5jfKtuBTnGqff/fZVyj53mUC5sVf9dtDLAi/S

Diff for: main.go

+26
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"flag"
5+
"fmt"
56
"os"
67

78
gohttp "net/http"
@@ -14,20 +15,25 @@ import (
1415
"github.com/mailhog/MailHog-UI/assets"
1516
cfgui "github.com/mailhog/MailHog-UI/config"
1617
"github.com/mailhog/MailHog-UI/web"
18+
cfgcom "github.com/mailhog/MailHog/config"
1719
"github.com/mailhog/http"
1820
"github.com/mailhog/mhsendmail/cmd"
21+
"golang.org/x/crypto/bcrypt"
1922
)
2023

2124
var apiconf *cfgapi.Config
2225
var uiconf *cfgui.Config
26+
var comconf *cfgcom.Config
2327
var exitCh chan int
2428

2529
func configure() {
30+
cfgcom.RegisterFlags()
2631
cfgapi.RegisterFlags()
2732
cfgui.RegisterFlags()
2833
flag.Parse()
2934
apiconf = cfgapi.Configure()
3035
uiconf = cfgui.Configure()
36+
comconf = cfgcom.Configure()
3137
}
3238

3339
func main() {
@@ -41,8 +47,28 @@ func main() {
4147
return
4248
}
4349

50+
if len(os.Args) > 1 && os.Args[1] == "bcrypt" {
51+
var pw string
52+
if len(os.Args) > 2 {
53+
pw = os.Args[2]
54+
} else {
55+
// TODO: read from stdin
56+
}
57+
b, err := bcrypt.GenerateFromPassword([]byte(pw), 4)
58+
if err != nil {
59+
log.Fatalf("error bcrypting password: %s", err)
60+
os.Exit(1)
61+
}
62+
fmt.Println(string(b))
63+
os.Exit(0)
64+
}
65+
4466
configure()
4567

68+
if comconf.AuthFile != "" {
69+
http.AuthFile(comconf.AuthFile)
70+
}
71+
4672
exitCh = make(chan int)
4773
if uiconf.UIBindAddr == apiconf.APIBindAddr {
4874
cb := func(r gohttp.Handler) {

0 commit comments

Comments
 (0)