csharp/Azure/azure-signalr/src/Microsoft.Azure.SignalR.AspNet/EndpointProvider/ServiceEndpointProvider.cs

ServiceEndpointProvider.cs
// 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.Collections.Generic;
using System.Net;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace Microsoft.Azure.SignalR.AspNet
{
    internal clast ServiceEndpointProvider : IServiceEndpointProvider
    {
        public static readonly string ConnectionStringNotFound =
            "No connection string was specified. " +
            $"Please specify a configuration entry for {Constants.Keys.ConnectionStringDefaultKey}, " +
            "or explicitly past one using IAppBuilder.RunAzureSignalR(connectionString) in Startup.ConfigureServices.";

        private const string ClientPath = "aspnetclient";
        private const string ServerPath = "aspnetserver";

        private readonly string _audienceBaseUrl;
        private readonly string _clientEndpoint;
        private readonly string _serverEndpoint;

        private readonly AccessKey _accessKey;
        private readonly string _appName;
        private readonly TimeSpan _accessTokenLifetime;
        private readonly AccessTokenAlgorithm _algorithm;

        public IWebProxy Proxy { get; }

        public ServiceEndpointProvider(
            ServiceEndpoint endpoint,
            ServiceOptions options)
        {
            _accessTokenLifetime = options.AccessTokenLifetime;

            // Version is ignored for aspnet signalr case
            _audienceBaseUrl = endpoint.AudienceBaseUrl;
            _clientEndpoint = endpoint.ClientEndpoint;
            _serverEndpoint = endpoint.Endpoint;
            _accessKey = endpoint.AccessKey;
            _appName = options.ApplicationName;
            _algorithm = options.AccessTokenAlgorithm;

            Proxy = options.Proxy;
        }

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

        public Task GenerateClientAccessTokenAsync(string hubName = null, IEnumerable claims = null, TimeSpan? lifetime = null)
        {
            var audience = $"{_audienceBaseUrl}/{ClientPath}";

            return _accessKey.GenerateAccessTokenAsync(audience, claims, lifetime ?? _accessTokenLifetime, _algorithm);
        }

        public Task GenerateServerAccessTokenAsync(string hubName, string userId, TimeSpan? lifetime = null)
        {
            if (_accessKey is AadAccessKey key)
            {
                return key.GenerateAadTokenAsync();
            }

            IEnumerable claims = null;
            if (userId != null)
            {
                claims = new[]
                {
                    new Claim(ClaimTypes.NameIdentifier, userId)
                };
            }

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

            return _accessKey.GenerateAccessTokenAsync(audience, claims, lifetime ?? _accessTokenLifetime, _algorithm);
        }

        public string GetClientEndpoint(string hubName = null, string originalPath = null, string queryString = null)
        {
            var queryBuilder = new StringBuilder();

            if (!string.IsNullOrEmpty(queryString))
            {
                queryBuilder.Append(queryString);
            }

            if (!string.IsNullOrEmpty(originalPath))
            {
                if (queryBuilder.Length == 0)
                {
                    queryBuilder.Append("?");
                }
                else
                {
                    queryBuilder.Append("&");
                }

                queryBuilder
                    .Append(Constants.QueryParameter.OriginalPath)
                    .Append("=")
                    .Append(WebUtility.UrlEncode(originalPath));
            }

            return $"{_clientEndpoint}/{ClientPath}{queryBuilder}";
        }

        public string GetServerEndpoint(string hubName)
        {
            return $"{_serverEndpoint}/{ServerPath}/?hub={GetPrefixedHubName(_appName, hubName)}";
        }
    }
}