Search code examples
javajava-8jwtazure-ad-msalkusto-java-sdk

Unable to authenticate Kusto Client using JWTToken


We use Java 8 and msal4j version 0.6.0-preview. To connect to Kusto, we use JWT Token:

ConnectionStringBuilder csb = ConnectionStringBuilder.createWithAadAccessTokenAuthentication(resourceUri, accessToken);
Client kustoClient = ClientFactory.createClient(csb);

Inside thencreateWithAadAccessTokenAuthentication(), it is calling this ConnectionStringBuilder constructor:

public static ConnectionStringBuilder createWithAadAccessTokenAuthentication(String resourceUri, String token) {
        if (StringUtils.isEmpty(resourceUri)) {
            throw new IllegalArgumentException("resourceUri cannot be null or empty");
        } else if (StringUtils.isEmpty(token)) {
            throw new IllegalArgumentException("token cannot be null or empty");
        } else {
            ConnectionStringBuilder csb = new ConnectionStringBuilder(resourceUri);
            csb.accessToken = token;
            return csb;
        }
    }

it is setting every field to null except for clusterUri.

private ConnectionStringBuilder(String resourceUri) {
        this.clusterUri = resourceUri;
        this.usernameHint = null;
        this.applicationClientId = null;
        this.applicationKey = null;
        this.aadAuthorityId = null;
        this.x509Certificate = null;
        this.privateKey = null;
        this.accessToken = null;
        this.tokenProvider = null;
    }

Thus we got an error from createClient() method. Because it is calling ClientImpl(csb). host and auth are returning null, which triggers null pointer exception in this line: String auth = clusterUri.getAuthority().toLowerCase();

public static Client createClient(ConnectionStringBuilder csb) throws URISyntaxException {
        return new ClientImpl(csb);
    }

 public ClientImpl(ConnectionStringBuilder csb) throws URISyntaxException {
        String url = csb.getClusterUrl();
        URI clusterUri = new URI(url);
        String host = clusterUri.getHost();
        String auth = clusterUri.getAuthority().toLowerCase();
        if (host == null && auth.endsWith(";fed=true")) {
            url = (new URIBuilder()).setScheme(clusterUri.getScheme()).setHost(auth.substring(0, clusterUri.getAuthority().indexOf(";fed=true"))).toString();
            csb.setClusterUrl(url);
        }

        this.clusterUrl = url;
        this.aadAuthenticationHelper = TokenProviderFactory.createTokenProvider(csb);
        this.clientVersionForTracing = "Kusto.Java.Client";
        String version = Utils.getPackageVersion();
        if (StringUtils.isNotBlank(version)) {
            this.clientVersionForTracing = this.clientVersionForTracing + ":" + version;
        }

        if (StringUtils.isNotBlank(csb.getClientVersionForTracing())) {
            this.clientVersionForTracing = this.clientVersionForTracing + "[" + csb.getClientVersionForTracing() + "]";
        }

        this.applicationNameForTracing = csb.getApplicationNameForTracing();
    }

What are the other alternatives here?


Solution

  • After talking F2F we found the issue is with the value passed in the resourceUri param, while this expects a url of the cluster ("https://cluster.region.kusto.windows.net") the provided uri was the ARM resource uri hence no host and no auth sections of the URL were parsed by the call to new URI().