-
Notifications
You must be signed in to change notification settings - Fork 227
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add middleware for jwt auth * fill in jwt auth functions * refactor and add tests * use viper to get jwt auth key env * remove iron token * remove unused import * Add auth tests for invalid tokens * refactor auth tests to own file * add tags to full stack tests * initial integration test * complete test tags * make make file accept tags * refactor fn to make easier testing * update integration tests * add make target for testing individual tags * update integration tests * add integration tests to circle ci * fix integration tests * add auth integration tests * set default values at env so that they are always initialized * add tests for create / delete route * add jwt route test and route call test * run server tests during test phase * add checks to confirm route being created and deleted * update documentation * cleanup test files after test
- Loading branch information
Showing
19 changed files
with
530 additions
and
174 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
// +build server | ||
|
||
package server | ||
|
||
import ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// +build integration | ||
|
||
package server | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
"testing" | ||
"time" | ||
|
||
"github.com/iron-io/functions/api/models" | ||
"github.com/iron-io/functions/fn/app" | ||
"github.com/spf13/viper" | ||
"github.com/urfave/cli" | ||
) | ||
|
||
var DB_FILE string | ||
var MQ_FILE string | ||
var API_URL string | ||
var PORT int | ||
var funcServer *Server | ||
var Cancel context.CancelFunc | ||
var Ctx context.Context | ||
var fn *cli.App | ||
|
||
func setupServer() { | ||
viper.Set(EnvDBURL, fmt.Sprintf("bolt://%s?bucket=funcs", DB_FILE)) | ||
viper.Set(EnvMQURL, fmt.Sprintf("bolt://%s", MQ_FILE)) | ||
viper.Set(EnvPort, PORT) | ||
Ctx, Cancel = context.WithCancel(context.Background()) | ||
funcServer = NewFromEnv(Ctx) | ||
go funcServer.Start(Ctx) | ||
time.Sleep(2 * time.Second) | ||
} | ||
|
||
func setupCli() { | ||
viper.Set("API_URL", API_URL) | ||
fn = app.NewFn() | ||
} | ||
|
||
func teardown() { | ||
os.Remove(DB_FILE) | ||
os.Remove(MQ_FILE) | ||
Cancel() | ||
time.Sleep(2 * time.Second) | ||
} | ||
|
||
func TestIntegration(t *testing.T) { | ||
DB_FILE = "/tmp/bolt.db" | ||
MQ_FILE = "/tmp/bolt_mq.db" | ||
PORT = 8080 | ||
API_URL = "http://localhost:8080" | ||
setupServer() | ||
setupCli() | ||
testIntegration(t) | ||
teardown() | ||
} | ||
|
||
func TestIntegrationWithAuth(t *testing.T) { | ||
viper.Set("jwt_auth_key", "test") | ||
DB_FILE = "/tmp/bolt_auth.db" | ||
MQ_FILE = "/tmp/bolt_auth_mq.db" | ||
PORT = 8081 | ||
API_URL = "http://localhost:8081" | ||
setupServer() | ||
setupCli() | ||
testIntegration(t) | ||
teardown() | ||
} | ||
|
||
func testIntegration(t *testing.T) { | ||
// Test list | ||
|
||
err := fn.Run([]string{"fn", "apps", "l"}) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
// Test create app | ||
|
||
err = fn.Run([]string{"fn", "apps", "c", "test"}) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
filter := &models.AppFilter{} | ||
apps, err := funcServer.Datastore.GetApps(Ctx, filter) | ||
|
||
if len(apps) != 1 { | ||
t.Error("fn apps create failed.") | ||
} | ||
|
||
if apps[0].Name != "test" { | ||
t.Error("fn apps create failed. - name doesnt match") | ||
} | ||
|
||
// Test create route | ||
|
||
err = fn.Run([]string{"fn", "routes", "c", "test", "/new-route", "--jwt-key", "route_key"}) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
routeFilter := &models.RouteFilter{} | ||
routes, err := funcServer.Datastore.GetRoutes(Ctx, routeFilter) | ||
|
||
if len(routes) != 1 { | ||
t.Error("fn routes create failed.") | ||
} | ||
|
||
if routes[0].Path != "/new-route" { | ||
t.Error("fn routes create failed. - path doesnt match") | ||
} | ||
|
||
// Test call route | ||
|
||
err = fn.Run([]string{"fn", "routes", "call", "test", "/new-route"}) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
// Test delete route | ||
|
||
err = fn.Run([]string{"fn", "routes", "delete", "test", "/new-route"}) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
routes, err = funcServer.Datastore.GetRoutes(Ctx, routeFilter) | ||
|
||
if len(routes) != 0 { | ||
t.Error("fn routes delete failed.") | ||
} | ||
|
||
// Test delete app | ||
|
||
err = fn.Run([]string{"fn", "apps", "delete", "test"}) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
apps, err = funcServer.Datastore.GetApps(Ctx, filter) | ||
|
||
if len(apps) != 0 { | ||
t.Error("fn apps delete failed.") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package server | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/iron-io/functions/api/models" | ||
"github.com/iron-io/functions/common" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
func SetupJwtAuth(funcServer *Server) { | ||
// Add default JWT AUTH if env variable set | ||
if jwtAuthKey := viper.GetString("jwt_auth_key"); jwtAuthKey != "" { | ||
funcServer.AddMiddlewareFunc(func(ctx MiddlewareContext, w http.ResponseWriter, r *http.Request, app *models.App) error { | ||
start := time.Now() | ||
fmt.Println("JwtAuthMiddlewareFunc called at:", start) | ||
ctx.Next() | ||
fmt.Println("Duration:", (time.Now().Sub(start))) | ||
return nil | ||
}) | ||
funcServer.AddMiddleware(&JwtAuthMiddleware{}) | ||
} | ||
} | ||
|
||
type JwtAuthMiddleware struct { | ||
} | ||
|
||
func (h *JwtAuthMiddleware) Serve(ctx MiddlewareContext, w http.ResponseWriter, r *http.Request, app *models.App) error { | ||
fmt.Println("JwtAuthMiddleware called") | ||
jwtAuthKey := viper.GetString("jwt_auth_key") | ||
|
||
if err := common.AuthJwt(jwtAuthKey, r); err != nil { | ||
w.WriteHeader(http.StatusUnauthorized) | ||
m := map[string]string{"error": "Invalid API Authorization token."} | ||
json.NewEncoder(w).Encode(m) | ||
return errors.New("Invalid API authorization token.") | ||
} | ||
|
||
fmt.Println("auth succeeded!") | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
// +build server | ||
|
||
package server | ||
|
||
import ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
// +build server | ||
|
||
package server | ||
|
||
import ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
// +build server | ||
|
||
package server | ||
|
||
import ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// +build server | ||
|
||
package server | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/gin-gonic/gin" | ||
"github.com/iron-io/functions/common" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
var UnAuthtestSuite = []struct { | ||
name string | ||
method string | ||
path string | ||
body string | ||
expectedCode int | ||
expectedCacheSize int | ||
}{ | ||
{"create my app", "POST", "/v1/apps", `{ "app": { "name": "myapp" } }`, http.StatusUnauthorized, 0}, | ||
{"list apps", "GET", "/v1/apps", ``, http.StatusUnauthorized, 0}, | ||
{"get app", "GET", "/v1/apps/myapp", ``, http.StatusUnauthorized, 0}, | ||
{"add myroute", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute", "path": "/myroute", "image": "iron/hello" } }`, http.StatusUnauthorized, 0}, | ||
{"add myroute2", "POST", "/v1/apps/myapp/routes", `{ "route": { "name": "myroute2", "path": "/myroute2", "image": "iron/error" } }`, http.StatusUnauthorized, 0}, | ||
{"get myroute", "GET", "/v1/apps/myapp/routes/myroute", ``, http.StatusUnauthorized, 0}, | ||
{"get myroute2", "GET", "/v1/apps/myapp/routes/myroute2", ``, http.StatusUnauthorized, 0}, | ||
{"get all routes", "GET", "/v1/apps/myapp/routes", ``, http.StatusUnauthorized, 0}, | ||
// These two are currently returning 404 because they dont get created : temporarily using StatusNotFound | ||
// {"execute myroute", "POST", "/r/myapp/myroute", `{ "name": "Teste" }`, http.StatusUnauthorized, 0}, | ||
// {"execute myroute2", "POST", "/r/myapp/myroute2", `{ "name": "Teste" }`, http.StatusUnauthorized, 0}, | ||
{"execute myroute", "POST", "/r/myapp/myroute", `{ "name": "Teste" }`, http.StatusNotFound, 0}, | ||
{"execute myroute2", "POST", "/r/myapp/myroute2", `{ "name": "Teste" }`, http.StatusNotFound, 0}, | ||
{"delete myroute", "DELETE", "/v1/apps/myapp/routes/myroute", ``, http.StatusUnauthorized, 0}, | ||
{"delete app (fail)", "DELETE", "/v1/apps/myapp", ``, http.StatusUnauthorized, 0}, | ||
{"delete myroute2", "DELETE", "/v1/apps/myapp/routes/myroute2", ``, http.StatusUnauthorized, 0}, | ||
{"delete app (success)", "DELETE", "/v1/apps/myapp", ``, http.StatusUnauthorized, 0}, | ||
{"get deleted app", "GET", "/v1/apps/myapp", ``, http.StatusUnauthorized, 0}, | ||
{"get deleteds route on deleted app", "GET", "/v1/apps/myapp/routes/myroute", ``, http.StatusUnauthorized, 0}, | ||
} | ||
|
||
func routerRequestWithAuth(t *testing.T, router *gin.Engine, method, path string, body io.Reader, setAuth func(*http.Request)) (*http.Request, *httptest.ResponseRecorder) { | ||
req, err := http.NewRequest(method, "http://127.0.0.1:8080"+path, body) | ||
setAuth(req) | ||
if err != nil { | ||
t.Fatalf("Test: Could not create %s request to %s: %v", method, path, err) | ||
} | ||
|
||
rec := httptest.NewRecorder() | ||
router.ServeHTTP(rec, req) | ||
|
||
return req, rec | ||
} | ||
|
||
func setJwtAuth(req *http.Request) { | ||
if jwtAuthKey := viper.GetString("jwt_auth_key"); jwtAuthKey != "" { | ||
jwtToken, err := common.GetJwt(jwtAuthKey, 60*60) | ||
if err == nil { | ||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", jwtToken)) | ||
} | ||
} | ||
} | ||
|
||
func setBrokenJwtAuth(req *http.Request) { | ||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", "broken token")) | ||
} | ||
|
||
func TestFullStackWithAuth(t *testing.T) { | ||
viper.Set("jwt_auth_key", "test") | ||
testFullStack(t, setJwtAuth, testSuite) | ||
teardown() | ||
} | ||
|
||
func TestFullStackWithBrokenAuth(t *testing.T) { | ||
viper.Set("jwt_auth_key", "test") | ||
testFullStack(t, setBrokenJwtAuth, UnAuthtestSuite) | ||
teardown() | ||
} |
Oops, something went wrong.