azure-sdk-for-java icon indicating copy to clipboard operation
azure-sdk-for-java copied to clipboard

[BUG] com.azure.resourcemanager.AzureResourceManager.Authenticated.activeDirectoryUsers() are returning null

Open luisCavalcantiDev opened this issue 2 years ago • 12 comments

Describe the bug All methods of the com.azure.resourcemanager.authorization.models.ActiveDirectoryUser obtained via com.azure.resourcemanager.AzureResourceManager.Authenticated.activeDirectoryUsers() are returning null (except for basic properties like principalName and id, for example).

Steps to reproduce the behavior: 1 - Configure credentials and create com.azure.resourcemanager.AzureResourceManager; 2 - List activeDirectoryUsers() and call methods;

Code Snippet

package br.com.luiscavalcantidev.azure.activedirectory;

import com.azure.core.management.AzureEnvironment;
import com.azure.core.management.profile.AzureProfile;
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.azure.resourcemanager.AzureResourceManager;
import com.azure.resourcemanager.AzureResourceManager.Authenticated;
import com.azure.resourcemanager.authorization.fluent.models.MicrosoftGraphUserInner;
import com.azure.resourcemanager.authorization.models.ActiveDirectoryUser;

public class AzureActiveDirectoryApp {
    public static void main(String[] args) {
        final String subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
        final String applicationId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
        final String tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
        final String secret = "xx.xxxxxxxxxxxx_xx_xxxxxxxxxxxxxxx";
        
        final AzureProfile azureProfile = new AzureProfile(tenantId, subscriptionId, AzureEnvironment.AZURE);
        
        final ClientSecretCredential secretCredential = new ClientSecretCredentialBuilder()
                .clientId(applicationId)
                .clientSecret(secret)
                .tenantId(tenantId)
                .build();

        final Authenticated azureResourceManager = AzureResourceManager.configure()
                .authenticate(secretCredential, azureProfile);
        
        for (ActiveDirectoryUser user : azureResourceManager.activeDirectoryUsers()
                .list()) {
            final MicrosoftGraphUserInner innerModel = user.innerModel();

            // Do not return null
            System.out.println("user.id                                  :" + user.id());
            System.out.println("user.mail                                :" + user.mail());
            System.out.println("user.principalName                       :" + user.userPrincipalName());
            System.out.println("innerModel.displayName                   :" + innerModel.displayName());

            // Return null
            System.out.println("innerModel.userType                      :" + innerModel.userType());
            System.out.println("innerModel.creationType                  :" + innerModel.creationType());
            System.out.println("innerModel.accountEnabled                :" + innerModel.accountEnabled());
            System.out.println("innerModel.createdDateTime               :" + innerModel.createdDateTime());
            System.out.println("innerModel.lastPasswordChangeDateTime    :" + innerModel.lastPasswordChangeDateTime());
        }
    }
}

Expected behavior Response with all methods returning what they "should" in the same way as console/CLI.

Screenshots overview (2)

Setup: OS: Linux/Windows IDE: Apache NetBeans 15 Library/Libraries: com.azure.resourcemanager 2.12.0 Java version: 8

Additional context We have all necessary/additional application API permissions for this operation: User.Read.All, Group.Read.All, Directory.Read.All and GroupMember.Read.All.

luisCavalcantiDev avatar Sep 15 '22 13:09 luisCavalcantiDev

@weidongxu-microsoft could you please take a look at this issue reported by @luisCavalcantiDev

joshfree avatar Sep 15 '22 18:09 joshfree

@XiaofeiCao Could you take a look?

There could be some field that not populated during List, but have value when Get on single item.

weidongxu-microsoft avatar Sep 16 '22 02:09 weidongxu-microsoft

@luisCavalcantiDev

PS: if you are doing advanced work on MSGraph, you might want to use their dedicated SDK here https://github.com/microsoftgraph/msgraph-sdk-java

weidongxu-microsoft avatar Sep 16 '22 02:09 weidongxu-microsoft

@luisCavalcantiDev Seems that default list returns only these properties(id, name, etc).

You can add select parameter to enable retrieval of the properties you need:

final String consistencyLevel = null;
final Integer top = null;
final Integer skip = null;
final String search = null;
final String filter = null;
final Boolean count = null;
final List<Get6ItemsItem> orderby = null;
// add properties you need to the list
final List<Get7ItemsItem> select = List.of(
  Get7ItemsItem.ID, 
  Get7ItemsItem.MAIL,
  Get7ItemsItem.USER_PRINCIPAL_NAME,
  Get7ItemsItem.DISPLAY_NAME,
  Get7ItemsItem.USER_TYPE,
  Get7ItemsItem.CREATION_TYPE,
  Get7ItemsItem.ACCOUNT_ENABLED,
  Get7ItemsItem.CREATED_DATE_TIME,
  Get7ItemsItem.LAST_PASSWORD_CHANGE_DATE_TIME
);

final List<Get8ItemsItem> expand = null;

