Permalink
Browse files

Authentication (#1946)

* Implementing https listener. Https and http may both be specified. Removing RelayListener.

* Better default handling if https is specified and http is not

* initial sketch of web again

* more work on auth

* auth closer to working

* UI for creating tokens

* slight change to token help

* update gorilla. tweak

* vendor. activating redis

* work on stuff

* ui changes

* default cookie secret.

* some code review changes

* compiling would be nice

* metadata and collect allow insecure to localhost.

* Trying to do as much in proc as possible. Gets rid of several dirty hacks.

* fix

* allowing username overrides for authorized users

* ui tweaks

* ui tweak

* ui tweak
  • Loading branch information...
1 parent cdcee21 commit 67f50fd8f053a3ec52a830b205b07b126302a2b6 @captncraig captncraig committed on GitHub Jan 6, 2017
Showing with 7,575 additions and 1,991 deletions.
  1. +8 −1 cmd/bosun/conf/conf.go
  2. +3 −1 cmd/bosun/conf/notify.go
  3. +70 −7 cmd/bosun/conf/system.go
  4. +5 −0 cmd/bosun/database/database.go
  5. +21 −19 cmd/bosun/main.go
  6. +1 −8 cmd/bosun/sched/sched.go
  7. BIN cmd/bosun/web/bosun.state
  8. +2 −17 cmd/bosun/web/embed.go
  9. +127 −0 cmd/bosun/web/middlewares.go
  10. +91 −0 cmd/bosun/web/roles.go
  11. +36 −0 cmd/bosun/web/roles_test.go
  12. +26 −17 cmd/bosun/web/save.go
  13. +1,962 −1,377 cmd/bosun/web/static.go
  14. +4 −3 cmd/bosun/web/static/css/bootstrap.min.css
  15. BIN cmd/bosun/web/static/fonts/glyphicons-halflings-regular.woff2
  16. +201 −185 cmd/bosun/web/static/js/0-bosun.ts
  17. +6 −7 cmd/bosun/web/static/js/action.ts
  18. +4 −1 cmd/bosun/web/static/js/annotation.ts
  19. +73 −0 cmd/bosun/web/static/js/authService.ts
  20. +5 −4 cmd/bosun/web/static/js/bootstrap.min.js
  21. +314 −127 cmd/bosun/web/static/js/bosun.js
  22. +7 −0 cmd/bosun/web/static/js/clipboard.min.js
  23. +1 −5 cmd/bosun/web/static/js/config.ts
  24. +2 −2 cmd/bosun/web/static/js/expr.ts
  25. +8 −5 cmd/bosun/web/static/js/graph.ts
  26. +2 −0 cmd/bosun/web/static/js/items.ts
  27. +25 −0 cmd/bosun/web/static/js/models.ts
  28. +4 −0 cmd/bosun/web/static/js/ngclipboard.min.js
  29. +2 −3 cmd/bosun/web/static/js/silence.ts
  30. +65 −0 cmd/bosun/web/static/js/tokenList.ts
  31. +58 −0 cmd/bosun/web/static/js/tokenNew.ts
  32. +1 −1 cmd/bosun/web/static/partials/action.html
  33. +1 −1 cmd/bosun/web/static/partials/annotation.html
  34. +3 −3 cmd/bosun/web/static/partials/config.html
  35. +1 −1 cmd/bosun/web/static/partials/graph.html
  36. +1 −1 cmd/bosun/web/static/partials/silence.html
  37. +55 −0 cmd/bosun/web/static/partials/tokenNew.html
  38. +11 −2 cmd/bosun/web/static/templates/index.html
  39. +205 −149 cmd/bosun/web/web.go
  40. +6 −0 collect/collect.go
  41. +32 −18 collect/queue.go
  42. +35 −1 metadata/metadata.go
  43. +1 −1 models/incidents.go
  44. +13 −0 vendor/github.com/NYTimes/gziphandler/LICENSE.md
  45. +52 −0 vendor/github.com/NYTimes/gziphandler/README.md
  46. +144 −0 vendor/github.com/NYTimes/gziphandler/gzip.go
  47. +0 −20 vendor/github.com/StackExchange/wmi/LICENSE
  48. +0 −4 vendor/github.com/StackExchange/wmi/README.md
  49. +87 −0 vendor/github.com/captncraig/easyauth/README.md
  50. +288 −0 vendor/github.com/captncraig/easyauth/auth.go
  51. +62 −0 vendor/github.com/captncraig/easyauth/cookie.go
  52. +21 −0 vendor/github.com/captncraig/easyauth/license
  53. +54 −0 vendor/github.com/captncraig/easyauth/options.go
  54. +164 −0 vendor/github.com/captncraig/easyauth/providers/ldap/ldap.go
  55. +103 −0 vendor/github.com/captncraig/easyauth/providers/token/json.go
  56. +106 −0 vendor/github.com/captncraig/easyauth/providers/token/redisStore/redisStore.go
  57. +126 −0 vendor/github.com/captncraig/easyauth/providers/token/token.go
  58. +53 −0 vendor/github.com/captncraig/easyauth/template.go
  59. +27 −0 vendor/gopkg.in/asn1-ber.v1/LICENSE
  60. +18 −0 vendor/gopkg.in/asn1-ber.v1/README.md
  61. +528 −0 vendor/gopkg.in/asn1-ber.v1/ber.go
  62. +27 −0 vendor/gopkg.in/ldap.v1/LICENSE
  63. +48 −0 vendor/gopkg.in/ldap.v1/README.md
  64. +135 −0 vendor/gopkg.in/ldap.v1/bind.go
  65. +350 −0 vendor/gopkg.in/ldap.v1/conn.go
  66. +300 −0 vendor/gopkg.in/ldap.v1/control.go
  67. +24 −0 vendor/gopkg.in/ldap.v1/debug.go
  68. +252 −0 vendor/gopkg.in/ldap.v1/filter.go
  69. +403 −0 vendor/gopkg.in/ldap.v1/ldap.go
  70. +156 −0 vendor/gopkg.in/ldap.v1/modify.go
  71. +137 −0 vendor/gopkg.in/ldap.v1/passwdmodify.go
  72. +370 −0 vendor/gopkg.in/ldap.v1/search.go
  73. +42 −0 vendor/vendor.json
@@ -31,7 +31,9 @@ import (
// outside of the package without a setter
type SystemConfProvider interface {
GetHTTPListen() string
- GetRelayListen() string
+ GetHTTPSListen() string
+ GetTLSCertFile() string
+ GetTLSKeyFile() string
GetSMTPHost() string
GetSMTPUsername() string // SMTP username
@@ -67,6 +69,8 @@ type SystemConfProvider interface {
GetAnnotateElasticHosts() expr.ElasticHosts
GetAnnotateIndex() string
+ GetAuthConf() *AuthConf
+
// Contexts
GetTSDBContext() opentsdb.Context
GetGraphiteContext() graphite.Context
@@ -90,6 +94,9 @@ func ValidateSystemConf(sc SystemConfProvider) error {
if sc.GetDefaultRunEvery() <= 0 {
return fmt.Errorf("default run every must be greater than 0, is %v", sc.GetDefaultRunEvery())
}
+ if sc.GetHTTPSListen() != "" && (sc.GetTLSCertFile() == "" || sc.GetTLSKeyFile() == "") {
+ return fmt.Errorf("must specify TLSCertFile and TLSKeyFile if HTTPSListen is specified")
+ }
return nil
}
@@ -158,7 +158,9 @@ func SendMail(addr, username, password string, from string, to []string, msg []b
if len(username) > 0 || len(password) > 0 {
hostWithoutPort := strings.Split(addr, ":")[0]
auth := smtp.PlainAuth("", username, password, hostWithoutPort)
- c.Auth(auth)
+ if err = c.Auth(auth); err != nil {
+ return err
+ }
}
}
if err = c.Mail(from); err != nil {
@@ -18,8 +18,11 @@ import (
// SystemConf contains all the information that bosun needs to run. Outside of the conf package
// usage should be through conf.SystemConfProvider
type SystemConf struct {
- HTTPListen string
- RelayListen string
+ HTTPListen string
+ HTTPSListen string
+ TLSCertFile string
+ TLSKeyFile string
+
Hostname string
Ping bool
PingDuration Duration // Duration from now to stop pinging hosts based on time since the host tag was touched
@@ -45,6 +48,8 @@ type SystemConf struct {
AnnotateConf AnnotateConf
+ AuthConf *AuthConf
+
EnableSave bool
EnableReload bool
CommandHookPath string
@@ -140,6 +145,43 @@ type SMTPConf struct {
Password string `json:"-"`
}
+//AuthConf is configuration for bosun's authentication
+type AuthConf struct {
+ AuthDisabled bool
+ //Secret string to hash auth tokens. Needed to enable token auth.
+ TokenSecret string
+ //Secret sting used to encrypt cookie.
+ CookieSecret string
+ //LDAP configuration
+ LDAP LDAPConf
+}
+
+type LDAPConf struct {
+ // Domain name (used to make domain/username)
+ Domain string
+ // LDAP server
+ LdapAddr string
+ // allow insecure ldap connection?
+ AllowInsecure bool
+ // default permission level for anyone who can log in. Try "Reader".
+ DefaultPermission string
+ //List of group level permissions
+ Groups []LDAPGroup
+ //List of user specific permission levels
+ Users map[string]string
+ //Root search path for group lookups. Usually something like "DC=myorg,DC=com".
+ //Only needed if using group permissions
+ RootSearchPath string
+}
+
+//LDAPGroup is a Group level access specification for ldap
+type LDAPGroup struct {
+ // group search path string
+ Path string
+ // Access to grant members of group Ex: "Admin"
+ Role string
+}
+
// GetSystemConfProvider returns the SystemConfProvider interface
// and validates the logic of the configuration. If the configuration
// is not valid an error is returned
@@ -151,12 +193,16 @@ func (sc *SystemConf) GetSystemConfProvider() (SystemConfProvider, error) {
return provider, nil
}
+const (
+ defaultHTTPListen = ":8070"
+)
+
// NewSystemConf retruns a system conf with default values set
func newSystemConf() *SystemConf {
return &SystemConf{
CheckFrequency: Duration{Duration: time.Minute * 5},
DefaultRunEvery: 1,
- HTTPListen: ":8070",
+ HTTPListen: defaultHTTPListen,
DBConf: DBConf{
LedisDir: "ledis_data",
LedisBindAddr: "127.0.0.1:9565",
@@ -199,6 +245,10 @@ func loadSystemConfig(conf string, isFileName bool) (*SystemConf, error) {
return sc, fmt.Errorf("undecoded fields in system configuration: %v", decodeMeta.Undecoded())
}
sc.md = decodeMeta
+ // clear default http listen if not explicitly specified
+ if !decodeMeta.IsDefined("HTTPListen") && decodeMeta.IsDefined("HTTPSListen") {
+ sc.HTTPListen = ""
+ }
return sc, nil
}
@@ -207,10 +257,19 @@ func (sc *SystemConf) GetHTTPListen() string {
return sc.HTTPListen
}
-// GetRelayListen returns an address on which bosun will listen and Proxy all requests to /api
-// it was added so one can make OpenTSDB API endpoints available at the same URL as Bosun.
-func (sc *SystemConf) GetRelayListen() string {
- return sc.RelayListen
+// GetHTTPSListen returns the hostname:port that Bosun should listen on with tls
+func (sc *SystemConf) GetHTTPSListen() string {
+ return sc.HTTPSListen
+}
+
+// GetTLSCertFile returns the path to the tls certificate to listen with (pem format). Must be specified with HTTPSListen.
+func (sc *SystemConf) GetTLSCertFile() string {
+ return sc.TLSCertFile
+}
+
+// GetTLSKeyFile returns the path to the tls key to listen with (pem format). Must be specified with HTTPSListen.
+func (sc *SystemConf) GetTLSKeyFile() string {
+ return sc.TLSKeyFile
}
// GetSMTPHost returns the SMTP mail server host that Bosun will use to relay through
@@ -271,6 +330,10 @@ func (sc *SystemConf) GetRedisPassword() string {
return sc.DBConf.RedisPassword
}
+func (sc *SystemConf) GetAuthConf() *AuthConf {
+ return sc.AuthConf
+}
+
// GetTimeAndDate returns the http://www.timeanddate.com/ that should be available to the UI
// so it can show links to translate UTC times to various timezones. This feature is only
// for creating UI Links as Bosun is expected to be running on a machine that is set to UTC
@@ -15,10 +15,13 @@ import (
"github.com/garyburd/redigo/redis"
"github.com/siddontang/ledisdb/config"
"github.com/siddontang/ledisdb/server"
+
+ "github.com/captncraig/easyauth/providers/token/redisStore"
)
// Core data access interface for everything sched needs
type DataAccess interface {
+ RedisConnector
Metadata() MetadataDataAccess
Configs() ConfigDataAccess
Search() SearchDataAccess
@@ -118,6 +121,8 @@ func (d *dataAccess) Get() redis.Conn {
}
}
+var _ redisStore.Connector = (*dataAccess)(nil) //just a compile time interface check
+
//gets name of function that called the currently executing function.
func myCallerName() string {
fpcs := make([]uintptr, 1)
View
@@ -109,32 +109,31 @@ func main() {
os.Exit(0)
}
var ruleProvider conf.RuleConfProvider = ruleConf
- httpListen := &url.URL{
- Scheme: "http",
- Host: sysProvider.GetHTTPListen(),
+
+ addrToSendTo := sysProvider.GetHTTPSListen()
+ proto := "https"
+ if addrToSendTo == "" {
+ addrToSendTo = sysProvider.GetHTTPListen()
+ proto = "http"
}
- if strings.HasPrefix(httpListen.Host, ":") {
- httpListen.Host = "localhost" + httpListen.Host
+ selfAddress := &url.URL{
+ Scheme: proto,
+ Host: addrToSendTo,
}
- if err := metadata.Init(httpListen, false); err != nil {
- slog.Fatal(err)
+ if strings.HasPrefix(selfAddress.Host, ":") {
+ selfAddress.Host = "localhost" + selfAddress.Host
}
+
if err := sched.Load(sysProvider, ruleProvider, *flagSkipLast, *flagQuiet); err != nil {
slog.Fatal(err)
}
- if sysProvider.GetRelayListen() != "" {
- go func() {
- mux := http.NewServeMux()
- mux.Handle("/api/", util.NewSingleHostProxy(httpListen))
- s := &http.Server{
- Addr: sysProvider.GetRelayListen(),
- Handler: mux,
- }
- slog.Fatal(s.ListenAndServe())
- }()
+ if err := metadata.InitF(false, func(k metadata.Metakey, v interface{}) error { return sched.DefaultSched.PutMetadata(k, v) }); err != nil {
+ slog.Fatal(err)
}
if sysProvider.GetTSDBHost() != "" {
- if err := collect.Init(httpListen, "bosun"); err != nil {
+ relay := web.Relay(sysProvider.GetTSDBHost())
+ collect.DirectHandler = relay
+ if err := collect.Init(selfAddress, "bosun"); err != nil {
slog.Fatal(err)
}
tsdbHost := &url.URL{
@@ -218,7 +217,9 @@ func main() {
ruleProvider.SetReload(reload)
go func() {
- slog.Fatal(web.Listen(sysProvider.GetHTTPListen(), *flagDev, sysProvider.GetTSDBHost(), reload))
+ slog.Fatal(web.Listen(sysProvider.GetHTTPListen(), sysProvider.GetHTTPSListen(),
+ sysProvider.GetTLSCertFile(), sysProvider.GetTLSKeyFile(), *flagDev,
+ sysProvider.GetTSDBHost(), reload, sysProvider.GetAuthConf()))
}()
go func() {
if !*flagNoChecks {
@@ -255,6 +256,7 @@ func main() {
}
func quit() {
+ slog.Error("Exiting")
os.Exit(0)
}
@@ -2,7 +2,6 @@ package sched // import "bosun.org/cmd/bosun/sched"
import (
"fmt"
- "reflect"
"strings"
"sync"
"time"
@@ -153,13 +152,7 @@ func (s *Schedule) PutMetadata(k metadata.Metakey, v interface{}) error {
slog.Error(err)
return err
}
- strVal, ok := v.(string)
- if !ok {
- err := fmt.Errorf("desc, rate, and unit require value to be string. Found: %s", reflect.TypeOf(v))
- slog.Error(err)
- return err
- }
- return s.DataAccess.Metadata().PutMetricMetadata(k.Metric, k.Name, strVal)
+ return s.DataAccess.Metadata().PutMetricMetadata(k.Metric, k.Name, fmt.Sprint(v))
}
func (s *Schedule) DeleteMetadata(tags opentsdb.TagSet, name string) error {
Binary file not shown.
@@ -3,7 +3,6 @@ package web
import (
"bufio"
"bytes"
- "io"
"log"
"os"
"os/exec"
@@ -47,25 +46,11 @@ func RunTsc() {
}
func run(name string, arg ...string) {
- log.Println("running", name)
+ log.Println("running", name, arg)
c := exec.Command(name, arg...)
- stdout, err := c.StdoutPipe()
- if err != nil {
- log.Fatal(err)
- }
- stderr, err := c.StderrPipe()
- if err != nil {
- log.Fatal(err)
- }
- if err := c.Start(); err != nil {
- log.Fatal(err)
- }
- go func() { io.Copy(os.Stdout, stdout) }()
- go func() { io.Copy(os.Stderr, stderr) }()
- if err := c.Wait(); err != nil {
+ if err := c.Run(); err != nil {
log.Printf("run error: %v: %v", name, err)
}
- log.Println("run complete:", name)
}
func deepCompareDifferent(file1, file2 string) bool {
Oops, something went wrong.

0 comments on commit 67f50fd

Please sign in to comment.