Skip to content
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

feat(iot-serv): Add ability to send custom authentication scopes for RBAC auth #3476

Merged
merged 14 commits into from
Nov 21, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ internal class IotHubTokenCrendentialProperties
private readonly TokenCredential _credential;
private readonly object _tokenLock = new object();
private AccessToken? _cachedAccessToken;
private string[] _scopes;

#endif

#if NET451
Expand All @@ -39,6 +41,13 @@ public IotHubTokenCrendentialProperties()
public IotHubTokenCrendentialProperties(string hostName, TokenCredential credential) : base(hostName)
{
_credential = credential;
_scopes = CommonConstants.IotHubAadTokenScopes;
}

public IotHubTokenCrendentialProperties(string hostName, TokenCredential credential, string[] scopes) : base(hostName)
{
_credential = credential;
_scopes = scopes;
}

#endif
Expand All @@ -57,7 +66,7 @@ public override string GetAuthorizationHeader()
|| TokenHelper.IsCloseToExpiry(_cachedAccessToken.Value.ExpiresOn))
{
_cachedAccessToken = _credential.GetToken(
new TokenRequestContext(CommonConstants.IotHubAadTokenScopes),
new TokenRequestContext(_scopes),
new CancellationToken());
}
}
Expand All @@ -69,7 +78,7 @@ public override string GetAuthorizationHeader()
#pragma warning disable CS1998 // Disabled as we need to throw exception for NET 451.

// The AMQP protocol uses this method to get a CBS token for authentication.
public async override Task<CbsToken> GetTokenAsync(Uri namespaceAddress, string appliesTo, string[] requiredClaims)
public override async Task<CbsToken> GetTokenAsync(Uri namespaceAddress, string appliesTo, string[] requiredClaims)
{
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
#if NET451
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Threading;
using Azure.Core;
using Microsoft.Azure.Devices.Authentication;
Expand All @@ -18,10 +19,18 @@ internal class DigitalTwinTokenCredential : DigitalTwinServiceClientCredentials
private readonly object _tokenLock = new object();
private AccessToken? _cachedAccessToken;
private readonly TokenCredential _credential;
private string[] _scopes;

public DigitalTwinTokenCredential(TokenCredential credential)
{
_credential = credential;
_scopes = CommonConstants.IotHubAadTokenScopes;
}

public DigitalTwinTokenCredential(TokenCredential credential, string[] scopes)
{
_credential = credential;
_scopes = scopes;
}

public override string GetAuthorizationHeader()
Expand All @@ -33,7 +42,7 @@ public override string GetAuthorizationHeader()
|| TokenHelper.IsCloseToExpiry(_cachedAccessToken.Value.ExpiresOn))
{
_cachedAccessToken = _credential.GetToken(
new TokenRequestContext(CommonConstants.IotHubAadTokenScopes),
new TokenRequestContext(_scopes),
new CancellationToken());
}
}
Expand Down
27 changes: 27 additions & 0 deletions iothub/service/src/DigitalTwin/DigitalTwinClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Azure;
using Azure.Core;
using Microsoft.Azure.Devices.Authentication;
using Microsoft.Azure.Devices.Common;
using Microsoft.Azure.Devices.DigitalTwin.Authentication;
using Microsoft.Azure.Devices.Extensions;
using Microsoft.Azure.Devices.Generated;
Expand Down Expand Up @@ -82,6 +83,32 @@ public static DigitalTwinClient Create(
string hostName,
TokenCredential credential,
params DelegatingHandler[] handlers)
{
return Create(hostName, credential, CommonConstants.IotHubAadTokenScopes, handlers);
}

