// Tests that the context is cleared or not cleared properly depending on // the configuration of the router func TestKeepContext(t *testing.T) { func1 := func(w http.ResponseWriter, r *http.Request) {} r := NewRouter() r.HandleFunc("/", func1).Name("func1") req, _ := http.NewRequest("GET", "http://localhost/", nil) context.Set(req, "t", 1) res := new(http.ResponseWriter) r.ServeHTTP(*res, req) if _, ok := context.GetOk(req, "t"); ok { t.Error("Context should have been cleared at end of request") } r.KeepContext = true req, _ = http.NewRequest("GET", "http://localhost/", nil) context.Set(req, "t", 1) r.ServeHTTP(*res, req) if _, ok := context.GetOk(req, "t"); !ok { t.Error("Context should NOT have been cleared at end of request") } }
func UserTFAPage(w http.ResponseWriter, req *http.Request) { args := handlers.GetArgs(req) u := quimby.NewUser(args.Vars["username"], quimby.UserDB(args.DB), quimby.UserTFA(handlers.TFA)) if err := u.Fetch(); err != nil { context.Set(req, "error", err) return } qrData, err := u.UpdateTFA() if err != nil { context.Set(req, "error", err) return } if _, err := u.Save(); err != nil { context.Set(req, "error", err) return } qr := qrPage{ userPage: userPage{ User: args.User.Username, Admin: handlers.Admin(args), Links: []link{ {"quimby", "/"}, {"admin", "/admin.html"}, }, }, QR: template.HTMLAttr(base64.StdEncoding.EncodeToString(qrData)), } templates["qr-code.html"].template.ExecuteTemplate(w, "base", qr) }
// Authorize authorizes the request func (c *Context) Authorize(request *http.Request, route *MatchedRoute) (interface{}, error) { if len(route.Authenticators) == 0 { return nil, nil } if v, ok := context.GetOk(request, ctxSecurityPrincipal); ok { return v, nil } var lastError error for scheme, authenticator := range route.Authenticators { applies, usr, err := authenticator.Authenticate(&security.ScopedAuthRequest{ Request: request, RequiredScopes: route.Scopes[scheme], }) if !applies || err != nil || usr == nil { if err != nil { lastError = err } continue } context.Set(request, ctxSecurityPrincipal, usr) context.Set(request, ctxSecurityScopes, route.Scopes[scheme]) return usr, nil } if lastError != nil { return nil, lastError } return nil, errors.Unauthenticated("invalid credentials") }
// SetUser is a HTTP middleware for setting the user and build information. func SetUser(h http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { context.Set(req, csrf.TemplateTag, csrf.TemplateField(req)) // Set CSRF field everywhere context.Set(req, "Version", Version) context.Set(req, "Branch", Branch) context.Set(req, "user", &Account{}) ses, err := store.Get(req, "evemu") if err != nil { log.Printf("Failed to get session cookie: %s", err.Error()) h.ServeHTTP(rw, req) return } if v, ok := ses.Values["user"]; ok { if v.(int) == 0 { h.ServeHTTP(rw, req) return } //a, err := DBAccountFromID(v.(int)) a, err := Layer.GetAccountFromID(v.(int)) // TODO: Unsafe, may panic if err != nil { log.Printf("Failed to get account from id: %s", err.Error()) h.ServeHTTP(rw, req) return } context.Set(req, "user", a) } h.ServeHTTP(rw, req) }) }
func TestBuildURL(t *testing.T) { assert := assert.New(t) api := NewAPI(NewConfiguration()) api.RegisterResourceHandler(TestResourceHandler{}) api.RegisterResourceHandler(ComplexTestResourceHandler{}) req, _ := http.NewRequest("GET", "https://example.com/api/v1/widgets", nil) gContext.Set(req, "version", "1") ctx := NewContextWithRouter(nil, req, api.(*muxAPI).router) url, _ := ctx.BuildURL("widgets", HandleCreate, nil) assert.Equal(url, "http://example.com/api/v1/widgets") url, _ = ctx.BuildURL("widgets", HandleRead, RouteVars{"resource_id": "111"}) assert.Equal(url, "http://example.com/api/v1/widgets/111") url, _ = ctx.BuildPath("widgets", HandleRead, RouteVars{"resource_id": "111"}) assert.Equal(url, "/api/v1/widgets/111") // Secure request should produce https URL req.TLS = &tls.ConnectionState{} url, _ = ctx.BuildURL("widgets", HandleRead, RouteVars{"resource_id": "222"}) assert.Equal(url, "https://example.com/api/v1/widgets/222") // Make sure this works with another version number gContext.Set(req, "version", "2") url, _ = ctx.BuildURL("resources", HandleCreate, RouteVars{ "company": "acme", "category": "anvils"}) assert.Equal(url, "https://example.com/api/v2/acme/anvils/resources") }
func UpdateGadget(w http.ResponseWriter, req *http.Request) { args := GetArgs(req) var g quimby.Gadget dec := json.NewDecoder(req.Body) err := dec.Decode(&g) if err != nil { context.Set(req, "error", err) return // err } g.DB = args.DB g.Id = args.Vars["id"] err = g.Save() if err != nil { context.Set(req, "error", err) return // err } u, err := url.Parse(fmt.Sprintf("/api/gadgets/%s", g.Id)) if err != nil { context.Set(req, "error", err) return //err } w.Header().Set("Location", u.String()) }
func UserChangePasswordPage(w http.ResponseWriter, req *http.Request) { args := handlers.GetArgs(req) u := quimby.NewUser(args.Vars["username"], quimby.UserDB(args.DB)) if err := u.Fetch(); err != nil { context.Set(req, "error", err) return } if err := req.ParseForm(); err != nil { context.Set(req, "error", err) return } u.Password = req.PostFormValue("password") pw := req.PostFormValue("password_confirm") if pw != u.Password { context.Set(req, "error", ErrPasswordsDoNotMatch) return } if _, err := u.Save(); err != nil { context.Set(req, "error", ErrPasswordsDoNotMatch) return } w.Header().Set("Location", "/admin.html") w.WriteHeader(http.StatusFound) }
func HandlerRegister(rw http.ResponseWriter, req *http.Request) { switch req.Method { case "POST": username := req.FormValue("username") password := req.FormValue("password") password2 := req.FormValue("password-c") if username == "" { context.Set(req, "error", fmt.Errorf("Username can't be blank")) DoTemplate("error.tmpl", rw, req) return } if password == "" || password == "" { context.Set(req, "error", fmt.Errorf("The passwords can't be blank")) DoTemplate("error.tmpl", rw, req) return } if password != password2 { context.Set(req, "error", fmt.Errorf("The passwords didn't match")) DoTemplate("error.tmpl", rw, req) return } err := Layer.NewAccount(username, password) if err != nil { context.Set(req, "error", err) DoTemplate("error.tmpl", rw, req) return } context.Set(req, "registered", true) } DoTemplate("register.tmpl", rw, req) }
func (rc *ResourceController) CreateHandler(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { decoder := json.NewDecoder(r.Body) resource := models.NewStructForResourceName(rc.Name) err := decoder.Decode(resource) if err != nil { http.Error(rw, err.Error(), http.StatusInternalServerError) } c := Database.C(models.PluralizeLowerResourceName(rc.Name)) i := bson.NewObjectId() reflect.ValueOf(resource).Elem().FieldByName("Id").SetString(i.Hex()) err = c.Insert(resource) if err != nil { http.Error(rw, err.Error(), http.StatusInternalServerError) } context.Set(r, rc.Name, resource) context.Set(r, "Resource", rc.Name) context.Set(r, "Action", "create") rw.Header().Add("Location", responseURL(r, rc.Name, i.Hex()).String()) rw.Header().Set("Content-Type", "application/json; charset=utf-8") rw.Header().Set("Access-Control-Allow-Origin", "*") rw.WriteHeader(http.StatusCreated) json.NewEncoder(rw).Encode(resource) }
// GetContext wraps each request in a function which fills in the context for a given request. // This includes setting the User and Session keys and values as necessary for use in later functions. func GetContext(handler http.Handler) http.HandlerFunc { // Set the context here return func(w http.ResponseWriter, r *http.Request) { // Parse the request form err := r.ParseForm() if err != nil { http.Error(w, "Error parsing request", http.StatusInternalServerError) } // Set the context appropriately here. // Set the session session, _ := auth.Store.Get(r, "gophish") // Put the session in the context so that ctx.Set(r, "session", session) if id, ok := session.Values["id"]; ok { u, err := models.GetUser(id.(int64)) if err != nil { ctx.Set(r, "user", nil) } else { ctx.Set(r, "user", u) } } else { ctx.Set(r, "user", nil) } handler.ServeHTTP(w, r) // Remove context contents ctx.Clear(r) } }
// TODO: Do something when the user doesn't POST here func HandlerLogin(rw http.ResponseWriter, req *http.Request) { switch req.Method { case "POST": username := req.FormValue("username") password := req.FormValue("password") a, err := Layer.Login(username, password) if err == sql.ErrNoRows { context.Set(req, "error", fmt.Errorf("db: User doesn't exist")) DoTemplate("error.tmpl", rw, req) return } else if err != nil { context.Set(req, "error", err) context.Set(req, "stack", string(debug.Stack())) DoTemplate("500.tmpl", rw, req) return } context.Set(req, "user", *a) ses, err := store.Get(req, "evemu") if err != nil { context.Set(req, "error", err) DoTemplate("500.tmpl", rw, req) return } ses.Values["user"] = a.ID ses.Save(req, rw) http.Redirect(rw, req, "/", http.StatusFound) } }
// 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) } }
// NewContext returns a RequestContext populated with parameters from the request path and // query string. func NewContext(parent context.Context, req *http.Request) RequestContext { if parent == nil { parent = context.Background() } for key, value := range req.URL.Query() { var val interface{} val = value // Query string values are slices (e.g. ?foo=bar,baz,qux yields // [bar, baz, qux] for foo), but we unbox single values (e.g. ?foo=bar // yields bar for foo). if len(value) == 1 { val = value[0] } gcontext.Set(req, key, val) } for key, value := range mux.Vars(req) { gcontext.Set(req, key, value) } // TODO: Keys can potentially be overwritten if the request path has // parameters with the same name as query string values. Figure out a // better way to handle this. return &gorillaRequestContext{parent, req, []string{}} }
func (sm *ServiceManager) authenticateRequest(r *http.Request) (username string, err error) { isAdmin := false token, err := auth.GetTokenFromRequest(r, []byte(sm.cfg.Auth.Token.SigningKey)) if err == nil { sm.log.Tracef("Token validated: %#v\n", *token) username = token.Claims["sub"].(string) if _, ok := token.Claims["admin"]; ok { isAdmin, _ = token.Claims["admin"].(bool) } } else if strings.Contains(err.Error(), "expired") { return } else { sm.log.Debugf("Skipping token auth: %s\n", err) var cacheHit bool if username, cacheHit, err = sm.authenticator.AuthenticateRequest(r); err != nil { return } sm.log.Tracef("Cache hit (%s): %v\n", username, cacheHit) isAdmin = sm.localAuthGroups.UserHasGroupMembership(username, "admin") } sm.log.Tracef("Setting request context: IsAdmin=%v\n", isAdmin) context.Set(r, handlers.IsAdmin, isAdmin) sm.log.Tracef("Setting request context: Username=%s\n", username) context.Set(r, handlers.Username, username) return }
// ServeHTTP as per the negroni.Handler interface func (m *MixedAuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { // HTTPS redirection err := util.NewSecure(m.service.GetConfig().IsDevelopment).Process(w, r) if err != nil { return } account, user, err := getMixedCredentialsFromRequest(r, m.service) if err != nil { // For security reasons, return a generic error message response.UnauthorizedError(w, ErrAccountOrUserAuthenticationRequired.Error()) return } if account != nil { context.Set(r, AuthenticatedAccountKey, account) } if user != nil { context.Set(r, AuthenticatedUserKey, user) } next(w, r) }
func (k *AuthKey) ProcessRequest(w http.ResponseWriter, r *http.Request, configuration interface{}) (error, int) { var thisConfig AuthKeyConfiguration thisConfig = configuration.(AuthKeyConfiguration) authHeaderValue := r.Header.Get(thisConfig.Auth.AuthHeaderName) if authHeaderValue == "" { // No header value, fail log.WithFields(logrus.Fields{ "path": r.URL.Path, "origin": r.RemoteAddr, }).Info("Attempted access with malformed header, no auth header found.") return errors.New("Authorization field missing"), 400 } // Check if API key valid thisSessionState, keyExists := k.TykMiddleware.CheckSessionAndIdentityForValidKey(authHeaderValue) if !keyExists { log.WithFields(logrus.Fields{ "path": r.URL.Path, "origin": r.RemoteAddr, "key": authHeaderValue, }).Info("Attempted access with non-existent key.") return errors.New("Key not authorised"), 403 } // Set session state on context, we will need it later context.Set(r, SessionData, thisSessionState) context.Set(r, AuthHeaderValue, authHeaderValue) return nil, 200 }
func (rc *ResourceController) UpdateHandler(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { var id bson.ObjectId idString := mux.Vars(r)["id"] if bson.IsObjectIdHex(idString) { id = bson.ObjectIdHex(idString) } else { http.Error(rw, "Invalid id", http.StatusBadRequest) } decoder := json.NewDecoder(r.Body) resource := models.NewStructForResourceName(rc.Name) err := decoder.Decode(resource) if err != nil { http.Error(rw, err.Error(), http.StatusInternalServerError) } c := Database.C(models.PluralizeLowerResourceName(rc.Name)) reflect.ValueOf(resource).Elem().FieldByName("Id").SetString(id.Hex()) err = c.Update(bson.M{"_id": id.Hex()}, resource) if err != nil { http.Error(rw, err.Error(), http.StatusInternalServerError) } context.Set(r, rc.Name, resource) context.Set(r, "Resource", rc.Name) context.Set(r, "Action", "update") rw.Header().Set("Content-Type", "application/json; charset=utf-8") rw.Header().Set("Access-Control-Allow-Origin", "*") json.NewEncoder(rw).Encode(resource) }
func bindPost(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { if r.Header["Content-Type"][0] == "application/json" { var post Post decoder := json.NewDecoder(r.Body) err := decoder.Decode(&post) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } context.Set(r, "post", post) next.ServeHTTP(w, r) return } r.ParseForm() title := r.PostFormValue("title") if title == "" { http.Error(w, "Title is required.", http.StatusBadRequest) return } var post Post post.Title = title post.Markdown = r.PostFormValue("markdown") context.Set(r, "post", post) next.ServeHTTP(w, r) } return http.HandlerFunc(fn) }
func (h *logHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { snapshot := h.logger.NewSnapshot(r) capture := h.logger.NewCapture(w) additional := &bytes.Buffer{} values := make(map[interface{}]interface{}) context.Set(r, kBufferKey, additional) context.Set(r, kValuesKey, values) startTime := h.now() defer func() { endTime := h.now() err := recover() maybeSend500(capture) h.writeLogRecord( &LogRecord{ T: startTime, R: snapshot, W: capture, Duration: endTime.Sub(startTime), Extra: additional.String(), Values: values}) if err != nil { h.writePanic(err, debug.Stack()) } }() h.handler.ServeHTTP(capture, r) }
func bindSearch(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { if r.Header["Content-Type"][0] == "application/json" { var search Search decoder := json.NewDecoder(r.Body) err := decoder.Decode(&search) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } context.Set(r, "search", search) next.ServeHTTP(w, r) return } r.ParseForm() query := r.PostFormValue("query") if query == "" { http.Error(w, "Query is required.", http.StatusBadRequest) return } var search Search search.Query = query context.Set(r, "search", search) next.ServeHTTP(w, r) } return http.HandlerFunc(fn) }
func RequireAPIKey(handler http.Handler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { r.ParseForm() ak := r.Form.Get("api_key") w.Header().Set("Access-Control-Allow-Origin", "*") if r.Method == "OPTIONS" { w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS") w.Header().Set("Access-Control-Max-Age", "1000") w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept") return } if ak == "" { JSONError(w, 400, "API Key not set") } else { u, err := models.GetUserByAPIKey(ak) if err != nil { JSONError(w, 400, "Invalid API Key") return } ctx.Set(r, "user_id", u.Id) ctx.Set(r, "api_key", ak) handler.ServeHTTP(w, r) } } }
func (sc *ServiceContext) CheckAccess(request *http.Request) bool { // if no authentication set, allow request if sc.authentication == nil { return true } // check cookie, if set = authenticated user := getUser(request) if user != "" { // set user in context for modules to pick the username // and get details about the user // In authenticated scenarios with login, it can be // fetched from cookies, but in BasicAuth on the service // layer, it needs to be fetched with every request, if needed context.Set(request, PropContextUser, user) return true } //check basic auth if buser, bpwd, ok := request.BasicAuth(); ok { if ba := sc.authentication.CheckLogin(buser, bpwd); ba != nil { // set user name in context context.Set(request, PropContextUser, buser) return true } } return false }
func (k *AuthKey) ProcessRequest(w http.ResponseWriter, r *http.Request, configuration interface{}) (error, int) { thisConfig := k.TykMiddleware.Spec.APIDefinition.Auth authHeaderValue := r.Header.Get(thisConfig.AuthHeaderName) if thisConfig.UseParam { tempRes := new(http.Request) *tempRes = *r defer r.Body.Close() // Buffer body data - don't like thi but we would otherwise drain the request body var bodyBuffer bytes.Buffer bodyBuffer2 := new(bytes.Buffer) k.copyResponse(&bodyBuffer, r.Body) *bodyBuffer2 = bodyBuffer // Create new ReadClosers so we can split output r.Body = ioutil.NopCloser(&bodyBuffer) tempRes.Body = ioutil.NopCloser(bodyBuffer2) // Set hte header name authHeaderValue = tempRes.FormValue(thisConfig.AuthHeaderName) } if authHeaderValue == "" { // No header value, fail log.WithFields(logrus.Fields{ "path": r.URL.Path, "origin": r.RemoteAddr, }).Info("Attempted access with malformed header, no auth header found.") return errors.New("Authorization field missing"), 400 } // Check if API key valid thisSessionState, keyExists := k.TykMiddleware.CheckSessionAndIdentityForValidKey(authHeaderValue) if !keyExists { log.WithFields(logrus.Fields{ "path": r.URL.Path, "origin": r.RemoteAddr, "key": authHeaderValue, }).Info("Attempted access with non-existent key.") // Fire Authfailed Event AuthFailed(k.TykMiddleware, r, authHeaderValue) // Report in health check ReportHealthCheckValue(k.Spec.Health, KeyFailure, "1") return errors.New("Key not authorised"), 403 } // Set session state on context, we will need it later context.Set(r, SessionData, thisSessionState) context.Set(r, AuthHeaderValue, authHeaderValue) return nil, 200 }
func (ah authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { //Check for header presence authzHeader := r.Header.Get("Authorization") if authzHeader == "" { log.Info("Missing Authorization header") w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Unauthorized\n")) return } claims, err := ah.rollAuthZ.ValidateAccessToken(authzHeader) if err != nil { log.Info(err.Error()) w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Unauthorized\n")) } //Check against the whitelist aud, ok := claims["aud"].(string) if !ok { log.Info("aud claim not present in token") w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Unauthorized\n")) return } if !ah.whiteListOK(aud) { log.Info("token failed whitelist check: ", aud) w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Unauthorized\n")) return } sub, ok := claims["sub"].(string) if !ok { log.Info("Unable to extract sub from token claims") w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Unauthorized\n")) return } context.Set(r, AuthzAdminScope, false) scope, ok := claims["scope"].(string) if ok && scope == "admin" { admin, err := ah.adminRepo.IsAdmin(sub) if err != nil { log.Info("error making admin scope determination: ", err.Error()) w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Unauthorized\n")) return } context.Set(r, AuthzAdminScope, admin) } context.Set(r, AuthzSubject, sub) ah.handler.ServeHTTP(w, r) context.Clear(r) }
/* StartAppContext is a middleware that should be early in the chain. This sets up the initial context and attaches important data to the Gorilla Context which comes across in the request. */ func (ctx *AppContext) StartAppContext(h http.Handler) http.Handler { return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { context.Set(request, "config", ctx.Config) context.Set(request, "layout", ctx.Layout) h.ServeHTTP(writer, request) }) }
// TokenAuthenticate authenticates a token from request. func TokenAuthenticate(w http.ResponseWriter, r *http.Request) chatable.CompoundError { token, err := jwt.ParseFromRequest(r, keyfunc) if err != nil || !token.Valid { return ErrUnauthenticated } context.Set(r, "user", token.Header["user"]) context.Set(r, "auth", token.Header["auth"]) return nil }
func DBMiddleware(session *mgo.Session, dbName string) negroni.Handler { return negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { s := session.Clone() defer s.Close() context.Set(r, "dbSession", s) context.Set(r, "DB", s.DB(dbName)) next(w, r) }) }
// PostProcess sets context variables and updates the storage. func (e *BaseExtractor) PostProcess(r *http.Request, thisSessionState SessionState, SessionID string) { var sessionLifetime = GetLifetime(e.Spec, &thisSessionState) e.Spec.SessionManager.UpdateSession(SessionID, thisSessionState, sessionLifetime) context.Set(r, SessionData, thisSessionState) context.Set(r, AuthHeaderValue, SessionID) return }
func TestTransaction(t *testing.T) { defer models.Db.Exec("DELETE FROM users") defer models.Db.Exec("DELETE FROM account") defer models.Db.Exec("DELETE FROM users_account") defer models.Db.Exec("DELETE FROM category") defer models.Db.Exec("DELETE FROM transaction") if err := models.ExecSQLScript("test_transaction.sql"); err != nil { panic(err) } //Create accountID := "3fd155dc-7a6f-4bac-a74b-902df936ed75" body := `{ "label": "myevent", "value": -210.65, "accountId": "3fd155dc-7a6f-4bac-a74b-902df936ed75", "categoryId": "fe36bfe6-bf22-45fe-babd-a3db9d324727" }` request, err := http.NewRequest("PUT", "/api/"+accountID+"/transaction", strings.NewReader(body)) if err != nil { panic(err) } context.Set(request, "currentId", "dc45ef40-1763-4dde-ab0f-978c224495e6") recorder := httptest.NewRecorder() mTransaction.ServeHTTP(recorder, request) if recorder.Code != http.StatusOK { t.Errorf("Bad response code : %d", recorder.Code) } //Get request, err = http.NewRequest("GET", "/api/"+accountID+"/transactions/0/10", nil) context.Set(request, "currentId", "dc45ef40-1763-4dde-ab0f-978c224495e6") if err != nil { panic(err) } recorder = httptest.NewRecorder() m.ServeHTTP(recorder, request) if recorder.Code != http.StatusOK { t.Errorf("Bad response code : %d", recorder.Code) } var transactions []models.Transaction err = json.Unmarshal(recorder.Body.Bytes(), &transactions) if err != nil { t.Errorf("Fail to decode account response %s", err) } if len(transactions) != 1 { t.Errorf("Bad len result : %d != 1", len(transactions)) return } if transactions[0].Label != "myevent" { t.Errorf("Bad account label : ''%s'", transactions[0].Label) } if transactions[0].Value != -210.65 { t.Errorf("Bad account label : ''%s'", transactions[0].Label) } }
// 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) } }