-
Notifications
You must be signed in to change notification settings - Fork 479
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Authentication] updates to support Arlington #3734
Conversation
libraries/Microsoft.Bot.Connector/Authentication/AdalAuthenticator.cs
Outdated
Show resolved
Hide resolved
...aries/Microsoft.Bot.Connector/Authentication/Government/MicrosoftGovernmentAppCredentials.cs
Outdated
Show resolved
Hide resolved
@@ -217,6 +221,9 @@ private bool IsAdalServiceUnavailable(Exception ex) | |||
return adalServiceException.ErrorCode == MsalTemporarilyUnavailable || adalServiceException.StatusCode == 429; | |||
} | |||
|
|||
private bool IsAdalServiceInvalidRequest(Exception ex) | |||
=> ex is AdalServiceException adal && adal.StatusCode == 400; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we only need to care about 400's or 4xx in general or perhaps not 2xx? is there any documentation around it that you refereed for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I verified the 400 for Arlington bot requesting against Fairfax resource app.
I have not yet verified the status code for Fairfax bot requesting against the Arlington resource app.
I didn't see documentation, unfortunately.
|
||
if (OAuthScope == GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope) | ||
{ | ||
var optionOld = Make(GovernmentAuthenticationConstants.ToChannelFromBotLoginUrl, GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of calling them old and new, consider maintaining a list instead...who knows if there'll be a new "new" later
} | ||
} | ||
|
||
if (info != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
slim down to info?.throw
var inner = this.inners[index]; | ||
try | ||
{ | ||
return await inner.GetTokenAsync(forceRefresh).ConfigureAwait(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest remembering which inner works and using that for further calls. it's just extra work to always loop through
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this needs to be thread safe, I was opting for simplicity.
var optionOld = Make(GovernmentAuthenticationConstants.ToChannelFromBotLoginUrl, GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope); | ||
var optionNew = Make("https://login.microsoftonline.us/botframework.onmicrosoft.us", "https://api.botframework.onmicrosoft.us"); | ||
|
||
return new Authenticators(optionOld, optionNew); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keep optionNew as your first argument. almost all new bots going forward will be in that new tenant and hence trying the new one first will make sure that the for loop doesnt execute more than one iteration for most new bots
/// <summary> | ||
/// TO GOVERNMENT CHANNEL FROM BOT: Login URL V2. | ||
/// </summary> | ||
public const string ToChannelFromBotLoginUrlV2 = "https://login.microsoftonline.us/botframework.onmicrosoft.us"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are no unit tests. here, despite quite a bit of code churn. How do we test this?
{ | ||
internal sealed class Authenticators : IAuthenticator | ||
{ | ||
private readonly IAuthenticator[] inners; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
naming convention. "_inners"
libraries/Microsoft.Bot.Connector/Authentication/Authenticators.cs
Outdated
Show resolved
Hide resolved
|
||
public Authenticators(params IAuthenticator[] inners) | ||
{ | ||
this.inners = inners ?? throw new ArgumentNullException(nameof(inners)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
coding standard here is just "_inners = inners ?? [...]"
} | ||
|
||
private bool IsAdalServiceInvalidRequest(Exception ex) | ||
=> ex is AdalServiceException adal && adal.StatusCode == (int)HttpStatusCode.BadRequest; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not at all clear on what this line of code is doing. Can you add a nice multi-line comment.
If nothing else, BadRequest and InvalidRequest are two very different things.
Also, the complexity of this if statement is staggering, as I've got to know the operator presicdence for:
- is
- &&
- ==
- (int)
... and understand the more modern C# declare inline syntax.
Please turn this into a simpler method.
@@ -0,0 +1,44 @@ | |||
// Copyright (c) Microsoft Corporation. All rights reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why adding Arlington as a new auth point requires a new class called "Authenticators". CAn you elaborte with a nice long
comment on the class?
{ | ||
ExceptionDispatchInfo info = null; | ||
|
||
for (int index = 0; index < this.inners.Length; ++index) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't follow this. I'm lost across "info, index, this.inners, and inners".
Please consider easier variable names.
/// <summary> | ||
/// TO GOVERNMENT CHANNEL FROM BOT: OAuth scope to request V2. | ||
/// </summary> | ||
public const string ToChannelFromBotOAuthScopeV2 = "https://api.botframework.onmicrosoft.us"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is really the only line I expected to see added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the hardcoded tenant above (cab8a31a-1906-4287-a0d8-4eef66b95f6e - USME) that needed to be updated to a different tenant. And then
- the scope (api.botframework.onmicrosoft.us) is trivially name-spaced within the resource app identifier (api.botframework.onmicrosoft.us), and
- the app identifier (api.botframework.onmicrosoft.us) is name-spaced within the tenant domain (botframework.onmicrosoft.us, which we may modify to a custom domain botframework.azure.us to match our DNS name).
@@ -62,5 +65,34 @@ public override string OAuthEndpoint | |||
{ | |||
get { return GovernmentAuthenticationConstants.ToChannelFromBotLoginUrl; } | |||
} | |||
|
|||
protected override Lazy<IAuthenticator> BuildIAuthenticator() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot follow this method, and all of it's nested lambda functions.
Please simplify.
return Make(OAuthEndpoint, OAuthScope); | ||
} | ||
}, | ||
LazyThreadSafetyMode.ExecutionAndPublication); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this, and are we sure it's right? I have no idea what it does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm following the existing style:
botbuilder-dotnet/libraries/Microsoft.Bot.Connector/Authentication/MicrosoftAppCredentials.cs
Line 144 in 55af969
LazyThreadSafetyMode.ExecutionAndPublication); |
} | ||
else | ||
{ | ||
return Make(OAuthEndpoint, OAuthScope); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get how this branch of the "IF" statement returns an "Make()" function result, while the other returns a new set of authenticators.
... yet the parent function needs the lazy.
There's got to be a more clear way to express this to simple minds like mine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@carlosscastro can you give some insight into the need for the two methods (with Lazy AdalAuthenticator and Lazy IAuthenticator)? I tried to copy the existing code pattern from MicrosoftAppCredentials.
@@ -225,7 +251,7 @@ private RetryParams ComputeAdalRetry(Exception ex) | |||
|
|||
// When the Service Token Server (STS) is too busy because of “too many requests”, | |||
// it returns an HTTP error 429 with a hint about when you can try again (Retry-After response field) as a delay in seconds | |||
if (adalServiceException.ErrorCode == MsalTemporarilyUnavailable || adalServiceException.StatusCode == 429) | |||
if (adalServiceException.ErrorCode == MsalTemporarilyUnavailable || adalServiceException.StatusCode == HttpTooManyRequests) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HttpTooManyRequests [](start = 119, length = 19)
(int)HttpStatusCode.TooManyRequests.
@@ -214,7 +220,27 @@ private bool IsAdalServiceUnavailable(Exception ex) | |||
|
|||
// When the Service Token Server (STS) is too busy because of “too many requests”, | |||
// it returns an HTTP error 429 | |||
return adalServiceException.ErrorCode == MsalTemporarilyUnavailable || adalServiceException.StatusCode == 429; | |||
return adalServiceException.ErrorCode == MsalTemporarilyUnavailable || adalServiceException.StatusCode == HttpTooManyRequests; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HttpTooManyRequests [](start = 118, length = 19)
(int)HttpStatusCode.TooManyRequests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -16,7 +16,7 @@ public static class GovernmentAuthenticationConstants | |||
/// <summary> | |||
/// TO GOVERNMENT CHANNEL FROM BOT: Login URL. | |||
/// </summary> | |||
public const string ToChannelFromBotLoginUrl = "https://login.microsoftonline.us/cab8a31a-1906-4287-a0d8-4eef66b95f6e"; | |||
public const string ToChannelFromBotLoginUrl = "https://login.microsoftonline.us/MicrosoftServices.onmicrosoft.us"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does casing matter here? URI Segments are normally not case sensitive, but I'm worried the casing here might cause comparison issues.
No description provided.