diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go index 383ab5dc25..1dc357519f 100644 --- a/examples/authenticated-api/echo/api/api.gen.go +++ b/examples/authenticated-api/echo/api/api.gen.go @@ -21,7 +21,7 @@ import ( ) const ( - BearerAuthScopes = "BearerAuth.Scopes" + BearerAuthScopes bearerAuthContextKey = "BearerAuth.Scopes" ) // Error defines model for Error. @@ -44,6 +44,9 @@ type ThingWithID struct { Name string `json:"name"` } +// bearerAuthContextKey is the context key for BearerAuth security scheme +type bearerAuthContextKey string + // AddThingJSONRequestBody defines body for AddThing for application/json ContentType. type AddThingJSONRequestBody = Thing @@ -425,7 +428,7 @@ type ServerInterfaceWrapper struct { func (w *ServerInterfaceWrapper) ListThings(ctx echo.Context) error { var err error - ctx.Set(BearerAuthScopes, []string{}) + ctx.Set(string(BearerAuthScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.ListThings(ctx) @@ -436,7 +439,7 @@ func (w *ServerInterfaceWrapper) ListThings(ctx echo.Context) error { func (w *ServerInterfaceWrapper) AddThing(ctx echo.Context) error { var err error - ctx.Set(BearerAuthScopes, []string{"things:w"}) + ctx.Set(string(BearerAuthScopes), []string{"things:w"}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.AddThing(ctx) diff --git a/examples/authenticated-api/stdhttp/api/api.gen.go b/examples/authenticated-api/stdhttp/api/api.gen.go index 91ced48c3d..bf3af4b293 100644 --- a/examples/authenticated-api/stdhttp/api/api.gen.go +++ b/examples/authenticated-api/stdhttp/api/api.gen.go @@ -22,7 +22,7 @@ import ( ) const ( - BearerAuthScopes = "BearerAuth.Scopes" + BearerAuthScopes bearerAuthContextKey = "BearerAuth.Scopes" ) // Error defines model for Error. @@ -45,6 +45,9 @@ type ThingWithID struct { Name string `json:"name"` } +// bearerAuthContextKey is the context key for BearerAuth security scheme +type bearerAuthContextKey string + // AddThingJSONRequestBody defines body for AddThing for application/json ContentType. type AddThingJSONRequestBody = Thing diff --git a/internal/test/any_of/codegen/inline/openapi.gen.go b/internal/test/any_of/codegen/inline/openapi.gen.go index d3f34bec6e..4179ed9495 100644 --- a/internal/test/any_of/codegen/inline/openapi.gen.go +++ b/internal/test/any_of/codegen/inline/openapi.gen.go @@ -16,7 +16,7 @@ import ( ) const ( - ApiKeyAuthScopes = "ApiKeyAuth.Scopes" + ApiKeyAuthScopes apiKeyAuthContextKey = "ApiKeyAuth.Scopes" ) // Cat This is a cat @@ -45,6 +45,9 @@ type Rat struct { Squeaks *bool `json:"squeaks,omitempty"` } +// apiKeyAuthContextKey is the context key for ApiKeyAuth security scheme +type apiKeyAuthContextKey string + // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(ctx context.Context, req *http.Request) error @@ -288,7 +291,7 @@ type ServerInterfaceWrapper struct { func (w *ServerInterfaceWrapper) GetPets(ctx echo.Context) error { var err error - ctx.Set(ApiKeyAuthScopes, []string{}) + ctx.Set(string(ApiKeyAuthScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.GetPets(ctx) diff --git a/internal/test/any_of/codegen/ref_schema/openapi.gen.go b/internal/test/any_of/codegen/ref_schema/openapi.gen.go index 38f87c47be..d255052757 100644 --- a/internal/test/any_of/codegen/ref_schema/openapi.gen.go +++ b/internal/test/any_of/codegen/ref_schema/openapi.gen.go @@ -17,7 +17,7 @@ import ( ) const ( - ApiKeyAuthScopes = "ApiKeyAuth.Scopes" + ApiKeyAuthScopes apiKeyAuthContextKey = "ApiKeyAuth.Scopes" ) // Cat This is a cat @@ -56,6 +56,9 @@ type Rat struct { Squeaks *bool `json:"squeaks,omitempty"` } +// apiKeyAuthContextKey is the context key for ApiKeyAuth security scheme +type apiKeyAuthContextKey string + // AsCat returns the union data inside the GetPetsDto_Data as a Cat func (t GetPetsDto_Data) AsCat() (Cat, error) { var body Cat @@ -380,7 +383,7 @@ type ServerInterfaceWrapper struct { func (w *ServerInterfaceWrapper) GetPets(ctx echo.Context) error { var err error - ctx.Set(ApiKeyAuthScopes, []string{}) + ctx.Set(string(ApiKeyAuthScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.GetPets(ctx) diff --git a/internal/test/client/client.gen.go b/internal/test/client/client.gen.go index 275c72cf0f..17135a2ea7 100644 --- a/internal/test/client/client.gen.go +++ b/internal/test/client/client.gen.go @@ -15,7 +15,7 @@ import ( ) const ( - OpenIdScopes = "OpenId.Scopes" + OpenIdScopes openIdContextKey = "OpenId.Scopes" ) // SchemaObject defines model for SchemaObject. @@ -24,6 +24,9 @@ type SchemaObject struct { Role string `json:"role"` } +// openIdContextKey is the context key for OpenId security scheme +type openIdContextKey string + // PostVendorJsonApplicationVndAPIPlusJSONBody defines parameters for PostVendorJson. type PostVendorJsonApplicationVndAPIPlusJSONBody = map[string]interface{} diff --git a/internal/test/client/client.yaml b/internal/test/client/client.yaml index ea4c1c3b1e..15119e593e 100644 --- a/internal/test/client/client.yaml +++ b/internal/test/client/client.yaml @@ -90,6 +90,10 @@ paths: schema: type: object components: + securitySchemes: + OpenId: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration schemas: SchemaObject: properties: diff --git a/internal/test/externalref/petstore/externalref.gen.go b/internal/test/externalref/petstore/externalref.gen.go index e8102f0d28..e4b540a404 100644 --- a/internal/test/externalref/petstore/externalref.gen.go +++ b/internal/test/externalref/petstore/externalref.gen.go @@ -18,8 +18,8 @@ import ( ) const ( - Api_keyScopes = "api_key.Scopes" - Petstore_authScopes = "petstore_auth.Scopes" + Api_keyScopes apiKeyContextKey = "api_key.Scopes" + Petstore_authScopes petstoreAuthContextKey = "petstore_auth.Scopes" ) // Defines values for OrderStatus. @@ -166,6 +166,12 @@ type User struct { // UserArray defines model for UserArray. type UserArray = []User +// apiKeyContextKey is the context key for api_key security scheme +type apiKeyContextKey string + +// petstoreAuthContextKey is the context key for petstore_auth security scheme +type petstoreAuthContextKey string + // FindPetsByStatusParams defines parameters for FindPetsByStatus. type FindPetsByStatusParams struct { // Status Status values that need to be considered for filter diff --git a/internal/test/issues/issue-1087/api.gen.go b/internal/test/issues/issue-1087/api.gen.go index 3c408cc8f9..7c154d9115 100644 --- a/internal/test/issues/issue-1087/api.gen.go +++ b/internal/test/issues/issue-1087/api.gen.go @@ -33,6 +33,9 @@ type N404 = externalRef0.Error // ThingResponse Object containing list of Things type ThingResponse = ThingList +// bearerAuthWebhookContextKey is the context key for bearerAuthWebhook security scheme +type bearerAuthWebhookContextKey string + // RequestEditorFn is the function signature for the RequestEditor callback function type RequestEditorFn func(ctx context.Context, req *http.Request) error diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go index 9c0871cb34..f8293f4608 100644 --- a/internal/test/schemas/schemas.gen.go +++ b/internal/test/schemas/schemas.gen.go @@ -25,7 +25,7 @@ import ( ) const ( - Access_tokenScopes = "access_token.Scopes" + Access_tokenScopes accessTokenContextKey = "access_token.Scopes" ) // Defines values for EnumInObjInArrayVal. @@ -111,6 +111,9 @@ type InnerRenamedAnonymousObject struct { // StringInPath defines model for StringInPath. type StringInPath = string +// accessTokenContextKey is the context key for access-token security scheme +type accessTokenContextKey string + // Issue9JSONBody defines parameters for Issue9. type Issue9JSONBody = interface{} @@ -1418,7 +1421,7 @@ type ServerInterfaceWrapper struct { func (w *ServerInterfaceWrapper) EnsureEverythingIsReferenced(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{}) + ctx.Set(string(Access_tokenScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.EnsureEverythingIsReferenced(ctx) @@ -1429,7 +1432,7 @@ func (w *ServerInterfaceWrapper) EnsureEverythingIsReferenced(ctx echo.Context) func (w *ServerInterfaceWrapper) Issue1051(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{}) + ctx.Set(string(Access_tokenScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.Issue1051(ctx) @@ -1440,7 +1443,7 @@ func (w *ServerInterfaceWrapper) Issue1051(ctx echo.Context) error { func (w *ServerInterfaceWrapper) Issue127(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{}) + ctx.Set(string(Access_tokenScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.Issue127(ctx) @@ -1451,7 +1454,7 @@ func (w *ServerInterfaceWrapper) Issue127(ctx echo.Context) error { func (w *ServerInterfaceWrapper) Issue185(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{}) + ctx.Set(string(Access_tokenScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.Issue185(ctx) @@ -1469,7 +1472,7 @@ func (w *ServerInterfaceWrapper) Issue209(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter str: %s", err)) } - ctx.Set(Access_tokenScopes, []string{}) + ctx.Set(string(Access_tokenScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.Issue209(ctx, str) @@ -1487,7 +1490,7 @@ func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter fallthrough: %s", err)) } - ctx.Set(Access_tokenScopes, []string{}) + ctx.Set(string(Access_tokenScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.Issue30(ctx, pFallthrough) @@ -1498,7 +1501,7 @@ func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error { func (w *ServerInterfaceWrapper) GetIssues375(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{}) + ctx.Set(string(Access_tokenScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.GetIssues375(ctx) @@ -1516,7 +1519,7 @@ func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1param: %s", err)) } - ctx.Set(Access_tokenScopes, []string{}) + ctx.Set(string(Access_tokenScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.Issue41(ctx, n1param) @@ -1527,7 +1530,7 @@ func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error { func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{}) + ctx.Set(string(Access_tokenScopes), []string{}) // Parameter object where we will unmarshal all parameters from the context var params Issue9Params @@ -1547,7 +1550,7 @@ func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error { func (w *ServerInterfaceWrapper) Issue975(ctx echo.Context) error { var err error - ctx.Set(Access_tokenScopes, []string{}) + ctx.Set(string(Access_tokenScopes), []string{}) // Invoke the callback with all the unmarshaled arguments err = w.Handler.Issue975(ctx) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 3a77729bff..6aedce1805 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -561,6 +561,12 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op return "", fmt.Errorf("error generating Go types for component request bodies: %w", err) } allTypes = append(allTypes, bodyTypes...) + + securitySchemeTypes, err := GenerateTypesForSecuritySchemes(t, swagger.Components.SecuritySchemes) + if err != nil { + return "", fmt.Errorf("error generating Go types for component security schemes: %w", err) + } + allTypes = append(allTypes, securitySchemeTypes...) } // Go through all operations, and add their types to allTypes, so that we can @@ -847,6 +853,29 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open return types, nil } +// GenerateTypesForSecuritySchemes generates type definitions for any custom types defined in the +// components/securitySchemes section of the Swagger spec. +func GenerateTypesForSecuritySchemes(t *template.Template, schemes map[string]*openapi3.SecuritySchemeRef) ([]TypeDefinition, error) { + var types []TypeDefinition + + for _, schemeName := range SortedSecuritySchemeKeys(schemes) { + // Generate a type to be used as a key in context.WithValue + goTypeName := LowercaseFirstCharacter(SchemaNameToTypeName(schemeName)) + "ContextKey" + goType := Schema{ + GoType: "string", + Description: fmt.Sprintf("is the context key for %s security scheme", schemeName), + } + + types = append(types, TypeDefinition{ + JsonName: schemeName, + TypeName: goTypeName, + Schema: goType, + }) + } + + return types, nil +} + // GenerateTypes passes a bunch of types to the template engine, and buffers // its output into a string. func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error) { diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go index e4d932116a..19c533f1e6 100644 --- a/pkg/codegen/template_helpers.go +++ b/pkg/codegen/template_helpers.go @@ -350,6 +350,7 @@ var TemplateFunctions = template.FuncMap{ "title": titleCaser.String, "stripNewLines": stripNewLines, "sanitizeGoIdentity": SanitizeGoIdentity, + "schemaNameToTypeName": SchemaNameToTypeName, "toGoString": StringToGoString, "toGoComment": StringWithTypeNameToGoComment, diff --git a/pkg/codegen/templates/constants.tmpl b/pkg/codegen/templates/constants.tmpl index 1c8cbd4922..df434e5377 100644 --- a/pkg/codegen/templates/constants.tmpl +++ b/pkg/codegen/templates/constants.tmpl @@ -1,7 +1,7 @@ {{- if gt (len .SecuritySchemeProviderNames) 0 }} const ( {{range $ProviderName := .SecuritySchemeProviderNames}} - {{- $ProviderName | sanitizeGoIdentity | ucFirst}}Scopes = "{{$ProviderName}}.Scopes" + {{- $ProviderName | sanitizeGoIdentity | ucFirst}}Scopes {{$ProviderName | schemaNameToTypeName | lcFirst}}ContextKey = "{{$ProviderName}}.Scopes" {{end}} ) {{end}} diff --git a/pkg/codegen/templates/echo/echo-wrappers.tmpl b/pkg/codegen/templates/echo/echo-wrappers.tmpl index 584a21f26c..a086d75d4e 100644 --- a/pkg/codegen/templates/echo/echo-wrappers.tmpl +++ b/pkg/codegen/templates/echo/echo-wrappers.tmpl @@ -26,7 +26,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error { {{end}} {{range .SecurityDefinitions}} - ctx.Set({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}}) + ctx.Set(string({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes), {{toStringArray .Scopes}}) {{end}} {{if .RequiresParamObject}} diff --git a/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl b/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl index 9c1856167c..9f7d608dda 100644 --- a/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl +++ b/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl @@ -26,7 +26,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx *echo.Context) error { {{end}} {{range .SecurityDefinitions}} - ctx.Set({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}}) + ctx.Set(string({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes), {{toStringArray .Scopes}}) {{end}} {{if .RequiresParamObject}} diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl index 63bc2cb831..eab735e5e6 100644 --- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl +++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl @@ -36,7 +36,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error { {{end}} {{range .SecurityDefinitions}} - c.Context().SetUserValue({{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}}) + c.Context().SetUserValue(({{.ProviderName | ucFirst}}Scopes), {{toStringArray .Scopes}}) {{end}} {{if .RequiresParamObject}} diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl index 272e2ec609..e18c0d644c 100644 --- a/pkg/codegen/templates/gin/gin-wrappers.tmpl +++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl @@ -40,7 +40,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) { {{end}} {{range .SecurityDefinitions}} - c.Set({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}}) + c.Set(string({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes), {{toStringArray .Scopes}}) {{end}} {{if .RequiresParamObject}} diff --git a/pkg/codegen/templates/iris/iris-middleware.tmpl b/pkg/codegen/templates/iris/iris-middleware.tmpl index 0bc6b1229b..7ee4ce9b2b 100644 --- a/pkg/codegen/templates/iris/iris-middleware.tmpl +++ b/pkg/codegen/templates/iris/iris-middleware.tmpl @@ -35,7 +35,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) { {{end}} {{range .SecurityDefinitions}} - ctx.Set({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}}) + ctx.Set(string({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes), {{toStringArray .Scopes}}) {{end}} {{if .RequiresParamObject}} diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index adfeb7c89f..b6fb91985f 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -405,6 +405,18 @@ func schemaXOrder(v *openapi3.SchemaRef) (int64, bool) { return 0, false } +// SortedParameterKeys returns sorted keys for a SecuritySchemeRef dict +func SortedSecuritySchemeKeys(dict map[string]*openapi3.SecuritySchemeRef) []string { + keys := make([]string, len(dict)) + i := 0 + for key := range dict { + keys[i] = key + i++ + } + sort.Strings(keys) + return keys +} + // StringInArray checks whether the specified string is present in an array // of strings func StringInArray(str string, array []string) bool {