github.com/volatiletech/authboss@v2.4.1+incompatible/authboss_test.go (about)

     1  package authboss
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"testing"
     8  )
     9  
    10  func TestAuthBossInit(t *testing.T) {
    11  	t.Parallel()
    12  
    13  	ab := New()
    14  	err := ab.Init()
    15  	if err != nil {
    16  		t.Error("Unexpected error:", err)
    17  	}
    18  }
    19  
    20  func TestAuthbossUpdatePassword(t *testing.T) {
    21  	t.Parallel()
    22  
    23  	user := &mockUser{}
    24  	storer := newMockServerStorer()
    25  
    26  	ab := New()
    27  	ab.Config.Storage.Server = storer
    28  
    29  	if err := ab.UpdatePassword(context.Background(), user, "hello world"); err != nil {
    30  		t.Error(err)
    31  	}
    32  
    33  	if len(user.Password) == 0 {
    34  		t.Error("password was not updated")
    35  	}
    36  }
    37  
    38  type testRedirector struct {
    39  	Opts RedirectOptions
    40  }
    41  
    42  func (r *testRedirector) Redirect(w http.ResponseWriter, req *http.Request, ro RedirectOptions) error {
    43  	r.Opts = ro
    44  	if len(ro.RedirectPath) == 0 {
    45  		panic("no redirect path on redirect call")
    46  	}
    47  	http.Redirect(w, req, ro.RedirectPath, ro.Code)
    48  	return nil
    49  }
    50  
    51  func TestAuthbossMiddleware(t *testing.T) {
    52  	t.Parallel()
    53  
    54  	ab := New()
    55  	ab.Core.Logger = mockLogger{}
    56  	ab.Storage.Server = &mockServerStorer{
    57  		Users: map[string]*mockUser{
    58  			"test@test.com": {},
    59  		},
    60  	}
    61  
    62  	setupMore := func(mountPathed, redirect, allowHalfAuth, force2fa bool) (*httptest.ResponseRecorder, bool, bool) {
    63  		r := httptest.NewRequest("GET", "/super/secret", nil)
    64  		rec := httptest.NewRecorder()
    65  		w := ab.NewResponse(rec)
    66  
    67  		var err error
    68  		r, err = ab.LoadClientState(w, r)
    69  		if err != nil {
    70  			t.Fatal(err)
    71  		}
    72  
    73  		var mid func(http.Handler) http.Handler
    74  		if !mountPathed {
    75  			mid = Middleware(ab, redirect, allowHalfAuth, force2fa)
    76  		} else {
    77  			mid = MountedMiddleware(ab, true, redirect, allowHalfAuth, force2fa)
    78  		}
    79  		var called, hadUser bool
    80  		server := mid(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    81  			called = true
    82  			hadUser = r.Context().Value(CTXKeyUser) != nil
    83  			w.WriteHeader(http.StatusOK)
    84  		}))
    85  
    86  		server.ServeHTTP(w, r)
    87  
    88  		return rec, called, hadUser
    89  	}
    90  
    91  	t.Run("Accept", func(t *testing.T) {
    92  		ab.Storage.SessionState = mockClientStateReadWriter{
    93  			state: mockClientState{SessionKey: "test@test.com"},
    94  		}
    95  
    96  		_, called, hadUser := setupMore(false, false, false, false)
    97  
    98  		if !called {
    99  			t.Error("should have been called")
   100  		}
   101  		if !hadUser {
   102  			t.Error("should have had user")
   103  		}
   104  	})
   105  	t.Run("AcceptHalfAuth", func(t *testing.T) {
   106  		ab.Storage.SessionState = mockClientStateReadWriter{
   107  			state: mockClientState{SessionKey: "test@test.com", SessionHalfAuthKey: "true"},
   108  		}
   109  
   110  		_, called, hadUser := setupMore(false, false, false, false)
   111  
   112  		if !called {
   113  			t.Error("should have been called")
   114  		}
   115  		if !hadUser {
   116  			t.Error("should have had user")
   117  		}
   118  	})
   119  	t.Run("Accept2FA", func(t *testing.T) {
   120  		ab.Storage.SessionState = mockClientStateReadWriter{
   121  			state: mockClientState{SessionKey: "test@test.com", Session2FA: "sms"},
   122  		}
   123  
   124  		_, called, hadUser := setupMore(false, false, false, true)
   125  
   126  		if !called {
   127  			t.Error("should have been called")
   128  		}
   129  		if !hadUser {
   130  			t.Error("should have had user")
   131  		}
   132  	})
   133  	t.Run("Reject404", func(t *testing.T) {
   134  		ab.Storage.SessionState = mockClientStateReadWriter{}
   135  
   136  		rec, called, hadUser := setupMore(false, false, false, false)
   137  
   138  		if rec.Code != http.StatusNotFound {
   139  			t.Error("wrong code:", rec.Code)
   140  		}
   141  		if called {
   142  			t.Error("should not have been called")
   143  		}
   144  		if hadUser {
   145  			t.Error("should not have had user")
   146  		}
   147  	})
   148  	t.Run("Reject401", func(t *testing.T) {
   149  		ab.Storage.SessionState = mockClientStateReadWriter{}
   150  
   151  		r := httptest.NewRequest("GET", "/super/secret", nil)
   152  		rec := httptest.NewRecorder()
   153  		w := ab.NewResponse(rec)
   154  
   155  		var err error
   156  		r, err = ab.LoadClientState(w, r)
   157  		if err != nil {
   158  			t.Fatal(err)
   159  		}
   160  
   161  		var mid func(http.Handler) http.Handler
   162  		mid = Middleware2(ab, RequireNone, RespondUnauthorized)
   163  		var called, hadUser bool
   164  		server := mid(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   165  			called = true
   166  			hadUser = r.Context().Value(CTXKeyUser) != nil
   167  			w.WriteHeader(http.StatusOK)
   168  		}))
   169  
   170  		server.ServeHTTP(w, r)
   171  
   172  		if rec.Code != http.StatusUnauthorized {
   173  			t.Error("wrong code:", rec.Code)
   174  		}
   175  		if called {
   176  			t.Error("should not have been called")
   177  		}
   178  		if hadUser {
   179  			t.Error("should not have had user")
   180  		}
   181  	})
   182  	t.Run("RejectRedirect", func(t *testing.T) {
   183  		redir := &testRedirector{}
   184  		ab.Config.Core.Redirector = redir
   185  
   186  		ab.Storage.SessionState = mockClientStateReadWriter{}
   187  
   188  		_, called, hadUser := setupMore(false, true, false, false)
   189  
   190  		if redir.Opts.Code != http.StatusTemporaryRedirect {
   191  			t.Error("code was wrong:", redir.Opts.Code)
   192  		}
   193  		if redir.Opts.RedirectPath != "/auth/login?redir=%2Fsuper%2Fsecret" {
   194  			t.Error("redirect path was wrong:", redir.Opts.RedirectPath)
   195  		}
   196  		if called {
   197  			t.Error("should not have been called")
   198  		}
   199  		if hadUser {
   200  			t.Error("should not have had user")
   201  		}
   202  	})
   203  	t.Run("RejectMountpathedRedirect", func(t *testing.T) {
   204  		redir := &testRedirector{}
   205  		ab.Config.Core.Redirector = redir
   206  
   207  		ab.Storage.SessionState = mockClientStateReadWriter{}
   208  
   209  		_, called, hadUser := setupMore(true, true, false, false)
   210  
   211  		if redir.Opts.Code != http.StatusTemporaryRedirect {
   212  			t.Error("code was wrong:", redir.Opts.Code)
   213  		}
   214  		if redir.Opts.RedirectPath != "/auth/login?redir=%2Fauth%2Fsuper%2Fsecret" {
   215  			t.Error("redirect path was wrong:", redir.Opts.RedirectPath)
   216  		}
   217  		if called {
   218  			t.Error("should not have been called")
   219  		}
   220  		if hadUser {
   221  			t.Error("should not have had user")
   222  		}
   223  	})
   224  	t.Run("RejectHalfAuth", func(t *testing.T) {
   225  		ab.Storage.SessionState = mockClientStateReadWriter{
   226  			state: mockClientState{SessionKey: "test@test.com", SessionHalfAuthKey: "true"},
   227  		}
   228  
   229  		rec, called, hadUser := setupMore(false, false, true, false)
   230  
   231  		if rec.Code != http.StatusNotFound {
   232  			t.Error("wrong code:", rec.Code)
   233  		}
   234  		if called {
   235  			t.Error("should not have been called")
   236  		}
   237  		if hadUser {
   238  			t.Error("should not have had user")
   239  		}
   240  	})
   241  	t.Run("RejectNo2FA", func(t *testing.T) {
   242  		ab.Storage.SessionState = mockClientStateReadWriter{
   243  			state: mockClientState{SessionKey: "test@test.com"},
   244  		}
   245  
   246  		rec, called, hadUser := setupMore(false, false, true, true)
   247  
   248  		if rec.Code != http.StatusNotFound {
   249  			t.Error("wrong code:", rec.Code)
   250  		}
   251  		if called {
   252  			t.Error("should not have been called")
   253  		}
   254  		if hadUser {
   255  			t.Error("should not have had user")
   256  		}
   257  	})
   258  }