// 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) } }
// Attempt to obtain the loader key from the file system and override the // built-in secret func loadLoaderKey() error { fd, err := os.Open(getLoaderKeyfile()) if err != nil { if os.IsNotExist(err) { return nil } return err } defer fd.Close() buf, _, err := bufio.NewReader(fd).ReadLine() if err != nil { // Nothing in the loader key file if err == io.EOF { return nil } return err } // Also trim any leading and trailing spaces from the loader key LOADERKEY = strings.Trim(string(buf), " ") err = mig.ValidateLoaderKey(LOADERKEY) if err != nil { return err } ctx.LoaderKey = LOADERKEY return nil }
// 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) }
// Change the key on an existing loader entry func (cli Client) LoaderEntryKey(le mig.LoaderEntry, key string) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("LoaderEntryKey() -> %v", e) } }() if key == "" { panic("invalid loader key specified") } err = mig.ValidateLoaderKey(key) if err != nil { panic(err) } data := url.Values{"loaderid": {fmt.Sprintf("%.0f", le.ID)}, "loaderkey": {key}} r, err := http.NewRequest("POST", cli.Conf.API.URL+"loader/key/", strings.NewReader(data.Encode())) if err != nil { panic(err) } r.Header.Set("Content-Type", "application/x-www-form-urlencoded") resp, err := cli.Do(r) if err != nil { panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } var resource *cljs.Resource if len(body) > 1 { err = json.Unmarshal(body, &resource) if err != nil { panic(err) } } if resp.StatusCode != http.StatusOK { err = fmt.Errorf("error: HTTP %d. Key update failed with error '%v' (code %s).", resp.StatusCode, resource.Collection.Error.Message, resource.Collection.Error.Code) panic(err) } return }