func (h *Handler) IntrospectHandler(w http.ResponseWriter, r *http.Request) { auth, err := osin.CheckBasicAuth(r) if _, err := h.OAuthStore.GetClient(auth.Username); err != nil { pkg.HttpError(w, errors.New("Unauthorized"), http.StatusUnauthorized) return } else if auth == nil { pkg.HttpError(w, errors.New("Unauthorized"), http.StatusUnauthorized) return } client, err := h.OAuthStore.GetClient(auth.Username) if err != nil { pkg.HttpError(w, errors.New("Unauthorized"), http.StatusUnauthorized) return } else if client.GetSecret() != auth.Password { pkg.HttpError(w, errors.New("Unauthorized"), http.StatusUnauthorized) return } result := make(map[string]interface{}) result["active"] = false r.ParseForm() if r.Form.Get("token") == "" { log.WithField("introspect", "fail").Warn("No token given.") result["error"] = "No token given." pkg.WriteJSON(w, result) return } token, err := h.JWT.VerifyToken([]byte(r.Form.Get("token"))) if err != nil { log.WithField("introspect", "fail").Warn("Token is invalid.") pkg.WriteJSON(w, result) return } claims := jwt.ClaimsCarrier(token.Claims) if claims.GetAudience() != auth.Username { log.WithFields(log.Fields{ "introspect": "fail", "actualAudience": auth.Username, "expectedAudience": claims.GetAudience(), }).Warn(`Token audience mismatch.`) pkg.WriteJSON(w, result) return } if claims.GetSubject() == "" { log.WithFields(log.Fields{ "introspect": "fail", }).Warn(`Token claims no subject.`) pkg.WriteJSON(w, result) return } result = token.Claims result["active"] = token.Valid pkg.WriteJSON(w, result) }
func (m *Middleware) IsAuthorized(resource, permission string, environment *middleware.Env) func(chd.ContextHandler) chd.ContextHandler { return func(next chd.ContextHandler) chd.ContextHandler { return chd.ContextHandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { if environment == nil { environment = middleware.NewEnv(req) } policies, err := authcon.PoliciesFromContext(ctx) if err != nil { log.WithFields(log.Fields{ "authorization": "forbidden", "error": err, }).Warnf(`Policy extraction failed.`) pkg.HttpError(rw, errors.New("Forbidden"), http.StatusForbidden) return } subject, err := authcon.SubjectFromContext(ctx) if err != nil { log.WithFields(log.Fields{ "authorization": "forbidden", "error": err, }).Warnf(`Subject extraction failed.`) pkg.HttpError(rw, errors.New("Forbidden"), http.StatusForbidden) return } ok, err := guard.IsGranted(resource, permission, subject, policies, environment.Ctx()) if err != nil || !ok { log.WithFields(log.Fields{ "authorization": "forbidden", "error": err, "valid": ok, "subject": subject, "permission": permission, "resource": resource, }).Warnf(`Subject is not allowed perform this action on this resource.`) pkg.HttpError(rw, errors.New("Forbidden"), http.StatusForbidden) return } log.WithFields(log.Fields{ "authorization": "success", "subject": subject, "permission": permission, "resource": resource, }).Infof(`Access granted.`) next.ServeHTTPContext(ctx, rw, req) }) } }
func TestIsAllowed(t *testing.T) { router := mux.NewRouter() router.HandleFunc("/oauth2/token", tokenHandler).Methods("POST") router.HandleFunc("/guard/allowed", func(rw http.ResponseWriter, req *http.Request) { if req.Header.Get("Authorization") != "Basic YXBwOmtleQ==" { http.Error(rw, req.Header.Get("Authorization"), http.StatusUnauthorized) return } var p handler.GrantedPayload decoder := json.NewDecoder(req.Body) if err := decoder.Decode(&p); err != nil { t.Logf("Could not decode body %s", err) pkg.HttpError(rw, errors.New(err), http.StatusBadRequest) return } assert.Equal(t, "foo", p.Permission) assert.Equal(t, "bar", p.Token) assert.Equal(t, "res", p.Resource) assert.Equal(t, "foo", p.Context.Owner) pkg.WriteJSON(rw, struct { Allowed bool `json:"allowed"` }{Allowed: true}) }).Methods("POST") ts := httptest.NewServer(router) defer ts.Close() c := New(ts.URL, "app", "key") allowed, err := c.IsAllowed(&AuthorizeRequest{Permission: "foo", Token: "bar", Resource: "res", Context: &operator.Context{Owner: "foo"}}) assert.Nil(t, err, "%s", err) assert.True(t, allowed) }
func (h *Handler) Create(ctx context.Context, rw http.ResponseWriter, req *http.Request) { var p DefaultPolicy decoder := json.NewDecoder(req.Body) if err := decoder.Decode(&p); err != nil { pkg.HttpError(rw, err, http.StatusBadRequest) return } p.ID = uuid.New() if err := h.s.Create(&p); err != nil { pkg.HttpError(rw, err, http.StatusInternalServerError) return } pkg.WriteCreatedJSON(rw, "/policies/"+p.ID, p) }
func (h *Handler) Delete(ctx context.Context, rw http.ResponseWriter, req *http.Request) { id, ok := mux.Vars(req)["id"] if !ok { pkg.HttpError(rw, errors.New("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 { pkg.HttpError(rw, errors.Errorf("Could not retrieve client: %s", id), http.StatusInternalServerError) return } rw.WriteHeader(http.StatusAccepted) }, )).ServeHTTPContext(ctx, rw, req) }
func (m *Middleware) IsAuthenticated(next chd.ContextHandler) chd.ContextHandler { return chd.ContextHandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { if !authcon.IsAuthenticatedFromContext(ctx) { log.WithFields(log.Fields{"authentication": "fail"}).Warn(`Not able to get authorization from context.`) pkg.HttpError(rw, errors.New("Unauthorized"), http.StatusUnauthorized) return } subject, err := authcon.SubjectFromContext(ctx) if err != nil { log.WithFields(log.Fields{"authentication": "fail"}).Warnf("Subject extraction failed: %s", err) pkg.HttpError(rw, errors.New("Unauthorized"), http.StatusUnauthorized) return } else if subject == "" { log.WithFields(log.Fields{"authentication": "fail"}).Warnf("No subject given.") pkg.HttpError(rw, errors.New("Unauthorized"), 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 { pkg.HttpError(rw, errors.New("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 { pkg.WriteError(rw, err) return } pkg.WriteJSON(rw, policy) }, )).ServeHTTPContext(ctx, rw, req) }
func (h *Handler) Granted(ctx context.Context, rw http.ResponseWriter, req *http.Request) { auth, err := osin.CheckBasicAuth(req) if err != nil { pkg.HttpError(rw, errors.New("Unauthorized"), http.StatusUnauthorized) return } else if auth == nil { pkg.HttpError(rw, errors.New("Unauthorized"), http.StatusUnauthorized) return } client, err := h.o.GetClient(auth.Username) if err != nil { pkg.HttpError(rw, errors.New("Unauthorized"), http.StatusUnauthorized) return } else if client.GetSecret() != auth.Password { pkg.HttpError(rw, errors.New("Unauthorized"), http.StatusUnauthorized) return } var p GrantedPayload decoder := json.NewDecoder(req.Body) if err := decoder.Decode(&p); err != nil { pkg.HttpError(rw, errors.New(err), http.StatusBadRequest) return } token, err := h.j.VerifyToken([]byte(p.Token)) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), "resource": p.Resource, "permission": p.Permission, "subject": "", "context": fmt.Sprintf("%s", p.Context), }).Warn("Token not valid.") pkg.WriteJSON(rw, struct { Allowed bool `json:"allowed"` Error string `json:"error"` }{Allowed: false, Error: err.Error()}) return } subject, ok := token.Claims["sub"].(string) if !ok { err := errors.New("Bearer token is not valid.") log.WithFields(log.Fields{ "error": err.Error(), "resource": p.Resource, "permission": p.Permission, "subject": "", "context": fmt.Sprintf("%s", p.Context), }).Warn("Token does not claim a subject.") pkg.WriteJSON(rw, struct { Allowed bool `json:"allowed"` Error string `json:"error"` }{Allowed: false, Error: err.Error()}) return } policies, err := h.s.FindPoliciesForSubject(subject) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), "resource": p.Resource, "permission": p.Permission, "subject": subject, "context": fmt.Sprintf("%s", p.Context), }).Warn("Could not fetch policies from store.") pkg.WriteJSON(rw, struct { Allowed bool `json:"allowed"` Error string `json:"error"` }{Allowed: false, Error: err.Error()}) return } allowed, err := h.g.IsGranted(p.Resource, p.Permission, subject, policies, p.Context) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), "resource": p.Resource, "permission": p.Permission, "subject": subject, "policies": fmt.Sprintf("%s", policies), "context": fmt.Sprintf("%s", p.Context), }).Warn("Granted check failed.") pkg.WriteJSON(rw, struct { Allowed bool `json:"allowed"` Error string `json:"error"` }{Allowed: false, Error: err.Error()}) return } log.WithFields(log.Fields{ "resource": p.Resource, "permission": p.Permission, "subject": subject, "allowed": allowed, "policies": fmt.Sprintf("%s", policies), "context": fmt.Sprintf("%s", p.Context), }).Info("Got guard decision.") pkg.WriteJSON(rw, struct { Allowed bool `json:"allowed"` }{Allowed: allowed}) }
func (h *Handler) RevokeHandler(w http.ResponseWriter, r *http.Request) { auth, err := osin.CheckBasicAuth(r) if err != nil { pkg.HttpError(w, errors.New("Unauthorized"), http.StatusUnauthorized) return } else if auth == nil { pkg.HttpError(w, errors.New("Unauthorized"), http.StatusUnauthorized) return } client, err := h.OAuthStore.GetClient(auth.Username) if err != nil { pkg.HttpError(w, errors.New("Unauthorized"), http.StatusUnauthorized) return } else if client.GetSecret() != auth.Password { pkg.HttpError(w, errors.New("Unauthorized"), http.StatusUnauthorized) return } r.ParseForm() tokenToRevoke := r.Form.Get("token") if tokenToRevoke == "" { log.WithField("revokation", "fail").Warn("No token given.") pkg.HttpError(w, errors.New("No token given"), http.StatusServiceUnavailable) return } getClaims := func(ud interface{}) (jwt.ClaimsCarrier, error) { data, ok := ud.(string) var claims jwt.ClaimsCarrier if !ok { return nil, errors.New("Could not assert UserData to string") } if err := json.Unmarshal([]byte(data), &claims); err != nil { return nil, errors.New("Could not unmarshal UserData") } return claims, nil } var ud interface{} var revokeToken *osin.AccessData if revokeToken, err = h.OAuthStore.LoadAccess(tokenToRevoke); err == pkg.ErrNotFound { revokeToken, err = h.OAuthStore.LoadRefresh(tokenToRevoke) if err != nil { log.WithField("revokation", "fail").WithField("error", err).Warn("Could not fetch refresh token.") pkg.HttpError(w, errors.New("Could not find token"), http.StatusServiceUnavailable) return } } else if err != nil { log.WithField("revokation", "fail").WithField("error", err).Warn("Could not fetch acccess token.") pkg.HttpError(w, errors.New("Could not find token"), http.StatusServiceUnavailable) return } ud = revokeToken.UserData claims, err := getClaims(ud) if err != nil { log.WithField("error", err).Warn("Could not retrieve claims.") pkg.HttpError(w, err, http.StatusServiceUnavailable) return } if claims.GetAudience() != client.GetId() { log.WithFields(log.Fields{ "claimAudience": claims.GetAudience(), "clientAudience": client.GetId(), }).Warn("Suspicious activity detected. Audience mismatch.") pkg.HttpError(w, errors.New("Forbidden"), http.StatusServiceUnavailable) return } if err := h.OAuthStore.RemoveAccess(revokeToken.AccessToken); err != nil { log.WithField("error", err).Warn("Could not revoke access token.") pkg.HttpError(w, err, http.StatusServiceUnavailable) return } w.WriteHeader(http.StatusOK) }