Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3348,11 +3348,13 @@ If you're using a specification with [Security Schemes](https://spec.openapis.or
> Out-of-the-box, the server-side code generated by `oapi-codegen` does not provide security validation.
>
> To perform authentication, you will need to use the [validation middleware](#requestresponse-validation-middleware).
>
> In the future, we plan to [implement server-side validation in the generated code](https://github.com/oapi-codegen/oapi-codegen/issues/1524)

To see how this can work, check out the [authenticated API example](examples/authenticated-api/echo).

If an operation includes an empty `{}` security alternative, generated server
middleware treats that operation as allowing anonymous requests and doesn't embed required
security scopes in the request context.

### On the client

With a generated client, you'll want to use the client's generated `WithRequestEditorFn` function to pass in a given request editor `RequestEditorFn`.
Expand Down
33 changes: 17 additions & 16 deletions internal/test/servers/middleware/fiber/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ package serversmiddlewarefiber
import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"runtime"
"strings"
"testing"

"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

type impl struct{}
Expand All @@ -21,14 +26,6 @@ func (i *impl) Test(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK)
}

// hasSecurityScopes returns true if the BearerAuthScopes key was set in context,
// even if the scopes slice is empty (an empty slice means the security scheme is
// defined on the operation with no required scopes, which still requires auth).
func hasSecurityScopes(c *fiber.Ctx) bool {
_, ok := c.Context().UserValue(BearerAuthScopes).([]string)
return ok
}

func TestIssue518(t *testing.T) {
server := &impl{}

Expand All @@ -47,23 +44,17 @@ func TestIssue518(t *testing.T) {
},
HandlerMiddlewares: []HandlerMiddlewareFunc{
func(c *fiber.Ctx, next fiber.Handler) error {
if hasSecurityScopes(c) && c.Get(fiber.HeaderAuthorization) == "" {
return c.SendStatus(fiber.StatusUnauthorized)
}
return next(c)
},
},
})
})

t.Run("secured endpoint requires auth when scopes are present", func(t *testing.T) {
t.Run("endpoint with anonymous security alternative allows missing auth", func(t *testing.T) {
r := fiber.New()
RegisterHandlersWithOptions(r, server, FiberServerOptions{
HandlerMiddlewares: []HandlerMiddlewareFunc{
func(c *fiber.Ctx, next fiber.Handler) error {
if hasSecurityScopes(c) && c.Get(fiber.HeaderAuthorization) == "" {
return c.SendStatus(fiber.StatusUnauthorized)
}
return next(c)
},
},
Expand All @@ -72,7 +63,7 @@ func TestIssue518(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/auth-check", nil)
resp, err := r.Test(req)
assert.NoError(t, err)
assert.Equal(t, fiber.StatusUnauthorized, resp.StatusCode)
assert.Equal(t, fiber.StatusOK, resp.StatusCode)

req = httptest.NewRequest(http.MethodGet, "/auth-check", nil)
req.Header.Set(fiber.HeaderAuthorization, "Bearer token")
Expand All @@ -87,6 +78,16 @@ func TestIssue518(t *testing.T) {
})
}

func TestIssue518AnonymousSecurityAlternativeDoesNotEmitScopes(t *testing.T) {
_, testFile, _, ok := runtime.Caller(0)
assert.True(t, ok)

generatedPath := filepath.Join(filepath.Dir(testFile), "middleware.gen.go")
generated, err := os.ReadFile(generatedPath)
require.NoError(t, err)
assert.False(t, strings.Contains(string(generated), "SetUserValue"))
}
Comment thread
kriptoburak marked this conversation as resolved.

// From issue-1469: registering fiber handlers (with and without options) for
// an operation with an empty-object requestBody must not panic.
func TestIssue1469(t *testing.T) {
Expand Down
6 changes: 0 additions & 6 deletions internal/test/servers/middleware/fiber/middleware.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions internal/test/servers/middleware/fiber/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ paths:
get:
operationId: authCheck
security:
- {}
- bearerAuth: []
responses:
200:
Expand Down
3 changes: 3 additions & 0 deletions pkg/codegen/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,9 @@ func DescribeSecurityDefinition(securityRequirements openapi3.SecurityRequiremen
outDefs := make([]SecurityDefinition, 0)

for _, sr := range securityRequirements {
if len(sr) == 0 {
return nil
}
Comment thread
kriptoburak marked this conversation as resolved.
for _, k := range SortedMapKeys(sr) {
v := sr[k]
outDefs = append(outDefs, SecurityDefinition{ProviderName: k, Scopes: v})
Expand Down