diff --git a/openapi2kong/openapi2kong.go b/openapi2kong/openapi2kong.go index 798fd5fd..2ea4a78b 100644 --- a/openapi2kong/openapi2kong.go +++ b/openapi2kong/openapi2kong.go @@ -162,28 +162,30 @@ func getOIDCdefaults( scheme *v3.SecurityScheme // the security-scheme object ) { - if len(requirements) == 0 || ignoreSecurityErrors { - // no security requirements or nothing is defined - // so return inherited (can be nil) + if len(requirements) == 0 { return inherited, nil } - if len(requirements) > 1 && !ignoreSecurityErrors { + if len(requirements) > 1 { + if ignoreSecurityErrors { + return inherited, nil + } return nil, fmt.Errorf("only a single security-requirement is supported") } requirement := requirements[0].Requirements - if requirement.Len() == 0 || ignoreSecurityErrors { - return inherited, nil // there is nothing defined, so return inherited (can be nil) + + if requirement.Len() == 0 { + return inherited, nil } - if requirement.Len() > 1 && !ignoreSecurityErrors { - // multiple schemes are a logical AND, which is not supported + if requirement.Len() > 1 { + if ignoreSecurityErrors { + return inherited, nil + } return nil, fmt.Errorf("within a security-requirement only a single security-scheme is supported") } - // requirement has only 1 entry - // So, we won't iterate reqPair := requirement.First() schemeName = reqPair.Key() scopes = reqPair.Value() @@ -192,20 +194,18 @@ func getOIDCdefaults( scheme, _ = schemes.Get(schemeName) if scheme == nil { - if !ignoreSecurityErrors { - return nil, fmt.Errorf("no security-schemes with name '%s' found in components", schemeName) + if ignoreSecurityErrors { + return inherited, nil } - return inherited, nil + return nil, fmt.Errorf("no security-schemes with name '%s' found in components", schemeName) } - // Check if scheme type is openIdConnect (case-insensitive, accepting camelCase, kebab-case and snake_case) normalizedType := strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(scheme.Type, "_", ""), "-", "")) if normalizedType != "openidconnect" { - // non-OIDC security directives are not supported - if !ignoreSecurityErrors { - return nil, fmt.Errorf("only security-schemes of type 'openIdConnect' are supported") + if ignoreSecurityErrors { + return inherited, nil } - return inherited, nil + return nil, fmt.Errorf("only security-schemes of type 'openIdConnect' are supported") } } diff --git a/openapi2kong/openapi2kong_test.go b/openapi2kong/openapi2kong_test.go index 3175a307..4dec0482 100644 --- a/openapi2kong/openapi2kong_test.go +++ b/openapi2kong/openapi2kong_test.go @@ -178,6 +178,116 @@ func Test_Openapi2kong_IgnoreCircularRefs(t *testing.T) { } } +func Test_Openapi2kong_IgnoreSecurityErrors(t *testing.T) { + t.Run("still generates valid openid-connect plugin", func(t *testing.T) { + testDataString := ` +openapi: 3.0.0 +info: + title: OIDC Test API + version: "1.0" +servers: + - url: https://api.example.com +security: + - OpenIDConnect: + - profile + - email +paths: + /widgets: + get: + operationId: listWidgets + responses: + "200": + description: OK +components: + securitySchemes: + OpenIDConnect: + type: openIdConnect + openIdConnectUrl: https://issuer.example.com/.well-known/openid-configuration +` + + dataOut, err := Convert([]byte(testDataString), O2kOptions{ + OIDC: true, + IgnoreSecurityErrors: true, + SkipID: true, + }) + + assert.NoError(t, err) + + plugins, ok := dataOut["plugins"].([]*map[string]interface{}) + assert.True(t, ok, "expected top-level plugins array") + + var oidcPlugin *map[string]interface{} + for _, plugin := range plugins { + if (*plugin)["name"] == "openid-connect" { + oidcPlugin = plugin + break + } + } + + if assert.NotNil(t, oidcPlugin, "expected openid-connect plugin to be generated") { + config, ok := (*oidcPlugin)["config"].(map[string]interface{}) + assert.True(t, ok, "expected openid-connect plugin config") + + assert.Equal(t, + "https://issuer.example.com/.well-known/openid-configuration", + config["issuer"], + ) + + assert.Equal(t, + []string{"email", "profile"}, + config["scopes_required"], + ) + } + }) + + t.Run("suppresses unsupported non-openid-connect security scheme", func(t *testing.T) { + testDataString := ` +openapi: 3.0.0 +info: + title: API Key Test API + version: "1.0" +servers: + - url: https://api.example.com +security: + - ApiKeyAuth: [] +paths: + /widgets: + get: + operationId: listWidgets + responses: + "200": + description: OK +components: + securitySchemes: + ApiKeyAuth: + type: apiKey + in: header + name: X-API-Key +` + + _, err := Convert([]byte(testDataString), O2kOptions{ + OIDC: true, + }) + assert.Error(t, err) + assert.Contains(t, err.Error(), "only security-schemes of type 'openIdConnect' are supported") + + dataOut, err := Convert([]byte(testDataString), O2kOptions{ + OIDC: true, + IgnoreSecurityErrors: true, + SkipID: true, + }) + + assert.NoError(t, err) + + plugins, ok := dataOut["plugins"].([]*map[string]interface{}) + if ok { + for _, plugin := range plugins { + assert.NotEqual(t, "openid-connect", (*plugin)["name"]) + } + } + }) +} + func Test_Openapi2kong_pathParamLength(t *testing.T) { testDataString := ` openapi: 3.0.3