Skip to content

Commit

Permalink
Aad token provider (#225)
Browse files Browse the repository at this point in the history
* Adding AAD token support.

* improve lock

* Adding MSI provider.

* Some small changes

* Adddresing comments and couple small fixes.

* Remove string resource

* Remove test secrets

* Renaming paramater endpoint to endpointAddress

* Renaming paramater endpoint to endpointAddress

* Remove unused AsyncLock

* Remove redundant config name

* Remove using

* Remove usings

* Merge fix

* API name change

* Xmldoc type fix.

* Remove SecurityToken internal constructor

* Build error fix

* Cleanup code

* Pass temporary audience instead of empty string to SecurityToken.

* Make token type required

* Refactoring SharedAccessSignatureToken for cleanup

* Function renaming to carry UTC notion.

* Remove procted accesors from SecurityToken class properties.
  • Loading branch information
serkantkaraca committed Feb 14, 2018
1 parent 5c525d7 commit e04faf6
Show file tree
Hide file tree
Showing 19 changed files with 874 additions and 354 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
<DefineConstants>$(DefineConstants);UAP10_0</DefineConstants>
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.14393.0</TargetPlatformVersion>
Expand Down
31 changes: 22 additions & 9 deletions src/Microsoft.Azure.EventHubs/Amqp/AmqpEventHubClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ namespace Microsoft.Azure.EventHubs.Amqp
{
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Azure.Amqp.Sasl;
using Microsoft.Azure.Amqp;
Expand All @@ -26,17 +25,33 @@ public AmqpEventHubClient(EventHubsConnectionStringBuilder csb)

if (!string.IsNullOrWhiteSpace(csb.SharedAccessSignature))
{
this.TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(csb.SharedAccessSignature);
this.InternalTokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(csb.SharedAccessSignature);
}
else
{
this.TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(csb.SasKeyName, csb.SasKey);
this.InternalTokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(csb.SasKeyName, csb.SasKey);
}

this.CbsTokenProvider = new TokenProviderAdapter(this);
this.ConnectionManager = new FaultTolerantAmqpObject<AmqpConnection>(this.CreateConnectionAsync, this.CloseConnection);
}

public AmqpEventHubClient(
Uri endpointAddress,
string entityPath,
ITokenProvider tokenProvider,
TimeSpan operationTimeout,
TransportType transportType)
: base(new EventHubsConnectionStringBuilder(endpointAddress, entityPath, operationTimeout, transportType))
{
this.ContainerId = Guid.NewGuid().ToString("N");
this.AmqpVersion = new Version(1, 0, 0, 0);
this.MaxFrameSize = AmqpConstants.DefaultMaxFrameSize;
this.InternalTokenProvider = tokenProvider;
this.CbsTokenProvider = new TokenProviderAdapter(this);
this.ConnectionManager = new FaultTolerantAmqpObject<AmqpConnection>(this.CreateConnectionAsync, this.CloseConnection);
}

internal ICbsTokenProvider CbsTokenProvider { get; }

internal FaultTolerantAmqpObject<AmqpConnection> ConnectionManager { get; }
Expand All @@ -47,7 +62,7 @@ public AmqpEventHubClient(EventHubsConnectionStringBuilder csb)

uint MaxFrameSize { get; }

internal TokenProvider TokenProvider { get; }
internal ITokenProvider InternalTokenProvider { get; }

internal override EventDataSender OnCreateEventSender(string partitionId)
{
Expand Down Expand Up @@ -110,7 +125,7 @@ internal static AmqpSettings CreateAmqpSettings(
string sslHostName = null,
bool useWebSockets = false,
bool sslStreamUpgrade = false,
NetworkCredential networkCredential = null,
System.Net.NetworkCredential networkCredential = null,
bool forceTokenProvider = true)
{
var settings = new AmqpSettings();
Expand Down Expand Up @@ -266,11 +281,9 @@ public TokenProviderAdapter(AmqpEventHubClient eventHubClient)

public async Task<CbsToken> GetTokenAsync(Uri namespaceAddress, string appliesTo, string[] requiredClaims)
{
string claim = requiredClaims?.FirstOrDefault();
var tokenProvider = this.eventHubClient.TokenProvider;
var timeout = this.eventHubClient.ConnectionStringBuilder.OperationTimeout;
var token = await tokenProvider.GetTokenAsync(appliesTo, claim, timeout).ConfigureAwait(false);
return new CbsToken(token.TokenValue, CbsConstants.ServiceBusSasTokenType, token.ExpiresAtUtc);
var token = await this.eventHubClient.InternalTokenProvider.GetTokenAsync(appliesTo, timeout).ConfigureAwait(false);
return new CbsToken(token.TokenValue, token.TokenType, token.ExpiresAtUtc);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.Azure.EventHubs/Amqp/AmqpServiceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@ async Task<string> GetTokenString()
// when checking for token expiry.
if (this.token == null || DateTime.UtcNow > this.token.ExpiresAtUtc.Subtract(TimeSpan.FromMinutes(5)))
{
this.token = await this.eventHubClient.TokenProvider.GetTokenAsync(
this.token = await this.eventHubClient.InternalTokenProvider.GetTokenAsync(
this.eventHubClient.ConnectionStringBuilder.Endpoint.AbsoluteUri,
ClaimConstants.Listen, this.eventHubClient.ConnectionStringBuilder.OperationTimeout).ConfigureAwait(false);
this.eventHubClient.ConnectionStringBuilder.OperationTimeout).ConfigureAwait(false);
}

return this.token.TokenValue.ToString();
Expand Down
153 changes: 152 additions & 1 deletion src/Microsoft.Azure.EventHubs/EventHubClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

namespace Microsoft.Azure.EventHubs
{
using Amqp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Azure.EventHubs.Amqp;
using Microsoft.IdentityModel.Clients.ActiveDirectory;

/// <summary>
/// Anchor class - all EventHub client operations start here.
Expand Down Expand Up @@ -70,6 +71,156 @@ public static EventHubClient CreateFromConnectionString(string connectionString)
return Create(csb);
}

/// <summary>
/// Creates a new instance of the Event Hubs client using the specified endpoint, entity path, and token provider.
/// </summary>
/// <param name="endpointAddress">Fully qualified domain name for Event Hubs. Most likely, {yournamespace}.servicebus.windows.net</param>
/// <param name="entityPath">Event Hub path</param>
/// <param name="tokenProvider">Token provider which will generate security tokens for authorization.</param>
/// <param name="operationTimeout">Operation timeout for Event Hubs operations.</param>
/// <param name="transportType">Transport type on connection.</param>
/// <returns></returns>
public static EventHubClient Create(
Uri endpointAddress,
string entityPath,
ITokenProvider tokenProvider,
TimeSpan? operationTimeout = null,
TransportType transportType = TransportType.Amqp)
{
if (endpointAddress == null)
{
throw Fx.Exception.ArgumentNull(nameof(endpointAddress));
}

if (string.IsNullOrWhiteSpace(entityPath))
{
throw Fx.Exception.ArgumentNullOrWhiteSpace(nameof(entityPath));
}

if (tokenProvider == null)
{
throw Fx.Exception.ArgumentNull(nameof(tokenProvider));
}

EventHubsEventSource.Log.EventHubClientCreateStart(endpointAddress.Host, entityPath);
EventHubClient eventHubClient = new AmqpEventHubClient(
endpointAddress,
entityPath,
tokenProvider,
operationTimeout?? ClientConstants.DefaultOperationTimeout,
transportType);
EventHubsEventSource.Log.EventHubClientCreateStop(eventHubClient.ClientId);
return eventHubClient;
}

/// <summary>
/// Creates a new instance of the Event Hubs client using the specified endpoint, entity path, AAD authentication context.
/// </summary>
/// <param name="endpointAddress">Fully qualified domain name for Event Hubs. Most likely, {yournamespace}.servicebus.windows.net</param>
/// <param name="entityPath">Event Hub path</param>
/// <param name="authContext">AuthenticationContext for AAD.</param>
/// <param name="clientCredential">The app credential.</param>
/// <param name="operationTimeout">Operation timeout for Event Hubs operations.</param>
/// <param name="transportType">Transport type on connection.</param>
/// <returns></returns>
public static EventHubClient Create(
Uri endpointAddress,
string entityPath,
AuthenticationContext authContext,
ClientCredential clientCredential,
TimeSpan? operationTimeout = null,
TransportType transportType = TransportType.Amqp)
{
return Create(
endpointAddress,
entityPath,
TokenProvider.CreateAadTokenProvider(authContext, clientCredential),
operationTimeout,
transportType);
}

/// <summary>
/// Creates a new instance of the Event Hubs client using the specified endpoint, entity path, AAD authentication context.
/// </summary>
/// <param name="endpointAddress">Fully qualified domain name for Event Hubs. Most likely, {yournamespace}.servicebus.windows.net</param>
/// <param name="entityPath">Event Hub path</param>
/// <param name="authContext">AuthenticationContext for AAD.</param>
/// <param name="clientId">ClientId for AAD.</param>
/// <param name="redirectUri">The redirectUri on Client App.</param>
/// <param name="platformParameters">Platform parameters</param>
/// <param name="userIdentifier">User Identifier</param>
/// <param name="operationTimeout">Operation timeout for Event Hubs operations.</param>
/// <param name="transportType">Transport type on connection.</param>
/// <returns></returns>
public static EventHubClient Create(
Uri endpointAddress,
string entityPath,
AuthenticationContext authContext,
string clientId,
Uri redirectUri,
IPlatformParameters platformParameters,
UserIdentifier userIdentifier = null,
TimeSpan? operationTimeout = null,
TransportType transportType = TransportType.Amqp)
{
return Create(
endpointAddress,
entityPath,
TokenProvider.CreateAadTokenProvider(authContext, clientId, redirectUri, platformParameters, userIdentifier),
operationTimeout,
transportType);
}

#if !UAP10_0
/// <summary>
/// Creates a new instance of the Event Hubs client using the specified endpoint, entity path, AAD authentication context.
/// </summary>
/// <param name="endpointAddress">Fully qualified domain name for Event Hubs. Most likely, {yournamespace}.servicebus.windows.net</param>
/// <param name="entityPath">Event Hub path</param>
/// <param name="authContext">AuthenticationContext for AAD.</param>
/// <param name="clientAssertionCertificate">The client assertion certificate credential.</param>
/// <param name="operationTimeout">Operation timeout for Event Hubs operations.</param>
/// <param name="transportType">Transport type on connection.</param>
/// <returns></returns>
public static EventHubClient Create(
Uri endpointAddress,
string entityPath,
AuthenticationContext authContext,
ClientAssertionCertificate clientAssertionCertificate,
TimeSpan? operationTimeout = null,
TransportType transportType = TransportType.Amqp)
{
return Create(
endpointAddress,
entityPath,
TokenProvider.CreateAadTokenProvider(authContext, clientAssertionCertificate),
operationTimeout,
transportType);
}
#endif

/// <summary>
/// Creates a new instance of the Event Hubs client using the specified endpoint, entity path on Azure Managed Service Identity authentication.
/// </summary>
/// <param name="endpointAddress">Fully qualified domain name for Event Hubs. Most likely, {yournamespace}.servicebus.windows.net</param>
/// <param name="entityPath">Event Hub path</param>
/// <param name="operationTimeout">Operation timeout for Event Hubs operations.</param>
/// <param name="transportType">Transport type on connection.</param>
/// <returns></returns>
public static EventHubClient CreateWithManagedServiceIdentity(
Uri endpointAddress,
string entityPath,
TimeSpan? operationTimeout = null,
TransportType transportType = TransportType.Amqp)
{
return Create(
endpointAddress,
entityPath,
TokenProvider.CreateManagedServiceIdentityTokenProvider(),
operationTimeout,
transportType);
}

static EventHubClient Create(EventHubsConnectionStringBuilder csb)
{
if (string.IsNullOrWhiteSpace(csb.EntityPath))
Expand Down
14 changes: 13 additions & 1 deletion src/Microsoft.Azure.EventHubs/Microsoft.Azure.EventHubs.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
<FileVersion>2.0.0.0</FileVersion>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net461' ">
<DefineConstants>$(DefineConstants);NET461</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'uap10.0'">
<DefineConstants>$(DefineConstants);UAP10_0</DefineConstants>
<NugetTargetMoniker>UAP,Version=v10.0</NugetTargetMoniker>
Expand All @@ -39,6 +43,10 @@
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<DefineConstants>$(DefineConstants);NETSTANDARD2_0</DefineConstants>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
Expand All @@ -50,12 +58,16 @@
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'uap10.0' ">
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform " Version="5.2.3" />
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform " Version="5.2.3" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Azure.Amqp" Version="2.1.1" />
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.1.0-preview" />
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="3.17.2" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="4.4.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.1.5" />
<PackageReference Include="System.Net.Http" Version="4.3.3" />
</ItemGroup>

</Project>
Loading

0 comments on commit e04faf6

Please sign in to comment.