github.com/safing/portbase@v0.19.5/api/authentication_test.go (about) 1 package api 2 3 import ( 4 "errors" 5 "fmt" 6 "net/http" 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 ) 11 12 var testToken = new(AuthToken) 13 14 func testAuthenticator(r *http.Request, s *http.Server) (*AuthToken, error) { 15 switch { 16 case testToken.Read == -127 || testToken.Write == -127: 17 return nil, errors.New("test error") 18 case testToken.Read == -128 || testToken.Write == -128: 19 return nil, fmt.Errorf("%wdenied", ErrAPIAccessDeniedMessage) 20 default: 21 return testToken, nil 22 } 23 } 24 25 type testAuthHandler struct { 26 Read Permission 27 Write Permission 28 } 29 30 func (ah *testAuthHandler) ReadPermission(r *http.Request) Permission { 31 return ah.Read 32 } 33 34 func (ah *testAuthHandler) WritePermission(r *http.Request) Permission { 35 return ah.Write 36 } 37 38 func (ah *testAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 39 // Check if request is as expected. 40 ar := GetAPIRequest(r) 41 switch { 42 case ar == nil: 43 http.Error(w, "ar == nil", http.StatusInternalServerError) 44 case ar.AuthToken == nil: 45 http.Error(w, "ar.AuthToken == nil", http.StatusInternalServerError) 46 default: 47 http.Error(w, "auth success", http.StatusOK) 48 } 49 } 50 51 func makeAuthTestPath(reading bool, p Permission) string { 52 if reading { 53 return fmt.Sprintf("/test/auth/read/%s", p) 54 } 55 return fmt.Sprintf("/test/auth/write/%s", p) 56 } 57 58 func init() { 59 // Set test authenticator. 60 err := SetAuthenticator(testAuthenticator) 61 if err != nil { 62 panic(err) 63 } 64 } 65 66 func TestPermissions(t *testing.T) { 67 t.Parallel() 68 69 testHandler := &mainHandler{ 70 mux: mainMux, 71 } 72 73 // Define permissions that need testing. 74 permissionsToTest := []Permission{ 75 NotSupported, 76 PermitAnyone, 77 PermitUser, 78 PermitAdmin, 79 PermitSelf, 80 Dynamic, 81 NotFound, 82 100, // Test a too high value. 83 -100, // Test a too low value. 84 -127, // Simulate authenticator failure. 85 -128, // Simulate authentication denied message. 86 } 87 88 // Register test handlers. 89 for _, p := range permissionsToTest { 90 RegisterHandler(makeAuthTestPath(true, p), &testAuthHandler{Read: p}) 91 RegisterHandler(makeAuthTestPath(false, p), &testAuthHandler{Write: p}) 92 } 93 94 // Test all the combinations. 95 for _, requestPerm := range permissionsToTest { 96 for _, handlerPerm := range permissionsToTest { 97 for _, method := range []string{ 98 http.MethodGet, 99 http.MethodHead, 100 http.MethodPost, 101 http.MethodPut, 102 http.MethodDelete, 103 } { 104 105 // Set request permission for test requests. 106 _, reading, _ := getEffectiveMethod(&http.Request{Method: method}) 107 if reading { 108 testToken.Read = requestPerm 109 testToken.Write = NotSupported 110 } else { 111 testToken.Read = NotSupported 112 testToken.Write = requestPerm 113 } 114 115 // Evaluate expected result. 116 var expectSuccess bool 117 switch { 118 case handlerPerm == PermitAnyone: 119 // This is fast-tracked. There are not additional checks. 120 expectSuccess = true 121 case handlerPerm == Dynamic: 122 // This is turned into PermitAnyone in the authenticator. 123 // But authentication is still processed and the result still gets 124 // sanity checked! 125 if requestPerm >= PermitAnyone && 126 requestPerm <= PermitSelf { 127 expectSuccess = true 128 } 129 // Another special case is when the handler requires permission to be 130 // processed but the authenticator fails to authenticate the request. 131 // In this case, a fallback token with PermitAnyone is used. 132 if requestPerm == -128 { 133 // -128 is used to simulate a permission denied message. 134 expectSuccess = true 135 } 136 case handlerPerm <= NotSupported: 137 // Invalid handler permission. 138 case handlerPerm > PermitSelf: 139 // Invalid handler permission. 140 case requestPerm <= NotSupported: 141 // Invalid request permission. 142 case requestPerm > PermitSelf: 143 // Invalid request permission. 144 case requestPerm < handlerPerm: 145 // Valid, but insufficient request permission. 146 default: 147 expectSuccess = true 148 } 149 150 if expectSuccess { 151 // Test for success. 152 if !assert.HTTPBodyContains( 153 t, 154 testHandler.ServeHTTP, 155 method, 156 makeAuthTestPath(reading, handlerPerm), 157 nil, 158 "auth success", 159 ) { 160 t.Errorf( 161 "%s with %s (%d) to handler %s (%d)", 162 method, 163 requestPerm, requestPerm, 164 handlerPerm, handlerPerm, 165 ) 166 } 167 } else { 168 // Test for error. 169 if !assert.HTTPError(t, 170 testHandler.ServeHTTP, 171 method, 172 makeAuthTestPath(reading, handlerPerm), 173 nil, 174 ) { 175 t.Errorf( 176 "%s with %s (%d) to handler %s (%d)", 177 method, 178 requestPerm, requestPerm, 179 handlerPerm, handlerPerm, 180 ) 181 } 182 } 183 } 184 } 185 } 186 } 187 188 func TestPermissionDefinitions(t *testing.T) { 189 t.Parallel() 190 191 if NotSupported != 0 { 192 t.Fatalf("NotSupported must be zero, was %v", NotSupported) 193 } 194 }