Skip to content

Commit

Permalink
Adding a few more AAD changes
Browse files Browse the repository at this point in the history
  • Loading branch information
David-Engel committed May 12, 2020
1 parent 0f83d2f commit 6c2745e
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ internal static string ConvertToString(object value)

internal static bool TryConvertToAuthenticationType(string value, out SqlAuthenticationMethod result)
{
Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 5, "SqlAuthenticationMethod enum has changed, update needed");
Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 6, "SqlAuthenticationMethod enum has changed, update needed");

bool isSuccess = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2242,7 +2242,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
}
break;
default:
throw new InvalidOperationException($"Failed to get a token with unsupported auth method {ConnectionOptions.Authentication}.");
throw SQL.UnsupportedAuthenticationSpecified(ConnectionOptions.Authentication);
}

Debug.Assert(fedAuthToken.accessToken != null, "AccessToken should not be null.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,11 @@ internal static Exception UnsupportedSqlAuthenticationMethod(SqlAuthenticationMe
return ADP.NotSupported(System.SRHelper.GetString(SR.SQL_UnsupportedSqlAuthenticationMethod, authentication));
}

internal static Exception UnsupportedAuthenticationSpecified(SqlAuthenticationMethod authentication)
{
return ADP.InvalidOperation(System.SRHelper.GetString(SR.SQL_UnsupportedAuthenticationSpecified, authentication));
}

internal static Exception CannotCreateAuthProvider(string authentication, string type, Exception e)
{
return ADP.Argument(System.SRHelper.GetString(SR.SQL_CannotCreateAuthProvider, authentication, type), e);
Expand Down Expand Up @@ -425,6 +430,12 @@ internal static Exception ParameterCannotBeEmpty(string paramName)
return ADP.ArgumentNull(System.SRHelper.GetString(SR.SQL_ParameterCannotBeEmpty, paramName));
}

internal static Exception ActiveDirectoryInteractiveTimeout()
{
return ADP.TimeoutException(SR.SQL_Timeout_Active_Directory_Interactive_Authentication);
}


//
// SQL.DataCommand
//
Expand Down
18 changes: 18 additions & 0 deletions src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion src/Microsoft.Data.SqlClient/netcore/src/Resources/SR.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1869,4 +1869,10 @@
<data name="SQL_SettingIntegratedWithCredential" xml:space="preserve">
<value>Cannot use 'Authentication=Active Directory Integrated', if the Credential property has been set.</value>
</data>
</root>
<data name="SQL_UnsupportedAuthenticationSpecified" xml:space="preserve">
<value>Unsupported authentication specified in this context: {0}</value>
</data>
<data name="SQL_Timeout_Active_Directory_Interactive_Authentication" xml:space="preserve">
<value>Active Directory Interactive authentication timed out. The user took too long to respond to the authentication request.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlClientEventSource.cs">
<Link>Microsoft\Data\SqlClient\SqlClientEventSource.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlClientLogger.cs" >
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlClientLogger.cs">
<Link>Microsoft\Data\SqlClient\SqlClientLogger.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\Common\ActivityCorrelator.cs">
<Link>>Microsoft\Data\Common\ActivityCorrelator.cs</Link>
<Link>Microsoft\Data\Common\ActivityCorrelator.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\Sql\SqlNotificationRequest.cs">
<Link>Microsoft\Data\Sql\SqlNotificationRequest.cs</Link>
Expand Down Expand Up @@ -126,7 +126,7 @@
<Compile Include="..\..\src\Microsoft\Data\SqlClient\ColumnEncryptionKeyInfo.cs">
<Link>Microsoft\Data\SqlClient\ColumnEncryptionKeyInfo.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\OnChangedEventHandler.cs" >
<Compile Include="..\..\src\Microsoft\Data\SqlClient\OnChangedEventHandler.cs">
<Link>Microsoft\Data\SqlClient\OnChangedEventHandler.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256Algorithm.cs">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ internal static ApplicationIntent ConvertToApplicationIntent(string keyword, obj

internal static bool TryConvertToAuthenticationType(string value, out SqlAuthenticationMethod result)
{
Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 5, "SqlAuthenticationMethod enum has changed, update needed");
Debug.Assert(Enum.GetNames(typeof(SqlAuthenticationMethod)).Length == 6, "SqlAuthenticationMethod enum has changed, update needed");

bool isSuccess = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2723,7 +2723,7 @@ internal SqlFedAuthToken GetFedAuthToken(SqlFedAuthInfo fedAuthInfo)
}
break;
default:
throw new InvalidOperationException($"Failed to get a token with unsupported auth method {ConnectionOptions.Authentication}.");
throw SQL.UnsupportedAuthenticationSpecified(ConnectionOptions.Authentication);
}

Debug.Assert(fedAuthToken.accessToken != null, "AccessToken should not be null.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,11 @@ static internal Exception UnsupportedSqlAuthenticationMethod(SqlAuthenticationMe
return ADP.NotSupported(StringsHelper.GetString(Strings.SQL_UnsupportedSqlAuthenticationMethod, authentication));
}

