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

Add ApplicationName to options and use it to prefix the HubName #449

Merged
merged 15 commits into from
Apr 8, 2019
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Microsoft.Azure.SignalR.AspNet
internal class ServiceEndpointManager : ServiceEndpointManagerBase
{
private readonly TimeSpan? _ttl;
private readonly ServiceOptions _options;

public ServiceEndpointManager(ServiceOptions options, ILoggerFactory loggerFactory) :
base(options,
Expand All @@ -20,6 +21,7 @@ public ServiceEndpointManager(ServiceOptions options, ILoggerFactory loggerFacto
}

_ttl = options.AccessTokenLifetime;
_options = options;
}

public override IServiceEndpointProvider GetEndpointProvider(ServiceEndpoint endpoint)
Expand All @@ -29,7 +31,7 @@ public override IServiceEndpointProvider GetEndpointProvider(ServiceEndpoint end
return null;
}

return new ServiceEndpointProvider(endpoint, _ttl);
return new ServiceEndpointProvider(endpoint, _options, _ttl);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ internal class ServiceEndpointProvider : IServiceEndpointProvider

private readonly string _endpoint;
private readonly string _accessKey;
private readonly string _appName;
private readonly int? _port;
private readonly TimeSpan _accessTokenLifetime;

public ServiceEndpointProvider(ServiceEndpoint endpoint, TimeSpan? ttl = null)
public ServiceEndpointProvider(ServiceEndpoint endpoint, ServiceOptions options, TimeSpan? ttl = null)
{
var connectionString = endpoint.ConnectionString;
if (string.IsNullOrEmpty(connectionString))
Expand All @@ -37,9 +38,15 @@ public ServiceEndpointProvider(ServiceEndpoint endpoint, TimeSpan? ttl = null)
// Version is ignored for aspnet signalr case
_endpoint = endpoint.Endpoint;
_accessKey = endpoint.AccessKey;
_appName = options.ApplicationName;
_port = endpoint.Port;
}

private string GetPrefixedHubName(string applicationName, string hubName)
{
return string.IsNullOrEmpty(applicationName) ? hubName.ToLower() : $"{applicationName.ToLower()}_{hubName.ToLower()}";
}

public string GenerateClientAccessToken(string hubName = null, IEnumerable<Claim> claims = null, TimeSpan? lifetime = null, string requestId = null)
{
var audience = $"{_endpoint}/{ClientPath}";
Expand All @@ -57,7 +64,7 @@ public string GenerateServerAccessToken(string hubName, string userId, TimeSpan?
};
}

var audience = $"{_endpoint}/{ServerPath}/?hub={hubName.ToLower()}";
var audience = $"{_endpoint}/{ServerPath}/?hub={GetPrefixedHubName(_appName, hubName)}";

return AuthenticationHelper.GenerateAccessToken(_accessKey, audience, claims, lifetime ?? _accessTokenLifetime, requestId);
}
Expand Down Expand Up @@ -96,8 +103,8 @@ public string GetClientEndpoint(string hubName = null, string originalPath = nul
public string GetServerEndpoint(string hubName)
{
return _port.HasValue ?
$"{_endpoint}:{_port}/{ServerPath}/?hub={hubName.ToLower()}" :
$"{_endpoint}/{ServerPath}/?hub={hubName.ToLower()}";
$"{_endpoint}:{_port}/{ServerPath}/?hub={GetPrefixedHubName(_appName, hubName)}" :
$"{_endpoint}/{ServerPath}/?hub={GetPrefixedHubName(_appName, hubName)}";
}
}
}
2 changes: 2 additions & 0 deletions src/Microsoft.Azure.SignalR.AspNet/OwinExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ private static void RunAzureSignalRCore(IAppBuilder builder, string applicationN
throw new ArgumentException(nameof(applicationName), "Empty application name is not allowed.");
}

options.ApplicationName = applicationName;

