mirror of
https://github.com/grafana/grafana.git
synced 2024-11-24 18:00:31 -06:00
SAML Role and Team sync (open source part) (#23391)
* SAML: add default params for role and team sync * SAML: add org_mapping option * SAML: support allowed_organizations option * Chore: expose RedirectWithError from HTTPServer * Chore: return RedirectResponse (fix superfluous response.writeheader message) * HTTPServer: expose ValidateRedirectTo() and CookieOptionsFromCfg() * Config: move SAML section to the enterprise
This commit is contained in:
parent
0205c42bfa
commit
f023e7a399
@ -423,47 +423,6 @@ tls_client_cert =
|
||||
tls_client_key =
|
||||
tls_client_ca =
|
||||
|
||||
#################################### SAML Auth ###########################
|
||||
[auth.saml] # Enterprise only
|
||||
# Defaults to false. If true, the feature is enabled
|
||||
enabled = false
|
||||
|
||||
# Base64-encoded public X.509 certificate. Used to sign requests to the IdP
|
||||
certificate =
|
||||
|
||||
# Path to the public X.509 certificate. Used to sign requests to the IdP
|
||||
certificate_path =
|
||||
|
||||
# Base64-encoded private key. Used to decrypt assertions from the IdP
|
||||
private_key =
|
||||
|
||||
# Path to the private key. Used to decrypt assertions from the IdP
|
||||
private_key_path =
|
||||
|
||||
# Base64-encoded IdP SAML metadata XML. Used to verify and obtain binding locations from the IdP
|
||||
idp_metadata =
|
||||
|
||||
# Path to the SAML metadata XML. Used to verify and obtain binding locations from the IdP
|
||||
idp_metadata_path =
|
||||
|
||||
# URL to fetch SAML IdP metadata. Used to verify and obtain binding locations from the IdP
|
||||
idp_metadata_url =
|
||||
|
||||
# Duration, since the IdP issued a response and the SP is allowed to process it. Defaults to 90 seconds
|
||||
max_issue_delay = 90s
|
||||
|
||||
# Duration, for how long the SP's metadata should be valid. Defaults to 48 hours
|
||||
metadata_valid_duration = 48h
|
||||
|
||||
# Friendly name or name of the attribute within the SAML assertion to use as the user's name
|
||||
assertion_attribute_name = displayName
|
||||
|
||||
# Friendly name or name of the attribute within the SAML assertion to use as the user's login handle
|
||||
assertion_attribute_login = mail
|
||||
|
||||
# Friendly name or name of the attribute within the SAML assertion to use as the user's email
|
||||
assertion_attribute_email = mail
|
||||
|
||||
#################################### Basic Auth ##########################
|
||||
[auth.basic]
|
||||
enabled = true
|
||||
|
@ -413,47 +413,6 @@
|
||||
;tls_client_key =
|
||||
;tls_client_ca =
|
||||
|
||||
#################################### SAML Auth ###########################
|
||||
[auth.saml] # Enterprise only
|
||||
# Defaults to false. If true, the feature is enabled.
|
||||
;enabled = false
|
||||
|
||||
# Base64-encoded public X.509 certificate. Used to sign requests to the IdP
|
||||
;certificate =
|
||||
|
||||
# Path to the public X.509 certificate. Used to sign requests to the IdP
|
||||
;certificate_path =
|
||||
|
||||
# Base64-encoded private key. Used to decrypt assertions from the IdP
|
||||
;private_key =
|
||||
|
||||
;# Path to the private key. Used to decrypt assertions from the IdP
|
||||
;private_key_path =
|
||||
|
||||
# Base64-encoded IdP SAML metadata XML. Used to verify and obtain binding locations from the IdP
|
||||
;idp_metadata =
|
||||
|
||||
# Path to the SAML metadata XML. Used to verify and obtain binding locations from the IdP
|
||||
;idp_metadata_path =
|
||||
|
||||
# URL to fetch SAML IdP metadata. Used to verify and obtain binding locations from the IdP
|
||||
;idp_metadata_url =
|
||||
|
||||
# Duration, since the IdP issued a response and the SP is allowed to process it. Defaults to 90 seconds.
|
||||
;max_issue_delay = 90s
|
||||
|
||||
# Duration, for how long the SP's metadata should be valid. Defaults to 48 hours.
|
||||
;metadata_valid_duration = 48h
|
||||
|
||||
# Friendly name or name of the attribute within the SAML assertion to use as the user's name
|
||||
;assertion_attribute_name = displayName
|
||||
|
||||
# Friendly name or name of the attribute within the SAML assertion to use as the user's login handle
|
||||
;assertion_attribute_login = mail
|
||||
|
||||
# Friendly name or name of the attribute within the SAML assertion to use as the user's email
|
||||
;assertion_attribute_email = mail
|
||||
|
||||
#################################### Basic Auth ##########################
|
||||
[auth.basic]
|
||||
;enabled = true
|
||||
|
@ -29,7 +29,7 @@ var getViewIndex = func() string {
|
||||
return ViewIndex
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) validateRedirectTo(redirectTo string) error {
|
||||
func (hs *HTTPServer) ValidateRedirectTo(redirectTo string) error {
|
||||
to, err := url.Parse(redirectTo)
|
||||
if err != nil {
|
||||
return login.ErrInvalidRedirectTo
|
||||
@ -45,7 +45,7 @@ func (hs *HTTPServer) validateRedirectTo(redirectTo string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) cookieOptionsFromCfg() middleware.CookieOptions {
|
||||
func (hs *HTTPServer) CookieOptionsFromCfg() middleware.CookieOptions {
|
||||
path := "/"
|
||||
if len(hs.Cfg.AppSubUrl) > 0 {
|
||||
path = hs.Cfg.AppSubUrl
|
||||
@ -78,7 +78,7 @@ func (hs *HTTPServer) LoginView(c *models.ReqContext) {
|
||||
//therefore the loginError should be passed to the view data
|
||||
//and the view should return immediately before attempting
|
||||
//to login again via OAuth and enter to a redirect loop
|
||||
middleware.DeleteCookie(c.Resp, LoginErrorCookieName, hs.cookieOptionsFromCfg)
|
||||
middleware.DeleteCookie(c.Resp, LoginErrorCookieName, hs.CookieOptionsFromCfg)
|
||||
viewData.Settings["loginError"] = loginError
|
||||
c.HTML(200, getViewIndex(), viewData)
|
||||
return
|
||||
@ -100,13 +100,13 @@ func (hs *HTTPServer) LoginView(c *models.ReqContext) {
|
||||
}
|
||||
|
||||
if redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")); len(redirectTo) > 0 {
|
||||
if err := hs.validateRedirectTo(redirectTo); err != nil {
|
||||
if err := hs.ValidateRedirectTo(redirectTo); err != nil {
|
||||
// the user is already logged so instead of rendering the login page with error
|
||||
// it should be redirected to the home page.
|
||||
log.Debug("Ignored invalid redirect_to cookie value: %v", redirectTo)
|
||||
redirectTo = hs.Cfg.AppSubUrl + "/"
|
||||
}
|
||||
middleware.DeleteCookie(c.Resp, "redirect_to", hs.cookieOptionsFromCfg)
|
||||
middleware.DeleteCookie(c.Resp, "redirect_to", hs.CookieOptionsFromCfg)
|
||||
c.Redirect(redirectTo)
|
||||
return
|
||||
}
|
||||
@ -184,12 +184,12 @@ func (hs *HTTPServer) LoginPost(c *models.ReqContext, cmd dtos.LoginCommand) Res
|
||||
}
|
||||
|
||||
if redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")); len(redirectTo) > 0 {
|
||||
if err := hs.validateRedirectTo(redirectTo); err == nil {
|
||||
if err := hs.ValidateRedirectTo(redirectTo); err == nil {
|
||||
result["redirectUrl"] = redirectTo
|
||||
} else {
|
||||
log.Info("Ignored invalid redirect_to cookie value: %v", redirectTo)
|
||||
}
|
||||
middleware.DeleteCookie(c.Resp, "redirect_to", hs.cookieOptionsFromCfg)
|
||||
middleware.DeleteCookie(c.Resp, "redirect_to", hs.CookieOptionsFromCfg)
|
||||
}
|
||||
|
||||
metrics.MApiLoginPost.Inc()
|
||||
@ -247,7 +247,25 @@ func (hs *HTTPServer) trySetEncryptedCookie(ctx *models.ReqContext, cookieName s
|
||||
return err
|
||||
}
|
||||
|
||||
middleware.WriteCookie(ctx.Resp, cookieName, hex.EncodeToString(encryptedError), 60, hs.cookieOptionsFromCfg)
|
||||
middleware.WriteCookie(ctx.Resp, cookieName, hex.EncodeToString(encryptedError), 60, hs.CookieOptionsFromCfg)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) redirectWithError(ctx *models.ReqContext, err error, v ...interface{}) {
|
||||
ctx.Logger.Error(err.Error(), v...)
|
||||
if err := hs.trySetEncryptedCookie(ctx, LoginErrorCookieName, err.Error(), 60); err != nil {
|
||||
hs.log.Error("Failed to set encrypted cookie", "err", err)
|
||||
}
|
||||
|
||||
ctx.Redirect(setting.AppSubUrl + "/login")
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) RedirectResponseWithError(ctx *models.ReqContext, err error, v ...interface{}) *RedirectResponse {
|
||||
ctx.Logger.Error(err.Error(), v...)
|
||||
if err := hs.trySetEncryptedCookie(ctx, LoginErrorCookieName, err.Error(), 60); err != nil {
|
||||
hs.log.Error("Failed to set encrypted cookie", "err", err)
|
||||
}
|
||||
|
||||
return Redirect(setting.AppSubUrl + "/login")
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
|
||||
}
|
||||
|
||||
hashedState := hashStatecode(state, setting.OAuthService.OAuthInfos[name].ClientSecret)
|
||||
middleware.WriteCookie(ctx.Resp, OauthStateCookieName, hashedState, hs.Cfg.OAuthCookieMaxAge, hs.cookieOptionsFromCfg)
|
||||
middleware.WriteCookie(ctx.Resp, OauthStateCookieName, hashedState, hs.Cfg.OAuthCookieMaxAge, hs.CookieOptionsFromCfg)
|
||||
if setting.OAuthService.OAuthInfos[name].HostedDomain == "" {
|
||||
ctx.Redirect(connect.AuthCodeURL(state, oauth2.AccessTypeOnline))
|
||||
} else {
|
||||
@ -82,7 +82,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
|
||||
cookieState := ctx.GetCookie(OauthStateCookieName)
|
||||
|
||||
// delete cookie
|
||||
middleware.DeleteCookie(ctx.Resp, OauthStateCookieName, hs.cookieOptionsFromCfg)
|
||||
middleware.DeleteCookie(ctx.Resp, OauthStateCookieName, hs.CookieOptionsFromCfg)
|
||||
|
||||
if cookieState == "" {
|
||||
ctx.Handle(500, "login.OAuthLogin(missing saved state)", nil)
|
||||
@ -227,8 +227,8 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
|
||||
metrics.MApiLoginOAuth.Inc()
|
||||
|
||||
if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
|
||||
if err := hs.validateRedirectTo(redirectTo); err == nil {
|
||||
middleware.DeleteCookie(ctx.Resp, "redirect_to", hs.cookieOptionsFromCfg)
|
||||
if err := hs.ValidateRedirectTo(redirectTo); err == nil {
|
||||
middleware.DeleteCookie(ctx.Resp, "redirect_to", hs.CookieOptionsFromCfg)
|
||||
ctx.Redirect(redirectTo)
|
||||
return
|
||||
}
|
||||
@ -242,12 +242,3 @@ func hashStatecode(code, seed string) string {
|
||||
hashBytes := sha256.Sum256([]byte(code + setting.SecretKey + seed))
|
||||
return hex.EncodeToString(hashBytes[:])
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) redirectWithError(ctx *models.ReqContext, err error, v ...interface{}) {
|
||||
ctx.Logger.Error(err.Error(), v...)
|
||||
if err := hs.trySetEncryptedCookie(ctx, LoginErrorCookieName, err.Error(), 60); err != nil {
|
||||
oauthLogger.Error("Failed to set encrypted cookie", "err", err)
|
||||
}
|
||||
|
||||
ctx.Redirect(setting.AppSubUrl + "/login")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user