diff --git a/extensions/big-data-cluster/src/bigDataCluster/controller/clusterControllerApi.ts b/extensions/big-data-cluster/src/bigDataCluster/controller/clusterControllerApi.ts index 88918db3d1..56b39a8126 100644 --- a/extensions/big-data-cluster/src/bigDataCluster/controller/clusterControllerApi.ts +++ b/extensions/big-data-cluster/src/bigDataCluster/controller/clusterControllerApi.ts @@ -159,17 +159,36 @@ export class ClusterController implements IClusterController { } } + /** + * Verify that this cluster supports Kerberos authentication. It does this by sending a request to the Token API route + * without any credentials and verifying that it gets a 401 response back with a Negotiate www-authenticate header. + */ private async verifyKerberosSupported(): Promise { let tokenApi = new TokenRouterApi(this._url); tokenApi.setDefaultAuthentication(new SslAuth()); try { await tokenApi.apiV1TokenPost(); - // If we get to here, the route for endpoints doesn't require auth so state this is false + console.warn(`Token API returned success without any auth while verifying Kerberos support for BDC Cluster ${this._url}`); + // If we get to here, the route for tokens doesn't require auth which is an unexpected error state return false; } catch (error) { - let auths = error && error.response && error.response.statusCode === 401 && error.response.headers['www-authenticate']; - return auths && auths.includes('Negotiate'); + if (!error.response) { + console.warn(`No response when verifying Kerberos support for BDC Cluster ${this._url} - ${error}`); + return false; + } + + if (error.response.statusCode !== 401) { + console.warn(`Got unexpected status code ${error.response.statusCode} when verifying Kerberos support for BDC Cluster ${this._url}`); + return false; + } + + const auths = error.response.headers['www-authenticate'] as string[] ?? []; + if (auths.includes('Negotiate')) { + return true; + } + console.warn(`Didn't get expected Negotiate auth type when verifying Kerberos support for BDC Cluster ${this.url}. Supported types : ${auths.join(', ')}`); + return false; } } diff --git a/extensions/mssql/src/sqlClusterLookUp.ts b/extensions/mssql/src/sqlClusterLookUp.ts index d67379fd53..6f7eeff69d 100644 --- a/extensions/mssql/src/sqlClusterLookUp.ts +++ b/extensions/mssql/src/sqlClusterLookUp.ts @@ -107,6 +107,12 @@ async function createSqlClusterConnInfo(sqlConnInfo: azdata.IConnectionProfile | options: {} }; + // We need to populate some extra information here in order to be able to browse the HDFS nodes. + // First - if the auth type isn't integrated auth then we need to try and find the username to connect + // to the knox endpoint with. + // Next we need the knox endpoint - if we didn't get that from the SQL instance (because the user didn't have permissions + // to see the full DMV usually) then we need to connect to the controller to fetch the full list of endpoints and get it + // that way. let clusterController: bdc.IClusterController | undefined = undefined; let authType = clusterConnInfo.options[constants.authenticationTypePropName] = sqlConnInfo.options[constants.authenticationTypePropName]; const controllerEndpoint = endpoints.find(ep => ep.name.toLowerCase() === 'controller'); @@ -129,12 +135,11 @@ async function createSqlClusterConnInfo(sqlConnInfo: azdata.IConnectionProfile | console.log(`Unexpected error getting Knox username for SQL Cluster connection: ${err}`); throw err; } - } else { - clusterController = await getClusterController(controllerEndpoint.endpoint, clusterConnInfo); } let hadoopEndpointIndex = endpoints.findIndex(ep => ep.name.toLowerCase() === constants.hadoopEndpointNameGateway.toLowerCase()); if (hadoopEndpointIndex < 0) { + clusterController = await getClusterController(controllerEndpoint.endpoint, clusterConnInfo); endpoints = (await clusterController.getEndPoints()).endPoints; hadoopEndpointIndex = endpoints.findIndex(ep => ep.name.toLowerCase() === constants.hadoopEndpointNameGateway.toLowerCase()); } @@ -156,7 +161,8 @@ async function getClusterController(controllerEndpoint: string, connInfo: Connec connInfo.options[constants.userPropName], connInfo.options[constants.passwordPropName]); try { - await controller.getClusterConfig(); + // We just want to test the connection - so using getEndpoints since that is available to all users (not just admin) + await controller.getEndPoints(); return controller; } catch (err) { // Initial username/password failed so prompt user for username password until either user @@ -187,7 +193,8 @@ async function getClusterController(controllerEndpoint: string, connInfo: Connec } const controller = bdcApi.getClusterController(controllerEndpoint, authType, username, password); try { - await controller.getClusterConfig(); + // We just want to test the connection - so using getEndpoints since that is available to all users (not just admin) + await controller.getEndPoints(); // Update our connection with the new info connInfo.options[constants.userPropName] = username; connInfo.options[constants.passwordPropName] = password; diff --git a/extensions/notebook/src/jupyter/jupyterSessionManager.ts b/extensions/notebook/src/jupyter/jupyterSessionManager.ts index 886cd9c4cd..2d4823edc0 100644 --- a/extensions/notebook/src/jupyter/jupyterSessionManager.ts +++ b/extensions/notebook/src/jupyter/jupyterSessionManager.ts @@ -395,7 +395,8 @@ async function getClusterController(controllerEndpoint: string, authType: bdc.Au username, password); try { - await controller.getClusterConfig(); + // We just want to test the connection - so using getEndpoints since that is available to all users (not just admin) + await controller.getEndPoints(); return controller; } catch (err) { // Initial username/password failed so prompt user for username password until either user @@ -426,7 +427,8 @@ async function getClusterController(controllerEndpoint: string, authType: bdc.Au } const controller = bdcApi.getClusterController(controllerEndpoint, authType, newUsername, newPassword); try { - await controller.getClusterConfig(); + // We just want to test the connection - so using getEndpoints since that is available to all users (not just admin) + await controller.getEndPoints(); return controller; } catch (err) { errorMessage = localize('bdcConnectError', "Error: {0}. ", err.message ?? err);