github.com/adacta-ru/mattermost-server/v6@v6.0.0/web/handlers_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package web
     5  
     6  import (
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"testing"
    10  
    11  	"github.com/adacta-ru/mattermost-server/v6/app"
    12  	"github.com/adacta-ru/mattermost-server/v6/model"
    13  	"github.com/adacta-ru/mattermost-server/v6/plugin/plugintest/mock"
    14  	"github.com/adacta-ru/mattermost-server/v6/store/storetest/mocks"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func handlerForHTTPErrors(c *Context, w http.ResponseWriter, r *http.Request) {
    20  	c.Err = model.NewAppError("loginWithSaml", "api.user.saml.not_available.app_error", nil, "", http.StatusFound)
    21  }
    22  
    23  func TestHandlerServeHTTPErrors(t *testing.T) {
    24  	th := SetupWithStoreMock(t)
    25  	defer th.TearDown()
    26  
    27  	web := New(th.Server, th.Server.AppOptions, th.Server.Router)
    28  	handler := web.NewHandler(handlerForHTTPErrors)
    29  
    30  	var flagtests = []struct {
    31  		name     string
    32  		url      string
    33  		mobile   bool
    34  		redirect bool
    35  	}{
    36  		{"redirect on desktop non-api endpoint", "/login/sso/saml", false, true},
    37  		{"not redirect on desktop api endpoint", "/api/v4/test", false, false},
    38  		{"not redirect on mobile non-api endpoint", "/login/sso/saml", true, false},
    39  		{"not redirect on mobile api endpoint", "/api/v4/test", true, false},
    40  	}
    41  
    42  	for _, tt := range flagtests {
    43  		t.Run(tt.name, func(t *testing.T) {
    44  			request := httptest.NewRequest("GET", tt.url, nil)
    45  			if tt.mobile {
    46  				request.Header.Add("X-Mobile-App", "mattermost")
    47  			}
    48  			response := httptest.NewRecorder()
    49  			handler.ServeHTTP(response, request)
    50  
    51  			if tt.redirect {
    52  				assert.Equal(t, response.Code, http.StatusFound)
    53  			} else {
    54  				assert.NotContains(t, response.Body.String(), "/error?message=")
    55  			}
    56  		})
    57  	}
    58  }
    59  
    60  func handlerForHTTPSecureTransport(c *Context, w http.ResponseWriter, r *http.Request) {
    61  }
    62  
    63  func TestHandlerServeHTTPSecureTransport(t *testing.T) {
    64  	th := SetupWithStoreMock(t)
    65  	defer th.TearDown()
    66  
    67  	mockStore := th.App.Srv().Store.(*mocks.Store)
    68  	mockUserStore := mocks.UserStore{}
    69  	mockUserStore.On("Count", mock.Anything).Return(int64(10), nil)
    70  	mockPostStore := mocks.PostStore{}
    71  	mockPostStore.On("GetMaxPostSize").Return(65535, nil)
    72  	mockSystemStore := mocks.SystemStore{}
    73  	mockSystemStore.On("GetByName", "UpgradedFromTE").Return(&model.System{Name: "UpgradedFromTE", Value: "false"}, nil)
    74  	mockSystemStore.On("GetByName", "InstallationDate").Return(&model.System{Name: "InstallationDate", Value: "10"}, nil)
    75  	mockSystemStore.On("GetByName", "FirstServerRunTimestamp").Return(&model.System{Name: "FirstServerRunTimestamp", Value: "10"}, nil)
    76  
    77  	mockStore.On("User").Return(&mockUserStore)
    78  	mockStore.On("Post").Return(&mockPostStore)
    79  	mockStore.On("System").Return(&mockSystemStore)
    80  
    81  	th.App.UpdateConfig(func(config *model.Config) {
    82  		*config.ServiceSettings.TLSStrictTransport = true
    83  		*config.ServiceSettings.TLSStrictTransportMaxAge = 6000
    84  	})
    85  
    86  	web := New(th.Server, th.Server.AppOptions, th.Server.Router)
    87  	handler := web.NewHandler(handlerForHTTPSecureTransport)
    88  
    89  	request := httptest.NewRequest("GET", "/api/v4/test", nil)
    90  
    91  	response := httptest.NewRecorder()
    92  	handler.ServeHTTP(response, request)
    93  	header := response.Header().Get("Strict-Transport-Security")
    94  
    95  	if header == "" {
    96  		t.Errorf("Strict-Transport-Security expected but not existent")
    97  	}
    98  
    99  	if header != "max-age=6000" {
   100  		t.Errorf("Expected max-age=6000, got %s", header)
   101  	}
   102  
   103  	th.App.UpdateConfig(func(config *model.Config) {
   104  		*config.ServiceSettings.TLSStrictTransport = false
   105  	})
   106  
   107  	request = httptest.NewRequest("GET", "/api/v4/test", nil)
   108  
   109  	response = httptest.NewRecorder()
   110  	handler.ServeHTTP(response, request)
   111  	header = response.Header().Get("Strict-Transport-Security")
   112  
   113  	if header != "" {
   114  		t.Errorf("Strict-Transport-Security header is not expected, but returned")
   115  	}
   116  }
   117  
   118  func handlerForCSRFToken(c *Context, w http.ResponseWriter, r *http.Request) {
   119  }
   120  
   121  func TestHandlerServeCSRFToken(t *testing.T) {
   122  	th := Setup(t).InitBasic()
   123  	defer th.TearDown()
   124  
   125  	session := &model.Session{
   126  		UserId:   th.BasicUser.Id,
   127  		CreateAt: model.GetMillis(),
   128  		Roles:    model.SYSTEM_USER_ROLE_ID,
   129  		IsOAuth:  false,
   130  	}
   131  	session.GenerateCSRF()
   132  	th.App.SetSessionExpireInDays(session, 1)
   133  	session, err := th.App.CreateSession(session)
   134  	if err != nil {
   135  		t.Errorf("Expected nil, got %s", err)
   136  	}
   137  
   138  	web := New(th.Server, th.Server.AppOptions, th.Server.Router)
   139  
   140  	handler := Handler{
   141  		GetGlobalAppOptions: web.GetGlobalAppOptions,
   142  		HandleFunc:          handlerForCSRFToken,
   143  		RequireSession:      true,
   144  		TrustRequester:      false,
   145  		RequireMfa:          false,
   146  		IsStatic:            false,
   147  	}
   148  
   149  	cookie := &http.Cookie{
   150  		Name:  model.SESSION_COOKIE_USER,
   151  		Value: th.BasicUser.Username,
   152  	}
   153  	cookie2 := &http.Cookie{
   154  		Name:  model.SESSION_COOKIE_TOKEN,
   155  		Value: session.Token,
   156  	}
   157  	cookie3 := &http.Cookie{
   158  		Name:  model.SESSION_COOKIE_CSRF,
   159  		Value: session.GetCSRF(),
   160  	}
   161  
   162  	// CSRF Token Used - Success Expected
   163  
   164  	request := httptest.NewRequest("POST", "/api/v4/test", nil)
   165  	request.AddCookie(cookie)
   166  	request.AddCookie(cookie2)
   167  	request.AddCookie(cookie3)
   168  	request.Header.Add(model.HEADER_CSRF_TOKEN, session.GetCSRF())
   169  	response := httptest.NewRecorder()
   170  	handler.ServeHTTP(response, request)
   171  
   172  	if response.Code != 200 {
   173  		t.Errorf("Expected status 200, got %d", response.Code)
   174  	}
   175  
   176  	// No CSRF Token Used - Failure Expected
   177  
   178  	request = httptest.NewRequest("POST", "/api/v4/test", nil)
   179  	request.AddCookie(cookie)
   180  	request.AddCookie(cookie2)
   181  	request.AddCookie(cookie3)
   182  	response = httptest.NewRecorder()
   183  	handler.ServeHTTP(response, request)
   184  
   185  	if response.Code != 401 {
   186  		t.Errorf("Expected status 401, got %d", response.Code)
   187  	}
   188  
   189  	// Fallback Behavior Used - Success expected
   190  	// ToDo (DSchalla) 2019/01/04: Remove once legacy CSRF Handling is removed
   191  	th.App.UpdateConfig(func(config *model.Config) {
   192  		*config.ServiceSettings.ExperimentalStrictCSRFEnforcement = false
   193  	})
   194  	request = httptest.NewRequest("POST", "/api/v4/test", nil)
   195  	request.AddCookie(cookie)
   196  	request.AddCookie(cookie2)
   197  	request.AddCookie(cookie3)
   198  	request.Header.Add(model.HEADER_REQUESTED_WITH, model.HEADER_REQUESTED_WITH_XML)
   199  	response = httptest.NewRecorder()
   200  	handler.ServeHTTP(response, request)
   201  
   202  	if response.Code != 200 {
   203  		t.Errorf("Expected status 200, got %d", response.Code)
   204  	}
   205  
   206  	// Fallback Behavior Used with Strict Enforcement - Failure Expected
   207  	// ToDo (DSchalla) 2019/01/04: Remove once legacy CSRF Handling is removed
   208  	th.App.UpdateConfig(func(config *model.Config) {
   209  		*config.ServiceSettings.ExperimentalStrictCSRFEnforcement = true
   210  	})
   211  	response = httptest.NewRecorder()
   212  	handler.ServeHTTP(response, request)
   213  
   214  	if response.Code != 401 {
   215  		t.Errorf("Expected status 200, got %d", response.Code)
   216  	}
   217  
   218  	// Handler with RequireSession set to false
   219  
   220  	handlerNoSession := Handler{
   221  		GetGlobalAppOptions: web.GetGlobalAppOptions,
   222  		HandleFunc:          handlerForCSRFToken,
   223  		RequireSession:      false,
   224  		TrustRequester:      false,
   225  		RequireMfa:          false,
   226  		IsStatic:            false,
   227  	}
   228  
   229  	// CSRF Token Used - Success Expected
   230  
   231  	request = httptest.NewRequest("POST", "/api/v4/test", nil)
   232  	request.AddCookie(cookie)
   233  	request.AddCookie(cookie2)
   234  	request.AddCookie(cookie3)
   235  	request.Header.Add(model.HEADER_CSRF_TOKEN, session.GetCSRF())
   236  	response = httptest.NewRecorder()
   237  	handlerNoSession.ServeHTTP(response, request)
   238  
   239  	if response.Code != 200 {
   240  		t.Errorf("Expected status 200, got %d", response.Code)
   241  	}
   242  
   243  	// No CSRF Token Used - Failure Expected
   244  
   245  	request = httptest.NewRequest("POST", "/api/v4/test", nil)
   246  	request.AddCookie(cookie)
   247  	request.AddCookie(cookie2)
   248  	request.AddCookie(cookie3)
   249  	response = httptest.NewRecorder()
   250  	handlerNoSession.ServeHTTP(response, request)
   251  
   252  	if response.Code != 401 {
   253  		t.Errorf("Expected status 401, got %d", response.Code)
   254  	}
   255  }
   256  
   257  func handlerForCSPHeader(c *Context, w http.ResponseWriter, r *http.Request) {
   258  }
   259  
   260  func TestHandlerServeCSPHeader(t *testing.T) {
   261  	t.Run("non-static", func(t *testing.T) {
   262  		th := SetupWithStoreMock(t)
   263  		defer th.TearDown()
   264  
   265  		web := New(th.Server, th.Server.AppOptions, th.Server.Router)
   266  
   267  		handler := Handler{
   268  			GetGlobalAppOptions: web.GetGlobalAppOptions,
   269  			HandleFunc:          handlerForCSPHeader,
   270  			RequireSession:      false,
   271  			TrustRequester:      false,
   272  			RequireMfa:          false,
   273  			IsStatic:            false,
   274  		}
   275  
   276  		request := httptest.NewRequest("POST", "/api/v4/test", nil)
   277  		response := httptest.NewRecorder()
   278  		handler.ServeHTTP(response, request)
   279  		assert.Equal(t, 200, response.Code)
   280  		assert.Empty(t, response.Header()["Content-Security-Policy"])
   281  	})
   282  
   283  	t.Run("static, without subpath", func(t *testing.T) {
   284  		th := SetupWithStoreMock(t)
   285  		defer th.TearDown()
   286  
   287  		web := New(th.Server, th.Server.AppOptions, th.Server.Router)
   288  
   289  		handler := Handler{
   290  			GetGlobalAppOptions: web.GetGlobalAppOptions,
   291  			HandleFunc:          handlerForCSPHeader,
   292  			RequireSession:      false,
   293  			TrustRequester:      false,
   294  			RequireMfa:          false,
   295  			IsStatic:            true,
   296  		}
   297  
   298  		request := httptest.NewRequest("POST", "/", nil)
   299  		response := httptest.NewRecorder()
   300  		handler.ServeHTTP(response, request)
   301  		assert.Equal(t, 200, response.Code)
   302  		assert.Equal(t, response.Header()["Content-Security-Policy"], []string{"frame-ancestors 'self'; script-src 'self' cdn.rudderlabs.com"})
   303  	})
   304  
   305  	t.Run("static, with subpath", func(t *testing.T) {
   306  		th := SetupWithStoreMock(t)
   307  		defer th.TearDown()
   308  
   309  		mockStore := th.App.Srv().Store.(*mocks.Store)
   310  		mockUserStore := mocks.UserStore{}
   311  		mockUserStore.On("Count", mock.Anything).Return(int64(10), nil)
   312  		mockPostStore := mocks.PostStore{}
   313  		mockPostStore.On("GetMaxPostSize").Return(65535, nil)
   314  		mockSystemStore := mocks.SystemStore{}
   315  		mockSystemStore.On("GetByName", "UpgradedFromTE").Return(&model.System{Name: "UpgradedFromTE", Value: "false"}, nil)
   316  		mockSystemStore.On("GetByName", "InstallationDate").Return(&model.System{Name: "InstallationDate", Value: "10"}, nil)
   317  		mockSystemStore.On("GetByName", "FirstServerRunTimestamp").Return(&model.System{Name: "FirstServerRunTimestamp", Value: "10"}, nil)
   318  
   319  		mockStore.On("User").Return(&mockUserStore)
   320  		mockStore.On("Post").Return(&mockPostStore)
   321  		mockStore.On("System").Return(&mockSystemStore)
   322  
   323  		th.App.UpdateConfig(func(cfg *model.Config) {
   324  			*cfg.ServiceSettings.SiteURL = *cfg.ServiceSettings.SiteURL + "/subpath"
   325  		})
   326  
   327  		web := New(th.Server, th.Server.AppOptions, th.Server.Router)
   328  
   329  		handler := Handler{
   330  			GetGlobalAppOptions: web.GetGlobalAppOptions,
   331  			HandleFunc:          handlerForCSPHeader,
   332  			RequireSession:      false,
   333  			TrustRequester:      false,
   334  			RequireMfa:          false,
   335  			IsStatic:            true,
   336  		}
   337  
   338  		request := httptest.NewRequest("POST", "/", nil)
   339  		response := httptest.NewRecorder()
   340  		handler.ServeHTTP(response, request)
   341  		assert.Equal(t, 200, response.Code)
   342  		assert.Equal(t, response.Header()["Content-Security-Policy"], []string{"frame-ancestors 'self'; script-src 'self' cdn.rudderlabs.com"})
   343  
   344  		// TODO: It's hard to unit test this now that the CSP directive is effectively
   345  		// decided in Setup(). Circle back to this in master once the memory store is
   346  		// merged, allowing us to mock the desired initial config to take effect in Setup().
   347  		// assert.Contains(t, response.Header()["Content-Security-Policy"], "frame-ancestors 'self'; script-src 'self' cdn.rudderlabs.com 'sha256-tPOjw+tkVs9axL78ZwGtYl975dtyPHB6LYKAO2R3gR4='")
   348  
   349  		th.App.UpdateConfig(func(cfg *model.Config) {
   350  			*cfg.ServiceSettings.SiteURL = *cfg.ServiceSettings.SiteURL + "/subpath2"
   351  		})
   352  
   353  		request = httptest.NewRequest("POST", "/", nil)
   354  		response = httptest.NewRecorder()
   355  		handler.ServeHTTP(response, request)
   356  		assert.Equal(t, 200, response.Code)
   357  		assert.Equal(t, response.Header()["Content-Security-Policy"], []string{"frame-ancestors 'self'; script-src 'self' cdn.rudderlabs.com"})
   358  		// TODO: See above.
   359  		// assert.Contains(t, response.Header()["Content-Security-Policy"], "frame-ancestors 'self'; script-src 'self' cdn.rudderlabs.com 'sha256-tPOjw+tkVs9axL78ZwGtYl975dtyPHB6LYKAO2R3gR4='", "csp header incorrectly changed after subpath changed")
   360  	})
   361  }
   362  
   363  func TestHandlerServeInvalidToken(t *testing.T) {
   364  	testCases := []struct {
   365  		Description                   string
   366  		SiteURL                       string
   367  		ExpectedSetCookieHeaderRegexp string
   368  	}{
   369  		{"no subpath", "http://localhost:8065", "^MMAUTHTOKEN=; Path=/"},
   370  		{"subpath", "http://localhost:8065/subpath", "^MMAUTHTOKEN=; Path=/subpath"},
   371  	}
   372  
   373  	for _, tc := range testCases {
   374  		t.Run(tc.Description, func(t *testing.T) {
   375  			th := Setup(t)
   376  			defer th.TearDown()
   377  
   378  			th.App.UpdateConfig(func(cfg *model.Config) {
   379  				*cfg.ServiceSettings.SiteURL = tc.SiteURL
   380  			})
   381  
   382  			web := New(th.Server, th.Server.AppOptions, th.Server.Router)
   383  
   384  			handler := Handler{
   385  				GetGlobalAppOptions: web.GetGlobalAppOptions,
   386  				HandleFunc:          handlerForCSRFToken,
   387  				RequireSession:      true,
   388  				TrustRequester:      false,
   389  				RequireMfa:          false,
   390  				IsStatic:            false,
   391  			}
   392  
   393  			cookie := &http.Cookie{
   394  				Name:  model.SESSION_COOKIE_TOKEN,
   395  				Value: "invalid",
   396  			}
   397  
   398  			request := httptest.NewRequest("POST", "/api/v4/test", nil)
   399  			request.AddCookie(cookie)
   400  			response := httptest.NewRecorder()
   401  			handler.ServeHTTP(response, request)
   402  			require.Equal(t, http.StatusUnauthorized, response.Code)
   403  
   404  			cookies := response.Header().Get("Set-Cookie")
   405  			assert.Regexp(t, tc.ExpectedSetCookieHeaderRegexp, cookies)
   406  		})
   407  	}
   408  }
   409  
   410  func TestCheckCSRFToken(t *testing.T) {
   411  	t.Run("should allow a POST request with a valid CSRF token header", func(t *testing.T) {
   412  		th := SetupWithStoreMock(t)
   413  		defer th.TearDown()
   414  
   415  		h := &Handler{
   416  			RequireSession: true,
   417  			TrustRequester: false,
   418  		}
   419  
   420  		token := "token"
   421  		tokenLocation := app.TokenLocationCookie
   422  
   423  		c := &Context{
   424  			App: th.App,
   425  		}
   426  		r, _ := http.NewRequest(http.MethodPost, "", nil)
   427  		r.Header.Set(model.HEADER_CSRF_TOKEN, token)
   428  		session := &model.Session{
   429  			Props: map[string]string{
   430  				"csrf": token,
   431  			},
   432  		}
   433  
   434  		checked, passed := h.checkCSRFToken(c, r, token, tokenLocation, session)
   435  
   436  		assert.True(t, checked)
   437  		assert.True(t, passed)
   438  		assert.Nil(t, c.Err)
   439  	})
   440  
   441  	t.Run("should allow a POST request with an X-Requested-With header", func(t *testing.T) {
   442  		th := SetupWithStoreMock(t)
   443  		defer th.TearDown()
   444  
   445  		h := &Handler{
   446  			RequireSession: true,
   447  			TrustRequester: false,
   448  		}
   449  
   450  		token := "token"
   451  		tokenLocation := app.TokenLocationCookie
   452  
   453  		c := &Context{
   454  			App: th.App,
   455  			Log: th.App.Log(),
   456  		}
   457  		r, _ := http.NewRequest(http.MethodPost, "", nil)
   458  		r.Header.Set(model.HEADER_REQUESTED_WITH, model.HEADER_REQUESTED_WITH_XML)
   459  		session := &model.Session{
   460  			Props: map[string]string{
   461  				"csrf": token,
   462  			},
   463  		}
   464  
   465  		checked, passed := h.checkCSRFToken(c, r, token, tokenLocation, session)
   466  
   467  		assert.True(t, checked)
   468  		assert.True(t, passed)
   469  		assert.Nil(t, c.Err)
   470  	})
   471  
   472  	t.Run("should not allow a POST request with an X-Requested-With header with strict CSRF enforcement enabled", func(t *testing.T) {
   473  		th := SetupWithStoreMock(t)
   474  		defer th.TearDown()
   475  
   476  		mockStore := th.App.Srv().Store.(*mocks.Store)
   477  		mockUserStore := mocks.UserStore{}
   478  		mockUserStore.On("Count", mock.Anything).Return(int64(10), nil)
   479  		mockPostStore := mocks.PostStore{}
   480  		mockPostStore.On("GetMaxPostSize").Return(65535, nil)
   481  		mockSystemStore := mocks.SystemStore{}
   482  		mockSystemStore.On("GetByName", "UpgradedFromTE").Return(&model.System{Name: "UpgradedFromTE", Value: "false"}, nil)
   483  		mockSystemStore.On("GetByName", "InstallationDate").Return(&model.System{Name: "InstallationDate", Value: "10"}, nil)
   484  		mockSystemStore.On("GetByName", "FirstServerRunTimestamp").Return(&model.System{Name: "FirstServerRunTimestamp", Value: "10"}, nil)
   485  
   486  		mockStore.On("User").Return(&mockUserStore)
   487  		mockStore.On("Post").Return(&mockPostStore)
   488  		mockStore.On("System").Return(&mockSystemStore)
   489  
   490  		th.App.UpdateConfig(func(cfg *model.Config) {
   491  			*cfg.ServiceSettings.ExperimentalStrictCSRFEnforcement = true
   492  		})
   493  
   494  		h := &Handler{
   495  			RequireSession: true,
   496  			TrustRequester: false,
   497  		}
   498  
   499  		token := "token"
   500  		tokenLocation := app.TokenLocationCookie
   501  
   502  		c := &Context{
   503  			App: th.App,
   504  			Log: th.App.Log(),
   505  		}
   506  		r, _ := http.NewRequest(http.MethodPost, "", nil)
   507  		r.Header.Set(model.HEADER_REQUESTED_WITH, model.HEADER_REQUESTED_WITH_XML)
   508  		session := &model.Session{
   509  			Props: map[string]string{
   510  				"csrf": token,
   511  			},
   512  		}
   513  
   514  		checked, passed := h.checkCSRFToken(c, r, token, tokenLocation, session)
   515  
   516  		assert.True(t, checked)
   517  		assert.False(t, passed)
   518  		assert.NotNil(t, c.Err)
   519  	})
   520  
   521  	t.Run("should not allow a POST request without either header", func(t *testing.T) {
   522  		th := SetupWithStoreMock(t)
   523  		defer th.TearDown()
   524  
   525  		h := &Handler{
   526  			RequireSession: true,
   527  			TrustRequester: false,
   528  		}
   529  
   530  		token := "token"
   531  		tokenLocation := app.TokenLocationCookie
   532  
   533  		c := &Context{
   534  			App: th.App,
   535  		}
   536  		r, _ := http.NewRequest(http.MethodPost, "", nil)
   537  		session := &model.Session{
   538  			Props: map[string]string{
   539  				"csrf": token,
   540  			},
   541  		}
   542  
   543  		checked, passed := h.checkCSRFToken(c, r, token, tokenLocation, session)
   544  
   545  		assert.True(t, checked)
   546  		assert.False(t, passed)
   547  		assert.NotNil(t, c.Err)
   548  	})
   549  
   550  	t.Run("should not check GET requests", func(t *testing.T) {
   551  		th := SetupWithStoreMock(t)
   552  		defer th.TearDown()
   553  
   554  		h := &Handler{
   555  			RequireSession: true,
   556  			TrustRequester: false,
   557  		}
   558  
   559  		token := "token"
   560  		tokenLocation := app.TokenLocationCookie
   561  
   562  		c := &Context{
   563  			App: th.App,
   564  		}
   565  		r, _ := http.NewRequest(http.MethodGet, "", nil)
   566  		session := &model.Session{
   567  			Props: map[string]string{
   568  				"csrf": token,
   569  			},
   570  		}
   571  
   572  		checked, passed := h.checkCSRFToken(c, r, token, tokenLocation, session)
   573  
   574  		assert.False(t, checked)
   575  		assert.False(t, passed)
   576  		assert.Nil(t, c.Err)
   577  	})
   578  
   579  	t.Run("should not check a request passing the auth token in a header", func(t *testing.T) {
   580  		th := SetupWithStoreMock(t)
   581  		defer th.TearDown()
   582  
   583  		h := &Handler{
   584  			RequireSession: true,
   585  			TrustRequester: false,
   586  		}
   587  
   588  		token := "token"
   589  		tokenLocation := app.TokenLocationHeader
   590  
   591  		c := &Context{
   592  			App: th.App,
   593  		}
   594  		r, _ := http.NewRequest(http.MethodPost, "", nil)
   595  		session := &model.Session{
   596  			Props: map[string]string{
   597  				"csrf": token,
   598  			},
   599  		}
   600  
   601  		checked, passed := h.checkCSRFToken(c, r, token, tokenLocation, session)
   602  
   603  		assert.False(t, checked)
   604  		assert.False(t, passed)
   605  		assert.Nil(t, c.Err)
   606  	})
   607  
   608  	t.Run("should not check a request passing a nil session", func(t *testing.T) {
   609  		th := SetupWithStoreMock(t)
   610  		defer th.TearDown()
   611  
   612  		h := &Handler{
   613  			RequireSession: false,
   614  			TrustRequester: false,
   615  		}
   616  
   617  		token := "token"
   618  		tokenLocation := app.TokenLocationCookie
   619  
   620  		c := &Context{
   621  			App: th.App,
   622  		}
   623  		r, _ := http.NewRequest(http.MethodPost, "", nil)
   624  		r.Header.Set(model.HEADER_CSRF_TOKEN, token)
   625  
   626  		checked, passed := h.checkCSRFToken(c, r, token, tokenLocation, nil)
   627  
   628  		assert.False(t, checked)
   629  		assert.False(t, passed)
   630  		assert.Nil(t, c.Err)
   631  	})
   632  
   633  	t.Run("should check requests for handlers that don't require a session but have one", func(t *testing.T) {
   634  		th := SetupWithStoreMock(t)
   635  		defer th.TearDown()
   636  
   637  		h := &Handler{
   638  			RequireSession: false,
   639  			TrustRequester: false,
   640  		}
   641  
   642  		token := "token"
   643  		tokenLocation := app.TokenLocationCookie
   644  
   645  		c := &Context{
   646  			App: th.App,
   647  		}
   648  		r, _ := http.NewRequest(http.MethodPost, "", nil)
   649  		r.Header.Set(model.HEADER_CSRF_TOKEN, token)
   650  		session := &model.Session{
   651  			Props: map[string]string{
   652  				"csrf": token,
   653  			},
   654  		}
   655  
   656  		checked, passed := h.checkCSRFToken(c, r, token, tokenLocation, session)
   657  
   658  		assert.True(t, checked)
   659  		assert.True(t, passed)
   660  		assert.Nil(t, c.Err)
   661  	})
   662  }