/// <summary>
/// Creates DigitalTwinClient, authenticating using an identity in Azure Active Directory (AAD).
/// </summary>
/// <remarks>
/// For more about information on the options of authenticating using a derived instance of <see cref="TokenCredential"/>, see
/// <see href="https://docs.microsoft.com/dotnet/api/overview/azure/identity-readme"/>.
/// For more information on configuring IoT hub with Azure Active Directory, see
/// <see href="https://docs.microsoft.com/azure/iot-hub/iot-hub-dev-guide-azure-ad-rbac"/>
/// </remarks>
/// <param name="hostName">IoT hub host name.</param>
/// <param name="credential">Azure Active Directory (AAD) credentials to authenticate with IoT hub. See <see cref="TokenCredential"/></param>
/// <param name="handlers">
/// The delegating handlers to add to the http client pipeline. You can add handlers for tracing,
/// implementing a retry strategy, routing requests through a proxy, etc.
/// </param>
/// <param name="scopes">The custom scopes to use when authenticating.</param>
/// <returns>A DigitalTwinsClient instance.</returns>
public static DigitalTwinClient Create(
string hostName,
TokenCredential credential,
string[] scopes,
params DelegatingHandler[] handlers)
{
if (string.IsNullOrEmpty(hostName))
{
Expand Down
25 changes: 24 additions & 1 deletion iothub/service/src/Jobs/JobClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,29 @@ public static JobClient Create(
string hostName,
TokenCredential credential,
HttpTransportSettings transportSettings = default)
{
return Create(hostName, credential, CommonConstants.IotHubAadTokenScopes, transportSettings);
}

/// <summary>
/// Creates JobClient, authenticating using an identity in Azure Active Directory (AAD).
/// </summary>
/// <remarks>
/// For more about information on the options of authenticating using a derived instance of <see cref="TokenCredential"/>, see
/// <see href="https://docs.microsoft.com/dotnet/api/overview/azure/identity-readme"/>.
/// For more information on configuring IoT hub with Azure Active Directory, see
/// <see href="https://docs.microsoft.com/azure/iot-hub/iot-hub-dev-guide-azure-ad-rbac"/>
/// </remarks>
/// <param name="hostName">IoT hub host name.</param>
/// <param name="credential">Azure Active Directory (AAD) credentials to authenticate with IoT hub. See <see cref="TokenCredential"/></param>
/// <param name="transportSettings">The HTTP transport settings.</param>
/// <param name="scopes">The custom scopes to authenticate with.</param>
/// <returns>A JobClient instance.</returns>
public static JobClient Create(
string hostName,
TokenCredential credential,
string[] scopes,
HttpTransportSettings transportSettings = default)
{
if (string.IsNullOrEmpty(hostName))
{
Expand All @@ -128,7 +151,7 @@ public static JobClient Create(
throw new ArgumentNullException(nameof(credential));
}

var tokenCredentialProperties = new IotHubTokenCrendentialProperties(hostName, credential);
var tokenCredentialProperties = new IotHubTokenCrendentialProperties(hostName, credential, scopes);
return new JobClient(tokenCredentialProperties, transportSettings ?? new HttpTransportSettings());
}

Expand Down
29 changes: 28 additions & 1 deletion iothub/service/src/Messaging/ServiceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,33 @@ public static ServiceClient Create(
TransportType transportType = TransportType.Amqp,
ServiceClientTransportSettings transportSettings = default,
ServiceClientOptions options = default)
{
return Create(hostName, credential, CommonConstants.IotHubAadTokenScopes, transportType, transportSettings, options);
}

/// <summary>
/// Creates ServiceClient, authenticating using an identity in Azure Active Directory (AAD).
/// </summary>
/// <remarks>
/// For more about information on the options of authenticating using a derived instance of <see cref="TokenCredential"/>, see
/// <see href="https://docs.microsoft.com/dotnet/api/overview/azure/identity-readme"/>.
/// For more information on configuring IoT hub with Azure Active Directory, see
/// <see href="https://docs.microsoft.com/azure/iot-hub/iot-hub-dev-guide-azure-ad-rbac"/>
/// </remarks>
/// <param name="hostName">IoT hub host name.</param>
/// <param name="credential">Azure Active Directory credentials to authenticate with IoT hub. See <see cref="TokenCredential"/></param>
/// <param name="transportType">Specifies whether Amqp or Amqp_WebSocket_Only transport is used.</param>
/// <param name="scopes">The custom scopes to use when authenticating.</param>
/// <param name="transportSettings">Specifies the AMQP_WS and HTTP proxy settings for service client.</param>
/// <param name="options">The options that allow configuration of the service client instance during initialization.</param>
/// <returns>A ServiceClient instance.</returns>
public static ServiceClient Create(
string hostName,
TokenCredential credential,
string[] scopes,
TransportType transportType = TransportType.Amqp,
ServiceClientTransportSettings transportSettings = default,
ServiceClientOptions options = default)
{
if (string.IsNullOrEmpty(hostName))
{
Expand All @@ -166,7 +193,7 @@ public static ServiceClient Create(
throw new ArgumentNullException($"{nameof(credential)}, Parameter cannot be null");
}

var tokenCredentialProperties = new IotHubTokenCrendentialProperties(hostName, credential);
var tokenCredentialProperties = new IotHubTokenCrendentialProperties(hostName, credential, scopes);
bool useWebSocketOnly = transportType == TransportType.Amqp_WebSocket_Only;

return new ServiceClient(
Expand Down
25 changes: 24 additions & 1 deletion iothub/service/src/Registry/RegistryManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,29 @@ public static RegistryManager Create(
string hostName,
TokenCredential credential,
HttpTransportSettings transportSettings = default)
{
return Create(hostName, credential, CommonConstants.IotHubAadTokenScopes, transportSettings);
}

/// <summary>
/// Creates RegistryManager, authenticating using an identity in Azure Active Directory (AAD).
/// </summary>
/// <remarks>
/// For more about information on the options of authenticating using a derived instance of <see cref="TokenCredential"/>, see
/// <see href="https://docs.microsoft.com/dotnet/api/overview/azure/identity-readme"/>.
/// For more information on configuring IoT hub with Azure Active Directory, see
/// <see href="https://docs.microsoft.com/azure/iot-hub/iot-hub-dev-guide-azure-ad-rbac"/>
/// </remarks>
/// <param name="hostName">IoT hub host name.</param>
/// <param name="credential">Azure Active Directory (AAD) credentials to authenticate with IoT hub.</param>
/// <param name="transportSettings">The HTTP transport settings.</param>
/// <param name="scopes">The custom scopes to use when authenticating.</param>
/// <returns>A RegistryManager instance.</returns>
public static RegistryManager Create(
string hostName,
TokenCredential credential,
string[] scopes,
HttpTransportSettings transportSettings = default)
{
if (string.IsNullOrEmpty(hostName))
{
Expand All @@ -164,7 +187,7 @@ public static RegistryManager Create(
throw new ArgumentNullException($"{nameof(credential)}, Parameter cannot be null");
}

var tokenCredentialProperties = new IotHubTokenCrendentialProperties(hostName, credential);
var tokenCredentialProperties = new IotHubTokenCrendentialProperties(hostName, credential, scopes);
return new RegistryManager(tokenCredentialProperties, transportSettings ?? new HttpTransportSettings());
}

Expand Down
Loading