locked
Is it possible to upload a x509 certificate programatically to Microsoft Registration Portal Manifest Using client_secret grant type? RRS feed

  • Question

  • User-1196723336 posted

    I have been stuck on this issue for some time now, I'm trying to upload a certificate that I have created programmatically on a asp.net web application.

    I know it's possible if the app was created on Azure ADD portal using https://graph.windows.net as resource and use

    var activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await Task.FromResult(accesstoken));
    
    var keyCredential = new KeyCredential
                    {
                        CustomKeyIdentifier = MyRootCAcert.GetCertHash(),
                        EndDate = expirationDate,
                        KeyId = Guid.NewGuid(),
                        StartDate = startDate,
                        Type = "AsymmetricX509Cert",
                        Usage = "Verify",
                        Value = binCert
                    };
    
    var application = await activeDirectoryClient.Applications
                      .GetByObjectId("***applicationID***").ExecuteAsync();
    
                    application.KeyCredentials.Add(keyCredential);
    application.UpdateAsync().Wait();

    However I have created a web app in Microsoft registration portal to access users calendars with read and write permissions and the code above doesn't work since my resource is https://graph.microsoft.com/ . I have been checking forums, documentation, blogs and everyone points to creating the app on Azure and using https://graph.windows.net as resource..

    Do I have to remake my app or is there a way to upload the certificate and I haven't researched good enough?

    All Help is appreciated!

    Tuesday, July 10, 2018 1:14 PM