static internal Exception UnsupportedAuthenticationSpecified(SqlAuthenticationMethod authentication)
{
return ADP.InvalidOperation(StringsHelper.GetString(Strings.SQL_UnsupportedAuthenticationSpecified, authentication));
}

static internal Exception CannotCreateAuthProvider(string authentication, string type, Exception e)
{
return ADP.Argument(StringsHelper.GetString(Strings.SQL_CannotCreateAuthProvider, authentication, type), e);
Expand Down Expand Up @@ -456,6 +461,11 @@ static internal Exception ParameterCannotBeEmpty(string paramName)
return ADP.ArgumentNull(StringsHelper.GetString(Strings.SQL_ParameterCannotBeEmpty, paramName));
}

static internal Exception ActiveDirectoryInteractiveTimeout()
{
return ADP.TimeoutException(Strings.SQL_Timeout_Active_Directory_Interactive_Authentication);
}

//
// SQL.DataCommand
//
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -4530,4 +4530,10 @@
<data name="SQLUDT_InvalidSize" xml:space="preserve">
<value>UDT size must be less than {1}, size: {0}</value>
</data>
<data name="SQL_UnsupportedAuthenticationSpecified" xml:space="preserve">
<value>Unsupported authentication specified in this context: {0}</value>
</data>
<data name="SQL_Timeout_Active_Directory_Interactive_Authentication" xml:space="preserve">
<value>Active Directory Interactive authentication timed out. The user took too long to respond to the authentication request.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Diagnostics;
using System.Linq;
using System.Security;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Client;

Expand Down Expand Up @@ -44,6 +48,7 @@ public override Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthentication
.WithAuthority(parameters.Authority)
.WithClientName(Common.DbConnectionStringDefaults.ApplicationName)
.WithClientVersion(Common.ADP.GetAssemblyVersion().ToString())
.WithRedirectUri("http://localhost")
.Build();
if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryIntegrated)
Expand All @@ -62,17 +67,89 @@ public override Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthentication
.WithCorrelationId(parameters.ConnectionId)
.ExecuteAsync().Result;
}
else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive)
{
var accounts = await app.GetAccountsAsync();
IAccount account;
if (!string.IsNullOrEmpty(parameters.UserId))
{
account = accounts.FirstOrDefault(a => parameters.UserId.Equals(a.Username, System.StringComparison.InvariantCultureIgnoreCase));
}
else
{
account = accounts.FirstOrDefault();
}
if (null != account)
{
try
{
result = await app.AcquireTokenSilent(scopes, account).ExecuteAsync();
}
catch (MsalUiRequiredException)
{
result = await AcquireTokenInteractive(app, scopes, parameters.ConnectionId, parameters.UserId);
}
}
else
{
result = await AcquireTokenInteractive(app, scopes, parameters.ConnectionId, parameters.UserId);
}
}
else
{
result = await app.AcquireTokenInteractive(scopes)
.WithCorrelationId(parameters.ConnectionId)
.WithLoginHint(parameters.UserId)
.ExecuteAsync();
throw SQL.UnsupportedAuthenticationSpecified(parameters.AuthenticationMethod);
}
return new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn);
});

private async Task<AuthenticationResult> AcquireTokenInteractive(IPublicClientApplication app, string[] scopes, Guid connectionId, string userId)
{
CancellationTokenSource cts = new CancellationTokenSource();
#if netcoreapp
/*
* On .NET Core, MSAL will start the system browser as a separate process. MSAL does not have control over this browser,
* but once the user finishes authentication, the web page is redirected in such a way that MSAL can intercept the Uri.
* MSAL cannot detect if the user navigates away or simply closes the browser. Apps using this technique are encouraged
* to define a timeout (via CancellationToken). We recommend a timeout of at least a few minutes, to take into account
* cases where the user is prompted to change password or perform 2FA.
*
* https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/System-Browser-on-.Net-Core#system-browser-experience
*/
cts.CancelAfter(180000);
#endif
try
{
return await app.AcquireTokenInteractive(scopes)
/*
* We will use the MSAL Embedded or System web browser which changes by Default in MSAL according to this table:
*
* Framework Embedded System Default
* -------------------------------------------
* .NET Classic Yes Yes^ Embedded
* .NET Core No Yes^ System
* .NET Standard No No NONE
* UWP Yes No Embedded
* Xamarin.Android Yes Yes System
* Xamarin.iOS Yes Yes System
* Xamarin.Mac Yes No Embedded
*
* ^ Requires "http://localhost" redirect URI
*
* https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/MSAL.NET-uses-web-browser#at-a-glance
*/
//.WithUseEmbeddedWebView(true)
.WithCorrelationId(connectionId)
.WithLoginHint(userId)
.ExecuteAsync(cts.Token);
}
catch (OperationCanceledException)
{
throw SQL.ActiveDirectoryInteractiveTimeout();
}
}

/// <summary>
/// Checks support for authentication type in lower case.
/// Interactive authentication added.
Expand Down

0 comments on commit 6c2745e

Please sign in to comment.