Example #1
0
// authenticateLoader is used to authenticate requests that are made to the
// loader API endpoints. Rather than operate on GPG signatures, the
// authentication instead uses the submitted loader key
func authenticateLoader(pass handler) handler {
	return func(w http.ResponseWriter, r *http.Request) {
		var (
			loaderid float64
			err      error
		)
		opid := getOpID(r)
		context.Set(r, opID, opid)
		lkey := r.Header.Get("X-LOADERKEY")
		if lkey == "" {
			resource := cljs.New(fmt.Sprintf("%s%s", ctx.Server.Host, r.URL.String()))
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: "X-LOADERKEY header not found"})
			respond(http.StatusUnauthorized, resource, w, r)
			return
		}
		// Do a sanity check here on the submitted loader string before
		// we attempt the authentication
		err = mig.ValidateLoaderKey(lkey)
		if err == nil {
			loaderid, err = ctx.DB.GetLoaderEntryID(lkey)
		}
		if err != nil {
			resource := cljs.New(fmt.Sprintf("%s%s", ctx.Server.Host, r.URL.String()))
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("Loader authorization failed")})
			respond(http.StatusUnauthorized, resource, w, r)
			return
		}
		context.Set(r, loaderID, loaderid)
		// accept request
		pass(w, r)
	}
}
Example #2
0
// authenticate is called prior to processing incoming requests. it implements the client
// authentication logic, which mostly consist of validating GPG signed tokens and setting the
// identity of the signer in the request context
func authenticate(pass handler, adminRequired bool) handler {
	return func(w http.ResponseWriter, r *http.Request) {
		var (
			err error
			inv mig.Investigator
		)
		opid := getOpID(r)
		context.Set(r, opID, opid)
		context.Set(r, apiRequestCategory, RequestCategoryInvestigator)
		if !ctx.Authentication.Enabled {
			inv.Name = "authdisabled"
			inv.ID = 0
			inv.IsAdmin = true
			goto authorized
		}
		if r.Header.Get("X-PGPAUTHORIZATION") == "" {
			inv.Name = "authmissing"
			inv.ID = -1
			resource := cljs.New(fmt.Sprintf("%s%s", ctx.Server.Host, r.URL.String()))
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: "X-PGPAUTHORIZATION header not found"})
			respond(http.StatusUnauthorized, resource, w, r)
			return
		}
		inv, err = verifySignedToken(r.Header.Get("X-PGPAUTHORIZATION"))
		if err != nil {
			inv.Name = "authfailed"
			inv.ID = -1
			resource := cljs.New(fmt.Sprintf("%s%s", ctx.Server.Host, r.URL.String()))
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("Authorization verification failed with error '%v'", err)})
			respond(http.StatusUnauthorized, resource, w, r)
			return
		}
	authorized:
		// store investigator identity in request context
		context.Set(r, authenticatedInvName, inv.Name)
		context.Set(r, authenticatedInvID, inv.ID)
		context.Set(r, authenticatedInvIsAdmin, inv.IsAdmin)
		// Validate investigator is an administrator if required
		if adminRequired {
			if !inv.IsAdmin {
				inv.Name = "authfailed"
				inv.ID = -1
				ctx.Channels.Log <- mig.Log{
					OpID: getOpID(r),
					Desc: fmt.Sprintf("Investigator '%v' %v has insufficient privileges to access API function", getInvName(r), getInvID(r)),
				}.Info()
				resource := cljs.New(fmt.Sprintf("%s%s", ctx.Server.Host, r.URL.String()))
				resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid),
					Message: "Insufficient privileges"})
				respond(http.StatusUnauthorized, resource, w, r)
				return
			}
		}
		// accept request
		pass(w, r)
	}
}
Example #3
0
// describeCreateInvestigator returns a resource that describes how to create an investigator
func describeCreateInvestigator(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := getOpID(request)
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			emsg := fmt.Sprintf("%v", e)
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: emsg}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: emsg})
			respond(500, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving describeCreateInvestigator()"}.Debug()
	}()
	err = resource.SetTemplate(cljs.Template{
		Data: []cljs.Data{
			{Name: "name", Value: "investigator's full name", Prompt: "Investigator Name"},
			{Name: "publickey", Value: "armored GPG public key", Prompt: "Public Key"},
		},
	})
	if err != nil {
		panic(err)
	}
	respond(200, resource, respWriter, request)
}
Example #4
0
File: api.go Project: Novemburr/mig
// getHeartbeat returns a 200
func getHeartbeat(respWriter http.ResponseWriter, request *http.Request) {
	opid := mig.GenID()
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getHeartbeat()"}.Debug()
	}()
	err := resource.AddItem(cljs.Item{
		Href: request.URL.String(),
		Data: []cljs.Data{
			{
				Name:  "heartbeat",
				Value: "gatorz say hi",
			},
		}})
	if err != nil {
		panic(err)
	}
	respond(200, resource, respWriter, request)
}
Example #5
0
// getCommand takes an actionid and a commandid and returns a command
func getCommand(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := mig.GenID()
	resource := cljs.New(request.URL.String())
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%d", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request, opid)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getCommand()"}.Debug()
	}()
	var actionID, commandID int
	aid := request.URL.Query()["actionid"][0]
	if aid != "" {
		actionID, err = strconv.Atoi(aid)
		if err != nil {
			panic(err)
		}
	}
	cmdid := request.URL.Query()["commandid"][0]
	if cmdid != "" {
		commandID, err = strconv.Atoi(cmdid)
		if err != nil {
			panic(err)
		}
	}

	// retrieve the action
	cmds := []mig.Command{}
	var iter *mgo.Iter
	if commandID > 0 {
		if actionID > 0 {
			iter = ctx.DB.Col.Cmd.Find(bson.M{"id": commandID, "action.id": actionID}).Iter()
		} else {
			iter = ctx.DB.Col.Cmd.Find(bson.M{"id": commandID}).Iter()
		}
	} else {
		// nothing to search for, return empty resource
		respond(200, resource, respWriter, request, opid)
	}
	err = iter.All(&cmds)
	if err != nil {
		panic(err)
	}
	if len(cmds) == 0 {
		resource.SetError(cljs.Error{Code: fmt.Sprintf("%d", opid), Message: "No command found"})
		respond(404, resource, respWriter, request, opid)
	}
	// store the results in the resource
	for _, cmd := range cmds {
		commandItem, err := commandToItem(cmd)
		if err != nil {
			panic(err)
		}
		resource.AddItem(commandItem)
	}
	respond(200, resource, respWriter, request, opid)
}
Example #6
0
// getAction queries the database and retrieves the detail of an action
func getAction(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := getOpID(request)
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			emsg := fmt.Sprintf("%v", e)
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: emsg}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: emsg})
			respond(http.StatusInternalServerError, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getAction()"}.Debug()
	}()
	actionID, err := strconv.ParseFloat(request.URL.Query()["actionid"][0], 64)
	if err != nil {
		err = fmt.Errorf("Wrong parameters 'actionid': '%v'", err)
		panic(err)
	}

	// retrieve the action
	var a mig.Action
	if actionID > 0 {
		a, err = ctx.DB.ActionByID(actionID)
		if err != nil {
			if a.ID == -1 {
				// not found, return 404
				resource.SetError(cljs.Error{
					Code:    fmt.Sprintf("%.0f", opid),
					Message: fmt.Sprintf("Action ID '%.0f' not found", actionID)})
				respond(http.StatusNotFound, resource, respWriter, request)
				return
			} else {
				panic(err)
			}
		}
	} else {
		// bad request, return 400
		resource.SetError(cljs.Error{
			Code:    fmt.Sprintf("%.0f", opid),
			Message: fmt.Sprintf("Invalid Action ID '%.0f'", actionID)})
		respond(http.StatusBadRequest, resource, respWriter, request)
		return
	}

	// retrieve investigators
	a.Investigators, err = ctx.DB.InvestigatorByActionID(a.ID)
	if err != nil {
		panic(err)
	}
	// store the results in the resource
	actionItem, err := actionToItem(a, true, ctx)
	if err != nil {
		panic(err)
	}
	resource.AddItem(actionItem)
	respond(http.StatusOK, resource, respWriter, request)
}
Example #7
0
// createInvestigator creates an investigator into the database
func createInvestigator(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := getOpID(request)
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			emsg := fmt.Sprintf("%v", e)
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: emsg}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: emsg})
			respond(500, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving createInvestigator()"}.Debug()
	}()
	var inv mig.Investigator
	err = request.ParseMultipartForm(20480)
	if err != nil {
		panic(err)
	}
	inv.Name = request.FormValue("name")
	if inv.Name == "" {
		panic("Investigator name must not be empty")
	}
	// publickey is stored in a multipart post form, extract it
	_, keyHeader, err := request.FormFile("publickey")
	if err != nil {
		panic(err)
	}
	keyReader, err := keyHeader.Open()
	if err != nil {
		panic(err)
	}
	inv.PublicKey, err = ioutil.ReadAll(keyReader)
	if err != nil {
		panic(err)
	}
	if len(inv.PublicKey) == 0 {
		panic("Investigator Public Key must not be empty")
	}
	// validate the public key and obtain a fingerprint from it
	inv.PGPFingerprint, err = pgp.LoadArmoredPubKey(inv.PublicKey)
	if err != nil {
		panic(err)
	}
	// create the investigator in database
	inv.ID, err = ctx.DB.InsertInvestigator(inv)
	if err != nil {
		panic(err)
	}
	ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "Investigator created in database"}
	err = resource.AddItem(cljs.Item{
		Href: fmt.Sprintf("%s/investigator?investigatorid=%.0f", ctx.Server.BaseURL, inv.ID),
		Data: []cljs.Data{{Name: "Investigator ID " + fmt.Sprintf("%.0f", inv.ID), Value: inv}},
	})
	respond(201, resource, respWriter, request)
}
Example #8
0
File: api.go Project: netantho/mig
func getDashboard(respWriter http.ResponseWriter, request *http.Request) {
	opid := mig.GenID()
	loc := fmt.Sprintf("http://%s:%d%s", ctx.Server.IP, ctx.Server.Port, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request, opid)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getDashboard()"}.Debug()
	}()

	// get summary of agents active in the last 5 minutes
	sum, err := ctx.DB.SumAgentsByVersion(time.Now().Add(-5 * time.Minute))
	if err != nil {
		panic(err)
	}
	count, err := ctx.DB.CountNewAgents(time.Now().Add(-24 * time.Hour))
	if err != nil {
		panic(err)
	}
	double, err := ctx.DB.CountDoubleAgents(time.Now().Add(-5 * time.Minute))
	if err != nil {
		panic(err)
	}
	disappeared, err := ctx.DB.CountDisappearedAgents(
		time.Now().Add(-7*24*time.Hour), time.Now().Add(-5*time.Minute))
	if err != nil {
		panic(err)
	}
	sumItem, err := agentsSummaryToItem(sum, count, double, disappeared, ctx)
	resource.AddItem(sumItem)

	// add the last 10 actions
	actions, err := ctx.DB.Last10Actions()
	if err != nil {
		panic(err)
	}
	for _, action := range actions {
		// retrieve investigators
		action.Investigators, err = ctx.DB.InvestigatorByActionID(action.ID)
		if err != nil {
			panic(err)
		}
		// store the results in the resource
		actionItem, err := actionToItem(action, false, ctx)
		if err != nil {
			panic(err)
		}
		resource.AddItem(actionItem)
	}
	respond(200, resource, respWriter, request, opid)
}
// getInvestigator takes an investigatorid and returns an investigator
func getInvestigator(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := getOpID(request)
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			emsg := fmt.Sprintf("%v", e)
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: emsg}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: emsg})
			respond(http.StatusInternalServerError, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getInvestigator()"}.Debug()
	}()
	iid, err := strconv.ParseFloat(request.URL.Query()["investigatorid"][0], 64)
	if err != nil {
		err = fmt.Errorf("Wrong parameters 'investigatorid': '%v'", err)
		panic(err)
	}

	// retrieve the investigator
	var inv mig.Investigator
	if iid > 0 {
		inv, err = ctx.DB.InvestigatorByID(iid)
		if err != nil {
			if fmt.Sprintf("%v", err) == "Error while retrieving investigator: 'sql: no rows in result set'" {
				// not found, return 404
				resource.SetError(cljs.Error{
					Code:    fmt.Sprintf("%.0f", opid),
					Message: fmt.Sprintf("Investigator ID '%.0f' not found", iid)})
				respond(http.StatusNotFound, resource, respWriter, request)
				return
			} else {
				panic(err)
			}
		}
	} else {
		// bad request, return 400
		resource.SetError(cljs.Error{
			Code:    fmt.Sprintf("%.0f", opid),
			Message: fmt.Sprintf("Invalid Investigator ID '%.0f'", iid)})
		respond(http.StatusBadRequest, resource, respWriter, request)
		return
	}
	// store the results in the resource
	investigatorItem, err := investigatorToItem(inv)
	if err != nil {
		panic(err)
	}
	resource.AddItem(investigatorItem)
	respond(http.StatusOK, resource, respWriter, request)
}
Example #10
0
// getCommand takes an actionid and a commandid and returns a command
func getCommand(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := getOpID(request)
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			emsg := fmt.Sprintf("%v", e)
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: emsg}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: emsg})
			respond(500, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getCommand()"}.Debug()
	}()
	commandID, err := strconv.ParseFloat(request.URL.Query()["commandid"][0], 64)
	if err != nil {
		err = fmt.Errorf("Wrong parameters 'commandid': '%v'", err)
		panic(err)
	}

	// retrieve the command
	var cmd mig.Command
	if commandID > 0 {
		cmd, err = ctx.DB.CommandByID(commandID)
		if err != nil {
			if fmt.Sprintf("%v", err) == "Error while retrieving command: 'sql: no rows in result set'" {
				// not found, return 404
				resource.SetError(cljs.Error{
					Code:    fmt.Sprintf("%.0f", opid),
					Message: fmt.Sprintf("Command ID '%.0f' not found", commandID)})
				respond(404, resource, respWriter, request)
				return
			} else {
				panic(err)
			}
		}
	} else {
		// bad request, return 400
		resource.SetError(cljs.Error{
			Code:    fmt.Sprintf("%.0f", opid),
			Message: fmt.Sprintf("Invalid Command ID '%.0f'", commandID)})
		respond(400, resource, respWriter, request)
		return
	}
	// store the results in the resource
	commandItem, err := commandToItem(cmd)
	if err != nil {
		panic(err)
	}
	resource.AddItem(commandItem)
	respond(200, resource, respWriter, request)
}
Example #11
0
File: api.go Project: Novemburr/mig
func getDashboard(respWriter http.ResponseWriter, request *http.Request) {
	var (
		err         error
		agentsStats mig.AgentsStats
	)
	opid := getOpID(request)
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getDashboard()"}.Debug()
	}()
	stats, err := ctx.DB.GetAgentsStats(1)
	if err != nil {
		panic(err)
	}
	if len(stats) > 1 {
		panic(fmt.Sprintf("expected 1 set of agents stats, got %d", len(stats)))
	}
	if len(stats) == 1 {
		agentsStats = stats[0]
		sumItem, err := agentsSummaryToItem(agentsStats, ctx)
		if err != nil {
			panic(err)
		}
		resource.AddItem(sumItem)
	}

	// add the last 10 actions
	actions, err := ctx.DB.LastActions(10)
	if err != nil {
		panic(err)
	}
	for _, action := range actions {
		// retrieve investigators
		action.Investigators, err = ctx.DB.InvestigatorByActionID(action.ID)
		if err != nil {
			panic(err)
		}
		// store the results in the resource
		actionItem, err := actionToItem(action, false, ctx)
		if err != nil {
			panic(err)
		}
		resource.AddItem(actionItem)
	}
	respond(200, resource, respWriter, request)
}
Example #12
0
func searchAgents(respWriter http.ResponseWriter, request *http.Request) {
	opid := mig.GenID()
	resource := cljs.New(request.URL.String())
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%d", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request, opid)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving searchAgents()"}.Debug()
	}()
	respond(501, resource, respWriter, request, opid)
}
Example #13
0
func getAgent(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := getOpID(request)
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getAgentsDashboard()"}.Debug()
	}()
	agentID, err := strconv.ParseFloat(request.URL.Query()["agentid"][0], 64)
	if err != nil {
		err = fmt.Errorf("Wrong parameters 'agentid': '%v'", err)
		panic(err)
	}

	// retrieve the command
	var agt mig.Agent
	if agentID > 0 {
		agt, err = ctx.DB.AgentByID(agentID)
		if err != nil {
			if fmt.Sprintf("%v", err) == "Error while retrieving agent: 'sql: no rows in result set'" {
				// not found, return 404
				resource.SetError(cljs.Error{
					Code:    fmt.Sprintf("%.0f", opid),
					Message: fmt.Sprintf("Agent ID '%.0f' not found", agentID)})
				respond(404, resource, respWriter, request)
				return
			} else {
				panic(err)
			}
		}
	} else {
		// bad request, return 400
		resource.SetError(cljs.Error{
			Code:    fmt.Sprintf("%.0f", opid),
			Message: fmt.Sprintf("Invalid Agent ID '%.0f'", agentID)})
		respond(400, resource, respWriter, request)
		return
	}
	// store the results in the resource
	agentItem, err := agentToItem(agt)
	if err != nil {
		panic(err)
	}
	resource.AddItem(agentItem)
	respond(200, resource, respWriter, request)
}
Example #14
0
// authenticateLoader is used to authenticate requests that are made to the
// loader API endpoints. Rather than operate on GPG signatures, the
// authentication instead uses the submitted loader key
func authenticateLoader(pass handler) handler {
	return func(w http.ResponseWriter, r *http.Request) {
		var (
			err error
			ldr mig.LoaderEntry
		)
		opid := getOpID(r)
		context.Set(r, opID, opid)
		context.Set(r, apiRequestCategory, RequestCategoryLoader)
		lkey := r.Header.Get("X-LOADERKEY")
		if lkey == "" {
			resource := cljs.New(fmt.Sprintf("%s%s", ctx.Server.Host, r.URL.String()))
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: "X-LOADERKEY header not found"})
			respond(http.StatusUnauthorized, resource, w, r)
			return
		}
		err = mig.ValidateLoaderPrefixAndKey(lkey)
		if err != nil {
			goto authfailed
		}

		ldr, err = hashAuthenticateLoader(lkey)
		if err != nil {
			goto authfailed
		}
		context.Set(r, loaderID, ldr.ID)
		context.Set(r, loaderName, ldr.Name)
		// accept request
		pass(w, r)
		return

	authfailed:
		context.Set(r, loaderName, "authfailed")
		resource := cljs.New(fmt.Sprintf("%s%s", ctx.Server.Host, r.URL.String()))
		resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("Loader authorization failed")})
		respond(http.StatusUnauthorized, resource, w, r)
	}
}
Example #15
0
File: api.go Project: Novemburr/mig
// authenticate is called prior to processing incoming requests. it implements the client
// authentication logic, which mostly consist of validating GPG signed tokens and setting the
// identity of the signer in the request context
func authenticate(pass handler) handler {
	return func(w http.ResponseWriter, r *http.Request) {
		var (
			err error
			inv mig.Investigator
		)
		opid := getOpID(r)
		context.Set(r, opID, opid)
		if !ctx.Authentication.Enabled {
			inv.Name = "authdisabled"
			inv.ID = 0
			goto authorized
		}
		if r.Header.Get("X-PGPAUTHORIZATION") == "" {
			inv.Name = "authmissing"
			inv.ID = -1
			resource := cljs.New(fmt.Sprintf("%s%s", ctx.Server.Host, r.URL.String()))
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: "X-PGPAUTHORIZATION header not found"})
			respond(401, resource, w, r)
			return
		}
		inv, err = verifySignedToken(r.Header.Get("X-PGPAUTHORIZATION"))
		if err != nil {
			inv.Name = "authfailed"
			inv.ID = -1
			resource := cljs.New(fmt.Sprintf("%s%s", ctx.Server.Host, r.URL.String()))
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("Authorization verification failed with error '%v'", err)})
			respond(401, resource, w, r)
			return
		}
	authorized:
		// store investigator identity in request context
		context.Set(r, authenticatedInvName, inv.Name)
		context.Set(r, authenticatedInvID, inv.ID)
		// accept request
		pass(w, r)
	}
}
Example #16
0
File: api.go Project: netantho/mig
// cancelCommand receives an action ID and a command ID and issues a cancellation order
func cancelCommand(respWriter http.ResponseWriter, request *http.Request) {
	opid := mig.GenID()
	loc := fmt.Sprintf("http://%s:%d%s", ctx.Server.IP, ctx.Server.Port, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request, opid)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving cancelCommand()"}.Debug()
	}()
	respond(501, resource, respWriter, request, opid)
}
Example #17
0
// Change key set on a loader entry
func keyLoader(respWriter http.ResponseWriter, request *http.Request) {
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	opid := getOpID(request)
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(http.StatusInternalServerError, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving keyLoader()"}.Debug()
	}()

	err := request.ParseForm()
	if err != nil {
		panic(err)
	}

	ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("Received loader key change request")}.Debug()

	loaderid, err := strconv.ParseFloat(request.FormValue("loaderid"), 64)
	if err != nil {
		panic(err)
	}
	lkey := request.FormValue("loaderkey")
	if lkey == "" {
		// bad request, return 400
		resource.SetError(cljs.Error{
			Code:    fmt.Sprintf("%.0f", opid),
			Message: "Invalid key specified"})
		respond(http.StatusBadRequest, resource, respWriter, request)
		return
	}
	err = mig.ValidateLoaderKey(lkey)
	if err != nil {
		panic(err)
	}
	hashkey, salt, err := hashLoaderKey(lkey, nil)
	if err != nil {
		panic(err)
	}
	err = ctx.DB.LoaderUpdateKey(loaderid, hashkey, salt)
	if err != nil {
		panic(err)
	}

	respond(http.StatusOK, resource, respWriter, request)
}
Example #18
0
// Manipulate the status of an existing manifest
func statusManifest(respWriter http.ResponseWriter, request *http.Request) {
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	opid := getOpID(request)
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(http.StatusInternalServerError, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving statusManifest()"}.Debug()
	}()

	err := request.ParseForm()
	if err != nil {
		panic(err)
	}

	ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("Received manifest status change request")}.Debug()

	manifestid, err := strconv.ParseFloat(request.FormValue("manifestid"), 64)
	if err != nil {
		panic(err)
	}
	sts := request.FormValue("status")
	// A manifest can only be marked as staged, or disabled. Once a
	// manifest has been disabled, it's status can no longer be changed.
	if sts == "staged" {
		err = ctx.DB.ManifestClearSignatures(manifestid)
		if err != nil {
			panic(err)
		}
		err = ctx.DB.ManifestUpdateStatus(manifestid, ctx.Manifest.RequiredSignatures)
		if err != nil {
			panic(err)
		}
	} else if sts == "disabled" {
		err = ctx.DB.ManifestDisable(manifestid)
		if err != nil {
			panic(err)
		}
	} else {
		panic("Invalid status specified, must be disabled or staged")
	}

	respond(http.StatusOK, resource, respWriter, request)
}
Example #19
0
// Return information describing an existing loader entry
func getLoader(respWriter http.ResponseWriter, request *http.Request) {
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	opid := getOpID(request)
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(http.StatusInternalServerError, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getLoader()"}.Debug()
	}()
	lid, err := strconv.ParseFloat(request.URL.Query()["loaderid"][0], 64)
	if err != nil {
		err = fmt.Errorf("Wrong parameters 'loaderid': '%v'", err)
		panic(err)
	}

	var le mig.LoaderEntry
	if lid > 0 {
		le, err = ctx.DB.GetLoaderFromID(lid)
		if err != nil {
			if fmt.Sprintf("%v", err) == "Error while retrieving loader: 'sql: no rows in result set'" {
				resource.SetError(cljs.Error{
					Code:    fmt.Sprintf("%.0f", opid),
					Message: fmt.Sprintf("Loader ID '%.0f' not found", lid)})
				respond(http.StatusNotFound, resource, respWriter, request)
				return
			} else {
				panic(err)
			}
		}
	} else {
		// bad request, return 400
		resource.SetError(cljs.Error{
			Code:    fmt.Sprintf("%.0f", opid),
			Message: fmt.Sprintf("Invalid Loader ID '%.0f'", lid)})
		respond(http.StatusBadRequest, resource, respWriter, request)
		return
	}
	li, err := loaderEntryToItem(le, ctx)
	if err != nil {
		panic(err)
	}
	resource.AddItem(li)
	respond(http.StatusOK, resource, respWriter, request)
}
Example #20
0
// Add a new loader entry
func newLoader(respWriter http.ResponseWriter, request *http.Request) {
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	opid := getOpID(request)
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(http.StatusInternalServerError, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving newLoader()"}.Debug()
	}()

	err := request.ParseForm()
	if err != nil {
		panic(err)
	}

	ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("Received new loader request")}.Debug()

	lestr := request.FormValue("loader")
	if lestr == "" {
		panic("no loader entry specified in form")
	}
	var le mig.LoaderEntry
	err = json.Unmarshal([]byte(lestr), &le)
	if err != nil {
		panic(err)
	}
	err = le.Validate()
	if err != nil {
		panic(err)
	}
	// Hash the loader key to provide it to LoaderAdd
	hkey, salt, err := hashLoaderKey(le.Key, nil)
	if err != nil {
		panic(err)
	}
	err = ctx.DB.LoaderAdd(le, hkey, salt)
	if err != nil {
		panic(err)
	}

	respond(http.StatusCreated, resource, respWriter, request)
}
Example #21
0
// updateInvestigator updates the status of an investigator in database
func updateInvestigator(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := getOpID(request)
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			emsg := fmt.Sprintf("%v", e)
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: emsg}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: emsg})
			respond(500, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving updateInvestigator()"}.Debug()
	}()
	var inv mig.Investigator
	err = request.ParseForm()
	if err != nil {
		panic(err)
	}
	iid := request.FormValue("id")
	if iid == "" {
		panic("Investigator ID must not be empty")
	}
	inv.ID, err = strconv.ParseFloat(iid, 64)
	if err != nil {
		panic(err)
	}
	inv.Status = request.FormValue("status")
	if inv.Status == "" {
		panic("Investigator status must not be empty")
	}
	// create the investigator in database
	err = ctx.DB.UpdateInvestigatorStatus(inv)
	if err != nil {
		panic(err)
	}
	ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("Investigator %.0f status changed to %s", inv.ID, inv.Status)}
	err = resource.AddItem(cljs.Item{
		Href: fmt.Sprintf("%s/investigator?investigatorid=%.0f", ctx.Server.BaseURL, inv.ID),
		Data: []cljs.Data{{Name: "Investigator ID " + fmt.Sprintf("%.0f", inv.ID), Value: inv}},
	})
	respond(200, resource, respWriter, request)
}
Example #22
0
func getAPIResource(t string, ctx Context) (resource *cljs.Resource, err error) {
	resp, err := ctx.HTTP.Client.Get(t)
	if err != nil {
		return
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	resource = cljs.New("")
	err = json.Unmarshal(body, &resource)
	if err != nil {
		return
	}
	if resp.StatusCode != 200 {
		err = fmt.Errorf("HTTP %d: %v (code %s)", resp.StatusCode, resource.Collection.Error.Message, resource.Collection.Error.Code)
		return
	}
	return
}
Example #23
0
// Add a new manifest record
func newManifest(respWriter http.ResponseWriter, request *http.Request) {
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	opid := getOpID(request)
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(http.StatusInternalServerError, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving newManifest()"}.Debug()
	}()

	err := request.ParseForm()
	if err != nil {
		panic(err)
	}

	ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("Received new manifest request")}.Debug()

	mrstr := request.FormValue("manifest")
	if mrstr == "" {
		panic("no manifest record specified in form")
	}
	var mr mig.ManifestRecord
	err = json.Unmarshal([]byte(mrstr), &mr)
	if err != nil {
		panic(err)
	}
	err = mr.Validate()
	if err != nil {
		panic(err)
	}
	err = ctx.DB.ManifestAdd(mr)
	if err != nil {
		panic(err)
	}

	respond(http.StatusCreated, resource, respWriter, request)
}
Example #24
0
// describeCreateAction returns a resource that describes how to POST new actions
func describeCreateAction(respWriter http.ResponseWriter, request *http.Request) {
	opid := mig.GenID()
	resource := cljs.New(request.URL.Path)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%d", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request, opid)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving describeCreateAction()"}.Debug()
	}()

	err := resource.SetTemplate(cljs.Template{
		Data: []cljs.Data{
			{Name: "action", Value: "", Prompt: "Signed MIG Action"},
		},
	})
	if err != nil {
		panic(err)
	}
	respond(200, resource, respWriter, request, opid)
}
Example #25
0
// describeCancelCommand returns a resource that describes how to cancel a command
func describeCancelCommand(respWriter http.ResponseWriter, request *http.Request) {
	opid := mig.GenID()
	resource := cljs.New(request.URL.String())
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%d", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request, opid)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving describeCancelCommand()"}.Debug()
	}()
	err := resource.SetTemplate(cljs.Template{
		Data: []cljs.Data{
			{Name: "actionid", Value: "[0-9]{1,20}", Prompt: "Action ID"},
			{Name: "commandid", Value: "[0-9]{1,20}", Prompt: "Command ID"},
		},
	})
	if err != nil {
		panic(err)
	}
	respond(200, resource, respWriter, request, opid)
}
Example #26
0
// getAction queries the database and retrieves the detail of an action
func getAction(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := mig.GenID()
	resource := cljs.New(request.URL.String())
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%d", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request, opid)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving getAction()"}.Debug()
	}()
	actionID, err := strconv.Atoi(request.URL.Query()["actionid"][0])
	if err != nil {
		panic(err)
	}

	// retrieve the action
	eas := []mig.ExtendedAction{}
	iter := ctx.DB.Col.Action.Find(bson.M{"action.id": actionID}).Iter()
	err = iter.All(&eas)
	if err != nil {
		panic(err)
	}
	if len(eas) == 0 {
		resource.SetError(cljs.Error{Code: fmt.Sprintf("%d", opid), Message: "Action not found"})
		respond(404, resource, respWriter, request, opid)
	}
	// store the results in the resource
	for _, ea := range eas {
		actionItem, err := extendedActionToItem(ea)
		if err != nil {
			panic(err)
		}
		resource.AddItem(actionItem)
	}

	respond(200, resource, respWriter, request, opid)
}
Example #27
0
// search is a generic function to run queries against mongodb
func search(respWriter http.ResponseWriter, request *http.Request) {
	opid := mig.GenID()
	resource := cljs.New(request.URL.String())
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%d", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request, opid)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving describeCreateAction()"}.Debug()
	}()

	search := request.URL.Query()["search"][0]
	switch search {
	case "positiveresults":
		actionID, err := strconv.Atoi(request.URL.Query()["actionid"][0])
		if err != nil {
			panic(err)
		}
		cmds, err := findPositiveResults(actionID)
		if err != nil {
			panic(err)
		}
		// store the results in the resource
		for _, cmd := range cmds {
			commandItem, err := commandToItem(cmd)
			if err != nil {
				panic(err)
			}
			resource.AddItem(commandItem)
		}
		respond(200, resource, respWriter, request, opid)

	default:
		panic("unknown search method")
	}
}
Example #28
0
// Request to sign an existing manifest
func signManifest(respWriter http.ResponseWriter, request *http.Request) {
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	opid := getOpID(request)
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(http.StatusInternalServerError, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving signManifest()"}.Debug()
	}()

	err := request.ParseForm()
	if err != nil {
		panic(err)
	}

	ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("Received manifest sign request")}.Debug()

	manifestid, err := strconv.ParseFloat(request.FormValue("manifestid"), 64)
	if err != nil {
		panic(err)
	}
	sig := request.FormValue("signature")
	if sig == "" {
		panic("Invalid signature specified")
	}

	err = ctx.DB.ManifestAddSignature(manifestid, sig, getInvID(request),
		ctx.Manifest.RequiredSignatures)
	if err != nil {
		panic(err)
	}

	respond(http.StatusOK, resource, respWriter, request)
}
Example #29
0
// Enable or disable a loader entry
func statusLoader(respWriter http.ResponseWriter, request *http.Request) {
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	opid := getOpID(request)
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(http.StatusInternalServerError, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving statusLoader()"}.Debug()
	}()

	err := request.ParseForm()
	if err != nil {
		panic(err)
	}

	ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("Received loader status change request")}.Debug()

	loaderid, err := strconv.ParseFloat(request.FormValue("loaderid"), 64)
	if err != nil {
		panic(err)
	}
	sts := request.FormValue("status")
	var setval bool
	if sts == "enabled" {
		setval = true
	}
	err = ctx.DB.LoaderUpdateStatus(loaderid, setval)
	if err != nil {
		panic(err)
	}

	respond(http.StatusOK, resource, respWriter, request)
}
Example #30
0
// describeCreateAction returns a resource that describes how to POST new actions
func describeCreateAction(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := getOpID(request)
	loc := fmt.Sprintf("%s%s", ctx.Server.Host, request.URL.String())
	resource := cljs.New(loc)
	defer func() {
		if e := recover(); e != nil {
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving describeCreateAction()"}.Debug()
	}()

	err = resource.SetTemplate(cljs.Template{
		Data: []cljs.Data{
			{Name: "action", Value: "URL encoded signed MIG action", Prompt: "Signed MIG Action"},
		},
	})
	if err != nil {
		panic(err)
	}
	respond(200, resource, respWriter, request)
}