diff --git a/pkg/api/login.go b/pkg/api/login.go index 8ab76c7b48d..83a2a2713eb 100644 --- a/pkg/api/login.go +++ b/pkg/api/login.go @@ -35,6 +35,11 @@ func LoginView(c *middleware.Context) { viewData.Settings["loginHint"] = setting.LoginHint viewData.Settings["disableLoginForm"] = setting.DisableLoginForm + if loginError, ok := c.Session.Get("loginError").(string); ok { + c.Session.Set("loginError", "") // TODO: is there a proper way to delete a session var? + viewData.Settings["loginError"] = loginError + } + if !tryLoginUsingRememberCookie(c) { c.HTML(200, VIEW_INDEX, viewData) return diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index 2bf9c484803..5fbd9fea709 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -23,6 +23,13 @@ import ( "github.com/grafana/grafana/pkg/social" ) +var ( + ErrProviderDeniedRequest = errors.New("Login provider denied login request") + ErrEmailNotAllowed = errors.New("Required email domain not fulfilled") + ErrSignUpNotAllowed = errors.New("Signup is not allowed for this adapter") + ErrUsersQuotaReached = errors.New("Users quota reached") +) + func GenStateString() string { rnd := make([]byte, 32) rand.Read(rnd) @@ -45,8 +52,7 @@ func OAuthLogin(ctx *middleware.Context) { error := ctx.Query("error") if error != "" { errorDesc := ctx.Query("error_description") - ctx.Logger.Info("OAuthLogin Failed", "error", error, "errorDesc", errorDesc) - ctx.Redirect(setting.AppSubUrl + "/login?failCode=1003") + redirectWithError(ctx, ErrProviderDeniedRequest, "error", error, "errorDesc", errorDesc) return } @@ -118,10 +124,8 @@ func OAuthLogin(ctx *middleware.Context) { // get user info userInfo, err := connect.UserInfo(client) if err != nil { - if err == social.ErrMissingTeamMembership { - ctx.Redirect(setting.AppSubUrl + "/login?failCode=1000") - } else if err == social.ErrMissingOrganizationMembership { - ctx.Redirect(setting.AppSubUrl + "/login?failCode=1001") + if sErr, ok := err.(*social.Error); ok { + redirectWithError(ctx, sErr) } else { ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err) } @@ -132,8 +136,7 @@ func OAuthLogin(ctx *middleware.Context) { // validate that the email is allowed to login to grafana if !connect.IsEmailAllowed(userInfo.Email) { - ctx.Logger.Info("OAuth login attempt with unallowed email", "email", userInfo.Email) - ctx.Redirect(setting.AppSubUrl + "/login?failCode=1002") + redirectWithError(ctx, ErrEmailNotAllowed) return } @@ -143,7 +146,7 @@ func OAuthLogin(ctx *middleware.Context) { // create account if missing if err == m.ErrUserNotFound { if !connect.IsSignupAllowed() { - ctx.Redirect(setting.AppSubUrl + "/login") + redirectWithError(ctx, ErrSignUpNotAllowed) return } limitReached, err := middleware.QuotaReached(ctx, "user") @@ -152,7 +155,7 @@ func OAuthLogin(ctx *middleware.Context) { return } if limitReached { - ctx.Redirect(setting.AppSubUrl + "/login") + redirectWithError(ctx, ErrUsersQuotaReached) return } cmd := m.CreateUserCommand{ @@ -186,3 +189,10 @@ func OAuthLogin(ctx *middleware.Context) { ctx.Redirect(setting.AppSubUrl + "/") } + +func redirectWithError(ctx *middleware.Context, err error, v ...interface{}) { + ctx.Logger.Info(err.Error(), v...) + // TODO: we can use the flash storage here once it's implemented + ctx.Session.Set("loginError", err.Error()) + ctx.Redirect(setting.AppSubUrl + "/login") +} diff --git a/pkg/social/github_oauth.go b/pkg/social/github_oauth.go index 64ff1d86851..271a472be84 100644 --- a/pkg/social/github_oauth.go +++ b/pkg/social/github_oauth.go @@ -2,7 +2,6 @@ package social import ( "encoding/json" - "errors" "fmt" "net/http" @@ -21,11 +20,8 @@ type SocialGithub struct { } var ( - ErrMissingTeamMembership = errors.New("User not a member of one of the required teams") -) - -var ( - ErrMissingOrganizationMembership = errors.New("User not a member of one of the required organizations") + ErrMissingTeamMembership = &Error{"User not a member of one of the required teams"} + ErrMissingOrganizationMembership = &Error{"User not a member of one of the required organizations"} ) func (s *SocialGithub) Type() int { diff --git a/pkg/social/social.go b/pkg/social/social.go index 860d068957e..29c4b7ecbb4 100644 --- a/pkg/social/social.go +++ b/pkg/social/social.go @@ -29,6 +29,14 @@ type SocialConnector interface { Client(ctx context.Context, t *oauth2.Token) *http.Client } +type Error struct { + s string +} + +func (e *Error) Error() string { + return e.s +} + var ( SocialBaseUrl = "/login/" SocialMap = make(map[string]SocialConnector) diff --git a/public/app/core/controllers/login_ctrl.js b/public/app/core/controllers/login_ctrl.js index fa3af3d10f0..54323711604 100644 --- a/public/app/core/controllers/login_ctrl.js +++ b/public/app/core/controllers/login_ctrl.js @@ -7,13 +7,6 @@ define([ function (angular, _, coreModule, config) { 'use strict'; - var failCodes = { - "1000": "Required team membership not fulfilled", - "1001": "Required organization membership not fulfilled", - "1002": "Required email domain not fulfilled", - "1003": "Login provider denied login request", - }; - coreModule.default.controller('LoginCtrl', function($scope, backendSrv, contextSrv, $location) { $scope.formModel = { user: '', @@ -36,11 +29,8 @@ function (angular, _, coreModule, config) { $scope.init = function() { $scope.$watch("loginMode", $scope.loginModeChanged); - var params = $location.search(); - if (params.failCode) { - $scope.appEvent('alert-warning', ['Login Failed', failCodes[params.failCode]]); - delete params.failedMsg; - $location.search(params); + if (config.loginError) { + $scope.appEvent('alert-warning', ['Login Failed', config.loginError]); } };