if (configuration == null)
{
// Keep the same as SignalR's exception
Expand Down
12 changes: 9 additions & 3 deletions src/Microsoft.Azure.SignalR.AspNet/ServiceOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ public class ServiceOptions : IServiceEndpointOptions
/// </summary>
public int ConnectionCount { get; set; } = 5;

/// <summary>
/// Gets applicationName, which will be used as a prefix to apply to each hub name
/// </summary>
internal string ApplicationName{ get; set; }
string IServiceEndpointOptions.ApplicationName => ApplicationName;

/// <summary>
/// Gets or sets the func to generate claims from <see cref="IOwinContext" />.
/// The claims will be included in the auto-generated token for clients.
Expand All @@ -47,7 +53,7 @@ public ServiceOptions()
for (int i = 0; i < count; i++)
{
var setting = ConfigurationManager.ConnectionStrings[i];
var (isDefault, endpoint) = GetEndpoint(setting.Name, () => setting.ConnectionString);
var (isDefault, endpoint) = GetEndpoint(setting.Name, this.ApplicationName, () => setting.ConnectionString);
if (endpoint != null)
{
if (isDefault)
Expand All @@ -64,7 +70,7 @@ public ServiceOptions()
// Fallback to use AppSettings
foreach(var key in ConfigurationManager.AppSettings.AllKeys)
{
var (isDefault, endpoint) = GetEndpoint(key, () => ConfigurationManager.AppSettings[key]);
var (isDefault, endpoint) = GetEndpoint(key, this.ApplicationName, () => ConfigurationManager.AppSettings[key]);
if (endpoint != null)
{
if (isDefault)
Expand All @@ -81,7 +87,7 @@ public ServiceOptions()
Endpoints = endpoints.ToArray();
}

private static (bool isDefault, ServiceEndpoint endpoint) GetEndpoint(string key, Func<string> valueGetter)
private static (bool isDefault, ServiceEndpoint endpoint) GetEndpoint(string key, string appName, Func<string> valueGetter)
{
if (key == Constants.ConnectionStringDefaultKey && !string.IsNullOrEmpty(valueGetter()))
{
Expand Down
3 changes: 3 additions & 0 deletions src/Microsoft.Azure.SignalR.Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ namespace Microsoft.Azure.SignalR
internal static class Constants
{
public const string ConnectionStringDefaultKey = "Azure:SignalR:ConnectionString";
public const string ApplicationNameDefaultKey = "Azure:SignalR:ApplicationName";

public static readonly string ConnectionStringSecondaryKey =
$"ConnectionStrings:{ConnectionStringDefaultKey}";

public static readonly string ConnectionStringKeyPrefix = $"{ConnectionStringDefaultKey}:";

public static readonly string ApplicationNameDefaultKeyPrefix = $"{ApplicationNameDefaultKey}:";

public static readonly string ConnectionStringSecondaryKeyPrefix = $"{ConnectionStringSecondaryKey}:";

// Default access token lifetime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Microsoft.Azure.SignalR
internal interface IServiceEndpointOptions
{
ServiceEndpoint[] Endpoints { get; }
string ApplicationName { get; }
string ConnectionString { get; }
}
}
13 changes: 10 additions & 3 deletions src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,25 @@ internal class RestApiProvider
private readonly RestApiAccessTokenGenerator _restApiAccessTokenGenerator;
private readonly string _baseEndpoint;
private readonly string _hubName;
private readonly string _appName;
private readonly string _requestPrefix;
private readonly string _audiencePrefix;
private readonly int? _port;

public RestApiProvider(string connectionString, string hubName)
public RestApiProvider(string connectionString, string hubName, string appName)
{
string accessKey;
(_baseEndpoint, accessKey, _, _port) = ConnectionStringParser.Parse(connectionString);
_hubName = hubName;
_appName = appName;
_restApiAccessTokenGenerator = new RestApiAccessTokenGenerator(accessKey);
_requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{_hubName}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{_hubName}";
_audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{_hubName}";
_requestPrefix = _port == null ? $"{_baseEndpoint}/api/v1/hubs/{GetPrefixedHubName(_appName, _hubName)}" : $"{_baseEndpoint}:{_port}/api/v1/hubs/{GetPrefixedHubName(_appName, _hubName)}";
_audiencePrefix = $"{_baseEndpoint}/api/v1/hubs/{GetPrefixedHubName(_appName, _hubName)}";
}

private string GetPrefixedHubName(string applicationName, string hubName)
{
return string.IsNullOrEmpty(applicationName) ? hubName.ToLower() : $"{applicationName.ToLower()}_{hubName.ToLower()}";
}

public RestApiEndpoint GetBroadcastEndpoint(TimeSpan? lifetime = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal class RestHubLifetimeManager : HubLifetimeManager<Hub>, IHubLifetimeMan

public RestHubLifetimeManager(ServiceManagerOptions serviceManagerOptions, string hubName)
{
_restApiProvider = new RestApiProvider(serviceManagerOptions.ConnectionString, hubName);
_restApiProvider = new RestApiProvider(serviceManagerOptions.ConnectionString, hubName, serviceManagerOptions.ApplicationName);
}

public override Task AddToGroupAsync(string connectionId, string groupName, CancellationToken cancellationToken = default)
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.Azure.SignalR.Management/ServiceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ internal ServiceManager(ServiceManagerOptions serviceManagerOptions)
{
_serviceManagerOptions = serviceManagerOptions;
_endpoint = new ServiceEndpoint(_serviceManagerOptions.ConnectionString, EndpointType.Secondary);
_endpointProvider = new ServiceEndpointProvider(_endpoint);
_endpointProvider = new ServiceEndpointProvider(_endpoint, appName: _serviceManagerOptions.ApplicationName);
}

public async Task<IServiceHubContext> CreateHubContextAsync(string hubName, ILoggerFactory loggerFactory = null, CancellationToken cancellationToken = default)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public class ServiceManagerOptions
/// </summary>
public string ConnectionString { get; set; } = null;

/// <summary>
/// Gets or sets the ApplicationName which will be prefixed to each hub name
/// </summary>
public string ApplicationName { get; set; }

internal void ValidateOptions()
{
ValidateConnectionString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ public DefaultServiceEndpointGenerator(string endpoint, string accessKey, string
Port = port;
}

public string GetClientAudience(string hubName) =>
InternalGetAudience(ClientPath, hubName);
public string GetClientAudience(string hubName, string applicationName) =>
InternalGetAudience(ClientPath, hubName, applicationName);

public string GetClientEndpoint(string hubName, string originalPath, string queryString)

public string GetClientEndpoint(string hubName, string applicationName, string originalPath, string queryString)
{
var queryBuilder = new StringBuilder();
if (!string.IsNullOrEmpty(originalPath))
Expand All @@ -46,21 +47,30 @@ public string GetClientEndpoint(string hubName, string originalPath, string quer
queryBuilder.Append("&").Append(queryString);
}

return $"{InternalGetEndpoint(ClientPath, hubName)}{queryBuilder}";
return $"{InternalGetEndpoint(ClientPath, hubName, applicationName)}{queryBuilder}";
}

public string GetServerAudience(string hubName) =>
InternalGetAudience(ServerPath, hubName);
public string GetServerAudience(string hubName, string applicationName) =>
InternalGetAudience(ServerPath, hubName, applicationName);

public string GetServerEndpoint(string hubName, string applicationName) =>
InternalGetEndpoint(ServerPath, hubName, applicationName);

public string GetServerEndpoint(string hubName) =>
InternalGetEndpoint(ServerPath, hubName);
private string GetPrefixedHubName(string applicationName, string hubName)
{
return string.IsNullOrEmpty(applicationName) ? hubName.ToLower() : $"{applicationName.ToLower()}_{hubName.ToLower()}";
}

private string InternalGetEndpoint(string path, string hubName) =>
Port.HasValue ?
$"{Endpoint}:{Port}/{path}/?hub={hubName.ToLower()}" :
$"{Endpoint}/{path}/?hub={hubName.ToLower()}";
private string InternalGetEndpoint(string path, string hubName, string applicationName)
{
return Port.HasValue ?
$"{Endpoint}:{Port}/{path}/?hub={GetPrefixedHubName(applicationName, hubName)}" :
$"{Endpoint}/{path}/?hub={GetPrefixedHubName(applicationName, hubName)}";
}

private string InternalGetAudience(string path, string hubName) =>
$"{Endpoint}/{path}/?hub={hubName.ToLower()}";
private string InternalGetAudience(string path, string hubName, string applicationName)
{
return $"{Endpoint}/{path}/?hub={GetPrefixedHubName(applicationName, hubName)}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ namespace Microsoft.Azure.SignalR
{
internal interface IServiceEndpointGenerator
{
string GetClientAudience(string hubName);
string GetClientEndpoint(string hubName, string originalPath, string queryString);
string GetServerAudience(string hubName);
string GetServerEndpoint(string hubName);
string GetClientAudience(string hubName, string applicationName);
string GetClientEndpoint(string hubName, string applicationName, string originalPath, string queryString);
string GetServerAudience(string hubName, string applicationName);
string GetServerEndpoint(string hubName, string applicationName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Microsoft.Azure.SignalR
{
internal class ServiceEndpointManager : ServiceEndpointManagerBase
{
private readonly IOptions<ServiceOptions> _options;
private readonly TimeSpan? _ttl;

public ServiceEndpointManager(IOptions<ServiceOptions> options, ILoggerFactory loggerFactory) :
Expand All @@ -20,6 +21,7 @@ public ServiceEndpointManager(IOptions<ServiceOptions> options, ILoggerFactory l
throw new ArgumentException(ServiceEndpointProvider.ConnectionStringNotFound);
}

_options = options;
_ttl = options.Value?.AccessTokenLifetime;
}

Expand All @@ -30,7 +32,7 @@ public override IServiceEndpointProvider GetEndpointProvider(ServiceEndpoint end
return null;
}

return new ServiceEndpointProvider(endpoint, _ttl);
return new ServiceEndpointProvider(endpoint, serviceOptions: _options, ttl: _ttl);
}
}
}
Loading