Skip to content

Commit f51dbcf

Browse files
authored
Merge pull request #495 from cnvergence/fix-ui-binding-cluster-id
fix: allow UI-only binding flow without CLI-provided cluster identity
2 parents 2494dd1 + 64ef41b commit f51dbcf

4 files changed

Lines changed: 29 additions & 17 deletions

File tree

backend/auth/middleware.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ type ClientType string
4444
const (
4545
ClientTypeUI ClientType = "ui"
4646
ClientTypeCLI ClientType = "cli"
47+
48+
// UIIdentity is the well-known identity value that the UI sends in bind requests.
49+
// The backend resolves it to the actual identity derived from the authenticated session.
50+
UIIdentity = "ui-identity"
4751
)
4852

4953
type AuthContext struct {

backend/http/handler.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -360,14 +360,26 @@ func (h *handler) handleBind(w http.ResponseWriter, r *http.Request) {
360360
return
361361
}
362362

363-
// TODO: Move to validating admission.
364-
if bindRequest.Spec.ClusterIdentity.Identity == "" {
365-
logger.Error(fmt.Errorf("missing cluster identity"), "invalid bind request")
366-
writeErrorResponse(w, http.StatusBadRequest, kubebindv1alpha2.ErrorCodeBadRequest, "Missing cluster identity in bind request", "The cluster identity must be provided in the bind request")
363+
// Identity is always required. CLI provides the cluster identity (kube-system UID),
364+
// and the UI sends the well-known "ui-identity" value.
365+
identity := bindRequest.Spec.ClusterIdentity.Identity
366+
if identity == "" {
367+
writeErrorResponse(w, http.StatusBadRequest, kubebindv1alpha2.ErrorCodeBadRequest, "Missing cluster identity", "spec.clusterIdentity.identity is required")
367368
return
368369
}
369370

370-
handleResult, err := h.kubeManager.HandleResources(r.Context(), state.Token.Subject, params.ConsumerID, params.ClusterID)
371+
// Resolve the UI sentinel to a real identity derived from the authenticated session.
372+
if identity == auth.UIIdentity {
373+
identity = state.Token.Issuer + "/" + state.Token.Subject
374+
logger.Info("Resolved ui-identity from session", "identity", identity)
375+
}
376+
377+
consumerID := params.ConsumerID
378+
if consumerID == "" {
379+
consumerID = identity
380+
}
381+
382+
handleResult, err := h.kubeManager.HandleResources(r.Context(), state.Token.Subject, consumerID, params.ClusterID)
371383
if err != nil {
372384
logger.Error(err, "failed to handle resources")
373385
statusCode, code, details := mapErrorToCode(err)

test/e2e/bind/happy-case_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,11 @@ func testHappyCase(
227227
}
228228

229229
t.Logf("Creating consumer workspace and starting konnector")
230-
consumer1Config, consumer1Kubeconfig := framework.NewWorkspace(t, framework.ClientConfig(t), framework.WithName("%s-consumer-%s", name, suffix))
230+
consumer1Config, consumer1Kubeconfig := framework.NewWorkspace(t, framework.ClientConfig(t),
231+
framework.WithGenerateName("%s-consumer-%s-", name, suffix))
232+
consumer2Config, consumer2Kubeconfig := framework.NewWorkspace(t, framework.ClientConfig(t),
233+
framework.WithGenerateName("%s-consumer-%s-", name, suffix))
231234
framework.StartKonnector(t, consumer1Config, "--kubeconfig="+consumer1Kubeconfig, "--server-address=:0")
232-
233-
consumer2Config, consumer2Kubeconfig := framework.NewWorkspace(t, framework.ClientConfig(t), framework.WithName("%s-consumer-%s", name, suffix))
234235
framework.StartKonnector(t, consumer2Config, "--kubeconfig="+consumer2Kubeconfig, "--server-address=:0")
235236

236237
serviceGVR := schema.GroupVersionResource{Group: "wildwest.dev", Version: "v1alpha1", Resource: "cowboys"}

web/src/views/Resources.vue

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -321,15 +321,10 @@ const handleBind = async (templateName: string, bindingName: string) => {
321321
const bindUrl = buildApiUrl('/bind')
322322
323323
// Create the binding request
324-
// Use consumerId if available (CLI flow), otherwise use sessionId as cluster identity
325-
// Read from Vue Router's route.query instead of window.location
326-
const sessionIdFromRoute = route.query.session_id as string || ''
327-
const clusterIdentity = consumerId.value || sessionIdFromRoute
328-
329-
if (!clusterIdentity) {
330-
showAlertModal('Missing cluster identity. Please ensure you have authenticated properly.', 'Binding Failed', 'error')
331-
return
332-
}
324+
// CLI flow: use consumerId (kube-system namespace UID)
325+
// UI flow: use the well-known "ui-identity" sentinel - the backend resolves
326+
// it to the actual identity from the authenticated OIDC session.
327+
const clusterIdentity = consumerId.value || 'ui-identity'
333328
334329
const bindingRequest: BindableResourcesRequest = {
335330
metadata: {

0 commit comments

Comments
 (0)