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  }