<commit_before>﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Client.ApiConfig.Parameters;
using Microsoft.Identity.Client.Core;
using Microsoft.Identity.Client.OAuth2;
using Microsoft.Identity.Client.Utils;

namespace Microsoft.Identity.Client.Internal.Requests
{
    internal class DeviceCodeRequest : RequestBase
    {
        private readonly AcquireTokenWithDeviceCodeParameters _deviceCodeParameters;

        public DeviceCodeRequest(
            IServiceBundle serviceBundle,
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenWithDeviceCodeParameters deviceCodeParameters)
            : base(serviceBundle, authenticationRequestParameters, deviceCodeParameters)
        {
            _deviceCodeParameters = deviceCodeParameters;
        }

        internal override async Task<AuthenticationResult> ExecuteAsync(CancellationToken cancellationToken)
        {
            //Adfs device code flow not currently supported
            if(ServiceBundle.Config.AuthorityInfo.AuthorityType == AuthorityType.Adfs)
            {
                throw new InvalidOperationException(MsalErrorMessage.AdfsDeviceFlowNotSupported);
            }

            await ResolveAuthorityEndpointsAsync().ConfigureAwait(false);

            var client = new OAuth2Client(ServiceBundle.DefaultLogger, ServiceBundle.HttpManager, ServiceBundle.TelemetryManager);

            var deviceCodeScopes = new HashSet<string>();
            deviceCodeScopes.UnionWith(AuthenticationRequestParameters.Scope);
            deviceCodeScopes.Add(OAuth2Value.ScopeOfflineAccess);
            deviceCodeScopes.Add(OAuth2Value.ScopeProfile);
            deviceCodeScopes.Add(OAuth2Value.ScopeOpenId);

            client.AddBodyParameter(OAuth2Parameter.ClientId, AuthenticationRequestParameters.ClientId);
            client.AddBodyParameter(OAuth2Parameter.Scope, deviceCodeScopes.AsSingleString());
            client.AddQueryParameter(OAuth2Parameter.Claims, AuthenticationRequestParameters.Claims);


            // Talked with Shiung, devicecode will be added to the discovery endpoint "soon".
            // Fow now, the string replace is correct.
            // TODO: We should NOT be talking to common, need to work with henrik/bogdan on why /common is being set
            // as default for msal.
            string deviceCodeEndpoint = AuthenticationRequestParameters.Endpoints.TokenEndpoint
                                                                       .Replace("token", "devicecode").Replace(
                                                                           "common",
                                                                           "organizations");
<commit_msg>Enabling Device Code flow with personal accounts (#1367)<commit_after>﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Client.ApiConfig.Parameters;
using Microsoft.Identity.Client.Core;
using Microsoft.Identity.Client.OAuth2;
using Microsoft.Identity.Client.Utils;

namespace Microsoft.Identity.Client.Internal.Requests
{
    internal class DeviceCodeRequest : RequestBase
    {
        private readonly AcquireTokenWithDeviceCodeParameters _deviceCodeParameters;

        public DeviceCodeRequest(
            IServiceBundle serviceBundle,
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenWithDeviceCodeParameters deviceCodeParameters)
            : base(serviceBundle, authenticationRequestParameters, deviceCodeParameters)
        {
            _deviceCodeParameters = deviceCodeParameters;
        }

        internal override async Task<AuthenticationResult> ExecuteAsync(CancellationToken cancellationToken)
        {
            //Adfs device code flow not currently supported
            if(ServiceBundle.Config.AuthorityInfo.AuthorityType == AuthorityType.Adfs)
            {
                throw new InvalidOperationException(MsalErrorMessage.AdfsDeviceFlowNotSupported);
            }

            await ResolveAuthorityEndpointsAsync().ConfigureAwait(false);

            var client = new OAuth2Client(ServiceBundle.DefaultLogger, ServiceBundle.HttpManager, ServiceBundle.TelemetryManager);

            var deviceCodeScopes = new HashSet<string>();
            deviceCodeScopes.UnionWith(AuthenticationRequestParameters.Scope);
            deviceCodeScopes.Add(OAuth2Value.ScopeOfflineAccess);
            deviceCodeScopes.Add(OAuth2Value.ScopeProfile);
            deviceCodeScopes.Add(OAuth2Value.ScopeOpenId);

            client.AddBodyParameter(OAuth2Parameter.ClientId, AuthenticationRequestParameters.ClientId);
            client.AddBodyParameter(OAuth2Parameter.Scope, deviceCodeScopes.AsSingleString());
            client.AddQueryParameter(OAuth2Parameter.Claims, AuthenticationRequestParameters.Claims);

            string deviceCodeEndpoint = AuthenticationRequestParameters.Endpoints.TokenEndpoint
                                                                       .Replace("token", "devicecode");

{'fraction_non_alphanumeric': 0.06469500924214418, 'fraction_numerical': 0.0036968576709796672, 'mean_word_length': 2.8512455516014237, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4232676', 'n_tokens_mistral': 1192, 'n_tokens_neox': 1178, 'n_words': 249}