Browse Source

Auth: SAML login button. (#17932)

* Auth: SAML login button.

* Fixed ts issue
Leonard Gram 6 years ago
parent
commit
e574147b1e

+ 1 - 0
packages/grafana-runtime/src/config.ts

@@ -30,6 +30,7 @@ export class GrafanaBootConfig {
   authProxyEnabled = false;
   authProxyEnabled = false;
   exploreEnabled = false;
   exploreEnabled = false;
   ldapEnabled = false;
   ldapEnabled = false;
+  samlEnabled = false;
   oauth: any;
   oauth: any;
   disableUserSignUp = false;
   disableUserSignUp = false;
   loginHint: any;
   loginHint: any;

+ 22 - 12
pkg/api/login.go

@@ -11,7 +11,7 @@ import (
 	"github.com/grafana/grafana/pkg/infra/metrics"
 	"github.com/grafana/grafana/pkg/infra/metrics"
 	"github.com/grafana/grafana/pkg/login"
 	"github.com/grafana/grafana/pkg/login"
 	"github.com/grafana/grafana/pkg/middleware"
 	"github.com/grafana/grafana/pkg/middleware"
-	m "github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/models"
 	"github.com/grafana/grafana/pkg/setting"
 	"github.com/grafana/grafana/pkg/setting"
 	"github.com/grafana/grafana/pkg/util"
 	"github.com/grafana/grafana/pkg/util"
 )
 )
@@ -21,7 +21,7 @@ const (
 	LoginErrorCookieName = "login_error"
 	LoginErrorCookieName = "login_error"
 )
 )
 
 
