diff --git a/internal/api/permissions.go b/internal/api/permissions.go index c88639e8..ccf73cb7 100644 --- a/internal/api/permissions.go +++ b/internal/api/permissions.go @@ -10,8 +10,7 @@ import ( "go.infratographer.com/x/urnx" ) -// checkAction will check if a subject is allowed to perform an action on a resource -// scoped to the tenant. +// checkAction will check if a subject is allowed to perform an action on a resource. // This is the permissions check endpoint. // It will return a 200 if the subject is allowed to perform the action on the resource. // It will return a 403 if the subject is not allowed to perform the action on the resource. @@ -20,21 +19,12 @@ import ( // contain the subject of the request in the "sub" claim. // // The following query parameters are required: -// - tenant: the tenant URN to check -// - action: the action to check -// -// The following query parameters are optional: // - resource: the resource URN to check +// - action: the action to check func (r *Router) checkAction(c echo.Context) error { ctx, span := tracer.Start(c.Request().Context(), "api.checkAction") defer span.End() - // Get the query parameters. These are mandatory. - tenantURNStr, hasQuery := getParam(c, "tenant") - if !hasQuery { - return echo.NewHTTPError(http.StatusBadRequest, "missing tenant query parameter") - } - action, hasQuery := getParam(c, "action") if !hasQuery { return echo.NewHTTPError(http.StatusBadRequest, "missing action query parameter") @@ -42,27 +32,21 @@ func (r *Router) checkAction(c echo.Context) error { // Optional query parameters resourceURNStr, hasResourceParam := getParam(c, "resource") + if !hasResourceParam { + return echo.NewHTTPError(http.StatusBadRequest, "missing resource query parameter") + } // Query parameter validation - // Note that we currently only check the tenant as a scope. The - // resource is not checked as of yet. - tenantURN, err := urnx.Parse(tenantURNStr) + resourceURN, err := urnx.Parse(resourceURNStr) if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "error processing tenant URN").SetInternal(err) + return echo.NewHTTPError(http.StatusBadRequest, "error processing resource URN").SetInternal(err) } - tenantResource, err := r.engine.NewResourceFromURN(tenantURN) + resource, err := r.engine.NewResourceFromURN(resourceURN) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, "error processing tenant resource URN").SetInternal(err) } - if hasResourceParam { - _, err := urnx.Parse(resourceURNStr) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "error processing resource URN").SetInternal(err) - } - } - // Subject validation subject, err := currentSubject(c) if err != nil { @@ -75,10 +59,10 @@ func (r *Router) checkAction(c echo.Context) error { } // Check the permissions - err = r.engine.SubjectHasPermission(ctx, subjectResource, action, tenantResource, "") + err = r.engine.SubjectHasPermission(ctx, subjectResource, action, resource, "") if err != nil && errors.Is(err, query.ErrActionNotAssigned) { - msg := fmt.Sprintf("subject '%s' does not have permission to perform action '%s' on resource '%s' scoped on tenant '%s'", - subject, action, resourceURNStr, tenantURNStr) + msg := fmt.Sprintf("subject '%s' does not have permission to perform action '%s' on resource '%s'", + subject, action, resourceURNStr) return echo.NewHTTPError(http.StatusForbidden, msg).SetInternal(err) } else if err != nil { diff --git a/pkg/client/v1/auth.go b/pkg/client/v1/auth.go index d9669ebb..db6b2447 100644 --- a/pkg/client/v1/auth.go +++ b/pkg/client/v1/auth.go @@ -8,7 +8,6 @@ import ( "fmt" "net/http" "net/url" - "path" "strings" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" @@ -59,14 +58,18 @@ func New(url string, doerClient Doer) (*Client, error) { } // Allowed checks if the client subject is permitted exec the action on the resource -func (c *Client) Allowed(ctx context.Context, action string, resourceURNPrefix string) (bool, error) { +func (c *Client) Allowed(ctx context.Context, action string, resourceURN string) (bool, error) { ctx, span := tracer.Start(ctx, "SubjectHasAction", trace.WithAttributes( attribute.String("action", action), - attribute.String("resource", resourceURNPrefix), + attribute.String("resource", resourceURN), )) defer span.End() - err := c.get(ctx, fmt.Sprintf("/has/%s/on/%s", action, resourceURNPrefix), map[string]string{}) + values := url.Values{} + values.Add("action", action) + values.Add("resource", resourceURN) + + err := c.get(ctx, "/allow", values, map[string]string{}) if err != nil { if errors.Is(err, ErrPermissionDenied) { return false, nil @@ -85,8 +88,8 @@ type ServerResponse struct { StatusCode int } -func (c Client) get(ctx context.Context, endpoint string, resp interface{}) error { - request, err := newGetRequest(ctx, c.url, endpoint) +func (c Client) get(ctx context.Context, endpoint string, query url.Values, resp interface{}) error { + request, err := newGetRequest(ctx, c.url, endpoint, query) if err != nil { return err } @@ -94,13 +97,17 @@ func (c Client) get(ctx context.Context, endpoint string, resp interface{}) erro return c.do(request, &resp) } -func newGetRequest(ctx context.Context, uri, endpoint string) (*http.Request, error) { +func newGetRequest(ctx context.Context, uri, endpoint string, query url.Values) (*http.Request, error) { u, err := url.Parse(uri) if err != nil { return nil, err } - u.Path = path.Join(apiVersion, endpoint) + u = u.JoinPath(apiVersion, endpoint) + + if len(query) > 0 { + u.RawQuery = query.Encode() + } return http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) }