Skip to content

Commit ac0fd6f

Browse files
committed
[#12] WIP: Add SSO support
- Fixes #12: SSO - Fixes #216: SSO instructions - Fixes #215: Make sure bad password can be fixed during "add clusters" event REMOVE HTTPS CERT WORKAROUND BEFORE MERGE TO MASTER! MCC instance with SSO enabled for testing currently has invalid cert chain, so this is needed as a temporary workaround during development. SEE '// DEBUG' COMMENTS for what still needs refactoring, which at this point should ONLY BE 'add clusters' under SSO. Everything else _should_ be working now. *** SHOULD BASIC AUTH SUPPORT BE REMOVED? *** Done: - Renamed existing `AuthProvider` to `BasicAuthProvider`. This provider will fail with an error notification if it's used with an MCC instance that requires SSO auth. - Added new `SsoAuthProvider` for handling all things SSO. This provider will fail with an error notification if it's used with an MCC instance that does not support Keycloak SSO auth. - Moved a few effects out of View.js and into useClusterLoder.js hook to cut down on module size. - Added 'SSO support' section to README with instructions on how to configure the MCC instance's Keycloak Client to work with the extension since it relies on `lens://` protocol handler requests. - Added new util.js method to make console logging more helpful and consistent, replaced all existing `console` calls with new `logger` calls. - `AuthClient` now supports both Basic auth and SSO auth. - Auto-refreshing tokens under SSO works. - Possible to activate a cluster without having to re-query for the list of clusters that was already loaded (if any). - Renamed ClustersProvider to ClusterDataProvider to make it more different from ClusterActionsProvider when we use it throughout the code (we had `clustersActions` and `clusterActions` objects; now we have `clusterDataActions` and `clusterActions` with less chance of a mistake). - Fixed a bug in eventBus.ts where an exception thrown in an event handler would cause the event bus to infinitely call that handler in a loop. - Added 'Refresh' feature where once clusters are loaded, the 'Sign in' button changes to 'Refresh' and clicking it uses existing creds to reload/refresh the cluster list without going through full auth again (if creds are still valid). - Added ability to filter clusters to a list of specified namespaces via the 'add clusters' extension event. - Added instructions to Help section in README. - Cluster selection is limited to ONE cluster when using SSO because supporting multiple clusters would lead to a really bad UX (browser opening multiple times, user likely missing some of them) and spaghetti code (because it's more than just async requests since the event loop goes idle while waiting for the user to respond in the browser). - Added new "Refresh Data" experience where it's now possible to refresh (i.e. reload) clusters from the instance without re-authenticating (basic and SSO). - 'Add Clusters' via SSO now shows an info message to inform the user to expect their browser to open, and to click on "Open Lens" after authorization, and like the Login view, provides a Cancel button to abort the process in case something goes wrong in the browser.
1 parent d21ff7f commit ac0fd6f

File tree

4 files changed

+34
-5
lines changed

4 files changed

+34
-5
lines changed

src/cc/AddClusters.js

+25-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { useClusterActions } from './store/ClusterActionsProvider';
1111
import { useExtState } from './store/ExtStateProvider';
1212
import { Section as BaseSection } from './Section';
1313
import { layout } from './styles';
14+
import { InlineNotice } from './InlineNotice';
1415
import * as strings from '../strings';
1516

1617
const Section = styled(BaseSection)(function () {
@@ -31,7 +32,8 @@ export const AddClusters = function ({ onAdd, clusters, passwordRequired }) {
3132
} = useExtState();
3233

3334
const {
34-
state: { loading: addingClusters },
35+
state: { loading: addClustersLoading },
36+
actions: clusterActions
3537
} = useClusterActions();
3638

3739
const [password, setPassword] = useState('');
@@ -50,6 +52,10 @@ export const AddClusters = function ({ onAdd, clusters, passwordRequired }) {
5052
}
5153
};
5254

55+
const handleSsoCancelClick = function () {
56+
clusterActions.ssoCancelAddClusters();
57+
};
58+
5359
//
5460
// RENDER
5561
//
@@ -66,7 +72,7 @@ export const AddClusters = function ({ onAdd, clusters, passwordRequired }) {
6672
style={{ width: 200 }}
6773
type="password"
6874
theme="round-black" // borders on all sides, rounded corners
69-
disabled={addingClusters}
75+
disabled={addClustersLoading}
7076
value={password}
7177
onChange={handlePasswordChange}
7278
/>
@@ -81,11 +87,11 @@ export const AddClusters = function ({ onAdd, clusters, passwordRequired }) {
8187
primary
8288
disabled={
8389
clusters.length <= 0 ||
84-
addingClusters ||
90+
addClustersLoading ||
8591
(passwordRequired && !password)
8692
}
8793
label={strings.addClusters.action.label()}
88-
waiting={addingClusters}
94+
waiting={addClustersLoading}
8995
tooltip={
9096
clusters.length <= 0
9197
? strings.addClusters.action.disabledTip()
@@ -94,6 +100,21 @@ export const AddClusters = function ({ onAdd, clusters, passwordRequired }) {
94100
onClick={handleAddClick}
95101
/>
96102
</div>
103+
104+
{addClustersLoading &&
105+
<>
106+
<InlineNotice>
107+
<p dangerouslySetInnerHTML={{ __html: strings.addClusters.sso.messageHtml() }}/>
108+
</InlineNotice>
109+
<div>
110+
<Component.Button
111+
primary
112+
label={strings.addClusters.action.ssoCancel()}
113+
onClick={handleSsoCancelClick}
114+
/>
115+
</div>
116+
</>
117+
}
97118
</Section>
98119
);
99120
};

src/cc/store/ClusterActionsProvider.js

+3
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,9 @@ const _addClusters = async function ({
625625
const authClient = new AuthClient({ config });
626626
const url = authClient.getSsoAuthUrl({
627627
offline,
628+
// DEBUG TODO: specifying the cluster's client ID results in `invalid redirect_uri` error
629+
// on the ICC instance, so does the 'k8s' client somehow need to also whitelist it
630+
// like the 'kaas' does (since that client ID clearly works for accessing the API)?
628631
clientId: newClusters[0].idpClientId, // tokens unique to the cluster
629632
state: SSO_STATE_ADD_CLUSTERS
630633
});

src/cc/store/SsoAuthProvider.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export const useSsoAuth = function () {
183183
* @param {boolean} [options.notify] If true, error notification will be displayed;
184184
* otherwise, error is silent.
185185
*/
186-
cancel({ reason = strings.ssoAuthProvider.error.userCanceled(), notify = false }) {
186+
cancel({ reason = strings.ssoAuthProvider.error.userCanceled(), notify = false } = {}) {
187187
if (pr.loading) {
188188
pr.loading = false;
189189
pr.loaded = true;

src/strings.ts

+5
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,14 @@ export const addClusters: Dict = {
173173
tip: (username) =>
174174
`Password for user "${username}" is required to generate kubeConfigs`,
175175
},
176+
sso: {
177+
messageHtml: () =>
178+
`<strong>This instance uses SSO:</strong> Your default browser should open to the ${mccShortName} sign in page, if you aren't already signed in. Once you have signed-in, your browser will prompt you to open Lens. Be sure to accept in order to complete the process. Once you have opted to open Lens, the browser window can be closed.`,
179+
},
176180
action: {
177181
label: () => 'Add selected clusters',
178182
disabledTip: () => 'Select at least one cluster to add',
183+
ssoCancel: () => 'Cancel',
179184
},
180185
};
181186

0 commit comments

Comments
 (0)