terminal/src/cascadia/TerminalConnection/AzureConnection.cpp

1016 lines
39 KiB
C++
Raw Normal View History

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "AzureConnection.h"
#include "AzureClientID.h"
#include <sstream>
#include <cstdlib>
#include <LibraryResources.h>
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
#include <unicode.hpp>
#include "AzureConnection.g.cpp"
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
#include "winrt/Windows.System.UserProfile.h"
#include "../../types/inc/Utils.hpp"
using namespace ::Microsoft::Console;
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
using namespace ::Microsoft::Terminal::Azure;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace web::websockets::client;
using namespace winrt::Windows::Security::Credentials;
static constexpr int CurrentCredentialVersion = 1;
static constexpr auto PasswordVaultResourceName = L"Terminal";
static constexpr auto HttpUserAgent = L"Terminal/0.0";
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
static constexpr int USER_INPUT_COLOR = 93; // yellow - the color of something the user can type
static constexpr int USER_INFO_COLOR = 97; // white - the color of clarifying information
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
static constexpr winrt::guid AzureConnectionType = { 0xd9fcfdfa, 0xa479, 0x412c, { 0x83, 0xb7, 0xc5, 0x64, 0xe, 0x61, 0xcd, 0x62 } };
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
static inline std::wstring _colorize(const unsigned int colorCode, const std::wstring_view text)
{
return fmt::format(L"\x1b[{0}m{1}\x1b[m", colorCode, text);
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
}
// Takes N resource names, loads the first one as a format string, and then
// loads all the remaining ones into the %s arguments in the first one after
// colorizing them in the USER_INPUT_COLOR.
// This is intended to be used to drop UserEntry resources into an existing string.
template<typename... Args>
static inline std::wstring _formatResWithColoredUserInputOptions(const std::wstring_view resourceKey, Args&&... args)
{
return fmt::format(std::wstring_view{ GetLibraryResourceString(resourceKey) }, (_colorize(USER_INPUT_COLOR, GetLibraryResourceString(args)))...);
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
static inline std::wstring _formatTenant(int tenantNumber, const Tenant& tenant)
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return fmt::format(std::wstring_view{ RS_(L"AzureIthTenant") },
_colorize(USER_INPUT_COLOR, std::to_wstring(tenantNumber)),
_colorize(USER_INFO_COLOR, tenant.DisplayName.value_or(std::wstring{ RS_(L"AzureUnknownTenantName") })),
tenant.DefaultDomain.value_or(tenant.ID)); // use the domain name if possible, ID if not.
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
}
namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
winrt::guid AzureConnection::ConnectionType() noexcept
{
return AzureConnectionType;
}
// This function exists because the clientID only gets added by the release pipelines
// and is not available on local builds, so we want to be able to make sure we don't
// try to make an Azure connection if its a local build
bool AzureConnection::IsAzureConnectionAvailable() noexcept
{
return (AzureClientID != L"0");
}
Switch Connections to use `ValueSet`s to initialize them (#10184) #### ⚠️ targets #10051 ## Summary of the Pull Request This PR does one big, primary thing. It removes all the constructors from any TerminalConnections, and changes them to use an `Initialize` method that accepts a `ValueSet` of properties. Why? For the upcoming window/content process work, we'll need the content process to be able to initialize the connection _in the content process_. However, the window process will be the one that knows what type of connection to make. Enter `ConnectionInformation`. This class will let us specify the class name of the type we want to create, and a set of settings to use when initializing that connection. **IMPORTANT**: As a part of this, the constructor for a connection must have 0 arguments. `RoActivateInstance` lets you just conjure a WinRT type just by class name, but that class must have a 0 arg ctor. Hence the need for `Initialize`, to actually pass the settings. We're using a `ValueSet` here because it's basically a json blob, with more steps. In the future, when extension authors want to have custom connections, we can always deserialize the json into a `ValueSet`, pass it to their connection's `Initialize`, and let then get what they need out of it. ## References * Tear-out: #1256 * Megathread: #5000 * Project: https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760298 * [x] I work here * [n/a] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments `ConnectionInformation` was included as a part of this PR, to demonstrate how this will eventually be used. `ConnectionInformation` is not _currently_ used. ## Validation Steps Performed It still builds and runs.
2021-07-20 17:02:17 +02:00
void AzureConnection::Initialize(const Windows::Foundation::Collections::ValueSet& settings)
{
Switch Connections to use `ValueSet`s to initialize them (#10184) #### ⚠️ targets #10051 ## Summary of the Pull Request This PR does one big, primary thing. It removes all the constructors from any TerminalConnections, and changes them to use an `Initialize` method that accepts a `ValueSet` of properties. Why? For the upcoming window/content process work, we'll need the content process to be able to initialize the connection _in the content process_. However, the window process will be the one that knows what type of connection to make. Enter `ConnectionInformation`. This class will let us specify the class name of the type we want to create, and a set of settings to use when initializing that connection. **IMPORTANT**: As a part of this, the constructor for a connection must have 0 arguments. `RoActivateInstance` lets you just conjure a WinRT type just by class name, but that class must have a 0 arg ctor. Hence the need for `Initialize`, to actually pass the settings. We're using a `ValueSet` here because it's basically a json blob, with more steps. In the future, when extension authors want to have custom connections, we can always deserialize the json into a `ValueSet`, pass it to their connection's `Initialize`, and let then get what they need out of it. ## References * Tear-out: #1256 * Megathread: #5000 * Project: https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760298 * [x] I work here * [n/a] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments `ConnectionInformation` was included as a part of this PR, to demonstrate how this will eventually be used. `ConnectionInformation` is not _currently_ used. ## Validation Steps Performed It still builds and runs.
2021-07-20 17:02:17 +02:00
if (settings)
{
_initialRows = winrt::unbox_value_or<uint32_t>(settings.TryLookup(L"initialRows").try_as<Windows::Foundation::IPropertyValue>(), _initialRows);
_initialCols = winrt::unbox_value_or<uint32_t>(settings.TryLookup(L"initialCols").try_as<Windows::Foundation::IPropertyValue>(), _initialCols);
}
}
// Method description:
// - helper that will write an unterminated string (generally, from a resource) to the output stream.
// Arguments:
// - str: the string to write.
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
void AzureConnection::_WriteStringWithNewline(const std::wstring_view str)
{
_TerminalOutputHandlers(str + L"\r\n");
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
// Method description:
// - helper that prints exception information to the output stream.
// Arguments:
// - [IMPLICIT] the current exception context
void AzureConnection::_WriteCaughtExceptionRecord()
{
try
{
throw;
}
catch (const std::exception& runtimeException)
{
// This also catches the AzureException, which has a .what()
_TerminalOutputHandlers(_colorize(91, til::u8u16(std::string{ runtimeException.what() })));
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
}
// Method description:
// - ascribes to the ITerminalConnection interface
// - creates the output thread (where we will do the authentication and actually connect to Azure)
void AzureConnection::Start()
{
// Create our own output handling thread
// Each connection needs to make sure to drain the output from its backing host.
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_hOutputThread.reset(CreateThread(
nullptr,
0,
[](LPVOID lpParameter) noexcept {
AzureConnection* const pInstance = static_cast<AzureConnection*>(lpParameter);
if (pInstance)
{
return pInstance->_OutputThread();
}
return gsl::narrow_cast<DWORD>(E_INVALIDARG);
},
this,
0,
nullptr));
THROW_LAST_ERROR_IF_NULL(_hOutputThread);
LOG_IF_FAILED(SetThreadDescription(_hOutputThread.get(), L"AzureConnection Output Thread"));
_transitionToState(ConnectionState::Connecting);
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
std::optional<std::wstring> AzureConnection::_ReadUserInput(InputMode mode)
{
std::unique_lock<std::mutex> inputLock{ _inputMutex };
if (_isStateAtOrBeyond(ConnectionState::Closing))
{
return std::nullopt;
}
_currentInputMode = mode;
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_TerminalOutputHandlers(L"> \x1b[92m"); // Make prompted user input green
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
_inputEvent.wait(inputLock, [this, mode]() {
return _currentInputMode != mode || _isStateAtOrBeyond(ConnectionState::Closing);
});
_TerminalOutputHandlers(L"\x1b[m");
if (_isStateAtOrBeyond(ConnectionState::Closing))
{
return std::nullopt;
}
std::wstring readInput{};
_userInput.swap(readInput);
return readInput;
}
// Method description:
// - ascribes to the ITerminalConnection interface
// - handles the different possible inputs in the different states
// Arguments:
// the user's input
void AzureConnection::WriteInput(hstring const& data)
{
// We read input while connected AND connecting.
if (!_isStateOneOf(ConnectionState::Connected, ConnectionState::Connecting))
{
return;
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
if (_state == AzureState::TermConnected)
{
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
// If we're connected, we don't need to do any fun input shenanigans.
websocket_outgoing_message msg;
const auto str = winrt::to_string(data);
msg.set_utf8_message(str);
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
_cloudShellSocket.send(msg).get();
return;
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
std::lock_guard<std::mutex> lock{ _inputMutex };
if (data.size() > 0 && (gsl::at(data, 0) == UNICODE_BACKSPACE || gsl::at(data, 0) == UNICODE_DEL)) // BS or DEL
{
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
if (_userInput.size() > 0)
{
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
_userInput.pop_back();
_TerminalOutputHandlers(L"\x08 \x08"); // overstrike the character with a space
}
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
else
{
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
_TerminalOutputHandlers(data); // echo back
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
switch (_currentInputMode)
{
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
case InputMode::Line:
if (data.size() > 0 && gsl::at(data, 0) == UNICODE_CARRIAGERETURN)
{
_TerminalOutputHandlers(L"\r\n"); // we probably got a \r, so we need to advance to the next line.
_currentInputMode = InputMode::None; // toggling the mode indicates completion
_inputEvent.notify_one();
break;
}
[[fallthrough]];
default:
std::copy(data.cbegin(), data.cend(), std::back_inserter(_userInput));
break;
}
}
}
// Method description:
// - ascribes to the ITerminalConnection interface
// - resizes the terminal
// Arguments:
// - the new rows/cols values
void AzureConnection::Resize(uint32_t rows, uint32_t columns)
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
try
{
if (!_isConnected())
{
_initialRows = rows;
_initialCols = columns;
}
else // We only transition to Connected when we've established the websocket.
{
// Initialize client
http_client terminalClient(_cloudShellUri);
// Initialize the request
http_request terminalRequest(L"POST");
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
terminalRequest.set_request_uri(fmt::format(L"terminals/{}/size?cols={}&rows={}&version=2019-01-01", _terminalID, columns, rows));
terminalRequest.set_body(json::value::null());
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
// Send the request (don't care about the response)
(void)_SendAuthenticatedRequestReturningJson(terminalClient, terminalRequest);
}
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
CATCH_LOG();
// Method description:
// - ascribes to the ITerminalConnection interface
// - closes the websocket connection and the output thread
void AzureConnection::Close()
{
if (_transitionToState(ConnectionState::Closing))
{
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
_inputEvent.notify_all();
if (_state == AzureState::TermConnected)
{
// Close the websocket connection
auto closedTask = _cloudShellSocket.close();
closedTask.wait();
}
if (_hOutputThread)
{
// Tear down our output thread
WaitForSingleObject(_hOutputThread.get(), INFINITE);
_hOutputThread.reset();
}
_transitionToState(ConnectionState::Closed);
}
}
// Method description:
// - This method returns a tenant's ID and display name (if one is available).
// If there is no display name, a placeholder is returned in its stead.
// Arguments:
// - tenant - the unparsed tenant
// Return value:
// - a tuple containing the ID and display name of the tenant.
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
static Tenant _crackTenant(const json::value& jsonTenant)
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
Tenant tenant{};
if (jsonTenant.has_string_field(L"tenantID"))
{
// for compatibility with version 1 credentials
tenant.ID = jsonTenant.at(L"tenantID").as_string();
}
else
{
// This one comes in off the wire
tenant.ID = jsonTenant.at(L"tenantId").as_string();
}
if (jsonTenant.has_string_field(L"displayName"))
{
tenant.DisplayName = jsonTenant.at(L"displayName").as_string();
}
if (jsonTenant.has_string_field(L"defaultDomain"))
{
tenant.DefaultDomain = jsonTenant.at(L"defaultDomain").as_string();
}
return tenant;
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
static void _packTenant(json::value& jsonTenant, const Tenant& tenant)
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
jsonTenant[L"tenantId"] = json::value::string(tenant.ID);
if (tenant.DisplayName.has_value())
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
jsonTenant[L"displayName"] = json::value::string(*tenant.DisplayName);
}
if (tenant.DefaultDomain.has_value())
{
jsonTenant[L"defaultDomain"] = json::value::string(*tenant.DefaultDomain);
}
}
// Method description:
// - this is the output thread, where we initiate the connection to Azure
// and establish a websocket connection
// Return value:
// - return status
DWORD AzureConnection::_OutputThread()
{
while (true)
{
if (_isStateAtOrBeyond(ConnectionState::Closing))
{
// If we enter a new state while closing, just bail.
return S_FALSE;
}
try
{
switch (_state)
{
// Initial state, check if the user has any stored connection settings and allow them to login with those
// or allow them to login with a different account or allow them to remove the saved settings
case AzureState::AccessStored:
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_RunAccessState();
break;
}
// User has no saved connection settings or has opted to login with a different account
// Azure authentication happens here
case AzureState::DeviceFlow:
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_RunDeviceFlowState();
break;
}
// User has multiple tenants in their Azure account, they need to choose which one to connect to
case AzureState::TenantChoice:
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_RunTenantChoiceState();
break;
}
// Ask the user if they want to save these connection settings for future logins
case AzureState::StoreTokens:
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_RunStoreState();
break;
}
// Connect to Azure, we only get here once we have everything we need (tenantID, accessToken, refreshToken)
case AzureState::TermConnecting:
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_RunConnectState();
break;
}
// We are connected, continuously read from the websocket until its closed
case AzureState::TermConnected:
{
_transitionToState(ConnectionState::Connected);
while (true)
{
// Read from websocket
pplx::task<websocket_incoming_message> msgT;
try
{
msgT = _cloudShellSocket.receive();
msgT.wait();
}
catch (...)
{
// Websocket has been closed; consider it a graceful exit?
// This should result in our termination.
if (_transitionToState(ConnectionState::Closed))
{
// End the output thread.
return S_FALSE;
}
}
auto msg = msgT.get();
auto msgStringTask = msg.extract_string();
auto msgString = msgStringTask.get();
// Convert to hstring
const auto hstr = winrt::to_hstring(msgString);
// Pass the output to our registered event handlers
_TerminalOutputHandlers(hstr);
}
return S_OK;
}
}
}
catch (...)
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_WriteCaughtExceptionRecord();
_transitionToState(ConnectionState::Failed);
return E_FAIL;
}
}
}
// Method description:
// - helper function to get the stored credentials (if any) and let the user choose what to do next
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
void AzureConnection::_RunAccessState()
{
bool oldVersionEncountered = false;
auto vault = PasswordVault();
winrt::Windows::Foundation::Collections::IVectorView<PasswordCredential> credList;
// FindAllByResource throws an exception if there are no credentials stored under the given resource so we wrap it in a try-catch block
try
{
credList = vault.FindAllByResource(PasswordVaultResourceName);
}
catch (...)
{
// No credentials are stored, so start the device flow
_state = AzureState::DeviceFlow;
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return;
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
int numTenants{ 0 };
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_tenantList.clear();
for (const auto& entry : credList)
{
auto nameJson = json::value::parse(entry.UserName().c_str());
std::optional<int> credentialVersion;
if (nameJson.has_integer_field(U("ver")))
{
credentialVersion = nameJson.at(U("ver")).as_integer();
}
if (!credentialVersion.has_value() || credentialVersion.value() != CurrentCredentialVersion)
{
// ignore credentials that aren't from the latest credential revision
vault.Remove(entry);
oldVersionEncountered = true;
continue;
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
auto newTenant{ _tenantList.emplace_back(_crackTenant(nameJson)) };
_WriteStringWithNewline(_formatTenant(numTenants, newTenant));
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
numTenants++;
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
if (!numTenants)
{
if (oldVersionEncountered)
{
_WriteStringWithNewline(RS_(L"AzureOldCredentialsFlushedMessage"));
}
// No valid up-to-date credentials were found, so start the device flow
_state = AzureState::DeviceFlow;
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return;
}
_WriteStringWithNewline(RS_(L"AzureEnterTenant"));
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
_WriteStringWithNewline(_formatResWithColoredUserInputOptions(USES_RESOURCE(L"AzureNewLogin"), USES_RESOURCE(L"AzureUserEntry_NewLogin")));
_WriteStringWithNewline(_formatResWithColoredUserInputOptions(USES_RESOURCE(L"AzureRemoveStored"), USES_RESOURCE(L"AzureUserEntry_RemoveStored")));
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
int selectedTenant{ -1 };
do
{
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
auto maybeTenantSelection = _ReadUserInput(InputMode::Line);
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
if (!maybeTenantSelection.has_value())
{
return;
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
const auto& tenantSelection = maybeTenantSelection.value();
if (tenantSelection == RS_(L"AzureUserEntry_RemoveStored"))
{
// User wants to remove the stored settings
_RemoveCredentials();
_state = AzureState::DeviceFlow;
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return;
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
}
else if (tenantSelection == RS_(L"AzureUserEntry_NewLogin"))
{
// User wants to login with a different account
_state = AzureState::DeviceFlow;
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return;
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
}
else
{
try
{
selectedTenant = std::stoi(tenantSelection);
if (selectedTenant < 0 || selectedTenant >= numTenants)
{
_WriteStringWithNewline(RS_(L"AzureNumOutOfBoundsError"));
continue; // go 'round again
}
break;
}
catch (...)
{
// suppress exceptions in conversion
}
}
// if we got here, we didn't break out of the loop early and need to go 'round again
_WriteStringWithNewline(_formatResWithColoredUserInputOptions(USES_RESOURCE(L"AzureInvalidAccessInput"), USES_RESOURCE(L"AzureUserEntry_NewLogin"), USES_RESOURCE(L"AzureUserEntry_RemoveStored")));
} while (true);
// User wants to login with one of the saved connection settings
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
auto desiredCredential = credList.GetAt(selectedTenant);
desiredCredential.RetrievePassword();
auto passWordJson = json::value::parse(desiredCredential.Password().c_str());
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_currentTenant = til::at(_tenantList, selectedTenant); // we already unpacked the name info, so we should just use it
_accessToken = passWordJson.at(L"accessToken").as_string();
_refreshToken = passWordJson.at(L"refreshToken").as_string();
_expiry = std::stoi(passWordJson.at(L"expiry").as_string());
const auto t1 = std::chrono::system_clock::now();
const auto timeNow = std::chrono::duration_cast<std::chrono::seconds>(t1.time_since_epoch()).count();
// Check if the token is close to expiring and refresh if so
if (timeNow + _expireLimit > _expiry)
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
try
{
_RefreshTokens();
// Store the updated tokens under the same username
_StoreCredential();
}
catch (const AzureException& e)
{
if (e.GetCode() == ErrorCodes::InvalidGrant)
{
_WriteCaughtExceptionRecord();
vault.Remove(desiredCredential);
// Delete this credential and try again.
_state = AzureState::AccessStored;
return;
}
throw; // rethrow. we couldn't handle this error.
}
}
// We have everything we need, so go ahead and connect
_state = AzureState::TermConnecting;
}
// Method description:
// - helper function to start the device code flow (required for authentication to Azure)
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
void AzureConnection::_RunDeviceFlowState()
{
// Initiate device code flow
const auto deviceCodeResponse = _GetDeviceCode();
// Print the message and store the device code, polling interval and expiry
const auto message = winrt::to_hstring(deviceCodeResponse.at(L"message").as_string().c_str());
_WriteStringWithNewline(message);
_WriteStringWithNewline(RS_(L"AzureCodeExpiry"));
const auto devCode = deviceCodeResponse.at(L"device_code").as_string();
const auto pollInterval = std::stoi(deviceCodeResponse.at(L"interval").as_string());
const auto expiresIn = std::stoi(deviceCodeResponse.at(L"expires_in").as_string());
// Wait for user authentication and obtain the access/refresh tokens
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
json::value authenticatedResponse = _WaitForUser(devCode, pollInterval, expiresIn);
_accessToken = authenticatedResponse.at(L"access_token").as_string();
_refreshToken = authenticatedResponse.at(L"refresh_token").as_string();
// Get the tenants and the required tenant id
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_PopulateTenantList();
if (_tenantList.size() == 0)
{
_WriteStringWithNewline(RS_(L"AzureNoTenants"));
_transitionToState(ConnectionState::Failed);
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return;
}
else if (_tenantList.size() == 1)
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_currentTenant = til::at(_tenantList, 0);
// We have to refresh now that we have the tenantID
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_RefreshTokens();
_state = AzureState::StoreTokens;
}
else
{
_state = AzureState::TenantChoice;
}
}
// Method description:
// - helper function to list the user's tenants and let them decide which tenant they wish to connect to
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
void AzureConnection::_RunTenantChoiceState()
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
auto numTenants = gsl::narrow<int>(_tenantList.size());
for (int i = 0; i < numTenants; i++)
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_WriteStringWithNewline(_formatTenant(i, til::at(_tenantList, i)));
}
_WriteStringWithNewline(RS_(L"AzureEnterTenant"));
int selectedTenant{ -1 };
do
{
auto maybeTenantSelection = _ReadUserInput(InputMode::Line);
if (!maybeTenantSelection.has_value())
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return;
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
const auto& tenantSelection = maybeTenantSelection.value();
try
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
selectedTenant = std::stoi(tenantSelection);
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
if (selectedTenant < 0 || selectedTenant >= numTenants)
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_WriteStringWithNewline(RS_(L"AzureNumOutOfBoundsError"));
continue;
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
break;
}
catch (...)
{
// suppress exceptions in conversion
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
// if we got here, we didn't break out of the loop early and need to go 'round again
_WriteStringWithNewline(RS_(L"AzureNonNumberError"));
} while (true);
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_currentTenant = til::at(_tenantList, selectedTenant);
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
// We have to refresh now that we have the tenantID
_RefreshTokens();
_state = AzureState::StoreTokens;
}
// Method description:
// - helper function to ask the user if they wish to store their credentials
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
void AzureConnection::_RunStoreState()
{
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
_WriteStringWithNewline(_formatResWithColoredUserInputOptions(USES_RESOURCE(L"AzureStorePrompt"), USES_RESOURCE(L"AzureUserEntry_Yes"), USES_RESOURCE(L"AzureUserEntry_No")));
// Wait for user input
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
do
{
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
auto maybeStoreCredentials = _ReadUserInput(InputMode::Line);
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
if (!maybeStoreCredentials.has_value())
{
return;
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
const auto& storeCredentials = maybeStoreCredentials.value();
if (storeCredentials == RS_(L"AzureUserEntry_Yes"))
{
_StoreCredential();
_WriteStringWithNewline(RS_(L"AzureTokensStored"));
break;
}
else if (storeCredentials == RS_(L"AzureUserEntry_No"))
{
break; // we're done, but the user wants nothing.
}
// if we got here, we didn't break out of the loop early and need to go 'round again
_WriteStringWithNewline(_formatResWithColoredUserInputOptions(USES_RESOURCE(L"AzureInvalidStoreInput"), USES_RESOURCE(L"AzureUserEntry_Yes"), USES_RESOURCE(L"AzureUserEntry_No")));
} while (true);
_state = AzureState::TermConnecting;
}
// Method description:
// - Helper function to parse the preferred shell type from user settings returned by cloud console API.
// We need this function because the field might be missing in the settings
// created with old versions of cloud console API.
std::optional<utility::string_t> AzureConnection::_ParsePreferredShellType(const web::json::value& settingsResponse)
{
if (settingsResponse.has_object_field(L"properties"))
{
const auto userSettings = settingsResponse.at(L"properties");
if (userSettings.has_string_field(L"preferredShellType"))
{
const auto preferredShellTypeValue = userSettings.at(L"preferredShellType");
return preferredShellTypeValue.as_string();
}
}
return std::nullopt;
}
// Method description:
// - helper function to connect the user to the Azure cloud shell
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
void AzureConnection::_RunConnectState()
{
// Get user's cloud shell settings
const auto settingsResponse = _GetCloudShellUserSettings();
if (settingsResponse.has_field(L"error"))
{
_WriteStringWithNewline(RS_(L"AzureNoCloudAccount"));
_transitionToState(ConnectionState::Failed);
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return;
}
// Request for a cloud shell
_WriteStringWithNewline(RS_(L"AzureRequestingCloud"));
_cloudShellUri = _GetCloudShell();
_WriteStringWithNewline(RS_(L"AzureSuccess"));
// Request for a terminal for said cloud shell
const auto shellType = _ParsePreferredShellType(settingsResponse);
_WriteStringWithNewline(RS_(L"AzureRequestingTerminal"));
const auto socketUri = _GetTerminal(shellType.value_or(L"pwsh"));
_TerminalOutputHandlers(L"\r\n");
// Step 8: connecting to said terminal
const auto connReqTask = _cloudShellSocket.connect(socketUri);
connReqTask.wait();
_state = AzureState::TermConnected;
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
std::wstring queuedUserInput{};
std::swap(_userInput, queuedUserInput);
if (queuedUserInput.size() > 0)
{
WriteInput(static_cast<winrt::hstring>(queuedUserInput)); // send the user's queued up input back through
}
}
// Method description:
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
// - helper function to send requests with default headers and extract responses as json values
// Arguments:
// - a http_client
// - a http_request for the client to send
// Return value:
// - the response from the server as a json value
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
json::value AzureConnection::_SendRequestReturningJson(http_client& theClient, http_request theRequest)
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
auto& headers{ theRequest.headers() };
headers.add(L"User-Agent", HttpUserAgent);
headers.add(L"Accept", L"application/json");
json::value jsonResult;
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
const auto responseTask = theClient.request(theRequest);
responseTask.wait();
const auto response = responseTask.get();
const auto responseJsonTask = response.extract_json();
responseJsonTask.wait();
jsonResult = responseJsonTask.get();
THROW_IF_AZURE_ERROR(jsonResult);
return jsonResult;
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
// Method description:
// - helper function to send _authenticated_ requests with json bodies whose responses are expected
// to be json. builds on _SendRequestReturningJson.
// Arguments:
// - the http_request
json::value AzureConnection::_SendAuthenticatedRequestReturningJson(http_client& theClient, http_request theRequest)
{
auto& headers{ theRequest.headers() };
headers.add(L"Authorization", L"Bearer " + _accessToken);
return _SendRequestReturningJson(theClient, std::move(theRequest));
}
// Method description:
// - helper function to start the device code flow
// Return value:
// - the response to the device code flow initiation
json::value AzureConnection::_GetDeviceCode()
{
// Initialize the client
http_client loginClient(_loginUri);
// Initialize the request
http_request commonRequest(L"POST");
commonRequest.set_request_uri(L"common/oauth2/devicecode");
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
const auto body{ fmt::format(L"client_id={}&resource={}", AzureClientID, _wantedResource) };
commonRequest.set_body(body.c_str(), L"application/x-www-form-urlencoded");
// Send the request and receive the response as a json value
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return _SendRequestReturningJson(loginClient, commonRequest);
}
// Method description:
// - helper function to wait for the user to authenticate using their web browser
// Arguments:
// - the device code that would have been received when authentication was initiated
// - the polling interval duration
// - the duration the code is still valid for
// Return value:
// - if authentication is done successfully, then return the response from the server
// - else, throw an exception
json::value AzureConnection::_WaitForUser(const utility::string_t deviceCode, int pollInterval, int expiresIn)
{
// Initialize the client
http_client pollingClient(_loginUri);
// Continuously send a poll request until the user authenticates
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
const auto body{ fmt::format(L"grant_type=device_code&resource={}&client_id={}&code={}", _wantedResource, AzureClientID, deviceCode) };
const auto requestUri = L"common/oauth2/token";
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
// use a steady clock here so it's not impacted by local time discontinuities
const auto tokenExpiry{ std::chrono::steady_clock::now() + std::chrono::seconds(expiresIn) };
while (std::chrono::steady_clock::now() < tokenExpiry)
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
std::this_thread::sleep_for(std::chrono::seconds(pollInterval));
// User might close the tab while we wait for them to authenticate, this case handles that
if (_isStateAtOrBeyond(ConnectionState::Closing))
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
// We're going down, there's no valid user for us to return
break;
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
http_request pollRequest(L"POST");
pollRequest.set_request_uri(requestUri);
pollRequest.set_body(body.c_str(), L"application/x-www-form-urlencoded");
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
try
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
auto response{ _SendRequestReturningJson(pollingClient, pollRequest) };
_WriteStringWithNewline(RS_(L"AzureSuccessfullyAuthenticated"));
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
// Got a valid response: we're done
return response;
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
catch (const AzureException& e)
{
if (e.GetCode() == ErrorCodes::AuthorizationPending)
{
// Handle the "auth pending" exception by retrying.
continue;
}
throw;
} // uncaught exceptions bubble up to the caller
}
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return json::value::null();
}
// Method description:
// - helper function to acquire the user's Azure tenants
// Return value:
// - the response which contains a list of the user's Azure tenants
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
void AzureConnection::_PopulateTenantList()
{
// Initialize the client
http_client tenantClient(_resourceUri);
// Initialize the request
http_request tenantRequest(L"GET");
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
tenantRequest.set_request_uri(L"tenants?api-version=2020-01-01");
// Send the request and return the response as a json value
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
auto tenantResponse{ _SendAuthenticatedRequestReturningJson(tenantClient, tenantRequest) };
auto tenantList{ tenantResponse.at(L"value").as_array() };
_tenantList.clear();
std::transform(tenantList.begin(), tenantList.end(), std::back_inserter(_tenantList), _crackTenant);
}
// Method description:
// - helper function to refresh the access/refresh tokens
// Return value:
// - the response with the new tokens
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
void AzureConnection::_RefreshTokens()
{
// Initialize the client
http_client refreshClient(_loginUri);
// Initialize the request
http_request refreshRequest(L"POST");
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
refreshRequest.set_request_uri(_currentTenant->ID + L"/oauth2/token");
const auto body{ fmt::format(L"client_id={}&resource={}&grant_type=refresh_token&refresh_token={}", AzureClientID, _wantedResource, _refreshToken) };
refreshRequest.set_body(body.c_str(), L"application/x-www-form-urlencoded");
// Send the request and return the response as a json value
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
auto refreshResponse{ _SendRequestReturningJson(refreshClient, refreshRequest) };
_accessToken = refreshResponse.at(L"access_token").as_string();
_refreshToken = refreshResponse.at(L"refresh_token").as_string();
_expiry = std::stoi(refreshResponse.at(L"expires_on").as_string());
}
// Method description:
// - helper function to get the user's cloud shell settings
// Return value:
// - the user's cloud shell settings
json::value AzureConnection::_GetCloudShellUserSettings()
{
// Initialize client
http_client settingsClient(_resourceUri);
// Initialize request
http_request settingsRequest(L"GET");
settingsRequest.set_request_uri(L"providers/Microsoft.Portal/userSettings/cloudconsole?api-version=2018-10-01");
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
return _SendAuthenticatedRequestReturningJson(settingsClient, settingsRequest);
}
// Method description:
// - helper function to request for a cloud shell
// Return value:
// - the uri for the cloud shell
utility::string_t AzureConnection::_GetCloudShell()
{
// Initialize client
http_client cloudShellClient(_resourceUri);
// Initialize request
http_request shellRequest(L"PUT");
shellRequest.set_request_uri(L"providers/Microsoft.Portal/consoles/default?api-version=2018-10-01");
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
// { "properties": { "osType": "linux" } }
auto body = json::value::object({ { U("properties"), json::value::object({ { U("osType"), json::value::string(U("linux")) } }) } });
shellRequest.set_body(body);
// Send the request and get the response as a json value
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
const auto cloudShell = _SendAuthenticatedRequestReturningJson(cloudShellClient, shellRequest);
// Return the uri
return cloudShell.at(L"properties").at(L"uri").as_string() + L"/";
}
// Method description:
// - helper function to request for a terminal
// Return value:
// - the uri for the terminal
utility::string_t AzureConnection::_GetTerminal(utility::string_t shellType)
{
// Initialize client
http_client terminalClient(_cloudShellUri);
// Initialize the request
http_request terminalRequest(L"POST");
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
terminalRequest.set_request_uri(fmt::format(L"terminals?cols={}&rows={}&version=2019-01-01&shell={}", _initialCols, _initialRows, shellType));
// LOAD-BEARING. the API returns "'content-type' should be 'application/json' or 'multipart/form-data'"
terminalRequest.set_body(json::value::null());
// Send the request and get the response as a json value
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
const auto terminalResponse = _SendAuthenticatedRequestReturningJson(terminalClient, terminalRequest);
_terminalID = terminalResponse.at(L"id").as_string();
// Return the uri
return terminalResponse.at(L"socketUri").as_string();
}
// Method description:
// - helper function to store the credentials
// - we store the display name, tenant ID, access/refresh tokens, and token expiry
void AzureConnection::_StoreCredential()
{
json::value userName;
userName[U("ver")] = CurrentCredentialVersion;
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
_packTenant(userName, *_currentTenant);
json::value passWord;
passWord[U("accessToken")] = json::value::string(_accessToken);
passWord[U("refreshToken")] = json::value::string(_refreshToken);
passWord[U("expiry")] = json::value::string(std::to_wstring(_expiry));
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
PasswordVault vault;
PasswordCredential newCredential{ PasswordVaultResourceName, userName.serialize(), passWord.serialize() };
vault.Add(newCredential);
}
// Method description:
// - helper function to remove all stored credentials
void AzureConnection::_RemoveCredentials()
{
Rework error handling and state flow in the Azure connection (#5356) This commit fixes a number of problems and code quality/health issues with the AzureConnection. This is a general tidying-up of the azure connection. It improves error logging (like: it actually emits error logs...) and retry logic and the state machine and it audits the exit points of the state machine for exceptions and removes the HRESULT returns (so they either succeed and transition to a new state or throw an exception or are going down anyway). There's also a change in here that changes how we display tenants. It adds the "default domain" to the name, so that instead of seeing this: Conhost (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) Default Directory (bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb) you see this Conhost (conhost.onmicrosoft.com) Default Directory (dustinhowett.onmicrosoft.com) Changes: * rework tenant/tenant storage and fix display names Switch to the 2020 tenant API. Instead of passing around four loose variables, create a Tenant class and use that for packing/unpacking into/out of json (and the windows credential store, where we "cleverly" used json for the tenant info there too). When displaying a tenant, use its display name if there is one, the unknown resource string if there isn't, and the default domain if there is one and the ID if there isn't. Fixes #5325. * use {fmt} for formatting request bodies * remove dead strings * rework/rename Request/HeaderHelper to Send(Authenticated)ReqReturningJson * rewrite polling to use std::chrono * remove HR returns from state machine * rename state handlers from _XHelper to _RunXState * cleanup namespaces, prefix user input with >, remove namespaces * Rework error handling - _RequestHelper no longer eats exceptions. - Delete the "no internet" error message. - Wrap exceptions coming out of Azure API in a well-known type. - Catch by type. - Extract error codes for known failures (keep polling, invalid grant). - When we get an Invalid Grant, dispose of the cached refresh token and force the user to log in again. - Catch all printable exceptions and print them. - Remove the NoConnect state completely -- just bail out when an exception hits the toplevel of the output thread. - Move 3x logic into _RefreshTokens and pop exceptions out of it. - Begin abstracting into AzureClient Fixes #5325 (by addressing its chief complaint). Fixes #4803 (by triggering auth flow again if the token expires). Improves diagnosability for #4575.
2020-04-17 02:32:52 +02:00
PasswordVault vault;
winrt::Windows::Foundation::Collections::IVectorView<PasswordCredential> credList;
// FindAllByResource throws an exception if there are no credentials stored under the given resource so we wrap it in a try-catch block
try
{
credList = vault.FindAllByResource(PasswordVaultResourceName);
}
catch (...)
{
// No credentials are stored, so just return
_WriteStringWithNewline(RS_(L"AzureNoTokens"));
return;
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
for (const auto& cred : credList)
{
try
{
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
vault.Remove(cred);
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
CATCH_LOG();
}
AzCon: improve input, usability, reliability (4 commits) (#4756) * Azure: rewrite user input handler This commit replaces the AzureConnection's input handler with one that acts more like "getline()". Instead of the Read thread setting a state and WriteInput filling in the right member variable, the reader blocks on the user's input and receives it in an optional<string>. This moves the input number parsing and error case handling closer to the point where those inputs are used, as opposed to where they're collected. It also switches our input to be "line-based", which is a huge boon for typing tenant numbers >9. This fixes #3233. A simple line editor (supporting only backspace and CR) is included. It also enables echo on user input, and prints it in a nice pretty green color. It also enables input queueing: if the user types anything before the connection is established, it'll be sent once it is. Fixes #3233. * Azure: display the user's options and additional information in color This commit colorizes parts of the AzCon's strings that include "user options" -- things the user can type -- in yellow. This is to help with accessibility. The implementation here is based on a discussion with the team. Alternative options for coloration were investigated, such as: * Embedding escape sequences in the resource file. This would have been confusing for translators. The RESW file format doesn't support &#x1B; escapes, so we would need some magic post-processing. * Embedding "markup" in the resource file (like #{93m}, ...) This still would have been annoying for translators. We settled on an implementation that takes resource names, colorizes them, and string-formats them into other resources. * Azure: follow the user's shell choice from the online portal Fixes #2266. * Azure: remove all credentials instead of just the first one
2020-03-04 20:30:20 +01:00
_WriteStringWithNewline(RS_(L"AzureTokensRemoved"));
}
}