mirror of
https://gitlab.com/ric_harvey/MailHog.git
synced 2024-11-23 22:34:04 +00:00
Attempt to add HTTP authentication for #40
This commit is contained in:
parent
9dc6ad8ed4
commit
dcc60fb961
6 changed files with 100 additions and 2 deletions
4
Makefile
4
Makefile
|
@ -1,4 +1,4 @@
|
||||||
VERSION=0.1.7
|
VERSION=0.2.0
|
||||||
|
|
||||||
all: deps fmt combined
|
all: deps fmt combined
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ deps:
|
||||||
go get labix.org/v2/mgo
|
go get labix.org/v2/mgo
|
||||||
# added to fix travis issues
|
# added to fix travis issues
|
||||||
go get code.google.com/p/go-uuid/uuid
|
go get code.google.com/p/go-uuid/uuid
|
||||||
go get code.google.com/p/go.crypto/bcrypt
|
go get golang.org/x/crypto/bcrypt
|
||||||
|
|
||||||
test-deps:
|
test-deps:
|
||||||
go get github.com/smartystreets/goconvey
|
go get github.com/smartystreets/goconvey
|
||||||
|
|
|
@ -41,6 +41,7 @@ MailHog is an email testing tool for developers:
|
||||||
* See [Introduction to Jim](/docs/JIM.md) for more information
|
* See [Introduction to Jim](/docs/JIM.md) for more information
|
||||||
* HTTP API to list, retrieve and delete messages
|
* HTTP API to list, retrieve and delete messages
|
||||||
* See [APIv1](/docs/APIv1.md) and [APIv2](/docs/APIv2.md) documentation for more information
|
* See [APIv1](/docs/APIv1.md) and [APIv2](/docs/APIv2.md) documentation for more information
|
||||||
|
* [HTTP basic authentication](docs/Auth.md) for MailHog UI and API
|
||||||
* Multipart MIME support
|
* Multipart MIME support
|
||||||
* Download individual MIME parts
|
* Download individual MIME parts
|
||||||
* In-memory message storage
|
* In-memory message storage
|
||||||
|
|
27
config/config.go
Normal file
27
config/config.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
|
||||||
|
"github.com/ian-kent/envconf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DefaultConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
AuthFile: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
AuthFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfg = DefaultConfig()
|
||||||
|
|
||||||
|
func Configure() *Config {
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterFlags() {
|
||||||
|
flag.StringVar(&cfg.AuthFile, "auth-file", envconf.FromEnvP("MH_AUTH_FILE", "").(string), "A username:bcryptpw mapping file")
|
||||||
|
}
|
43
docs/Auth.md
Normal file
43
docs/Auth.md
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
Authentication
|
||||||
|
==============
|
||||||
|
|
||||||
|
HTTP basic authentication is supported using a password file.
|
||||||
|
|
||||||
|
See [example-auth](example-auth) for an example.
|
||||||
|
|
||||||
|
Authentication applies to all HTTP requests, including static content
|
||||||
|
and API endpoints.
|
||||||
|
|
||||||
|
### Password file format
|
||||||
|
|
||||||
|
The password file format is:
|
||||||
|
|
||||||
|
* One user per line
|
||||||
|
* `username:password`
|
||||||
|
* Password is bcrypted
|
||||||
|
|
||||||
|
By default, a bcrypt difficulty of 4 is used to reduce page load times.
|
||||||
|
|
||||||
|
### Generating a bcrypted password
|
||||||
|
|
||||||
|
You can use a MailHog shortcut to generate a bcrypted password:
|
||||||
|
|
||||||
|
MailHog bcrypt <password>
|
||||||
|
|
||||||
|
### Enabling HTTP authentication
|
||||||
|
|
||||||
|
To enable authentication, pass an `-auth-file` flag to MailHog:
|
||||||
|
|
||||||
|
MailHog -auth-file=docs/example-auth
|
||||||
|
|
||||||
|
This also works if you're running MailHog-UI and MailHog-Server separately:
|
||||||
|
|
||||||
|
MailHog-Server -auth-file=docs/example-auth
|
||||||
|
MailHog-UI -auth-file=docs/example-auth
|
||||||
|
|
||||||
|
## Future compatibility
|
||||||
|
|
||||||
|
Authentication has been a bit of an experiment.
|
||||||
|
|
||||||
|
The exact implementation may change over time, e.g. using sessions in the UI
|
||||||
|
and tokens for the API to avoid frequently bcrypting passwords.
|
1
docs/example-auth
Normal file
1
docs/example-auth
Normal file
|
@ -0,0 +1 @@
|
||||||
|
test:$2a$04$qxRo.ftFoNep7ld/5jfKtuBTnGqff/fZVyj53mUC5sVf9dtDLAi/S
|
26
main.go
26
main.go
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
gohttp "net/http"
|
gohttp "net/http"
|
||||||
|
@ -14,20 +15,25 @@ import (
|
||||||
"github.com/mailhog/MailHog-UI/assets"
|
"github.com/mailhog/MailHog-UI/assets"
|
||||||
cfgui "github.com/mailhog/MailHog-UI/config"
|
cfgui "github.com/mailhog/MailHog-UI/config"
|
||||||
"github.com/mailhog/MailHog-UI/web"
|
"github.com/mailhog/MailHog-UI/web"
|
||||||
|
cfgcom "github.com/mailhog/MailHog/config"
|
||||||
"github.com/mailhog/http"
|
"github.com/mailhog/http"
|
||||||
"github.com/mailhog/mhsendmail/cmd"
|
"github.com/mailhog/mhsendmail/cmd"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var apiconf *cfgapi.Config
|
var apiconf *cfgapi.Config
|
||||||
var uiconf *cfgui.Config
|
var uiconf *cfgui.Config
|
||||||
|
var comconf *cfgcom.Config
|
||||||
var exitCh chan int
|
var exitCh chan int
|
||||||
|
|
||||||
func configure() {
|
func configure() {
|
||||||
|
cfgcom.RegisterFlags()
|
||||||
cfgapi.RegisterFlags()
|
cfgapi.RegisterFlags()
|
||||||
cfgui.RegisterFlags()
|
cfgui.RegisterFlags()
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
apiconf = cfgapi.Configure()
|
apiconf = cfgapi.Configure()
|
||||||
uiconf = cfgui.Configure()
|
uiconf = cfgui.Configure()
|
||||||
|
comconf = cfgcom.Configure()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -41,8 +47,28 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(os.Args) > 1 && os.Args[1] == "bcrypt" {
|
||||||
|
var pw string
|
||||||
|
if len(os.Args) > 2 {
|
||||||
|
pw = os.Args[2]
|
||||||
|
} else {
|
||||||
|
// TODO: read from stdin
|
||||||
|
}
|
||||||
|
b, err := bcrypt.GenerateFromPassword([]byte(pw), 4)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error bcrypting password: %s", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println(string(b))
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
configure()
|
configure()
|
||||||
|
|
||||||
|
if comconf.AuthFile != "" {
|
||||||
|
http.AuthFile(comconf.AuthFile)
|
||||||
|
}
|
||||||
|
|
||||||
exitCh = make(chan int)
|
exitCh = make(chan int)
|
||||||
if uiconf.UIBindAddr == apiconf.APIBindAddr {
|
if uiconf.UIBindAddr == apiconf.APIBindAddr {
|
||||||
cb := func(r gohttp.Handler) {
|
cb := func(r gohttp.Handler) {
|
||||||
|
|
Loading…
Reference in a new issue