Skip to content

Commit dc8641a

Browse files
julius-malcovskyBjoernKarmaiagarbastefan-ctrlron96g
committed
feat(multi-url-realm): let gateway realms have multiple urls and issuer urls
Co-authored-by: Björn Kottner <BjoernKarma@users.noreply.github.com> Co-authored-by: Ismael Garba <iagarba@users.noreply.github.com> Co-authored-by: Stefan Siber <stefan-ctrl@users.noreply.github.com> Co-authored-by: Ron Gummich <ron96g@users.noreply.github.com>
1 parent 90c1712 commit dc8641a

12 files changed

Lines changed: 136 additions & 36 deletions

File tree

admin/internal/controller/zone_controller_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ func VerifyZone(ctx context.Context, g Gomega, namespacedName client.ObjectKey,
252252

253253
gatewayRealmSpec := gatewayapi.RealmSpec{
254254
Gateway: types.ObjectRefFromObject(gateway),
255-
Url: "https://test-stargate.de/",
256-
IssuerUrl: "https://test-iris.de/auth/realms/test",
255+
Urls: []string{"https://test-stargate.de/"},
256+
IssuerUrls: []string{"https://test-iris.de/auth/realms/test"},
257257
DefaultConsumers: []string{},
258258
}
259259
g.Expect(gatewayRealm.Spec).To(Equal(gatewayRealmSpec))
@@ -288,8 +288,8 @@ func VerifyZone(ctx context.Context, g Gomega, namespacedName client.ObjectKey,
288288

289289
teamApiGatewayRealmSpec := gatewayapi.RealmSpec{
290290
Gateway: types.ObjectRefFromObject(gateway),
291-
Url: "https://test-stargate.de/",
292-
IssuerUrl: "https://test-iris.de/auth/realms/team-test",
291+
Urls: []string{"https://test-stargate.de/"},
292+
IssuerUrls: []string{"https://test-iris.de/auth/realms/team-test"},
293293
DefaultConsumers: []string{},
294294
}
295295
g.Expect(teamApiGatewayRealm.Spec).To(Equal(teamApiGatewayRealmSpec))

admin/internal/handler/zone/handler.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ func (h *ZoneHandler) CreateOrUpdate(ctx context.Context, obj *adminv1.Zone) err
143143
return err
144144
}
145145
obj.Status.TeamApiGatewayRealm = types.ObjectRefFromObject(teamApisGatewayRealm)
146-
obj.Status.Links.TeamIssuer = teamApisGatewayRealm.Spec.IssuerUrl
146+
if len(teamApisGatewayRealm.Spec.IssuerUrls) > 0 {
147+
obj.Status.Links.TeamIssuer = teamApisGatewayRealm.Spec.IssuerUrls[0]
148+
}
147149

148150
// Team api routes
149151
var teamApiRouteRefs []types.ObjectRef
@@ -198,11 +200,15 @@ func createTeamApiRoute(ctx context.Context, handlingContext HandlingContext, te
198200
if err != nil {
199201
return err
200202
}
203+
issuerUrl := ""
204+
if len(gatewayRealm.Spec.IssuerUrls) > 0 {
205+
issuerUrl = gatewayRealm.Spec.IssuerUrls[0]
206+
}
201207
downstream := gatewayapi.Downstream{
202208
Host: downstreamUrl.Host,
203209
Port: 0,
204210
Path: downstreamUrl.Path,
205-
IssuerUrl: gatewayRealm.Spec.IssuerUrl,
211+
IssuerUrl: issuerUrl,
206212
}
207213

208214
teamRoute.Spec = gatewayapi.RouteSpec{
@@ -272,8 +278,8 @@ func createGatewayRealm(ctx context.Context, handlingContext HandlingContext, ga
272278

273279
gatewayRealm.Spec = gatewayapi.RealmSpec{
274280
Gateway: types.ObjectRefFromObject(gateway),
275-
Url: handlingContext.Zone.Spec.Gateway.Url,
276-
IssuerUrl: urls.ForGatewayRealm(handlingContext.Zone.Spec.IdentityProvider.Url, realmName),
281+
Urls: []string{handlingContext.Zone.Spec.Gateway.Url},
282+
IssuerUrls: []string{urls.ForGatewayRealm(handlingContext.Zone.Spec.IdentityProvider.Url, realmName)},
277283
DefaultConsumers: []string{},
278284
}
279285
return nil

api/internal/controller/apiexposure_controller_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ func NewRealm(name, zoneName string) *gatewayapi.Realm {
8282
},
8383
},
8484
Spec: gatewayapi.RealmSpec{
85-
Url: fmt.Sprintf("http://my-gateway.%s:8080", zoneName),
86-
IssuerUrl: fmt.Sprintf("http://my-issuer.%s:8080/auth/realms/%s", zoneName, testEnvironment),
85+
Urls: []string{fmt.Sprintf("http://my-gateway.%s:8080", zoneName)},
86+
IssuerUrls: []string{fmt.Sprintf("http://my-issuer.%s:8080/auth/realms/%s", zoneName, testEnvironment)},
8787
},
8888
Status: gatewayapi.RealmStatus{},
8989
}

api/internal/controller/remoteapisubscription_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ var _ = Describe("RemoteApiSubscription Controller - Provider Scenario", Ordered
141141
By("Creating the remote Zone")
142142
remoteZone = CreateZone(remoteOrgId + "-" + zoneName)
143143
remoteRealm := NewRealm(testEnvironment, remoteZone.Name)
144-
remoteRealm.Spec.Url = "https://ger.gateway.es"
144+
remoteRealm.Spec.Urls = []string{"https://ger.gateway.es"}
145145
err := k8sClient.Create(ctx, remoteRealm)
146146
Expect(err).ToNot(HaveOccurred())
147147
remoteRealm.SetCondition(condition.NewReadyCondition("Ready", "testing"))

api/internal/handler/util_proxy_route_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ func CreateRealm(name, zoneName string) *gatewayapi.Realm {
6666
},
6767
},
6868
Spec: gatewayapi.RealmSpec{
69-
Url: fmt.Sprintf("http://%s.%s.de:8080", name, zoneName),
70-
IssuerUrl: fmt.Sprintf("http://issuer.%s.de:8080/auth/realms/test", zoneName),
69+
Urls: []string{fmt.Sprintf("http://%s.%s.de:8080", name, zoneName)},
70+
IssuerUrls: []string{fmt.Sprintf("http://issuer.%s.de:8080/auth/realms/test", zoneName)},
7171
},
7272
Status: gatewayapi.RealmStatus{},
7373
}

gateway/api/v1/realm_types.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package v1
66

77
import (
8+
"errors"
89
"net/url"
910
"path"
1011

@@ -19,10 +20,16 @@ type RealmSpec struct {
1920
// Gateway is the Gateway that is associated with the Realm
2021
// If empty, the realm considered a virtual realm
2122
Gateway *types.ObjectRef `json:"gateway,omitempty"`
22-
// Url is the URL of the Gateway when its used as an upstream
23-
Url string `json:"url"`
24-
// IssuerUrl is the URL of the issuer of the Token sent by the Gateway when its used as a downstream
25-
IssuerUrl string `json:"issuerUrl"`
23+
// Urls is the list of Gateway URLs that this realm should accept traffic from
24+
// +listType=set
25+
// +kubebuilder:validation:MinItems=1
26+
// +kubebuilder:validation:items:Format=uri
27+
Urls []string `json:"urls"`
28+
// IssuerUrls is the list of token issuer URLs that are trusted for this realm
29+
// +listType=set
30+
// +kubebuilder:validation:MinItems=1
31+
// +kubebuilder:validation:items:Format=uri
32+
IssuerUrls []string `json:"issuerUrls"`
2633
// DefaultConsumers is a list of consumers that are allowed to access the Realm for all Routes
2734
// +listType=set
2835
// +kubebuilder:default={}
@@ -72,7 +79,11 @@ func (r *Realm) SetCondition(condition metav1.Condition) bool {
7279
}
7380

7481
func (r *Realm) AsUpstream(apiBasePath string) (ups Upstream, err error) {
75-
url, err := url.Parse(r.Spec.Url)
82+
// Use the first URL as the upstream URL
83+
if len(r.Spec.Urls) == 0 {
84+
return ups, errors.New("no upstreams found")
85+
}
86+
url, err := url.Parse(r.Spec.Urls[0])
7687
if err != nil {
7788
return ups, err
7889
}
@@ -86,15 +97,24 @@ func (r *Realm) AsUpstream(apiBasePath string) (ups Upstream, err error) {
8697
}
8798

8899
func (r *Realm) AsDownstream(apiBasePath string) (dws Downstream, err error) {
89-
url, err := url.Parse(r.Spec.Url)
100+
// Use the first URL as the downstream URL
101+
if len(r.Spec.Urls) == 0 {
102+
return dws, errors.New("no downstreams found")
103+
}
104+
url, err := url.Parse(r.Spec.Urls[0])
90105
if err != nil {
91106
return dws, err
92107
}
108+
// Use the first issuer URL
109+
issuerUrl := ""
110+
if len(r.Spec.IssuerUrls) > 0 {
111+
issuerUrl = r.Spec.IssuerUrls[0]
112+
}
93113
dws = Downstream{
94114
Host: url.Hostname(),
95115
Port: GetPortOrDefaultFromScheme(url),
96116
Path: path.Join(url.Path, apiBasePath),
97-
IssuerUrl: r.Spec.IssuerUrl,
117+
IssuerUrl: issuerUrl,
98118
}
99119
return
100120
}

gateway/api/v1/zz_generated.deepcopy.go

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gateway/config/crd/bases/gateway.cp.ei.telekom.de_realms.yaml

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,28 @@ spec:
6969
- name
7070
- namespace
7171
type: object
72-
issuerUrl:
73-
description: IssuerUrl is the URL of the issuer of the Token sent
74-
by the Gateway when its used as a downstream
75-
type: string
76-
url:
77-
description: Url is the URL of the Gateway when its used as an upstream
78-
type: string
72+
issuerUrls:
73+
description: IssuerUrls is the list of token issuer URLs that are
74+
trusted for this realm
75+
items:
76+
format: uri
77+
type: string
78+
minItems: 1
79+
type: array
80+
x-kubernetes-list-type: set
81+
urls:
82+
description: Urls is the list of Gateway URLs that this realm should
83+
accept traffic from
84+
items:
85+
format: uri
86+
type: string
87+
minItems: 1
88+
type: array
89+
x-kubernetes-list-type: set
7990
required:
8091
- defaultConsumers
81-
- issuerUrl
82-
- url
92+
- issuerUrls
93+
- urls
8394
type: object
8495
status:
8596
description: RealmStatus defines the observed state of Realm

gateway/internal/controller/realm_controller_test.go

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ func NewRealm(name string) *gatewayv1.Realm {
2727
},
2828
},
2929
Spec: gatewayv1.RealmSpec{
30-
Url: "https://realm.url",
31-
IssuerUrl: "https://issuer.url",
30+
Urls: []string{"https://realm.url"},
31+
IssuerUrls: []string{"https://issuer.url"},
3232
DefaultConsumers: []string{
3333
"test",
3434
},
@@ -120,4 +120,54 @@ var _ = Describe("Realm Controller", Ordered, func() {
120120

121121
})
122122
})
123+
124+
Context("URL Validation", func() {
125+
It("should reject invalid URLs", func() {
126+
invalidRealm := &gatewayv1.Realm{
127+
ObjectMeta: metav1.ObjectMeta{
128+
Name: "invalid-realm",
129+
Namespace: testNamespace,
130+
Labels: map[string]string{
131+
config.EnvironmentLabelKey: testEnvironment,
132+
config.BuildLabelKey("zone"): "test",
133+
},
134+
},
135+
Spec: gatewayv1.RealmSpec{
136+
Urls: []string{"not-a-valid-url"},
137+
IssuerUrls: []string{"also-not-valid"},
138+
DefaultConsumers: []string{},
139+
},
140+
}
141+
142+
By("Attempting to create a realm with invalid URLs")
143+
err := k8sClient.Create(ctx, invalidRealm)
144+
Expect(err).To(HaveOccurred(), "Expected validation error for invalid URLs")
145+
})
146+
147+
It("should accept valid URLs", func() {
148+
validRealm := &gatewayv1.Realm{
149+
ObjectMeta: metav1.ObjectMeta{
150+
Name: "valid-realm",
151+
Namespace: testNamespace,
152+
Labels: map[string]string{
153+
config.EnvironmentLabelKey: testEnvironment,
154+
config.BuildLabelKey("zone"): "test",
155+
},
156+
},
157+
Spec: gatewayv1.RealmSpec{
158+
Urls: []string{"https://valid.example.com", "http://another.example.com:8080/path"},
159+
IssuerUrls: []string{"https://issuer.example.com/auth/realms/test"},
160+
DefaultConsumers: []string{},
161+
},
162+
}
163+
164+
By("Creating a realm with valid URLs")
165+
err := k8sClient.Create(ctx, validRealm)
166+
Expect(err).NotTo(HaveOccurred(), "Valid URLs should be accepted")
167+
168+
By("Cleaning up the valid realm")
169+
err = k8sClient.Delete(ctx, validRealm)
170+
Expect(err).NotTo(HaveOccurred())
171+
})
172+
})
123173
})

gateway/internal/features/builder_ratelimiting_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ var _ = Describe("FeatureBuilder RateLimiting", Ordered, func() {
133133
Namespace: "default",
134134
},
135135
Spec: gatewayv1.RealmSpec{
136-
Url: "https://realm.url",
137-
IssuerUrl: "https://issuer.url",
136+
Urls: []string{"https://realm.url"},
137+
IssuerUrls: []string{"https://issuer.url"},
138138
},
139139
}
140140
})

0 commit comments

Comments
 (0)