-func (hs *HTTPServer) LoginView(c *m.ReqContext) {
+func (hs *HTTPServer) LoginView(c *models.ReqContext) {
 	viewData, err := hs.setIndexViewData(c)
 	viewData, err := hs.setIndexViewData(c)
 	if err != nil {
 	if err != nil {
 		c.Handle(500, "Failed to get settings", err)
 		c.Handle(500, "Failed to get settings", err)
@@ -38,6 +38,7 @@ func (hs *HTTPServer) LoginView(c *m.ReqContext) {
 	viewData.Settings["loginHint"] = setting.LoginHint
 	viewData.Settings["loginHint"] = setting.LoginHint
 	viewData.Settings["passwordHint"] = setting.PasswordHint
 	viewData.Settings["passwordHint"] = setting.PasswordHint
 	viewData.Settings["disableLoginForm"] = setting.DisableLoginForm
 	viewData.Settings["disableLoginForm"] = setting.DisableLoginForm
+	viewData.Settings["samlEnabled"] = isSamlEnabled()
 
 
 	if loginError, ok := tryGetEncryptedCookie(c, LoginErrorCookieName); ok {
 	if loginError, ok := tryGetEncryptedCookie(c, LoginErrorCookieName); ok {
 		deleteCookie(c, LoginErrorCookieName)
 		deleteCookie(c, LoginErrorCookieName)
@@ -62,7 +63,16 @@ func (hs *HTTPServer) LoginView(c *m.ReqContext) {
 	c.Redirect(setting.AppSubUrl + "/")
 	c.Redirect(setting.AppSubUrl + "/")
 }
 }
 
 
-func tryOAuthAutoLogin(c *m.ReqContext) bool {
+func isSamlEnabled() bool {
+	enabledCmd := models.IsSAMLEnabledCommand{}
+	if err := bus.Dispatch(&enabledCmd); err != nil {
+		return false
+	}
+
+	return enabledCmd.Result
+}
+
+func tryOAuthAutoLogin(c *models.ReqContext) bool {
 	if !setting.OAuthAutoLogin {
 	if !setting.OAuthAutoLogin {
 		return false
 		return false
 	}
 	}
@@ -80,7 +90,7 @@ func tryOAuthAutoLogin(c *m.ReqContext) bool {
 	return false
 	return false
 }
 }
 
 
-func (hs *HTTPServer) LoginAPIPing(c *m.ReqContext) Response {
+func (hs *HTTPServer) LoginAPIPing(c *models.ReqContext) Response {
 	if c.IsSignedIn || c.IsAnonymous {
 	if c.IsSignedIn || c.IsAnonymous {
 		return JSON(200, "Logged in")
 		return JSON(200, "Logged in")
 	}
 	}
@@ -88,12 +98,12 @@ func (hs *HTTPServer) LoginAPIPing(c *m.ReqContext) Response {
 	return Error(401, "Unauthorized", nil)
 	return Error(401, "Unauthorized", nil)
 }
 }
 
 
-func (hs *HTTPServer) LoginPost(c *m.ReqContext, cmd dtos.LoginCommand) Response {
+func (hs *HTTPServer) LoginPost(c *models.ReqContext, cmd dtos.LoginCommand) Response {
 	if setting.DisableLoginForm {
 	if setting.DisableLoginForm {
 		return Error(401, "Login is disabled", nil)
 		return Error(401, "Login is disabled", nil)
 	}
 	}
 
 
-	authQuery := &m.LoginUserQuery{
+	authQuery := &models.LoginUserQuery{
 		ReqContext: c,
 		ReqContext: c,
 		Username:   cmd.User,
 		Username:   cmd.User,
 		Password:   cmd.Password,
 		Password:   cmd.Password,
@@ -129,7 +139,7 @@ func (hs *HTTPServer) LoginPost(c *m.ReqContext, cmd dtos.LoginCommand) Response
 	return JSON(200, result)
 	return JSON(200, result)
 }
 }
 
 
-func (hs *HTTPServer) loginUserWithUser(user *m.User, c *m.ReqContext) {
+func (hs *HTTPServer) loginUserWithUser(user *models.User, c *models.ReqContext) {
 	if user == nil {
 	if user == nil {
 		hs.log.Error("user login with nil user")
 		hs.log.Error("user login with nil user")
 	}
 	}
@@ -142,8 +152,8 @@ func (hs *HTTPServer) loginUserWithUser(user *m.User, c *m.ReqContext) {
 	middleware.WriteSessionCookie(c, userToken.UnhashedToken, hs.Cfg.LoginMaxLifetimeDays)
 	middleware.WriteSessionCookie(c, userToken.UnhashedToken, hs.Cfg.LoginMaxLifetimeDays)
 }
 }
 
 
-func (hs *HTTPServer) Logout(c *m.ReqContext) {
-	if err := hs.AuthTokenService.RevokeToken(c.Req.Context(), c.UserToken); err != nil && err != m.ErrUserTokenNotFound {
+func (hs *HTTPServer) Logout(c *models.ReqContext) {
+	if err := hs.AuthTokenService.RevokeToken(c.Req.Context(), c.UserToken); err != nil && err != models.ErrUserTokenNotFound {
 		hs.log.Error("failed to revoke auth token", "error", err)
 		hs.log.Error("failed to revoke auth token", "error", err)
 	}
 	}
 
 
@@ -157,7 +167,7 @@ func (hs *HTTPServer) Logout(c *m.ReqContext) {
 	}
 	}
 }
 }
 
 
-func tryGetEncryptedCookie(ctx *m.ReqContext, cookieName string) (string, bool) {
+func tryGetEncryptedCookie(ctx *models.ReqContext, cookieName string) (string, bool) {
 	cookie := ctx.GetCookie(cookieName)
 	cookie := ctx.GetCookie(cookieName)
 	if cookie == "" {
 	if cookie == "" {
 		return "", false
 		return "", false
@@ -172,11 +182,11 @@ func tryGetEncryptedCookie(ctx *m.ReqContext, cookieName string) (string, bool)
 	return string(decryptedError), err == nil
 	return string(decryptedError), err == nil
 }
 }
 
 
-func deleteCookie(ctx *m.ReqContext, cookieName string) {
+func deleteCookie(ctx *models.ReqContext, cookieName string) {
 	ctx.SetCookie(cookieName, "", -1, setting.AppSubUrl+"/")
 	ctx.SetCookie(cookieName, "", -1, setting.AppSubUrl+"/")
 }
 }
 
 
-func (hs *HTTPServer) trySetEncryptedCookie(ctx *m.ReqContext, cookieName string, value string, maxAge int) error {
+func (hs *HTTPServer) trySetEncryptedCookie(ctx *models.ReqContext, cookieName string, value string, maxAge int) error {
 	encryptedError, err := util.Encrypt([]byte(value), setting.SecretKey)
 	encryptedError, err := util.Encrypt([]byte(value), setting.SecretKey)
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 5 - 0
pkg/models/saml.go

@@ -0,0 +1,5 @@
+package models
+
+type IsSAMLEnabledCommand struct {
+	Result bool
+}

+ 1 - 0
public/app/core/controllers/login_ctrl.ts

@@ -20,6 +20,7 @@ export class LoginCtrl {
     $scope.oauthEnabled = _.keys(config.oauth).length > 0;
     $scope.oauthEnabled = _.keys(config.oauth).length > 0;
     $scope.ldapEnabled = config.ldapEnabled;
     $scope.ldapEnabled = config.ldapEnabled;
     $scope.authProxyEnabled = config.authProxyEnabled;
     $scope.authProxyEnabled = config.authProxyEnabled;
+    $scope.samlEnabled = config.samlEnabled;
 
 
     $scope.disableLoginForm = config.disableLoginForm;
     $scope.disableLoginForm = config.disableLoginForm;
     $scope.disableUserSignUp = config.disableUserSignUp;
     $scope.disableUserSignUp = config.disableUserSignUp;

+ 4 - 0
public/app/partials/login.html

@@ -68,6 +68,10 @@
             <i class="btn-service-icon fa fa-sign-in"></i>
             <i class="btn-service-icon fa fa-sign-in"></i>
             Sign in with {{oauth.generic_oauth.name}}
             Sign in with {{oauth.generic_oauth.name}}
           </a>
           </a>
+          <a class="btn btn-medium btn-service btn-service--github login-btn" href="login/saml" target="_self" ng-if="samlEnabled">
+            <i class="btn-service-icon fa fa-key"></i>
+            Sign in with SAML
+          </a>
         </div>
         </div>
         <div class="login-signup-box" ng-show="!disableUserSignUp">
         <div class="login-signup-box" ng-show="!disableUserSignUp">
           <div class="login-signup-title p-r-1">
           <div class="login-signup-title p-r-1">