Skip to content

Configuring GraphServiceClient with no scope throws UnsupportedOperationException during runtime #1882

@joakibj

Description

@joakibj

Expected behavior

Initializing GraphServiceClient with no scope argument should default to scope https://graph.microsoft.com/.default when using azure-identity TokenCredential and fetch the token

Actual behavior

Attempt to fetch Azure token fails with UnsupportedOperationException during runtime

Steps to reproduce the behavior

Java version:

openjdk version "17.0.10" 2024-01-16
OpenJDK Runtime Environment Temurin-17.0.10+7 (build 17.0.10+7)
OpenJDK 64-Bit Server VM Temurin-17.0.10+7 (build 17.0.10+7, mixed mode, sharing)

Include on classpath:

<dependency>
	<groupId>com.microsoft.graph</groupId>
	<artifactId>microsoft-graph</artifactId>
	<version>6.4.0</version>
</dependency>
<dependency>
	<groupId>com.azure</groupId>
	<artifactId>azure-identity</artifactId>
	<version>1.11.3</version>
</dependency>

Implement the following code:

public class MsGraphConsumer {
	private final GraphServiceClient graphClient;

	public MsGraphConsumer(AzureProperties azureProperties) {
		ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
				.tenantId(azureProperties.appTenantId())
				.clientId(azureProperties.appClientId())
				.clientSecret(azureProperties.appClientSecret())
				.build();
		this.graphClient = new GraphServiceClient(clientSecretCredential);
	}

	public Optional<User> getUser(String orgInternalId) {
		try {
			List<User> res = graphClient
					.users()
					.get(requestConfiguration -> {
						requestConfiguration.headers.add("ConsistencyLevel", "eventual");
						requestConfiguration.queryParameters.filter = "onPremisesSamAccountName eq '" + orgInternalId + "'";
						requestConfiguration.queryParameters.count = true;
						requestConfiguration.queryParameters.select = new String[]{"id"};
					}).getValue();
			if (res.isEmpty()) {
				return Optional.empty();
			}
			return Optional.of(res.get(0));
		} catch (ApiException e) {
			throw e;
		}
	}
}

Execute the method msGraphConsumer.getUser("hello"). Observe the following stacktrace:

java.lang.UnsupportedOperationException: null
	at java.base/java.util.AbstractList.add(AbstractList.java:153)
	at java.base/java.util.AbstractList.add(AbstractList.java:111)
	at com.microsoft.kiota.authentication.AzureIdentityAccessTokenProvider.getAuthorizationToken(AzureIdentityAccessTokenProvider.java:133)
	at com.microsoft.kiota.authentication.BaseBearerTokenAuthenticationProvider.authenticateRequest(BaseBearerTokenAuthenticationProvider.java:46)
	at com.microsoft.kiota.http.OkHttpRequestAdapter.getHttpResponseMessage(OkHttpRequestAdapter.java:709)
	at com.microsoft.kiota.http.OkHttpRequestAdapter.send(OkHttpRequestAdapter.java:274)
	at com.microsoft.graph.users.UsersRequestBuilder.get(UsersRequestBuilder.java:120)
	at com.github.example.MsGraphConsumer.getUser(MsGraphConsumer.java:53)

Workaround

Set the scope directly or initialise scopes as null:

new GraphServiceClient(clientSecretCredential, "https://graph.microsoft.com/.default");
new GraphServiceClient(clientSecretCredential,  null);

Authors remarks

Looks like this is due to com.microsoft.kiota.authentication.AzureIdentityAccessTokenProvider:66 assigns scopes using the Arrays.ArrayList type that does not implement add

Metadata

Metadata

Assignees

No one assigned

    Labels

    Standard GitHub labelIssue caused by core project dependency modules or librarybug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions