示例#1
0
// dbManager manages database connections, and communicates back and forth with the manager goroutine
func dbManager(conf config.Config, dbLaunchChan chan struct{}, dbKillChan chan struct{}) {
	log.Println("db: starting...")

	// Attempt to open database connection, depending on configuration
	// sqlite
	if conf.Sqlite != nil {
		log.Println("db: sqlite:", conf.Sqlite.File)

		// Replace the home character to set path
		path := common.ExpandHomeDir(conf.Sqlite.File)

		// Set DSN
		data.DB = new(data.SqliteBackend)
		data.DB.DSN(path)

		// Set up the database
		if err := data.DB.Setup(); err != nil {
			log.Fatalf("db: could not set up database: %s", err.Error())
		}

		// Verify database file exists and is ready
		if _, err := os.Stat(path); err != nil {
			log.Fatalf("db: database file does not exist: %s", conf.Sqlite.File)
		}

		// Open the database connection
		if err := data.DB.Open(); err != nil {
			log.Fatalf("db: could not open database: %s", err)
		}

		// TODO: temporary, create a test user
		data.NewUser("test", "test", data.RoleAdmin)
	} else {
		// Invalid config
		log.Fatalf("db: invalid database selected")
	}

	// Database set up, trigger manager that it's ready
	close(dbLaunchChan)

	// Trigger events via channel
	for {
		select {
		// Stop database manager
		case <-dbKillChan:
			// Close the database connection pool
			if err := data.DB.Close(); err != nil {
				log.Fatalf("db: could not close connection")
			}

			// Inform manager that shutdown is complete
			log.Println("db: stopped!")
			dbKillChan <- struct{}{}
			return
		}
	}
}
示例#2
0
文件: users.go 项目: postfix/wavepipe
// PostUsers creates a new user for the wavepipe API, and returns a HTTP status and JSON.
func PostUsers(w http.ResponseWriter, r *http.Request) {
	// Retrieve render
	ren := context.Get(r, CtxRender).(*render.Render)

	// Attempt to retrieve user from context
	sessionUser := new(data.User)
	if tempUser := context.Get(r, CtxUser); tempUser != nil {
		sessionUser = tempUser.(*data.User)
	} else {
		// No sessionUser stored in context
		log.Println("api: no sessionUser stored in request context!")
		ren.JSON(w, 500, serverErr)
		return
	}

	// Output struct for users request
	out := UsersResponse{}

	// Check API version
	if version, ok := mux.Vars(r)["version"]; ok {
		// Check if this API call is supported in the advertised version
		if !apiVersionSet.Has(version) {
			ren.JSON(w, 400, errRes(400, "unsupported API version: "+version))
			return
		}
	}

	// Only allow administrators to create users
	if sessionUser.RoleID < data.RoleAdmin {
		ren.JSON(w, 403, permissionErr)
		return
	}

	// Check for required username, password, and role parameters
	username := r.PostFormValue("username")
	if username == "" {
		ren.JSON(w, 400, errRes(400, "missing required parameter: username"))
		return
	}

	password := r.PostFormValue("password")
	if password == "" {
		ren.JSON(w, 400, errRes(400, "missing required parameter: password"))
		return
	}

	// Check for role ID
	role := r.PostFormValue("role")
	if role == "" {
		ren.JSON(w, 400, errRes(400, "missing required parameter: role"))
		return
	}

	// Ensure role is valid integer, and valid role
	roleID, err := strconv.Atoi(role)
	if err != nil || (roleID != data.RoleGuest && roleID != data.RoleUser && roleID != data.RoleAdmin) {
		ren.JSON(w, 400, errRes(400, "invalid integer role ID"))
		return
	}

	// Generate a new user using the input username, password, and role
	user, err := data.NewUser(username, password, roleID)
	if err != nil {
		log.Println(err)
		ren.JSON(w, 500, serverErr)
		return
	}

	// HTTP 200 OK with JSON
	out.Users = []data.User{*user}
	ren.JSON(w, 200, out)
	return
}
示例#3
0
// TestAuthenticate runs through the entire authentication process with a newly-created user
func TestAuthenticate(t *testing.T) {
	// Load database configuration
	data.DB = new(data.SqliteBackend)
	data.DB.DSN("~/.config/wavepipe/wavepipe.db")
	if err := data.DB.Open(); err != nil {
		t.Fatalf("Could not open database connection: %s", err.Error())
	}
	defer data.DB.Close()

	// Create a temporary user, remove it on return
	user, err := data.NewUser("auth_test", "auth_test", data.RoleGuest)
	if err != nil {
		t.Fatal(err)
	}
	defer user.Delete()

	// Table of bcrypt tests and expected output
	var bcryptTests = []struct {
		username  string
		password  string
		clientErr error
	}{
		// No username
		{"", "auth_test", ErrNoUsername},
		// No password
		{"auth_test", "", ErrNoPassword},
		// Invalid user
		{"no_exist", "auth_test", ErrInvalidUsername},
		// Invalid password
		{"auth_test", "bad_pass", ErrInvalidPassword},
		// Correct credentials
		{"auth_test", "auth_test", nil},
	}

	// Iterate all bcrypt tests and check for valid output
	for _, test := range bcryptTests {
		// Generate POST data
		postData := url.Values{}
		postData.Set("username", test.username)
		postData.Set("password", test.password)

		// Generate a HTTP request
		req, err := http.NewRequest("POST", "http://localhost:8080/api/v0/login", bytes.NewBufferString(postData.Encode()))
		if err != nil {
			t.Fatal(err)
		}

		// Set required headers
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		req.Header.Set("Content-Length", strconv.Itoa(len(postData.Encode())))

		// Attempt authentication via bcrypt
		_, authSession, clientErr, serverErr := bcryptAuthenticate(req)

		// Check for nil session, since sessions are not generated on login (they are generated in the API)
		if authSession != nil {
			t.Fatalf("non-nil session: %v", authSession)
		}

		// Check for expected client error
		if clientErr != test.clientErr {
			t.Fatalf("mismatched clientErr: %v != %v", clientErr, test.clientErr)
		}

		// Check for no server errors
		if serverErr != nil {
			t.Fatal(err)
		}
	}

	// Create a temporary session, remove it on return
	session, err := user.CreateSession("auth_test")
	if err != nil {
		t.Fatal(err)
	}
	defer session.Delete()

	// Table of token tests and expected output
	var tokenTests = []struct {
		token     string
		clientErr error
	}{
		// No token
		{"", ErrNoToken},
		// Invalid token
		{"some_token", ErrInvalidToken},
		// Correct token
		{session.Key, nil},
	}

	// Iterate all token tests and check for valid output
	for _, test := range tokenTests {
		// Generate a HTTP request
		req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:8080/api/v0/status?s=%s", test.token), nil)
		if err != nil {
			t.Fatal(err)
		}

		// Attempt authentication via token
		_, _, clientErr, serverErr := tokenAuthenticate(req)

		// Check for expected client error
		if clientErr != test.clientErr {
			t.Fatalf("mismatched clientErr: %v != %v", clientErr, test.clientErr)
		}

		// Check for no server errors
		if serverErr != nil {
			t.Fatal(err)
		}
	}
}