func userLoginHandler(cmd *CmdMessage) error { data := make(map[string]interface{}) email, ok1 := cmd.Data["email"].(string) pass, ok2 := cmd.Data["password"].(string) if !(ok1 && ok2) { return errors.New("Login failed: missing email or password") } ClearOldSessions() user := &db.User{} err := db.C("users").Find(bson.M{"email": email, "password": pass}).One(user) if err != nil { return errors.New("Login failed: bad email or password") } // creating the session sess := &db.Session{UId: user.Id, Created: time.Now().Unix()} sess.GenId() db.C("sessions").Insert(sess) data["session_id"] = sess.Id.Hex() data["id"] = user.Id.Hex() data["org_id"] = user.OrgId.Hex() cmd.Conn.owner.Authenticate(user.Id) return DispatchMessage("login", data, cmd.Conn) }
func Test_daemonLoginHandler(t *testing.T) { // when there is a daemon ----------------------------------------- tmpD := &db.Daemon{ Id: bson.ObjectIdHex("52a4ed348350a921bd000001"), OrgId: bson.ObjectIdHex("52a4ed348350a921bd000002"), Name: "daemon", Password: "******", } db.AddTemp("daemons", tmpD) // a field missing lcmd := &CmdMessage{ Data: make(map[string]interface{}), Conn: &Connection{owner: &Daemon{}}, } lcmd.Data["org_id"] = "52a4ed348350a921bd000002" lcmd.Data["name"] = "daemon" err := LoginHandler(lcmd) test.Assert(err != nil, "it sends an error if there is a field missing", t) // wrong password lcmd.Data["password"] = "******" err = LoginHandler(lcmd) test.Assert(err != nil, "it sends an error if password is wrong", t) // all correct lcmd.Data["password"] = "******" err = LoginHandler(lcmd) cmd := GetLastCmd() test.Assert(cmd.Data["id"].(string) == "52a4ed348350a921bd000001", "it returns a daemon id", t) test.Assert(err == nil, "it does not throw an error", t) test.Assert(lcmd.Conn.owner.(*Daemon).Entry != nil, "it extracts the database information and puts it on the connection", t) db.DelTemps("daemons") // when there is no daemon ---------------------------------------- err = LoginHandler(lcmd) test.Assert(err == nil, "it does not throw an error", t) cmd = GetLastCmd() err = db.C("daemons").FindId(bson.ObjectIdHex(cmd.Data["id"].(string))).One(tmpD) test.Assert(err == nil, "it creates a new daemon, if one does not exist", t) test.Assert(tmpD.Status == "NOT_KNOWN", "the daemon is set as unknown", t) db.C("daemons").RemoveId(bson.ObjectIdHex(cmd.Data["id"].(string))) }
func daemonLoginHandler(cmd *CmdMessage) error { data := make(map[string]interface{}) name, ok1 := cmd.Data["name"].(string) pass, ok2 := cmd.Data["password"].(string) orgId, ok3 := cmd.Data["org_id"].(string) if !(ok1 && ok2 && ok3) { return errors.New("Login failed: missing name or password or org_id") } if !bson.IsObjectIdHex(orgId) { return errors.New("Organisation ID is invalid") } daemon := &db.Daemon{} err := db.C("daemons").Find(bson.M{ "name": name, "password": pass, "org_id": bson.ObjectIdHex(orgId), }).One(daemon) if err != nil { err = db.C("daemons").Find(bson.M{ "name": name, "org_id": bson.ObjectIdHex(orgId), }).One(daemon) // if there is a mistake in password then it is an error if err == nil { return errors.New("Login failed: bad password") } // otherwise we have to create a new entry daemon = &db.Daemon{ Name: name, Password: pass, OrgId: bson.ObjectIdHex(orgId), Status: "NOT_KNOWN", } daemon.GenId() db.C("daemons").Insert(daemon) } data["id"] = daemon.Id.Hex() cmd.Conn.owner.Authenticate(daemon.Id) DispatchMessage("login", data, cmd.Conn) return nil }
func storeMonitoringData(cmd *CmdMessage) error { // creating a new data point list, ok := cmd.Data["list"].([]interface{}) if !ok { return errors.New("A list of parameters is not specified") } c := db.C("monitoring_of_" + cmd.Conn.owner.(*Daemon).Id) for _, e := range list { entry, ok1 := e.(map[string]interface{}) if !ok1 { return errors.New("Monitoring entry is invalid") } parameter, ok2 := entry["parameter"].(string) values, ok3 := entry["values"].(map[string]interface{}) if !(ok2 && ok3) { return errors.New("You need to specify parameter and values") } for t, v := range values { time, _ := strconv.Atoi(t) value, ok := v.(float64) if !ok { return errors.New("Non floating point number value supplied") } c.Insert(bson.M{ "parameter": parameter, "time": time, "value": value, }) } } return nil }
func Test_MonitoringHandlerUser(t *testing.T) { // before user := &User{OrgId: "Anonymous"} daemon := &Daemon{Id: "a", OrgId: "Anonymous"} user.Authorise() data1 := &db.Data{"", "cpu", 1000, 12.5} data2 := &db.Data{"", "cpu", 1500, 14.5} data3 := &db.Data{"", "cpu", 1600, 15.5} data4 := &db.Data{"", "cpu", 1900, 11.5} data5 := &db.Data{"", "ram", 1200, 9000} db.AddTemp("monitoring_of_a", data1) db.AddTemp("monitoring_of_a", data2) db.AddTemp("monitoring_of_a", data3) db.AddTemp("monitoring_of_a", data4) db.AddTemp("monitoring_of_a", data5) // let's try it from the string... msg := &Message{ msg: ` { "type": "monitoring", "data": { "daemon_id": "a", "parameter": "cpu", "from": 1100, "to": 1600 } } `, c: &Connection{owner: user}, } // the daemon is not in the org err, _ := HandleMsg(msg) test.Assert(err != nil, "it doesn't allow to monitor foreign daemons", t) // daemon exists in the org daemon.Authorise() err, _ = HandleMsg(msg) cmd := GetLastCmd() test.Assert(err == nil, "it does allow to monitor your daemons", t) vals := cmd.Data["values"].(map[string]float64) test.Assert(len(vals) == 2, "it returns the right number of answers", t) test.Assert(vals["1500"] == 14.5, "it has the correct data", t) test.Assert(vals["1600"] == 15.5, "it has the correct data", t) // cleaning up db.C("monitoring_of_a").DropCollection() user.Deauthorise() daemon.Deauthorise() }
//------------------------------------------------------- // methods //------------------------------------------------------- // obtain all the data and proceed to authorisation func (d *Daemon) Authenticate(id bson.ObjectId) error { c := db.C("daemons") err := c.FindId(id).One(&d.Entry) if err == nil { d.Id = id.Hex() d.OrgId = d.Entry.OrgId.Hex() return d.Authorise() } return err }
//------------------------------------------------------- // methods //------------------------------------------------------- // obtain all the data and proceed to authorisation func (u *User) Authenticate(id bson.ObjectId) error { c := db.C("users") err := c.FindId(id).One(&u.Entry) if err == nil { u.Id = id.Hex() u.OrgId = u.Entry.OrgId.Hex() return u.Authorise() } return err }
func Test_userLoginHandler(t *testing.T) { tmpU := &db.User{Id: bson.ObjectIdHex("52a4ed348350a921bd000001"), OrgId: bson.ObjectIdHex("52a4ed348350a921bd000002"), Email: "*****@*****.**", Password: "******"} db.AddTemp("users", tmpU) // no password lcmd := &CmdMessage{Data: make(map[string]interface{}), Conn: &Connection{owner: &User{}}} lcmd.Data["email"] = "*****@*****.**" err := LoginHandler(lcmd) test.Assert(err != nil, "it sends an error if there is no password", t) // wrong password lcmd.Data["password"] = "******" err = LoginHandler(lcmd) test.Assert(err != nil, "it sends an error if password is wrong", t) // all correct lcmd.Data["password"] = "******" err = LoginHandler(lcmd) cmd := GetLastCmd() test.Assert(len(cmd.Data["session_id"].(string)) == 24, "it returns a session_id for this user", t) test.Assert(err == nil, "it does not throw an error", t) test.Assert(cmd.Data["id"].(string) == "52a4ed348350a921bd000001", "it returns a user id", t) session := &db.Session{} err = db.C("sessions").Find(bson.M{"_id": bson.ObjectIdHex(cmd.Data["session_id"].(string))}).One(session) test.Assert(err == nil, "it creates a session in the database", t) test.Assert(lcmd.Conn.owner.(*User).Entry != nil, "it extracts the database information and puts it on the connection", t) db.DelTemps("users") db.C("sessions").RemoveAll(bson.M{"uid": bson.ObjectIdHex("52a4ed348350a921bd000001")}) // no user at all err = LoginHandler(lcmd) test.Assert(err != nil, "it sends an error if there is no such user", t) }
// removes all the stub data from the database func cleanTheDB() { fmt.Println("Cleaning up the DB, don't turn off...") // delete all the users db.DelTemps("users") // all the monitoring information for _, d := range daemons { db.C("monitoring_of_" + d.Id.Hex()).DropCollection() } // all the daemons db.DelTemps("daemons") // all the orgs db.DelTemps("organisations") fmt.Println("Bye!") }
func Test_LogoutHandler(t *testing.T) { // a user is removed from the organisation // and his session is deleted tmpS := &db.Session{UId: bson.ObjectIdHex("52a4ed348350a921bd000001")} db.AddTemp("sessions", tmpS) user := &User{ Id: "52a4ed348350a921bd000001", SessionId: tmpS.GetId().Hex(), OrgId: "Anonymous", } msg := &Message{ msg: `{"type":"logout","data":{}}`, c: &Connection{owner: user}, } user.Authorise() test.Assert(user.IsAuthorised(), "user is authorised before logout", t) err, _ := HandleMsg(msg) test.Assert(err == nil, "it logs out successfully", t) test.Assert(!user.IsAuthorised(), "user is not in the organisation any more", t) err = db.C("sessions").Find(bson.M{ "uid": bson.ObjectIdHex("52a4ed348350a921bd000001"), }).One(tmpS) test.Assert(err != nil, "there are no sessions for this user", t) // it does not break if session was already gone err, _ = HandleMsg(msg) test.Assert(err == nil, "it does not blow up without session", t) // a daemon is removed from the organisation daemon := &Daemon{ Id: "52a4ed348350a921bd000001", OrgId: "Anonymous", } msg = &Message{ msg: `{"type":"logout","data":{}}`, c: &Connection{owner: daemon}, } daemon.Authorise() test.Assert(daemon.IsAuthorised(), "daemon is authorised before logout", t) err, _ = HandleMsg(msg) test.Assert(err == nil, "it logs out successfully", t) test.Assert(!daemon.IsAuthorised(), "daemon is not in the organisation any more", t) }
// a handler that deauthorises the user or the daemon func LogoutHandler(cmd *CmdMessage) error { data := make(map[string]interface{}) cmd.Conn.owner.Deauthorise() // if it is user, delete the session if cmd.Conn.owner.IsUser() { db.C("sessions").RemoveAll(bson.M{ "uid": bson.ObjectIdHex(cmd.Conn.owner.(*User).Id), }) } data["status"] = "OK" DispatchMessage("logout", data, cmd.Conn) return nil }
// a handler that either stores monitoring information // for that particular daemon, or sends the stats to the user func MonitoringHandler(cmd *CmdMessage) error { if !cmd.Conn.owner.IsAuthorised() { return errors.New("Logging in is required before using this handler") } if !cmd.Conn.owner.IsUser() { return storeMonitoringData(cmd) } daemonId, ok := cmd.Data["daemon_id"].(string) if !ok { return errors.New("wrong daemon_id supplied") } daemons := cmd.Conn.owner.GetOrg().Daemons _, ok = daemons[daemonId] if !ok { return errors.New("daemon not found") } param, ok1 := cmd.Data["parameter"].(string) from, ok2 := cmd.Data["from"].(float64) to, ok3 := cmd.Data["to"].(float64) if !(ok1 && ok2 && ok3) { return errors.New("Some parameters are missing!") } c := db.C("monitoring_of_" + daemonId) var inf []db.Data = nil c.Find(bson.M{ "time": bson.M{"$gte": from, "$lte": to}, "parameter": param, }).All(&inf) vals := make(map[string]float64) for _, d := range inf { vals[strconv.FormatInt(d.Time, 10)] = d.Value } data := make(map[string]interface{}) data["daemon_id"] = daemonId data["parameter"] = param data["values"] = vals return DispatchMessage("monitoring", data, cmd.Conn) }
func daemonUpdateInfo(cmd *CmdMessage) error { platform, ok1 := cmd.Data["daemon_platform"].(string) par, ok2 := cmd.Data["daemon_all_parameters"].([]interface{}) mon, ok3 := cmd.Data["daemon_monitored_parameters"].([]interface{}) if !(ok1 && ok2 && ok3) { return errors.New("All parameters must be supplied") } parameters, err1 := ToStringSlice(par) monitored, err2 := ToStringSlice(mon) if err1 != nil || err2 != nil { return errors.New("Non-string parameters given") } // update elements for this id daemon := cmd.Conn.owner.(*Daemon) db.C("daemons").UpdateId(daemon.Entry.Id, bson.M{ "$set": bson.M{ "platform": platform, "parameters": parameters, "monitored": monitored, }, }) // update them on the daemon itself daemon.Entry.Platform = platform daemon.Entry.Parameters = parameters daemon.Entry.Monitored = monitored // send information to all the users in the org for _, ucon := range daemon.GetOrg().Users { err := sendDaemonMessage(daemon, ucon) if err != nil { return err } } return nil }
//------------------------------------------------------- // helper functions //------------------------------------------------------- // get the id from the session and proceed to authentication func AuthFromSession(sessId string) (bson.ObjectId, error) { c := db.C("sessions") result := &db.Session{} err := c.FindId(bson.ObjectIdHex(sessId)).One(result) return result.UId, err }
func Test_MonitoringHandlerDaemon(t *testing.T) { daemon := &Daemon{Id: "a", OrgId: NO_ORG, Entry: &db.Daemon{}} msg := &Message{ msg: `{ "type": "monitoring", "data": { "list": [{ "parameter": "cpu", "values": { "1104699": 12.5 } }] } }`, c: &Connection{owner: daemon}, } // without authorisation err, _ := HandleMsg(msg) test.Assert(err != nil, "the daemon must be authorised", t) // with authorisation daemon.OrgId = "Anonymous" daemon.Authorise() err, _ = HandleMsg(msg) test.Assert(err == nil, "it does not throw errors, when the daemon is authorised", t) data := &db.Data{} db.C("monitoring_of_a").Find(bson.M{"parameter": "cpu"}).One(data) test.Assert(data.Time == 1104699, "it stores the time right", t) test.Assert(data.Value == 12.5, "it stores the metric right", t) // adding additional metrics to it msg.msg = `{ "type": "monitoring", "data": { "list": [{ "parameter": "cpu", "values": { "1104670": 15 } }] } }` err, _ = HandleMsg(msg) test.Assert(err == nil, "it still doesn't throw errors", t) q := db.C("monitoring_of_a").Find(bson.M{"parameter": "cpu"}) count, err := q.Count() test.Assert(count == 2, "it returns additional values", t) q.Sort("time").One(data) test.Assert(data.Time == 1104670, "it stores the time right", t) test.Assert(data.Value == 15, "it stores the metric right", t) // cleaning up db.C("monitoring_of_a").DropCollection() daemon.Deauthorise() }
// remove all old sessions func ClearOldSessions() { expired := time.Now().Unix() - 10*24*60*60 db.C("sessions").Remove(bson.M{"created": bson.M{"$ls": expired}}) }
func Test_DaemonHandler(t *testing.T) { user := &User{ Id: "52a4ed348350a921bd000001", OrgId: NO_ORG, } lcmd := &CmdMessage{ Data: make(map[string]interface{}), Conn: &Connection{owner: user}, } lcmd.Data["daemon_id"] = "a" daemon := &Daemon{ Id: "a", OrgId: "Random_org", c: &Connection{}, Entry: &db.Daemon{}, } daemon.c.owner = daemon daemon.Authorise() // user has to be authorised, to get daemons data err := DaemonHandler(lcmd) test.Assert(err != nil, "user has to be authorised", t) // if the daemon does not exist, then an error is returned user.OrgId = "Anonymous" user.Authorise() err = DaemonHandler(lcmd) test.Assert(err != nil, "the daemon has to exist in the org", t) // if everything is ok, the daemon information is returned daemon.Deauthorise() daemon.OrgId = "Anonymous" daemon.Authorise() err = DaemonHandler(lcmd) test.Assert(err == nil, "it does not send the error", t) cmd := GetLastCmd() test.Assert(cmd.Data["daemon_id"].(string) == "a", "it returns the daemon information", t) //-------------------------------------------------- // if it is a daemon //-------------------------------------------------- // not sending the data msg := &Message{ msg: `{"type":"daemon","data":{"daemon_id":"id of the daemon"}}`, c: &Connection{owner: daemon}, } err, _ = HandleMsg(msg) test.Assert(err != nil, "it has to contain information", t) // when the data is sent, it stores it in the database msg.msg = `{ "type":"daemon", "data":{ "daemon_id":"id of the daemon", "daemon_platform":"Linux", "daemon_all_parameters":["cpu","ram","network"], "daemon_monitored_parameters":["cpu","ram"] } }` tmpD := &db.Daemon{OrgId: bson.ObjectIdHex("52a4ed348350a921bd000002"), Name: "a", Password: "******"} db.AddTemp("daemons", tmpD) daemon.Entry = tmpD daemon.Id = tmpD.Id.Hex() err, _ = HandleMsg(msg) test.Assert(err == nil, "no errors are raised", t) dbd := &db.Daemon{} db.C("daemons").FindId(tmpD.Id).One(dbd) test.Assert(dbd.Platform == "Linux", "it stores the platform in the database", t) test.Assert(len(dbd.Parameters) == 3, "it stores all the parameters", t) test.Assert(len(dbd.Monitored) == 2, "it also stores what it is monitoring", t) // it also sends new information to all the users in the org cmd = GetLastCmd() test.Assert(cmd.Type == "daemon", "it sends a daemon message", t) test.Assert(cmd.Data["daemon_id"].(string) == daemon.Id, "with the latest information about this daemon", t) // cleaning up daemon.Deauthorise() user.Deauthorise() db.DelTemps("daemons") }