Skip to content

Commit

Permalink
echo middleware: support being called with raw context (#10)
Browse files Browse the repository at this point in the history
The echo middleware handles interacting with iam-runtime using an echo context.
Results are then checked and a proper echo error is returned.

However when the user has a standard context.Context instead of an echo.Context,
they can no longer take advantage of the echo middleware's ability to return
proper echo errors.

One scenario where this may come up is when adding tracing spans to your methods.
The first thing you do is create a new span which returns a standard context.Context.
In order to take advantage of the echo middleware while keeping the trace context,
the user would have to replace the echo.Context's request with one with the updated context.

This adds unnecessary work for the user as the echo middleware simply unwraps the
request context before processing it anyways.
So a simple solution which simplifies usability is to simply expose a function which
can act on a context.Context while still handling echo errors properly.

Signed-off-by: Mike Mason <[email protected]>
  • Loading branch information
mikemrm authored Jun 13, 2024
1 parent 2720a2a commit 6e1222d
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 5 deletions.
8 changes: 7 additions & 1 deletion middleware/echo/iamruntimemiddleware/authentication.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package iamruntimemiddleware

import (
"context"
"errors"
"fmt"

Expand Down Expand Up @@ -44,7 +45,12 @@ func setAuthenticationContext(c echo.Context) error {
// ValidateCredential executes an access request on the runtime in the context with the provided actions.
// If any error is returned, the error is converted to an echo error with a proper status code.
func ValidateCredential(c echo.Context, in *authentication.ValidateCredentialRequest, opts ...grpc.CallOption) error {
if err := iamruntime.ContextValidateCredential(c.Request().Context(), in, opts...); err != nil {
return ContextValidateCredential(c.Request().Context(), in, opts...)
}

// ContextValidateCredential same as [ValidateCredential] except it works off a context.Context.
func ContextValidateCredential(ctx context.Context, in *authentication.ValidateCredentialRequest, opts ...grpc.CallOption) error {
if err := iamruntime.ContextValidateCredential(ctx, in, opts...); err != nil {
switch {
case errors.Is(err, iamruntime.ErrTokenNotFound), errors.Is(err, iamruntime.ErrInvalidCredentials):
return echo.ErrUnauthorized.WithInternal(err)
Expand Down
29 changes: 25 additions & 4 deletions middleware/echo/iamruntimemiddleware/authorization.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package iamruntimemiddleware

import (
"context"
"errors"
"fmt"

Expand All @@ -22,7 +23,12 @@ func setRuntimeContext(r Runtime, c echo.Context) error {
// CheckAccess executes an access request on the runtime in the context with the provided actions.
// If any error is returned, the error is converted to an echo error with a proper status code.
func CheckAccess(c echo.Context, actions []*authorization.AccessRequestAction, opts ...grpc.CallOption) error {
if err := iamruntime.ContextCheckAccess(c.Request().Context(), actions, opts...); err != nil {
return ContextCheckAccess(c.Request().Context(), actions, opts...)
}

// ContextCheckAccess same as [CheckAccess] except it works on a context.Context.
func ContextCheckAccess(ctx context.Context, actions []*authorization.AccessRequestAction, opts ...grpc.CallOption) error {
if err := iamruntime.ContextCheckAccess(ctx, actions, opts...); err != nil {
switch {
case errors.Is(err, iamruntime.ErrTokenNotFound):
return echo.ErrBadRequest.WithInternal(err)
Expand All @@ -43,7 +49,12 @@ func CheckAccess(c echo.Context, actions []*authorization.AccessRequestAction, o
// CheckAccessTo builds a check access request and executes it on the runtime in the provided context.
// Arguments must be pairs of Resource ID and Role Actions.
func CheckAccessTo(c echo.Context, resourceIDActionPairs ...string) error {
if err := iamruntime.ContextCheckAccessTo(c.Request().Context(), resourceIDActionPairs...); err != nil {
return ContextCheckAccessTo(c.Request().Context(), resourceIDActionPairs...)
}

// ContextCheckAccessTo same as [CheckAccessTo] except it works on a context.Context.
func ContextCheckAccessTo(ctx context.Context, resourceIDActionPairs ...string) error {
if err := iamruntime.ContextCheckAccessTo(ctx, resourceIDActionPairs...); err != nil {
switch {
case errors.Is(err, iamruntime.ErrTokenNotFound):
return echo.ErrBadRequest.WithInternal(err)
Expand All @@ -62,7 +73,12 @@ func CheckAccessTo(c echo.Context, resourceIDActionPairs ...string) error {
// CreateRelationships executes a create relationship request on the runtime in the context.
// If any error is returned, the error is converted to an echo error with a proper status code.
func CreateRelationships(c echo.Context, in *authorization.CreateRelationshipsRequest, opts ...grpc.CallOption) (*authorization.CreateRelationshipsResponse, error) {
resp, err := iamruntime.ContextCreateRelationships(c.Request().Context(), in, opts...)
return ContextCreateRelationships(c.Request().Context(), in, opts...)
}

// ContextCreateRelationships same as [CreateRelationships] except it works on a context.Context.
func ContextCreateRelationships(ctx context.Context, in *authorization.CreateRelationshipsRequest, opts ...grpc.CallOption) (*authorization.CreateRelationshipsResponse, error) {
resp, err := iamruntime.ContextCreateRelationships(ctx, in, opts...)
if err != nil {
switch {
case errors.Is(err, iamruntime.ErrRuntimeNotFound), errors.Is(err, iamruntime.ErrRelationshipRequestFailed):
Expand All @@ -78,7 +94,12 @@ func CreateRelationships(c echo.Context, in *authorization.CreateRelationshipsRe
// DeleteRelationships executes a delete relationship request on the runtime in the context.
// If any error is returned, the error is converted to an echo error with a proper status code.
func DeleteRelationships(c echo.Context, in *authorization.DeleteRelationshipsRequest, opts ...grpc.CallOption) (*authorization.DeleteRelationshipsResponse, error) {
resp, err := iamruntime.ContextDeleteRelationships(c.Request().Context(), in, opts...)
return ContextDeleteRelationships(c.Request().Context(), in, opts...)
}

// ContextDeleteRelationships same as [DeleteRelationships] except it works on a context.Context.
func ContextDeleteRelationships(ctx context.Context, in *authorization.DeleteRelationshipsRequest, opts ...grpc.CallOption) (*authorization.DeleteRelationshipsResponse, error) {
resp, err := iamruntime.ContextDeleteRelationships(ctx, in, opts...)
if err != nil {
switch {
case errors.Is(err, iamruntime.ErrRuntimeNotFound), errors.Is(err, iamruntime.ErrRelationshipRequestFailed):
Expand Down

0 comments on commit 6e1222d

Please sign in to comment.