ソースを参照

Add common type for oauth authorization errors

Alexander Menzhinsky 9 年 前
コミット
30c334a2b8

+ 5 - 0
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

+ 20 - 10
pkg/api/login_oauth.go

@@ -22,6 +22,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)
@@ -44,8 +51,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
 	}
 
@@ -117,10 +123,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)
 		}
@@ -131,8 +135,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
 	}
 
@@ -142,7 +145,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")
@@ -151,7 +154,7 @@ func OAuthLogin(ctx *middleware.Context) {
 			return
 		}
 		if limitReached {
-			ctx.Redirect(setting.AppSubUrl + "/login")
+			redirectWithError(ctx, ErrUsersQuotaReached)
 			return
 		}
 		cmd := m.CreateUserCommand{
@@ -179,3 +182,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")
+}

+ 2 - 6
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 {

+ 8 - 0
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)

+ 2 - 12
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]);
       }
     };