Auth Proxy improvements
- adds the option to use ldap groups for authorization in combination with an auth proxy - adds an option to limit where auth proxy requests come from by configure a list of ip's - fixes a security issue, session could be reused
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/login"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
@@ -17,6 +23,12 @@ func initContextWithAuthProxy(ctx *Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// if auth proxy ip(s) defined, check if request comes from one of those
|
||||
if err := checkAuthenticationProxy(ctx, proxyHeaderValue); err != nil {
|
||||
ctx.Handle(407, "Proxy authentication required", err)
|
||||
return true
|
||||
}
|
||||
|
||||
query := getSignedInUserQueryForProxyAuth(proxyHeaderValue)
|
||||
if err := bus.Dispatch(query); err != nil {
|
||||
if err != m.ErrUserNotFound {
|
||||
@@ -26,6 +38,10 @@ func initContextWithAuthProxy(ctx *Context) bool {
|
||||
|
||||
if setting.AuthProxyAutoSignUp {
|
||||
cmd := getCreateUserCommandForProxyAuth(proxyHeaderValue)
|
||||
if setting.LdapEnabled {
|
||||
cmd.SkipOrgSetup = true
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(cmd); err != nil {
|
||||
ctx.Handle(500, "Failed to create user specified in auth proxy header", err)
|
||||
return true
|
||||
@@ -46,6 +62,30 @@ func initContextWithAuthProxy(ctx *Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Make sure that we cannot share a session between different users!
|
||||
if getRequestUserId(ctx) > 0 && getRequestUserId(ctx) != query.Result.UserId {
|
||||
// remove session
|
||||
if err := ctx.Session.Destory(ctx); err != nil {
|
||||
log.Error(3, "Failed to destory session, err")
|
||||
}
|
||||
|
||||
// initialize a new session
|
||||
if err := ctx.Session.Start(ctx); err != nil {
|
||||
log.Error(3, "Failed to start session", err)
|
||||
}
|
||||
}
|
||||
|
||||
// When ldap is enabled, sync userinfo and org roles
|
||||
if err := syncGrafanaUserWithLdapUser(ctx, query); err != nil {
|
||||
if err == login.ErrInvalidCredentials {
|
||||
ctx.Handle(500, "Unable to authenticate user", err)
|
||||
return false
|
||||
}
|
||||
|
||||
ctx.Handle(500, "Failed to sync user", err)
|
||||
return false
|
||||
}
|
||||
|
||||
ctx.SignedInUser = query.Result
|
||||
ctx.IsSignedIn = true
|
||||
ctx.Session.Set(SESS_KEY_USERID, ctx.UserId)
|
||||
@@ -53,6 +93,56 @@ func initContextWithAuthProxy(ctx *Context) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var syncGrafanaUserWithLdapUser = func(ctx *Context, query *m.GetSignedInUserQuery) error {
|
||||
if setting.LdapEnabled {
|
||||
expireEpoch := time.Now().Add(time.Duration(-setting.AuthProxyLdapSyncTtl) * time.Minute).Unix()
|
||||
|
||||
var lastLdapSync int64
|
||||
if lastLdapSyncInSession := ctx.Session.Get(SESS_KEY_LASTLDAPSYNC); lastLdapSyncInSession != nil {
|
||||
lastLdapSync = lastLdapSyncInSession.(int64)
|
||||
}
|
||||
|
||||
if lastLdapSync < expireEpoch {
|
||||
ldapCfg := login.LdapCfg
|
||||
|
||||
for _, server := range ldapCfg.Servers {
|
||||
auther := login.NewLdapAuthenticator(server)
|
||||
if err := auther.SyncSignedInUser(query.Result); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Session.Set(SESS_KEY_LASTLDAPSYNC, time.Now().Unix())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkAuthenticationProxy(ctx *Context, proxyHeaderValue string) error {
|
||||
if len(strings.TrimSpace(setting.AuthProxyWhitelist)) > 0 {
|
||||
proxies := strings.Split(setting.AuthProxyWhitelist, ",")
|
||||
remoteAddrSplit := strings.Split(ctx.Req.RemoteAddr, ":")
|
||||
sourceIP := remoteAddrSplit[0]
|
||||
|
||||
found := false
|
||||
for _, proxyIP := range proxies {
|
||||
if sourceIP == strings.TrimSpace(proxyIP) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
msg := fmt.Sprintf("Request for user (%s) is not from the authentication proxy", proxyHeaderValue)
|
||||
err := errors.New(msg)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSignedInUserQueryForProxyAuth(headerVal string) *m.GetSignedInUserQuery {
|
||||
query := m.GetSignedInUserQuery{}
|
||||
if setting.AuthProxyHeaderProperty == "username" {
|
||||
|
||||
Reference in New Issue
Block a user