Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Route metadata #750

Closed
1 task done
deborggraever opened this issue Jan 15, 2024 · 0 comments · Fixed by #760
Closed
1 task done

[FEATURE] Route metadata #750

deborggraever opened this issue Jan 15, 2024 · 0 comments · Fixed by #760

Comments

@deborggraever
Copy link

deborggraever commented Jan 15, 2024

Is there an existing feature request for this?

  • I have searched the existing feature requests

Is your feature request related to a problem? Please describe.

Currently it is difficult to do authorization on routes based on claim requirements, unless we do the check inside the http handler.
Coming from a C# .NET world, there it is easy because it support attributes like an [Authorize] attribute.

As workaround i added a unique name to each route, and created a authorization mapping between the route name and the authorization policy.

Middleware

var routePolicies map[string]string
var authPolicies map[string]authorization.Policy

func authMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		route := mux.CurrentRoute(r)
		policyName, ok := routePolicies[route.GetName()]
		if !ok {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		policy, ok := authPolicies[policyName]
		if !ok || !policy.MeetsRequirements(r.Context()) {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		next.ServeHTTP(w, r)
	})
}

Setup

// Register the route
r.HandleFunc("/v1/product", api.GetProductsHandlerV1).Methods(http.MethodGet).Name("product_api:GetProductsHandlerV1")
r.HandleFunc("/v1/product/{id}", api.GetProductByIdHandlerV1).Methods(http.MethodGet).Name("product_api:GetProductByIdHandlerV1")

// Set the route policies
routePolicies["product_api:GetProductsHandlerV1"] = "product.read"
routePolicies["product_api:GetProductByIdHandlerV1"] = "product.read"

// Create the policies
authPolicies["product.read"] = authorization.NewPolicy(
    "product.read",
    NewUserRequirement(),
    NewScopeRequirement("product.read"),
)

Describe the solution that you would like.

To make it easy to create an authorization middleware with limited code, it would be nice to have metadata on a route.

Example:

r.HandleFunc("/v1/product", api.GetProductsHandlerV1).Methods(http.MethodGet).Metadata("authPolicy", "product.read")
r.HandleFunc("/v1/product/{id}", api.GetProductByIdHandlerV1).Methods(http.MethodGet).Metadata("authPolicy", "product.read")

func authMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		route := mux.CurrentRoute(r)
		policy, ok := authPolicies[route.GetMetadata()["authPolicy"]]
		if !ok || !policy.MeetsRequirements(r.Context()) {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		next.ServeHTTP(w, r)
	})
}

Route metadata could be used for many other solutions, where u want to set some properties on a route to use inside the handler or middlewares

Describe alternatives you have considered.

No response

Anything else?

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant