Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New connection to MSCommerce #46

Open
andikrueger opened this issue Apr 1, 2020 · 28 comments
Open

New connection to MSCommerce #46

andikrueger opened this issue Apr 1, 2020 · 28 comments

Comments

@andikrueger
Copy link
Contributor

The current implementation of the MSCommerce module does not allow to pass credentials into Connect-MSCommerce cmdLet. The module is used to change the self service licensing options within PowerPlatform.

The implementation could be very similar to Get-PowerPlatformTokenInfo:

$ClientId = "3d5cffa9-04da-4657-8cab-c7f074657cad"
$Resource = "aeb86249-8ea3-49e2-900b-54cc8e308f85" # Licensemanager API
$O365Credentials

Import-Module 'Microsoft.PowerApps.Administration.PowerShell' -Force
$authContext = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext("https://login.windows.net/common");
$credential = [Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential]::new($O365Credentials.Username, $O365Credentials.Password)
$token = $authContext.AcquireToken($Resource, $ClientId, $O365Credentials) 
@andikrueger
Copy link
Contributor Author

I did some test with the MSCommerce module and do not see a feasible way to get this one implemented any soon. The Connect-MSCommerce function doesn't have a credential parameter and will prompt for credentials.

I tried to create a connection with the sinpped above (which works great by the way) but am not able to inject the token into the PSCmdlet Sessionstate that is used be the module to handle authentication information.

@andikrueger
Copy link
Contributor Author

Actually there is a way to create a connection with credentials. I outlined the solution here. The solution requires some modification of the MSCommerce module.

https://github.com/MicrosoftDocs/microsoft-365-docs/issues/799#issuecomment-895024416

@salbeck-sit
Copy link

salbeck-sit commented Sep 27, 2023

Maybe the trail has gone cold, but I'd like to add that it's also possible to add parameter TenantId to Connect-MSCommerce. It can be used either with or without credentials as it simply changes the 'authority-URL' used in the code to create the context for the accesstoken.

Like this:

if ($TenantId) {
$authorityUrl = "https://login.microsoftonline.com/$TenantId"
} else {
$authorityUrl = "https://login.microsoftonline.com/common"
}

$authCtx = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" $authorityUrl

$platformParams = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" ([Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Always)

if ($PSBoundParameters.ContainsKey('UserCredential')) {
$credential = [Microsoft.IdentityModel.Clients.ActiveDirectory.UserPasswordCredential]::new($UserCredential.Username, $UserCredential.Password)
$token = [Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContextIntegratedAuthExtensions]::AcquireTokenAsync($authCtx, $Resource, $ClientId, $credential).Result
} else {
$token = $authCtx.AcquireTokenAsync($Resource, $ClientId, $RedirectUri, $platformParams).Result
}

@andikrueger
Copy link
Contributor Author

I just found this repository and this looks like a feasible approach to handle this request:

https://github.com/Gerenios/AADInternals/blob/master/MSCommerce.ps1

@salbeck-sit
Copy link

As in the above suggestion it still has to be verified that MFA-less authentication is possible with credentials, ie that the app respects Conditional Access policies.
The M365 License Manager app that is utilized provides only one app-permission that seems like it might be useful (LicenseManager.Fulfillment) and that is in my view the problem. OTOH if it does prove useful that changes the picture.

Since MS is pushing the Secure Application Method more and more, I'd like to see that push reflected here, ie. in an additional AppRole that allows management of self-service purchase options, but the team that is responsible for maintaining self-service purchasing apparently doesn't see the feature as something that enterprises (or CSPs) would want to control.

@rvdwegen
Copy link

rvdwegen commented Apr 7, 2024

Since MS is pushing the Secure Application Method more and more, I'd like to see that push reflected here, ie. in an additional AppRole that allows management of self-service purchase options, but the team that is responsible for maintaining self-service purchasing apparently doesn't see the feature as something that enterprises (or CSPs) would want to control.

Or skip the module all together, https://blog.vdwegen.app/posts/disable-selfservice-licenses/

@Grime121
Copy link

Grime121 commented Apr 9, 2024

rvdwegen,

Where am I supposed to get the RefreshToken from?