for (MicrosoftGraphUserInner innerModel : azureResourceManager.activeDirectoryUsers()
   .manager().serviceClient().getUsersUsers().listUser(consistencyLevel, top, skip, search, filter, count, orderby, select, expand, Context.NONE)) {

   // Do not return null
   System.out.println("user.id                                  :" + innerModel.id());
   System.out.println("user.mail                                :" + innerModel.mail());
   System.out.println("user.principalName                       :" + innerModel.userPrincipalName());
   System.out.println("innerModel.displayName                   :" + innerModel.displayName());

   // Should return non-null value for existing properties
   System.out.println("innerModel.userType                      :" + innerModel.userType());
   System.out.println("innerModel.creationType                  :" + innerModel.creationType());
   System.out.println("innerModel.accountEnabled                :" + innerModel.accountEnabled());
   System.out.println("innerModel.createdDateTime               :" + innerModel.createdDateTime());
   System.out.println("innerModel.lastPasswordChangeDateTime    :" + innerModel.lastPasswordChangeDateTime());
}

XiaofeiCao avatar Sep 16 '22 07:09 XiaofeiCao

@XiaofeiCao

If those fields are exposed by AADUser model, we probably should set them in select on our list API.

But if these fields are not exposed, user is recommended to use MSGraph lib. The few AAD related API in this lib is mostly for getting an AADUser and assign some access control to it via RBAC, not actually for managing AAD users.

weidongxu-microsoft avatar Sep 19 '22 08:09 weidongxu-microsoft

@weidongxu-microsoft

The fields are exposed in MicrosoftGraphUserInner.

In portal, list and get use different sets of select paramters. The properties that this issue requests (createdDateTime, accountEnabled, etc) is not included in list but rather in get.

We can use same sets of select to align with portal. But I'm not sure this is what the issue wants.

XiaofeiCao avatar Sep 20 '22 02:09 XiaofeiCao

@XiaofeiCao I mean our handwritten model, not the Inner one (we assume user will not use the Inner, if they use, they are on their own).

weidongxu-microsoft avatar Sep 20 '22 02:09 weidongxu-microsoft

@weidongxu-microsoft Oh, sorry. They are not exposed in our handwritten model ActiveDirectoryUser.

XiaofeiCao avatar Sep 20 '22 02:09 XiaofeiCao

Hi @luisCavalcantiDev. Thank you for opening this issue and giving us the opportunity to assist. We believe that this has been addressed. If you feel that further discussion is needed, please add a comment with the text “/unresolve” to remove the “issue-addressed” label and continue the conversation.

ghost avatar Sep 22 '22 02:09 ghost

/unresolve

luisCavalcantiDev avatar Sep 22 '22 13:09 luisCavalcantiDev

@XiaofeiCao, @weidongxu-microsoft thanks for the replies.

The suggestion of using selection as an argument to the User list is working.

However, I understand the original method I used is broken the way it is, since there is nothing suggesting the returned objects will be half populated. Either the current behavior should be documented or it should be fixed to populate all properties as expected.

luisCavalcantiDev avatar Sep 22 '22 13:09 luisCavalcantiDev

@XiaofeiCao

If those fields are exposed by AADUser model, we probably should set them in select on our list API.

But if these fields are not exposed, user is recommended to use MSGraph lib. The few AAD related API in this lib is mostly for getting an AADUser and assign some access control to it via RBAC, not actually for managing AAD users.

@luisCavalcantiDev The simple thing is that we don't recommend to use this lib to manage AAD user. Please switch to https://github.com/microsoftgraph/msgraph-sdk-java

weidongxu-microsoft avatar Sep 23 '22 01:09 weidongxu-microsoft

@weidongxu-microsoft We're taking a look at the API you recommended, despite our intention being simply to perform read only operations, not to manage users or groups. However, there is no clear statement in the documentation about the limitations of the API we're using and AADUser IinnerModel having many methods which seem to return relevant information but end up being useless may confuse users.

luisCavalcantiDev avatar Sep 26 '22 18:09 luisCavalcantiDev

@luisCavalcantiDev

Some context, the innerModel is considered an implementation detail, and serves as an escape-hatch -- when user cannot find the property from other getters, they can try query there, as service may add new JSON property without our notice.

However, the drawback is that it is not something guaranteed (we don't test these), and it might get broken without notice (as it is considered implementation detail). Actually, we had already changed that detail when upgrading from AD Graph to MS Graph around SDK version 2.2.0.

Similar about the REST API reported by Xiaofei https://github.com/Azure/azure-sdk-for-java/issues/30981#issuecomment-1249042764. It is regarded as implementation, as hinted by the meaningless naming.

Sorry about above not well documented.


I will leave the decision to @XiaofeiCao, of whether to add an overload of "list" with "select" parameter to let you input the required properties as String.

But know that this would not be our priority. Our priority is still to better provide the feature to manage Azure resource (this does not include AAD), and AAD is only included to provide easy-to-use RBAC on the Azure resource.

weidongxu-microsoft avatar Sep 27 '22 13:09 weidongxu-microsoft