Exemple #1
1
// AccountMatchesParam returns an AuthCheck that grants access if paramName is the same
// as the account's ID; so, for instance, on a route to /accounts/:accountId, with
// a request to /accounts/asdf, the AuthCheck will return true if the account's ID is asdf.
// As a special case, account.Nobody and account.Super will never match in this method.
func AccountMatchesParam(paramName string) AuthCheck {

	return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {

		var acct account.Account
		if err := GetAccount(ctx, &acct); err != nil {
			return err
		} else if acct.Super() || acct.Nobody() {
			return ErrAccountIDDoesNotMatch
		} else if acct.Key(ctx).Encode() != kami.Param(ctx, paramName) {
			return ErrAccountIDDoesNotMatch
		} else {
			return nil
		}

	}

}
func TestMiddleware(t *testing.T) {

	var acct account.Account
	ctx := test.WithConfig(context.Background(), map[string]interface{}{"AuthSecret": "foo"})

	// a user is no one (i.e., no Authorization header)
	w := httptest.NewRecorder()
	r, _ := http.NewRequest("GET", "/", nil)

	resultCtx := Middleware(ctx, w, r)

	err := GetAccount(resultCtx, &acct)
	if err != nil {
		t.Errorf("Unexpected error %s", err)
	}
	if !acct.Nobody() {
		t.Errorf("acct should have been the zero value, but got %+v", acct)
	}

	// bad jwt
	w = httptest.NewRecorder()
	r, _ = http.NewRequest("GET", "/", nil)
	r.Header.Set("Authorization", "wrong")

	resultCtx = Middleware(ctx, w, r)

	err = GetAccount(resultCtx, &acct)
	if err != InvalidJWTError {
		t.Errorf("Unexpected error %s", err)
	}

	// super (i.e., they passed in the secret itself)
	w = httptest.NewRecorder()
	r, _ = http.NewRequest("GET", "/", nil)
	r.Header.Set("Authorization", "foo")

	resultCtx = Middleware(ctx, w, r)

	err = GetAccount(resultCtx, &acct)
	if err != nil {
		t.Errorf("Unexpected error %s", err)
	}
	if !acct.Super() {
		t.Errorf("Expected the super account, but got %+v", acct)
	}

	// super (i.e., they passed in the secret itself)
	w = httptest.NewRecorder()
	r, _ = http.NewRequest("GET", "/", nil)
	r.Header.Set("Authorization", "foo")

	resultCtx = Middleware(ctx, w, r)

	err = GetAccount(resultCtx, &acct)
	if err != nil {
		t.Errorf("Unexpected error %s", err)
	}
	if !acct.Super() {
		t.Errorf("Expected the super account, but got %+v", acct)
	}

	// test against App Engine dev environment from this point forward
	realCtx, done, _ := aetest.NewContext()
	defer done()

	account.New(realCtx, "*****@*****.**", "foobar")

	realCtx = test.WithConfig(realCtx, map[string]interface{}{"AuthSecret": "foo"})

	// nonexistent account
	w = httptest.NewRecorder()
	r, _ = http.NewRequest("GET", "/", nil)
	r.Header.Set("Authorization", test.JWT(&jws.ClaimSet{Sub: "*****@*****.**"}, "foo"))

	resultCtx = Middleware(realCtx, w, r)
	if resultCtx != nil {
		t.Errorf("Expected Middleware to terminate (i.e. to return nil), but it didn't", err)
	}

	// existent account (i.e., the happy path)
	w = httptest.NewRecorder()
	r, _ = http.NewRequest("GET", "/", nil)
	r.Header.Set("Authorization", test.JWT(&jws.ClaimSet{Sub: "*****@*****.**"}, "foo"))

	resultCtx = Middleware(realCtx, w, r)
	if resultCtx == nil {
		t.Errorf("Expected Middleware not to terminate (i.e. to return another context), but it terminated")
	} else if err = GetAccount(resultCtx, &acct); err != nil {
		t.Errorf("Expected no error when getting a properly authenticated account, but got %s", err)
	} else if acct.Email != "*****@*****.**" {
		t.Errorf("Unexpected account on retrieval: %+v", acct)
	}

}