func TestMiddleware(t *testing.T) { m := &Middleware{} for k, c := range cases { h := hcon.NewContextAdapter( context.Background(), mockContext(c), m.IsAuthenticated, ).ThenFunc(hcon.ContextHandlerFunc(handler(m, c))) ts := httptest.NewServer(h) defer ts.Close() res, err := http.Get(ts.URL) require.Nil(t, err) res.Body.Close() if !c.expectAuthN { assert.Equal(t, http.StatusUnauthorized, res.StatusCode, "Authentication failed case %d", k) } else if !c.expectAuthZ { assert.Equal(t, http.StatusForbidden, res.StatusCode, "Authorization failed case %d", k) } else { assert.Equal(t, http.StatusOK, res.StatusCode, "Case %d should be authorized but wasn't.", k) } } }
func (m *Middleware) IsAuthorized(resource, permission string, environment *env) func(hydcon.ContextHandler) hydcon.ContextHandler { return func(next hydcon.ContextHandler) hydcon.ContextHandler { return hydcon.ContextHandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { if environment == nil { environment = Env(req) } policies, err := hydcon.PoliciesFromContext(ctx) if err != nil { log.WithFields(log.Fields{"authorization": "forbidden"}).Warnf(`Policy extraction failed: "%s".`, err) errorHandler(rw, req, http.StatusForbidden) return } subject, err := hydcon.SubjectFromContext(ctx) if err != nil { log.WithFields(log.Fields{"authorization": "forbidden"}).Warnf(`Forbidden! Subject extraction failed: "%s".`, err) errorHandler(rw, req, http.StatusForbidden) return } ok, err := guard.IsGranted(resource, permission, subject, policies, environment.Ctx()) if err != nil || !ok { log.WithFields(log.Fields{"authorization": "forbidden"}).Warnf(`Forbidden! Subject "%s" is not being granted access "%s" to resource "%s".`, subject, permission, resource) errorHandler(rw, req, http.StatusForbidden) return } log.WithFields(log.Fields{"authorization": "success"}).Infof(`Allowed! Granting subject "%s" access "%s" to resource "%s".`, subject, permission, resource) next.ServeHTTPContext(ctx, rw, req) }) } }
func mockAuthorization(c test) func(h hcon.ContextHandler) hcon.ContextHandler { return func(h hcon.ContextHandler) hcon.ContextHandler { return hcon.ContextHandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { claims := hjwt.NewClaimsCarrier(uuid.New(), "hydra", c.subject, "tests", time.Now(), time.Now()) ctx = hcon.NewContextFromAuthValues(ctx, claims, &c.token, c.policies) h.ServeHTTPContext(ctx, rw, req) }) } }
func handler(m *Middleware, c test) func(context.Context, http.ResponseWriter, *http.Request) { return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { m.IsAuthorized(c.resource, c.permission, Env(req).Owner(c.owner))(hcon.ContextHandlerFunc( func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { fmt.Fprintln(rw, "ok") }, )).ServeHTTPContext(ctx, rw, req) } }
func (h *Handler) Delete(ctx context.Context, rw http.ResponseWriter, req *http.Request) { id, ok := mux.Vars(req)["id"] if !ok { http.Error(rw, "No id given.", http.StatusBadRequest) return } h.m.IsAuthorized(permission(id), "delete", middleware.Env(req).Owner(id))(hydcon.ContextHandlerFunc( func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { if err := h.s.Delete(id); err != nil { http.Error(rw, err.Error(), http.StatusInternalServerError) return } rw.WriteHeader(http.StatusAccepted) }), ).ServeHTTPContext(ctx, rw, req) }
func (h *Handler) Delete(ctx context.Context, rw http.ResponseWriter, req *http.Request) { id, ok := mux.Vars(req)["id"] if !ok { http.Error(rw, "No id given.", http.StatusBadRequest) return } h.m.IsAuthorized(permission(id), "delete", nil)(hctx.ContextHandlerFunc( func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { if err := h.s.Delete(id); err != nil { http.Error(rw, fmt.Sprintf("Could not retrieve client: %s", id), http.StatusInternalServerError) return } rw.WriteHeader(http.StatusAccepted) }, )).ServeHTTPContext(ctx, rw, req) }
func (h *Handler) Get(ctx context.Context, rw http.ResponseWriter, req *http.Request) { id, ok := mux.Vars(req)["id"] if !ok { http.Error(rw, "No id given.", http.StatusBadRequest) return } h.m.IsAuthorized(permission(id), "get", nil)(hctx.ContextHandlerFunc( func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { policy, err := h.s.Get(id) if err != nil { http.NotFound(rw, req) } pkg.WriteJSON(rw, policy) }, )) }
func (h *Handler) Find(ctx context.Context, rw http.ResponseWriter, req *http.Request) { subject, ok := mux.Vars(req)["subject"] if !ok { http.Error(rw, "No id given.", http.StatusBadRequest) return } h.m.IsAuthorized(connectionsPermission, "get", middleware.Env(req).Owner(subject))(hydcon.ContextHandlerFunc( func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { conns, err := h.s.FindAllByLocalSubject(subject) if err != nil { http.Error(rw, err.Error(), http.StatusNotFound) return } WriteJSON(rw, conns) }, )).ServeHTTPContext(ctx, rw, req) }
func (h *Handler) Get(ctx context.Context, rw http.ResponseWriter, req *http.Request) { id, ok := mux.Vars(req)["id"] if !ok { http.Error(rw, "No id given.", http.StatusBadRequest) return } h.m.IsAuthorized(permission(id), "get", nil)(hydcon.ContextHandlerFunc( func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { client, err := h.s.GetClient(id) if err != nil { http.Error(rw, fmt.Sprintf("Could not retrieve client: %s", id), http.StatusNotFound) return } WriteJSON(rw, client) }, )).ServeHTTPContext(ctx, rw, req) }
func (h *Handler) Get(ctx context.Context, rw http.ResponseWriter, req *http.Request) { id, ok := mux.Vars(req)["id"] if !ok { http.Error(rw, "No id given.", http.StatusBadRequest) return } h.m.IsAuthorized(permission(id), "get", middleware.Env(req).Owner(id))(hydcon.ContextHandlerFunc( func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { user, err := h.s.Get(id) if err == ErrNotFound { http.Error(rw, err.Error(), http.StatusNotFound) return } else if err != nil { http.Error(rw, err.Error(), http.StatusInternalServerError) return } WriteJSON(rw, user) }), ).ServeHTTPContext(ctx, rw, req) }
func (m *Middleware) IsAuthenticated(next hydcon.ContextHandler) hydcon.ContextHandler { return hydcon.ContextHandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { if !hydcon.IsAuthenticatedFromContext(ctx) { log.WithFields(log.Fields{"authentication": "fail"}).Warn(`Not able to get authorization from context.`) errorHandler(rw, req, http.StatusUnauthorized) return } subject, err := hydcon.SubjectFromContext(ctx) if err != nil { log.WithFields(log.Fields{"authentication": "fail"}).Warnf("Subject extraction failed: %s", err) errorHandler(rw, req, http.StatusUnauthorized) return } else if subject == "" { log.WithFields(log.Fields{"authentication": "fail"}).Warnf("No subject given.") errorHandler(rw, req, http.StatusUnauthorized) return } log.WithFields(log.Fields{"authentication": "success"}).Infof(`Authenticated subject "%s".`, subject) next.ServeHTTPContext(ctx, rw, req) }) }
func (h *Handler) Get(ctx context.Context, rw http.ResponseWriter, req *http.Request) { id, ok := mux.Vars(req)["id"] if !ok { http.Error(rw, "No id given.", http.StatusBadRequest) return } conn, err := h.s.Get(id) if err != nil { http.Error(rw, err.Error(), http.StatusNotFound) return } h.m.IsAuthorized(permission(id), "get", middleware.Env(req).Owner(conn.GetLocalSubject()))(hydcon.ContextHandlerFunc( func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { WriteJSON(rw, conn) }, )).ServeHTTPContext(ctx, rw, req) }
func (m *Middleware) ExtractAuthentication(next hydcon.ContextHandler) hydcon.ContextHandler { return hydcon.ContextHandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { ctx = hydcon.NewContextFromAuthorization(ctx, req, m.jwtService, m.policyStore) next.ServeHTTPContext(ctx, rw, req) }) }