All replies

  • User1724605321 posted

    Hi Ako Ni,

    Welcome to ASP.NET Forum .

    Ako Ni

    However I have created a web app in Microsoft registration portal to access users calendars with read and write permissions and the code above doesn't work since my resource is https://graph.microsoft.com/ . I have been checking forums, documentation, blogs and everyone points to creating the app on Azure and using https://graph.windows.net as resource..

    If https://graph.microsoft.com/ is your resource , you  are acquiring access token to use Microsoft Graph API , if https://graph.windows.net is your resource , you are using the Azure AD Graph API . There are two different APIs , you can't use an access token to access two different apis .

    You can  update x509 certificate to the Azure application mainfest with Microsoft.Azure.ActiveDirectory.GraphClient. (Azure AD Graph SDK). And you need to grant "Access the directory as signed-in userDELEGATED PERMISSIONS to your application in Azure portal .

    Please see the step by step code sample from here .

    Best Regards,

    Nan Yu

    Wednesday, July 11, 2018 6:29 AM
  • User-1196723336 posted

    If https://graph.microsoft.com/ is your resource , you  are acquiring access token to use Microsoft Graph API , if https://graph.windows.net is your resource , you are using the Azure AD Graph API . There are two different APIs , you can't use an access token to access two different apis .

    I know that, it just seems strange that it is possible with with Azure AD Graph API and not Microsoft Graph API. According to documentation by Microsoft, there will be no more development on Azure AD Graph API so I don't want to use that.

    Please see the step by step code sample from here .

    I know that as well, tried it and it works well but the other drawback is that I don't want a Native app, I'm fine with creating a one time signup experience for new users but I don't want them to sign in every time and especially not to cache Tokens to keep the application "alive".

    So the only way to go is via a Native app with Delegated Permissions?

    Wednesday, July 11, 2018 7:37 AM
  • User1724605321 posted

    Hi Ako Ni ,

    I know that, it just seems strange that it is possible with with Azure AD Graph API and not Microsoft Graph API. According to documentation by Microsoft, there will be no more development on Azure AD Graph API so I don't want to use that.

    Yes , Microsoft Grap API is recommended . I am not sure whether Microsoft Graph API supports uploading x509 certificate , you can request for Microsoft Graph API support .

    So the only way to go is via a Native app with Delegated Permissions?

    You can use web app , the difference is you need to provide client secret during authentication . As pointed in that thread , delegate permission is the only way if using Azure AD Graph API . Application permission can't do that .

    Best Regards,

    Nan Yu 

    Wednesday, July 11, 2018 8:26 AM
  • User-1196723336 posted

    Excuse the messy code but I just quickly created a web app to show the error code when trying to use client_credentials.

    var cliSecret = "JYgJb0Cn7m*";
    
    var cliID = "92786d43*";
    
    string authority = "https://login.microsoftonline.com/{0}/oauth2/v2.0/token";
    string graphResourceId = "https://graph.windows.net";
    authority = String.Format(authority, tenant);
    Uri servicePointUri = new Uri(graphResourceId);
    Uri serviceRoot = new Uri(servicePointUri, tenantID);
    
    AuthenticationContext authContext = new AuthenticationContext(authority);
    var accessToken = authContext.AcquireTokenAsync(graphResourceId, new ClientCredential(cli, clise)).Result.AccessToken;
    
    AsymmetricKeyParameter myCAprivateKey = null;
                    
    //generate a root CA cert and obtain the privateKey
    X509Certificate2 MyRootCAcert = CreateCertificateAuthorityCertificate("CN=OutlookIntegration", out myCAprivateKey);
    
    var activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await Task.FromResult(accessToken));
    
    //this works
    var userrs = await activeDirectoryClient.Users.ExecuteAsync();
    
    
    var expirationDate = DateTime.Parse(MyRootCAcert.GetExpirationDateString()).ToUniversalTime();
    var startDate = DateTime.Parse(MyRootCAcert.GetEffectiveDateString()).ToUniversalTime();
    var binCert = MyRootCAcert.GetRawCertData();
    var keyCredential = new KeyCredential
        {
            CustomKeyIdentifier = MyRootCAcert.GetCertHash(),
            EndDate = expirationDate,
            KeyId = Guid.NewGuid(),
            StartDate = startDate,
            Type = "AsymmetricX509Cert",
            Usage = "Verify",
            Value = binCert
         };
    
    
    var application = await activeDirectoryClient.Applications.GetByObjectId("170187*").ExecuteAsync();
    application.KeyCredentials.Add(keyCredential);
    
    //exits with error
    await application.UpdateAsync();
    
    
    
    //error Code
    {"odata.error":{"code":"Authorization_RequestDenied","message":{"lang":"en","value":"Insufficient privileges to complete the operation."}}}

    I am the admin of my own domain, I have given "Access the directory as the signed-in user" and granted but still get "Insufficient privileges to complete the operation." Keep in mind that now it's a web app and I get the token without a user

    Wednesday, July 11, 2018 8:27 AM
  • User1724605321 posted

    Hi Ako Ni,

    See your authority :   

    string authority = "https://login.microsoftonline.com/{0}/oauth2/v2.0/token";

    You are using the Azure AD V2.0 Endpoint . May I confirm where you register the application ? If in azure portal , you are uing Azure AD v1.0 endpoint ,just delete the v2.0 part in authority .

    When using :

    var accessToken = authContext.AcquireTokenAsync(graphResourceId, new ClientCredential(cli, clise)).Result.AccessToken;
    

    You are acquiring access token using client credential flow , as i pointed , you can't using client credential flow . please use code flow to acquire access token .

    Best Regards,

    Nan Yu

    Wednesday, July 11, 2018 8:36 AM
  • User-1196723336 posted

    Hi Nan Yu,

    Thanks for the help! I think I will give up on this since I don't want to use code flow and cache tokens (I'm assuming you mean this) and maybe go for the worst case scenario and use selenium to automate the process. This is indeed very strange, if this operation already exists with Azure Graph Api I see no reason why it shouldn't exist for Microsoft Graph Api since it's where Microsoft is spending all their efforts.

    Thanks for the help and clarification :)!

    Wednesday, July 11, 2018 8:47 AM
  • User1724605321 posted

    Hi Ako Ni,

    Then i would suggest you could ask for microsoft graph api support(ask on SO with Microsoft Graph api tag ) since it may provide the application permission to upload the certificate .

    Best Regards,

    Nan Yu

    Wednesday, July 11, 2018 9:16 AM
  • User-1196723336 posted

    Hi Nan Yu,

    Could you clearify one more thing for me, If I understand correctly Client_Assertion is used for Azure Grapp Api and not Microsoft Graph api? so inorder to use client_assertion grant type then the app must use Azure graph api?

    Wednesday, July 11, 2018 1:09 PM
  • User1724605321 posted

    Hi Ako Ni ,

    You can use client secret or Client_Assertion to  prove the token request came from the client  ,see :

    https://docs.microsoft.com/en-us/azure/architecture/multitenant-identity/client-assertion 

    That is nothing related to  Azure Graph Api /Microsoft Graph API or any other API . That is a way for the client  to authenticate itself to the server during the authentication .

    Best Regards,

    Nan Yu

    Thursday, July 12, 2018 1:47 AM