@salbeck-sit
Copy link

The blog contains a link to an another article that describes how to get it.

@Grime121
Copy link

Grime121 commented Apr 10, 2024

I didn’t see any clear way of obtaining it via that website. Maybe I overlooked it. If you could point it out, that would be helpful. All I saw on there was normal stuff about how to create a Registered App and a Client Secret. Do you have to use Postman or something to get the RefreshToken? I don’t have much experience with that…. I have quite a lot of PS experience, but not much with HTTP requests or API-related stuff. Everything else in the articles appears to be Web GUI and PS-based. If obtaining the RefreshToken has to be done via some other method, some clearer instructions would be helpful.

I’m not writing a web application here…. I’m simply trying to disable the Self-Service Teams Premium Trial licenses. The stupid MSCommerce module doesn’t work. I can’t get Connect-MSCommerce to work despite creating my own registered app for it, so I’m trying this method now. I’ve had a case open with MS for the issue for over a week now, and all they seem to be able to tell me is “Duuuh, well, it works in my test environment, so I dunno…”

@salbeck-sit
Copy link

It's the link near the top hiding behind 'this post from Nick from T-Minus 365'.
https://tminus365.com/my-automations-break-with-gdap-the-fix/

@Grime121
Copy link

Yeah, I saw that, but the New-PartnerAccessToken cmlet didn't work. I thought it was kind of strange that I had to do anything related to partner access to get this working, too, but I finally figured out that I needed to install the PartnerCenter module. The instructions are just a bit convoluted, but once I installed the module I was able to piece it all together, and it get it to work.

Thanks!

@CharbelNemnom
Copy link

CharbelNemnom commented May 27, 2024

Hello @salbeck-sit, what if we don't use Partner Center, how to get this working without interactive login (for automation) and without using the MSCommerce module?
I need to do it on one Tenant for testing. So, the 'RefreshToken' is not option in our case as described above.
Could you please illustrate with more details?

CC @Grime121, could you please describe your steps you took in more details?
Thanks!

@salbeck-sit
Copy link

@CharbelNemnom the article I linked to contains a REST-call to obtain a token. I'm not particularly fond of refresh-tokens either and though I haven't had time to verify it, my thought is to use something like Get-MsalToken from MSAL.PS to obtain the required bearer token.
Interestingly, the cmdlets in the MSCommerce-module all contain the parameter -Token so once you have that you can use the official code. I hope to get some time to try it out myself but that's my thoughts so far.

@CharbelNemnom
Copy link

Thank you @salbeck-sit, which article are you referring to, is this one ()?

I just checked, the Connect-MSCommerce function in the official code does NOT contain the "-Token" parameter. Are you sure? I am using the MSCommerce Version 2.3 official module.

The issue that I am facing that I need to connect non-interactive to disable self-service purchase licenses.

Any guidance is highly appreciated!

@salbeck-sit
Copy link

The Connect-MSCommerce cmdlet does not support -Token as the purpose of the cmdlet is to provide a token.
You can use the -Token parameter on other MSCommerce-cmdlets instead of relying on Connect-MSCommerce.
As I wrote, I haven't had time to test it but it seems reasonable given that the cmdlets are all pure Powershell and the code indicates that the token provided in the -Token parameter will override that provided by Connect-MSCommerce.

@CharbelNemnom
Copy link

CharbelNemnom commented May 28, 2024

Thank you @salbeck-sit, I tried your approach by using the Get-MsalToken from MSAL.PS to obtain the required bearer token, as follows.

$TenantId = "000000000000000000"
$ApplicationID = "000000000000000000000"
$ApplicationSecret = "00000000000000000"
$scope = 'https://graph.microsoft.com/.default'
$AppCredential = ConvertTo-SecureString $ApplicationSecret -AsPlainText -Force

$token = Get-MsalToken -ClientId $ApplicationID -ClientSecret $AppCredential -TenantId $TenantId -Scope $scope -RedirectUri 'http://localhost/m365/commerce'

$products = Get-MSCommerceProductPolicies -Token $token.AccessToken -PolicyId AllowSelfServicePurchase | Where-Object { $_.PolicyValue -eq "Enabled" }

