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

Non interactive user auth #68

Open
Safirion opened this issue Jan 27, 2021 · 3 comments
Open

Non interactive user auth #68

Safirion opened this issue Jan 27, 2021 · 3 comments

Comments

@Safirion
Copy link

Safirion commented Jan 27, 2021

Feature Request

Maybe I have missunderstand the SecureAppModel and what I looking for is already existing. The year before, when MFA was not mandatory, I could use User Auth by directly getting access token with user credential like this :

"Authentication": {
        "ApplicationId": "mypartnercenterappid",
        "ApplicationSecret": "mypartnercenterappsecret", 
        "ApplicationDomain": "xxxxxxxxx.onmicrosoft.com",
        "User": "[email protected]",
        "Password": "myuserpassword",
        "TenantId": "tenant of my organization",
        "Authority": "https://login.windows.net",
        "ResourceUrl": "https://graph.windows.net",
        "PartnerServiceApiRoot": "https://api.partnercenter.microsoft.com"
      }
        public async Task<IPartner> GetPartnerConnection()
        {
            if (_aggregatePartner != null && !_aggregatePartner.Credentials.IsExpired())
                return _aggregatePartner;
            PartnerService.Instance.ApiRootUrl = Configurations.Authentication.PartnerServiceApiRoot;

            IPartnerCredentials partnerCredentials = await PartnerCredentials.Instance.GenerateByUserCredentialsAsync(Configurations.Authentication.ApplicationId, await GetUserToken());
            _aggregatePartner = PartnerService.Instance.CreatePartnerOperations(partnerCredentials);
            
            return _aggregatePartner;
        }

        private async Task<AuthenticationToken> GetUserToken()
        {
            HttpResponseMessage response = await _client.PostAsync($"{Configurations.Authentication.Authority}/{Configurations.Authentication.TenantId}/oauth2/token", new FormUrlEncodedContent(new Dictionary<string, string>
            {
                { "scope", "openid" },
                { "grant_type", "password" },
                { "resource", Configurations.Authentication.PartnerServiceApiRoot },
                { "client_id", Configurations.Authentication.ApplicationId },
                { "client_secret", Configurations.Authentication.ApplicationSecret },
                { "username", Configurations.Authentication.User },
                { "password", Configurations.Authentication.Password }
            }));
            if (!response.IsSuccessStatusCode)
                throw new Exception($"Can't get partner center token for user \"{Configurations.Authentication.User}\"");
            JObject auth = JsonConvert.DeserializeObject<JObject>(await response.Content.ReadAsStringAsync());
            string accessToken = auth["access_token"].Value<string>();
            long expiresOn = auth["expires_on"].Value<long>();
            return new AuthenticationToken(accessToken, new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(expiresOn).ToLocalTime());
        }

It was so simple, now, since arround october I can't use my GetUserToken function because response.IsSuccessStatusCode is false.

My application is an API that allow our customer's users to do actions on partner centers like : listing there users account and add/remove licence on user account.
For this, application auth is not sufficient, so I have to use User Auth. I want to use a service account that auto-login in background as before. Is there any solution ?

@jhughes17
Copy link

I realize this is a year old and I hope you managed to solve your problem. We had the same issue and it caused quite a bit of problem when MFA and secure model got adopted as we needed each of our employees to authorize every request we were automating.

We solved this by having a user authorize once, storing their token in the Azure Key Vault then having the refresh token used to keep doing automated tasks to the partner center in the background.

https://docs.microsoft.com/en-us/partner-center/develop/partner-center-authentication#partner-consent

This describes the process we followed hope it helps for others!

@RommelWZ
Copy link

Feature Request

Maybe I have missunderstand the SecureAppModel and what I looking for is already existing. The year before, when MFA was not mandatory, I could use User Auth by directly getting access token with user credential like this :

"Authentication": {
        "ApplicationId": "mypartnercenterappid",
        "ApplicationSecret": "mypartnercenterappsecret", 
        "ApplicationDomain": "xxxxxxxxx.onmicrosoft.com",
        "User": "[email protected]",
        "Password": "myuserpassword",
        "TenantId": "tenant of my organization",
        "Authority": "https://login.windows.net",
        "ResourceUrl": "https://graph.windows.net",
        "PartnerServiceApiRoot": "https://api.partnercenter.microsoft.com"
      }
        public async Task<IPartner> GetPartnerConnection()
        {
            if (_aggregatePartner != null && !_aggregatePartner.Credentials.IsExpired())
                return _aggregatePartner;
            PartnerService.Instance.ApiRootUrl = Configurations.Authentication.PartnerServiceApiRoot;

            IPartnerCredentials partnerCredentials = await PartnerCredentials.Instance.GenerateByUserCredentialsAsync(Configurations.Authentication.ApplicationId, await GetUserToken());
            _aggregatePartner = PartnerService.Instance.CreatePartnerOperations(partnerCredentials);
            
            return _aggregatePartner;
        }

        private async Task<AuthenticationToken> GetUserToken()
        {
            HttpResponseMessage response = await _client.PostAsync($"{Configurations.Authentication.Authority}/{Configurations.Authentication.TenantId}/oauth2/token", new FormUrlEncodedContent(new Dictionary<string, string>
            {
                { "scope", "openid" },
                { "grant_type", "password" },
                { "resource", Configurations.Authentication.PartnerServiceApiRoot },
                { "client_id", Configurations.Authentication.ApplicationId },
                { "client_secret", Configurations.Authentication.ApplicationSecret },
                { "username", Configurations.Authentication.User },
                { "password", Configurations.Authentication.Password }
            }));
            if (!response.IsSuccessStatusCode)
                throw new Exception($"Can't get partner center token for user \"{Configurations.Authentication.User}\"");
            JObject auth = JsonConvert.DeserializeObject<JObject>(await response.Content.ReadAsStringAsync());
            string accessToken = auth["access_token"].Value<string>();
            long expiresOn = auth["expires_on"].Value<long>();
            return new AuthenticationToken(accessToken, new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(expiresOn).ToLocalTime());
        }

It was so simple, now, since arround october I can't use my GetUserToken function because response.IsSuccessStatusCode is false.

My application is an API that allow our customer's users to do actions on partner centers like : listing there users account and add/remove licence on user account. For this, application auth is not sufficient, so I have to use User Auth. I want to use a service account that auto-login in background as before. Is there any solution ?

Have you figure out how to change the console app sdk to be non interactive? Could you share how you did it?

@Safirion
Copy link
Author

I have give up and just generate a token/refresh token manually first time.

Then I have stock the access token/refresh token in a SQL table and my app update theses tokens automatically when they expire.

A proper solution may exists but I don't found

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

3 participants