Skip to content

Commit

Permalink
Refactor jwt OAS conversion (TykTechnologies#3934)
Browse files Browse the repository at this point in the history
  • Loading branch information
furkansenharputlu authored Mar 11, 2022
1 parent 1bdd59c commit b405a7d
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 13 deletions.
29 changes: 29 additions & 0 deletions apidef/oas/oas.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,39 @@ func (s *OAS) getTykTokenAuth(name string) (token *Token) {
return
}

func (s *OAS) getTykJWTAuth(name string) (jwt *JWT) {
securityScheme := s.getTykSecurityScheme(name)
if securityScheme == nil {
return
}

mapSecurityScheme, ok := securityScheme.(map[string]interface{})
if ok {
jwt = &JWT{}
inBytes, _ := json.Marshal(mapSecurityScheme)
_ = json.Unmarshal(inBytes, jwt)
s.getTykSecuritySchemes()[name] = jwt
return
}

jwt = securityScheme.(*JWT)

return
}

func (s *OAS) getTykSecuritySchemes() (securitySchemes map[string]interface{}) {
if s.getTykAuthentication() != nil {
securitySchemes = s.getTykAuthentication().SecuritySchemes
}

return
}

func (s *OAS) getTykSecurityScheme(name string) interface{} {
securitySchemes := s.getTykSecuritySchemes()
if securitySchemes == nil {
return nil
}

return securitySchemes[name]
}
2 changes: 1 addition & 1 deletion apidef/oas/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestXTykAPIGateway(t *testing.T) {
oas.Components.SecuritySchemes = openapi3.SecuritySchemes{
"custom": {
Value: &openapi3.SecurityScheme{
Type: apiKey,
Type: typeApiKey,
Name: "x-query",
In: "query",
},
Expand Down
99 changes: 92 additions & 7 deletions apidef/oas/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import (
)

const (
apiKey = "apiKey"
typeApiKey = "apiKey"
typeHttp = "http"
schemeBearer = "bearer"
bearerFormatJWT = "JWT"

header = "header"
query = "query"
Expand Down Expand Up @@ -57,6 +60,86 @@ func (s *OAS) extractTokenTo(api *apidef.APIDefinition, name string) {
api.AuthConfigs[apidef.AuthTokenType] = authConfig
}

func (s *OAS) fillJWT(api apidef.APIDefinition) {
ac, ok := api.AuthConfigs[apidef.JWTType]
if !ok || ac.Name == "" {
return
}

ss := s.Components.SecuritySchemes
if ss == nil {
ss = make(map[string]*openapi3.SecuritySchemeRef)
s.Components.SecuritySchemes = ss
}

ref, ok := ss[ac.Name]
if !ok {
ref = &openapi3.SecuritySchemeRef{
Value: openapi3.NewSecurityScheme(),
}
ss[ac.Name] = ref
}

ref.Value.WithType(typeHttp).WithScheme(schemeBearer).WithBearerFormat(bearerFormatJWT)

s.appendSecurity(ac.Name)

jwt := &JWT{}
jwt.Enabled = api.EnableJWT
jwt.AuthSources.Fill(ac)
jwt.Source = api.JWTSource
jwt.SigningMethod = api.JWTSigningMethod
jwt.IdentityBaseField = api.JWTIdentityBaseField
jwt.SkipKid = api.JWTSkipKid
jwt.PolicyFieldName = api.JWTPolicyFieldName
jwt.ClientBaseField = api.JWTClientIDBaseField

if jwt.Scopes == nil {
jwt.Scopes = &Scopes{}
}

jwt.Scopes.Fill(&api.Scopes.JWT)
if ShouldOmit(jwt.Scopes) {
jwt.Scopes = nil
}

jwt.DefaultPolicies = api.JWTDefaultPolicies
jwt.IssuedAtValidationSkew = api.JWTIssuedAtValidationSkew
jwt.NotBeforeValidationSkew = api.JWTNotBeforeValidationSkew
jwt.ExpiresAtValidationSkew = api.JWTExpiresAtValidationSkew

s.getTykSecuritySchemes()[ac.Name] = jwt

if ShouldOmit(jwt) {
delete(s.getTykSecuritySchemes(), ac.Name)
}
}

func (s *OAS) extractJWTTo(api *apidef.APIDefinition, name string) {
ac := apidef.AuthConfig{Name: name, DisableHeader: true}

jwt := s.getTykJWTAuth(name)
api.EnableJWT = jwt.Enabled
jwt.AuthSources.ExtractTo(&ac)
api.JWTSource = jwt.Source
api.JWTSigningMethod = jwt.SigningMethod
api.JWTIdentityBaseField = jwt.IdentityBaseField
api.JWTSkipKid = jwt.SkipKid
api.JWTPolicyFieldName = jwt.PolicyFieldName
api.JWTClientIDBaseField = jwt.ClientBaseField

if jwt.Scopes != nil {
jwt.Scopes.ExtractTo(&api.Scopes.JWT)
}

api.JWTDefaultPolicies = jwt.DefaultPolicies
api.JWTIssuedAtValidationSkew = jwt.IssuedAtValidationSkew
api.JWTNotBeforeValidationSkew = jwt.NotBeforeValidationSkew
api.JWTExpiresAtValidationSkew = jwt.ExpiresAtValidationSkew

api.AuthConfigs[apidef.JWTType] = ac
}

func (s *OAS) extractSecurityTo(api *apidef.APIDefinition) {
if a := s.getTykAuthentication(); a != nil {
api.UseKeylessAccess = !a.Enabled
Expand All @@ -76,11 +159,12 @@ func (s *OAS) extractSecurityTo(api *apidef.APIDefinition) {

for schemeName := range s.getTykSecuritySchemes() {
if _, ok := s.Security[0][schemeName]; ok {
switch s.Components.SecuritySchemes[schemeName].Value.Type {
case apiKey:
if s.getTykTokenAuth(schemeName) != nil {
s.extractTokenTo(api, schemeName)
}
v := s.Components.SecuritySchemes[schemeName].Value
switch {
case v.Type == typeApiKey:
s.extractTokenTo(api, schemeName)
case v.Type == typeHttp && v.Scheme == schemeBearer && v.BearerFormat == bearerFormatJWT:
s.extractJWTTo(api, schemeName)
}
}
}
Expand All @@ -102,6 +186,7 @@ func (s *OAS) fillSecurity(api apidef.APIDefinition) {
a.BaseIdentityProvider = api.BaseIdentityProvidedBy

s.fillToken(api)
s.fillJWT(api)

if ShouldOmit(a) {
s.GetTykExtension().Server.Authentication = nil
Expand Down Expand Up @@ -143,7 +228,7 @@ func (s *OAS) fillApiKeyScheme(ac *apidef.AuthConfig) {
ac.UseCookie = false
}

ref.Value.WithName(key).WithIn(loc).WithType(apiKey)
ref.Value.WithName(key).WithIn(loc).WithType(typeApiKey)

s.appendSecurity(ac.Name)
}
Expand Down
55 changes: 50 additions & 5 deletions apidef/oas/security_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestOAS_ApiKeyScheme(t *testing.T) {
expSecuritySchemes := openapi3.SecuritySchemes{
authName: &openapi3.SecuritySchemeRef{
Value: &openapi3.SecurityScheme{
Type: apiKey,
Type: typeApiKey,
In: in,
Name: name,
},
Expand Down Expand Up @@ -112,7 +112,7 @@ func TestOAS_ApiKeyScheme(t *testing.T) {
oas.Components.SecuritySchemes = openapi3.SecuritySchemes{
authName: &openapi3.SecuritySchemeRef{
Value: &openapi3.SecurityScheme{
Type: apiKey,
Type: typeApiKey,
In: in,
Name: name,
},
Expand Down Expand Up @@ -154,7 +154,7 @@ func TestOAS_Token(t *testing.T) {
oas.Components.SecuritySchemes = openapi3.SecuritySchemes{
securityName: {
Value: &openapi3.SecurityScheme{
Type: apiKey,
Type: typeApiKey,
Name: "x-query",
In: query,
},
Expand Down Expand Up @@ -204,14 +204,14 @@ func TestOAS_Token_MultipleSecuritySchemes(t *testing.T) {
oas.Components.SecuritySchemes = openapi3.SecuritySchemes{
securityName: {
Value: &openapi3.SecurityScheme{
Type: apiKey,
Type: typeApiKey,
Name: "x-query",
In: query,
},
},
securityName2: {
Value: &openapi3.SecurityScheme{
Type: apiKey,
Type: typeApiKey,
Name: "x-header",
In: header,
},
Expand Down Expand Up @@ -284,3 +284,48 @@ func TestOAS_AppendSecurity(t *testing.T) {
})

}

func TestOAS_JWT(t *testing.T) {
const securityName = "custom"

var oas OAS
oas.Security = openapi3.SecurityRequirements{
{
securityName: []string{},
},
}

oas.Components.SecuritySchemes = openapi3.SecuritySchemes{
securityName: {
Value: &openapi3.SecurityScheme{
Type: typeHttp,
Scheme: schemeBearer,
BearerFormat: bearerFormatJWT,
},
},
}

var jwt JWT
Fill(t, &jwt, 0)
oas.Extensions = map[string]interface{}{
ExtensionTykAPIGateway: &XTykAPIGateway{
Server: Server{
Authentication: &Authentication{
SecuritySchemes: map[string]interface{}{
securityName: &jwt,
},
},
},
},
}

var api apidef.APIDefinition
api.AuthConfigs = make(map[string]apidef.AuthConfig)
oas.extractJWTTo(&api, securityName)

var convertedOAS OAS
convertedOAS.SetTykExtension(&XTykAPIGateway{Server: Server{Authentication: &Authentication{SecuritySchemes: map[string]interface{}{}}}})
convertedOAS.fillJWT(api)

assert.Equal(t, oas, convertedOAS)
}

0 comments on commit b405a7d

Please sign in to comment.