But when I tried to use the "Get-MSCommerceProductPolicies -Token $token.AccessToken" I am getting the following error:

Write-Error: Your credentials have expired. Please, call Connect-MSCommerce again to regain access to MSCommerce Module.

Any guidance is highly appreciated!

@rvdwegen
Copy link

@CharbelNemnom
Could you help me understand your situation a bit better? It would help in recommending a specific path.
From your comments I think:

  • You do manage multiple tenants
  • You are not a Microsoft Partner and/or do not have Partner Center

Is that correct?

@CharbelNemnom
Copy link

Hello @rvdwegen, yes, I am in the situation you described above.

I tried your code, but it didn’t work as we don’t have Partner Center.
I need to simply automate and disable purchase licenses (non-interactive) using the API through Entra Client ID and Secret or using the MSCommerce module.

Could you please provide more details?

Thank You!

@rvdwegen
Copy link

As far as I can tell without specific testing the M365 License Manager app doesn't expose any application context permissions that allow for enabling/disabling self purchase. That's likely the main issue here.
You need a delegated identity that has the role permissions needed to manage these which has access to all tenants. But given you don't have Partner Center and thus no GDAP you don't have that.

I can think of ways around this, but they're all convoluted (setup individual automation per tenant) or dirty (make a service account in your tenant, add them as guest users in customer tenants and give them whatever role is needed).

@CharbelNemnom
Copy link

Thank you @rvdwegen, for the information!

Just to simplify this. We already have an individual Service Principal in each customer's tenant. My idea is to use it, add the M365 License Manager API permissions to it, and automate by connecting to each tenant and disabling self-purchase.

But as you mentioned, the M365 License Manager app doesn't expose any application context permissions that allow for enabling/disabling self-purchase, so here the main issue lies.

I didn't understand the workaround you noted below. Could you provide more details.

//I can think of ways around this, but they're all convoluted (setup individual automation per tenant) or dirty (make a service account in your tenant, add them as guest users in customer tenants and give them whatever role is needed).\

Thank You!

@salbeck-sit
Copy link

Did a quick test with a custom app. Got the same error you did (code 403 - forbidden).
I then noticed that the latest version of MSCommerce (2.3) now uses class [Microsoft.Identity.Client.PublicClientApplicationBuilder] to build the clientApp used to acquire a token. The resulting clientApp exposes methods AcquireTokenAsync but the module uses AcquireTokenInteractive. The module could but doesn't use clientbuilder.WithAuthority(..) to specify a tenant meaning that the principal logging in also identifies the tenant as it does in version 1.10 that I previously fiddled with.
There's also an option to specify an alternate clientId using clientbuilder.WithClientId(...) and for this purpose also ...WithRedirectUri(...)
The resulting token should nonetheless be the same as when acquiring the token explicitly via REST
Not sure if the above is easier or harder - it seems to assume that you are familiar with .NET which I'm not, so for me this would be hit-and-miss.

@rvdwegen
Copy link

Doesn't matter how you request a token. What matters here is if its app or delegated context

@CharbelNemnom
Copy link

What is the workaround @rvdwegen, in this case?

@rvdwegen
Copy link

You need to either work interactively, or request and store a refreshtoken (not for partner center in your case but likely for graph) per tenant

@salbeck-sit
Copy link

I think a key issue is that the app-role in M365 License Manager that needs to be assigned to 'the app' is a delegated permission and not an app permission. That could be why the resulting token isn't accepted

@rvdwegen
Copy link

It is. If you take a token generated in application context and throw it in jwt.ms you'll notice the correct permission just isn't present in the token.

@salbeck-sit
Copy link

I've tried to assign the available app permission to my test-app - now the resulting token indeed contains '"roles": [
"LicenseManager.Fulfillment",
"LicensedProduct.Read.All",
"AllotmentSource.Read.All"
],
But apparently that doesn't satisfy the API. I'm starting to suspect that it doesn't like apps - much less automation...

@rvdwegen
Copy link

Yea there was a faint chance LicenseManager.Fulfillment could work but that's likely just for buying licenses, not enabling/disabling self purchase.
On the delegated side there's a .AccessAsUser permission.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants