func TestCreateTrackerQueryREST(t *testing.T) { resource.Require(t, resource.Database) privatekey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(almtoken.RSAPrivateKey)) if err != nil { t.Fatal("Could not parse Key ", err) } service := goa.New("API") controller := NewTrackerController(service, gormapplication.NewGormDB(DB), RwiScheduler) payload := app.CreateTrackerAlternatePayload{ URL: "http://api.github.com", Type: "github", } _, tracker := test.CreateTrackerCreated(t, nil, nil, controller, &payload) jwtMiddleware := goajwt.New(&privatekey.PublicKey, nil, app.NewJWTSecurity()) app.UseJWTMiddleware(service, jwtMiddleware) controller2 := NewTrackerqueryController(service, gormapplication.NewGormDB(DB), RwiScheduler) app.MountTrackerqueryController(service, controller2) server := httptest.NewServer(service.Mux) tqPayload := fmt.Sprintf(`{"query": "abcdefgh", "schedule": "1 1 * * * *", "trackerID": "%s"}`, tracker.ID) trackerQueryCreateURL := "/api/trackerqueries" req, _ := http.NewRequest("POST", server.URL+trackerQueryCreateURL, strings.NewReader(tqPayload)) jwtToken := getValidAuthHeader(t, privatekey) req.Header.Set("Authorization", jwtToken) client := http.Client{} res, err := client.Do(req) if err != nil { t.Fatalf("Server error %s", err) } if res.StatusCode != http.StatusCreated { t.Fatalf("Expected a 201 Created response, got %d", res.StatusCode) } server.Close() }
JustBeforeEach(func() { middleware = configFunc(securityScheme, scopesFetcher) dispatchResult = middleware(handler)(context.Background(), respRecord, request) }) Context("HMAC keys signed token", func() { BeforeEach(func() { // HS256 {"scopes":"scope1","admin":true}, signed with "keys" request.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZXMiOiJzY29wZTEiLCJhZG1pbiI6dHJ1ZX0.UCvEfbD_yuS5dCZidxZgogVi2yF0ZVecMsQQbY1HJy0") }) Context("with a single key", func() { BeforeEach(func() { configFunc = jwt.New("keys", nil) }) It("should go through", func() { Ω(dispatchResult).ShouldNot(HaveOccurred()) Ω(fetchedToken).ShouldNot(BeNil()) }) }) Context("with keys that didn't the JWT", func() { BeforeEach(func() { configFunc = jwt.New("otherkey", nil) }) It("should fail with an error", func() { Ω(dispatchResult).Should(HaveOccurred())
func main() { // -------------------------------------------------------------------- // Parse flags // -------------------------------------------------------------------- var configFilePath string var printConfig bool var migrateDB bool var scheduler *remoteworkitem.Scheduler flag.StringVar(&configFilePath, "config", "", "Path to the config file to read") flag.BoolVar(&printConfig, "printConfig", false, "Prints the config (including merged environment variables) and exits") flag.BoolVar(&migrateDB, "migrateDatabase", false, "Migrates the database to the newest version and exits.") flag.Parse() // Override default -config switch with environment variable only if -config switch was // not explicitly given via the command line. configSwitchIsSet := false flag.Visit(func(f *flag.Flag) { if f.Name == "config" { configSwitchIsSet = true } }) if !configSwitchIsSet { if envConfigPath, ok := os.LookupEnv("ALMIGHTY_CONFIG_FILE_PATH"); ok { configFilePath = envConfigPath } } var err error if err = configuration.Setup(configFilePath); err != nil { logrus.Panic(nil, map[string]interface{}{ "configFilePath": configFilePath, "err": err, }, "failed to setup the configuration") } if printConfig { os.Exit(0) } // Initialized developer mode flag for the logger log.InitializeLogger(configuration.IsPostgresDeveloperModeEnabled()) printUserInfo() var db *gorm.DB for { db, err = gorm.Open("postgres", configuration.GetPostgresConfigString()) if err != nil { db.Close() log.Logger().Errorf("ERROR: Unable to open connection to database %v\n", err) log.Logger().Infof("Retrying to connect in %v...\n", configuration.GetPostgresConnectionRetrySleep()) time.Sleep(configuration.GetPostgresConnectionRetrySleep()) } else { defer db.Close() break } } if configuration.IsPostgresDeveloperModeEnabled() { db = db.Debug() } // Migrate the schema err = migration.Migrate(db.DB()) if err != nil { log.Panic(nil, map[string]interface{}{ "err": fmt.Sprintf("%+v", err), }, "failed migration") } // Nothing to here except exit, since the migration is already performed. if migrateDB { os.Exit(0) } // Make sure the database is populated with the correct types (e.g. bug etc.) if configuration.GetPopulateCommonTypes() { // set a random request ID for the context ctx, req_id := client.ContextWithRequestID(context.Background()) log.Debug(ctx, nil, "Initializing the population of the database... Request ID: %v", req_id) if err := models.Transactional(db, func(tx *gorm.DB) error { return migration.PopulateCommonTypes(ctx, tx, workitem.NewWorkItemTypeRepository(tx)) }); err != nil { log.Panic(ctx, map[string]interface{}{ "err": fmt.Sprintf("%+v", err), }, "failed to populate common types") } if err := models.Transactional(db, func(tx *gorm.DB) error { return migration.BootstrapWorkItemLinking(ctx, link.NewWorkItemLinkCategoryRepository(tx), link.NewWorkItemLinkTypeRepository(tx)) }); err != nil { log.Panic(ctx, map[string]interface{}{ "err": fmt.Sprintf("%+v", err), }, "failed to bootstap work item linking") } } // Scheduler to fetch and import remote tracker items scheduler = remoteworkitem.NewScheduler(db) defer scheduler.Stop() scheduler.ScheduleAllQueries() // Create service service := goa.New("alm") // Mount middleware service.Use(middleware.RequestID()) service.Use(middleware.LogRequest(configuration.IsPostgresDeveloperModeEnabled())) service.Use(gzip.Middleware(9)) service.Use(jsonapi.ErrorHandler(service, true)) service.Use(middleware.Recover()) service.WithLogger(goalogrus.New(log.Logger())) publicKey, err := token.ParsePublicKey(configuration.GetTokenPublicKey()) if err != nil { log.Panic(nil, map[string]interface{}{ "err": fmt.Sprintf("%+v", err), }, "failed to parse public token") } // Setup Account/Login/Security identityRepository := account.NewIdentityRepository(db) userRepository := account.NewUserRepository(db) tokenManager := token.NewManager(publicKey) app.UseJWTMiddleware(service, jwt.New(publicKey, nil, app.NewJWTSecurity())) service.Use(login.InjectTokenManager(tokenManager)) // Mount "login" controller oauth := &oauth2.Config{ ClientID: configuration.GetKeycloakClientID(), ClientSecret: configuration.GetKeycloakSecret(), Scopes: []string{"user:email"}, Endpoint: oauth2.Endpoint{ AuthURL: configuration.GetKeycloakEndpointAuth(), TokenURL: configuration.GetKeycloakEndpointToken(), }, } appDB := gormapplication.NewGormDB(db) loginService := login.NewKeycloakOAuthProvider(oauth, identityRepository, userRepository, tokenManager, appDB) loginCtrl := NewLoginController(service, loginService, tokenManager) app.MountLoginController(service, loginCtrl) // Mount "status" controller statusCtrl := NewStatusController(service, db) app.MountStatusController(service, statusCtrl) // Mount "workitem" controller workitemCtrl := NewWorkitemController(service, appDB) app.MountWorkitemController(service, workitemCtrl) // Mount "workitemtype" controller workitemtypeCtrl := NewWorkitemtypeController(service, appDB) app.MountWorkitemtypeController(service, workitemtypeCtrl) // Mount "work item link category" controller workItemLinkCategoryCtrl := NewWorkItemLinkCategoryController(service, appDB) app.MountWorkItemLinkCategoryController(service, workItemLinkCategoryCtrl) // Mount "work item link type" controller workItemLinkTypeCtrl := NewWorkItemLinkTypeController(service, appDB) app.MountWorkItemLinkTypeController(service, workItemLinkTypeCtrl) // Mount "work item link" controller workItemLinkCtrl := NewWorkItemLinkController(service, appDB) app.MountWorkItemLinkController(service, workItemLinkCtrl) // Mount "work item comments" controller workItemCommentsCtrl := NewWorkItemCommentsController(service, appDB) app.MountWorkItemCommentsController(service, workItemCommentsCtrl) // Mount "work item relationships links" controller workItemRelationshipsLinksCtrl := NewWorkItemRelationshipsLinksController(service, appDB) app.MountWorkItemRelationshipsLinksController(service, workItemRelationshipsLinksCtrl) // Mount "comments" controller commentsCtrl := NewCommentsController(service, appDB) app.MountCommentsController(service, commentsCtrl) // Mount "tracker" controller c5 := NewTrackerController(service, appDB, scheduler) app.MountTrackerController(service, c5) // Mount "trackerquery" controller c6 := NewTrackerqueryController(service, appDB, scheduler) app.MountTrackerqueryController(service, c6) // Mount "space" controller spaceCtrl := NewSpaceController(service, appDB) app.MountSpaceController(service, spaceCtrl) // Mount "user" controller userCtrl := NewUserController(service, appDB, tokenManager) app.MountUserController(service, userCtrl) // Mount "search" controller searchCtrl := NewSearchController(service, appDB) app.MountSearchController(service, searchCtrl) // Mount "indentity" controller identityCtrl := NewIdentityController(service, appDB) app.MountIdentityController(service, identityCtrl) // Mount "users" controller usersCtrl := NewUsersController(service, appDB) app.MountUsersController(service, usersCtrl) // Mount "iterations" controller iterationCtrl := NewIterationController(service, appDB) app.MountIterationController(service, iterationCtrl) // Mount "spaceiterations" controller spaceIterationCtrl := NewSpaceIterationsController(service, appDB) app.MountSpaceIterationsController(service, spaceIterationCtrl) // Mount "userspace" controller userspaceCtrl := NewUserspaceController(service, db) app.MountUserspaceController(service, userspaceCtrl) // Mount "render" controller renderCtrl := NewRenderController(service) app.MountRenderController(service, renderCtrl) // Mount "areas" controller areaCtrl := NewAreaController(service, appDB) app.MountAreaController(service, areaCtrl) spaceAreaCtrl := NewSpaceAreasController(service, appDB) app.MountSpaceAreasController(service, spaceAreaCtrl) log.Logger().Infoln("Git Commit SHA: ", Commit) log.Logger().Infoln("UTC Build Time: ", BuildTime) log.Logger().Infoln("UTC Start Time: ", StartTime) log.Logger().Infoln("Dev mode: ", configuration.IsPostgresDeveloperModeEnabled()) http.Handle("/api/", service.Mux) http.Handle("/", http.FileServer(assetFS())) http.Handle("/favicon.ico", http.NotFoundHandler()) // Start http if err := http.ListenAndServe(configuration.GetHTTPAddress(), nil); err != nil { log.Error(nil, map[string]interface{}{ "addr": configuration.GetHTTPAddress(), "err": err, }, "unable to connect to server") service.LogError("startup", "err", err) } }
}) Context("HMAC keys signed token", func() { BeforeEach(func() { // HS256 {"scopes":"scope1","admin":true}, signed with "keys" request.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZXMiOiJzY29wZTEiLCJhZG1pbiI6dHJ1ZX0.UCvEfbD_yuS5dCZidxZgogVi2yF0ZVecMsQQbY1HJy0") }) Context("with a single key", func() { var err1, err2 error BeforeEach(func() { keyResolver, err := jwt.NewResolver(nil, "keyname") err1 = err err2 = keyResolver.AddKeys("mykeys", "keys") middleware = jwt.New(keyResolver, nil, securityScheme) }) It("should go through", func() { Ω(err1).ShouldNot(HaveOccurred()) Ω(err2).ShouldNot(HaveOccurred()) Ω(dispatchResult).ShouldNot(HaveOccurred()) Ω(fetchedToken).ShouldNot(BeNil()) }) }) Context("with a single key and specified jwt keyname field", func() { var err1, err2 error BeforeEach(func() { request.Header.Set("keyname", "mykeys") keyResolver, err := jwt.NewResolver(nil, "keyname")
}) JustBeforeEach(func() { dispatchResult = middleware(handler)(context.Background(), respRecord, request) }) Context("HMAC keys signed token", func() { BeforeEach(func() { // HS256 {"scopes":"scope1","admin":true}, signed with "keys" request.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZXMiOiJzY29wZTEiLCJhZG1pbiI6dHJ1ZX0.UCvEfbD_yuS5dCZidxZgogVi2yF0ZVecMsQQbY1HJy0") }) Context("with a single key", func() { BeforeEach(func() { middleware = jwt.New("keys", nil, securityScheme) }) It("should go through", func() { Ω(dispatchResult).ShouldNot(HaveOccurred()) Ω(fetchedToken).ShouldNot(BeNil()) }) }) Context("with keys that didn't the JWT", func() { BeforeEach(func() { middleware = jwt.New("otherkey", nil, securityScheme) }) It("should fail with an error", func() { Ω(dispatchResult).Should(HaveOccurred())
// UnauthorizeCreateUpdateDeleteTest will check authorized access to Create/Update/Delete APIs func UnauthorizeCreateUpdateDeleteTest(t *testing.T, getDataFunc func(t *testing.T) []testSecureAPI, createServiceFunc func() *goa.Service, mountCtrlFunc func(service *goa.Service) error) { resource.Require(t, resource.Database) // This will be modified after merge PR for "Viper Environment configurations" publickey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(almtoken.RSAPublicKey)) if err != nil { t.Fatal("Could not parse Key ", err) } tokenTests := getDataFunc(t) for _, testObject := range tokenTests { // Build a request var req *http.Request var err error if testObject.payload == nil { req, err = http.NewRequest(testObject.method, testObject.url, nil) } else { req, err = http.NewRequest(testObject.method, testObject.url, testObject.payload) } // req, err := http.NewRequest(testObject.method, testObject.url, testObject.payload) if err != nil { t.Fatal("could not create a HTTP request") } // Add Authorization Header req.Header.Add("Authorization", testObject.jwtToken) rr := httptest.NewRecorder() service := createServiceFunc() require.NotNil(t, service) // if error is thrown during request processing, it will be caught by ErrorHandler middleware // this will put error code, status, details in recorder object. // e.g> {"id":"AL6spYb2","code":"jwt_security_error","status":401,"detail":"JWT validation failed: crypto/rsa: verification error"} //service.Use(middleware.ErrorHandler(service, true)) // e.g. > {"errors":[{"code":"unknown_error","detail":"[19v4Bp8f] 401 jwt_security_error: JWT validation failed: Token is expired","status":"401","title":"Unauthorized"}]} service.Use(jsonapi.ErrorHandler(service, true)) // append a middleware to service. Use appropriate RSA keys jwtMiddleware := goajwt.New(publickey, nil, app.NewJWTSecurity()) // Adding middleware via "app" is important // Because it will check the design and accordingly apply the middleware if mentioned in design // But if I use `service.Use(jwtMiddleware)` then middleware is applied for all the requests (without checking design) app.UseJWTMiddleware(service, jwtMiddleware) if err := mountCtrlFunc(service); err != nil { t.Fatalf("Failed to mount controller: %s", err.Error()) } // Hit the service with own request service.Mux.ServeHTTP(rr, req) require.Equal(t, testObject.expectedStatusCode, rr.Code, testObject.String()) // Below code tries to open Body response which is expected to be a JSON // If could not parse it correctly into app.JSONAPIErrors // Then it gets logged and continue the test loop //fmt.Printf("\nrr.Body = %s\n", string(rr.Body.Bytes())) jerrors := app.JSONAPIErrors{} err = json.Unmarshal(rr.Body.Bytes(), &jerrors) if err != nil { t.Log("Could not parse JSON response: ", rr.Body) // safe to continue because we alread checked rr.Code=required_value continue } // Additional checks for 'more' confirmation require.Equal(t, testObject.expectedErrorCode, *jerrors.Errors[0].Code) require.Equal(t, strconv.Itoa(testObject.expectedStatusCode), *jerrors.Errors[0].Status, testObject.String()) } }