Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion frontend/public/actions/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ const ssarCheckActions = ssarChecks.map(({ flag, resourceAttributes, after }) =>
after(dispatch, allowed);
}
},
(err) => handleError({ response: err.graphQLErrors[0]?.extensions }, flag, dispatch, fn),
(err) => {
handleError({ response: err.graphQLErrors[0]?.extensions }, flag, dispatch, fn);
},
);
return fn;
});
Expand Down
7 changes: 3 additions & 4 deletions frontend/public/actions/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { detectFeatures } from './features';
import { clearSSARFlags } from './flags';
import { OverviewSpecialGroup } from '../components/overview/constants';
import { setClusterID, setCreateProjectMessage, ActionType } from './common';
import { subsClient } from '../graphql/client';
import { subsClient, setForceHTTP } from '../graphql/client';
import {
beginImpersonate,
endImpersonate,
Expand Down Expand Up @@ -241,15 +241,14 @@ export const startImpersonate = (kind: string, name: string, groups?: string[])
// This ensures flags refresh happens in sync with React's render cycle
};

// Action to refresh features after impersonation change
// Don't clear flags - just re-detect them. Old values remain until new ones are fetched.
// This prevents components from seeing PENDING state and showing loading spinners.
export const refreshFeaturesAfterImpersonation = () => (dispatch) => {
setForceHTTP(true);
dispatch(detectFeatures());
};
export const stopImpersonate = () => (dispatch) => {
dispatch(endImpersonate());
subsClient.close(false, true);
setForceHTTP(false);
dispatch(clearSSARFlags());
dispatch(detectFeatures());
};
Expand Down
8 changes: 7 additions & 1 deletion frontend/public/graphql/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import { URLQueryType, URLQueryVariables } from '../../@types/console/generated/
import { getConsoleRequestHeaders, coFetch } from '../co-fetch';

let wssErrors = 0;
// @ts-ignore TS6133 - forceHTTP is read inside the split() closure below
let forceHTTP = false;

export const setForceHTTP = (force: boolean) => {
forceHTTP = force;
};

class GraphQLReady {
private callback: VoidFunction;
Expand Down Expand Up @@ -68,7 +74,7 @@ const wsLink = new WebSocketLink(subsClient);

// fallback to http connection if websocket connection was not successful
// iOS does not allow wss with self signed certificate
const link = split(() => wssErrors > 4, httpLink, wsLink);
const link = split(() => wssErrors > 4 || forceHTTP, httpLink, wsLink);

const client = new ApolloClient({
link,
Expand Down
16 changes: 14 additions & 2 deletions pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,21 @@ func (s *Server) HTTPHandler() (http.Handler, error) {
handler.InitPayload = resolver.InitPayload
graphQLHandler := handler.NewHandlerFunc(schema, gql.NewHttpHandler(schema))
handle("/api/graphql", authHandlerWithUser(func(user *auth.User, w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(context.Background(), resolver.HeadersKey, map[string]interface{}{
headers := map[string]interface{}{
"Authorization": fmt.Sprintf("Bearer %s", user.Token),
})
}
if impUser := r.Header.Get("Impersonate-User"); impUser != "" {
headers["Impersonate-User"] = impUser
}
if consoleGroups := r.Header.Get("X-Console-Impersonate-Groups"); consoleGroups != "" {
groups := strings.Split(consoleGroups, ",")
groups = append(groups, "system:authenticated")
headers["Impersonate-Group"] = groups
} else if impGroups := r.Header.Values("Impersonate-Group"); len(impGroups) > 0 {
impGroups = append(impGroups, "system:authenticated")
headers["Impersonate-Group"] = impGroups
}
ctx := context.WithValue(r.Context(), resolver.HeadersKey, headers)
graphQLHandler(w, r.WithContext(ctx))
}))

Expand Down