auth_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package login
  2. import (
  3. "errors"
  4. "testing"
  5. m "github.com/grafana/grafana/pkg/models"
  6. . "github.com/smartystreets/goconvey/convey"
  7. )
  8. func TestAuthenticateUser(t *testing.T) {
  9. Convey("Authenticate user", t, func() {
  10. authScenario("When a user authenticates without setting a password", func(sc *authScenarioContext) {
  11. mockLoginAttemptValidation(nil, sc)
  12. mockLoginUsingGrafanaDB(nil, sc)
  13. mockLoginUsingLdap(false, nil, sc)
  14. loginQuery := m.LoginUserQuery{
  15. Username: "user",
  16. Password: "",
  17. }
  18. err := AuthenticateUser(&loginQuery)
  19. Convey("login should fail", func() {
  20. So(sc.grafanaLoginWasCalled, ShouldBeFalse)
  21. So(sc.ldapLoginWasCalled, ShouldBeFalse)
  22. So(err, ShouldEqual, ErrPasswordEmpty)
  23. })
  24. })
  25. authScenario("When a user authenticates having too many login attempts", func(sc *authScenarioContext) {
  26. mockLoginAttemptValidation(ErrTooManyLoginAttempts, sc)
  27. mockLoginUsingGrafanaDB(nil, sc)
  28. mockLoginUsingLdap(true, nil, sc)
  29. mockSaveInvalidLoginAttempt(sc)
  30. err := AuthenticateUser(sc.loginUserQuery)
  31. Convey("it should result in", func() {
  32. So(err, ShouldEqual, ErrTooManyLoginAttempts)
  33. So(sc.loginAttemptValidationWasCalled, ShouldBeTrue)
  34. So(sc.grafanaLoginWasCalled, ShouldBeFalse)
  35. So(sc.ldapLoginWasCalled, ShouldBeFalse)
  36. So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse)
  37. })
  38. })
  39. authScenario("When grafana user authenticate with valid credentials", func(sc *authScenarioContext) {
  40. mockLoginAttemptValidation(nil, sc)
  41. mockLoginUsingGrafanaDB(nil, sc)
  42. mockLoginUsingLdap(true, ErrInvalidCredentials, sc)
  43. mockSaveInvalidLoginAttempt(sc)
  44. err := AuthenticateUser(sc.loginUserQuery)
  45. Convey("it should result in", func() {
  46. So(err, ShouldEqual, nil)
  47. So(sc.loginAttemptValidationWasCalled, ShouldBeTrue)
  48. So(sc.grafanaLoginWasCalled, ShouldBeTrue)
  49. So(sc.ldapLoginWasCalled, ShouldBeFalse)
  50. So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse)
  51. })
  52. })
  53. authScenario("When grafana user authenticate and unexpected error occurs", func(sc *authScenarioContext) {
  54. customErr := errors.New("custom")
  55. mockLoginAttemptValidation(nil, sc)
  56. mockLoginUsingGrafanaDB(customErr, sc)
  57. mockLoginUsingLdap(true, ErrInvalidCredentials, sc)
  58. mockSaveInvalidLoginAttempt(sc)
  59. err := AuthenticateUser(sc.loginUserQuery)
  60. Convey("it should result in", func() {
  61. So(err, ShouldEqual, customErr)
  62. So(sc.loginAttemptValidationWasCalled, ShouldBeTrue)
  63. So(sc.grafanaLoginWasCalled, ShouldBeTrue)
  64. So(sc.ldapLoginWasCalled, ShouldBeFalse)
  65. So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse)
  66. })
  67. })
  68. authScenario("When a non-existing grafana user authenticate and ldap disabled", func(sc *authScenarioContext) {
  69. mockLoginAttemptValidation(nil, sc)
  70. mockLoginUsingGrafanaDB(m.ErrUserNotFound, sc)
  71. mockLoginUsingLdap(false, nil, sc)
  72. mockSaveInvalidLoginAttempt(sc)
  73. err := AuthenticateUser(sc.loginUserQuery)
  74. Convey("it should result in", func() {
  75. So(err, ShouldEqual, ErrInvalidCredentials)
  76. So(sc.loginAttemptValidationWasCalled, ShouldBeTrue)
  77. So(sc.grafanaLoginWasCalled, ShouldBeTrue)
  78. So(sc.ldapLoginWasCalled, ShouldBeTrue)
  79. So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse)
  80. })
  81. })
  82. authScenario("When a non-existing grafana user authenticate and invalid ldap credentials", func(sc *authScenarioContext) {
  83. mockLoginAttemptValidation(nil, sc)
  84. mockLoginUsingGrafanaDB(m.ErrUserNotFound, sc)
  85. mockLoginUsingLdap(true, ErrInvalidCredentials, sc)
  86. mockSaveInvalidLoginAttempt(sc)
  87. err := AuthenticateUser(sc.loginUserQuery)
  88. Convey("it should result in", func() {
  89. So(err, ShouldEqual, ErrInvalidCredentials)
  90. So(sc.loginAttemptValidationWasCalled, ShouldBeTrue)
  91. So(sc.grafanaLoginWasCalled, ShouldBeTrue)
  92. So(sc.ldapLoginWasCalled, ShouldBeTrue)
  93. So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeTrue)
  94. })
  95. })
  96. authScenario("When a non-existing grafana user authenticate and valid ldap credentials", func(sc *authScenarioContext) {
  97. mockLoginAttemptValidation(nil, sc)
  98. mockLoginUsingGrafanaDB(m.ErrUserNotFound, sc)
  99. mockLoginUsingLdap(true, nil, sc)
  100. mockSaveInvalidLoginAttempt(sc)
  101. err := AuthenticateUser(sc.loginUserQuery)
  102. Convey("it should result in", func() {
  103. So(err, ShouldBeNil)
  104. So(sc.loginAttemptValidationWasCalled, ShouldBeTrue)
  105. So(sc.grafanaLoginWasCalled, ShouldBeTrue)
  106. So(sc.ldapLoginWasCalled, ShouldBeTrue)
  107. So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse)
  108. })
  109. })
  110. authScenario("When a non-existing grafana user authenticate and ldap returns unexpected error", func(sc *authScenarioContext) {
  111. customErr := errors.New("custom")
  112. mockLoginAttemptValidation(nil, sc)
  113. mockLoginUsingGrafanaDB(m.ErrUserNotFound, sc)
  114. mockLoginUsingLdap(true, customErr, sc)
  115. mockSaveInvalidLoginAttempt(sc)
  116. err := AuthenticateUser(sc.loginUserQuery)
  117. Convey("it should result in", func() {
  118. So(err, ShouldEqual, customErr)
  119. So(sc.loginAttemptValidationWasCalled, ShouldBeTrue)
  120. So(sc.grafanaLoginWasCalled, ShouldBeTrue)
  121. So(sc.ldapLoginWasCalled, ShouldBeTrue)
  122. So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeFalse)
  123. })
  124. })
  125. authScenario("When grafana user authenticate with invalid credentials and invalid ldap credentials", func(sc *authScenarioContext) {
  126. mockLoginAttemptValidation(nil, sc)
  127. mockLoginUsingGrafanaDB(ErrInvalidCredentials, sc)
  128. mockLoginUsingLdap(true, ErrInvalidCredentials, sc)
  129. mockSaveInvalidLoginAttempt(sc)
  130. err := AuthenticateUser(sc.loginUserQuery)
  131. Convey("it should result in", func() {
  132. So(err, ShouldEqual, ErrInvalidCredentials)
  133. So(sc.loginAttemptValidationWasCalled, ShouldBeTrue)
  134. So(sc.grafanaLoginWasCalled, ShouldBeTrue)
  135. So(sc.ldapLoginWasCalled, ShouldBeTrue)
  136. So(sc.saveInvalidLoginAttemptWasCalled, ShouldBeTrue)
  137. })
  138. })
  139. })
  140. }
  141. type authScenarioContext struct {
  142. loginUserQuery *m.LoginUserQuery
  143. grafanaLoginWasCalled bool
  144. ldapLoginWasCalled bool
  145. loginAttemptValidationWasCalled bool
  146. saveInvalidLoginAttemptWasCalled bool
  147. }
  148. type authScenarioFunc func(sc *authScenarioContext)
  149. func mockLoginUsingGrafanaDB(err error, sc *authScenarioContext) {
  150. loginUsingGrafanaDB = func(query *m.LoginUserQuery) error {
  151. sc.grafanaLoginWasCalled = true
  152. return err
  153. }
  154. }
  155. func mockLoginUsingLdap(enabled bool, err error, sc *authScenarioContext) {
  156. loginUsingLdap = func(query *m.LoginUserQuery) (bool, error) {
  157. sc.ldapLoginWasCalled = true
  158. return enabled, err
  159. }
  160. }
  161. func mockLoginAttemptValidation(err error, sc *authScenarioContext) {
  162. validateLoginAttempts = func(username string) error {
  163. sc.loginAttemptValidationWasCalled = true
  164. return err
  165. }
  166. }
  167. func mockSaveInvalidLoginAttempt(sc *authScenarioContext) {
  168. saveInvalidLoginAttempt = func(query *m.LoginUserQuery) {
  169. sc.saveInvalidLoginAttemptWasCalled = true
  170. }
  171. }
  172. func authScenario(desc string, fn authScenarioFunc) {
  173. Convey(desc, func() {
  174. origLoginUsingGrafanaDB := loginUsingGrafanaDB
  175. origLoginUsingLdap := loginUsingLdap
  176. origValidateLoginAttempts := validateLoginAttempts
  177. origSaveInvalidLoginAttempt := saveInvalidLoginAttempt
  178. sc := &authScenarioContext{
  179. loginUserQuery: &m.LoginUserQuery{
  180. Username: "user",
  181. Password: "pwd",
  182. IpAddress: "192.168.1.1:56433",
  183. },
  184. }
  185. defer func() {
  186. loginUsingGrafanaDB = origLoginUsingGrafanaDB
  187. loginUsingLdap = origLoginUsingLdap
  188. validateLoginAttempts = origValidateLoginAttempts
  189. saveInvalidLoginAttempt = origSaveInvalidLoginAttempt
  190. }()
  191. fn(sc)
  192. })
  193. }