Как решить эту проблему круговой зависимости? - PullRequest
0 голосов
/ 19 сентября 2018

У меня есть два интерфейса для компонентов, каждый из которых требует функциональности от другого.Тот, который генерирует токены Oauth, и другой, который получает секреты от секретного провайдера (хранилище ключей Azure).

Проблема заключается в том, что провайдеру токенов необходимо получить секретное значение (пароль) для выполнения своего HTTP-вызова.и класс Secret Provider должен получить токен для вызова Azure.Проблема курицы и яйца.

Из других вопросов, которые я прочитал, предлагается создать третий класс / интерфейс, от которого зависят исходные 2, но я не уверен, как это будет работать здесь.

Любая помощь и предложения будут оценены.Код для всех соответствующих классов / интерфейсов показан ниже.

public interface ISecretProvider
{
    string GetSecret(string secretName);
}

public interface ITokenProvider
{
    string GetKeyVaultToken();
}

public class OktaTokenProvider : ITokenProvider
{
    ISecretProvider _secretProvider;

    public string GetKeyVaultToken()
    {
        var tokenUrl = ConfigurationManager.AppSettings["KeyVault.Token.Url"];
        var clientId = ConfigurationManager.AppSettings["KeyVault.Token.ClientId"];
        var clientSecret = _secretProvider.GetSecret("ClientSecret");
        var scope = ConfigurationManager.AppSettings["KeyVault.Scope"];

        var token = GetToken(tokenUrl, clientId, clientSecret, scope);

        return token;
    }

    private string GetToken(string tokenUrl, string clientId, string clientSecret, string scope)
    {
        var clientCredentials = $"Basic {Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"))}";

        string responseFromServer = string.Empty;
        bool success = false;
        int retryCount = 0;

        while (!success)
        {
            try
            {
                var tokenWebRequest = (HttpWebRequest)WebRequest.Create(tokenUrl);

                tokenWebRequest.Method = "POST";
                tokenWebRequest.Headers.Add($"Authorization:{clientCredentials}");
                tokenWebRequest.Headers.Add("Cache-control:no-cache");
                tokenWebRequest.ContentType = "application/x-www-form-urlencoded";

                using (var streamWriter = new StreamWriter(tokenWebRequest.GetRequestStream()))
                {
                    streamWriter.Write($"grant_type=client_credentials&scope={scope}");
                    streamWriter.Flush();
                    streamWriter.Close();
                }

                using (WebResponse response = tokenWebRequest.GetResponse())
                {
                    using (var dataStream = response.GetResponseStream())
                    {
                        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                        {
                            responseFromServer = reader.ReadToEnd();
                            reader.Close();
                        }
                        dataStream.Close();
                    }

                    response.Close();
                    response.Dispose();
                }

                success = true;
            }
            catch (Exception)
            {
                if (retryCount > 3)
                {
                    throw;
                }
                else
                {
                    retryCount++;
                }
            }
        }

        JToken token = JObject.Parse(responseFromServer);

        var accessToken = $"Bearer {token.SelectToken("access_token").ToString()}";

        return accessToken;
    }

}


public class KeyVaultSecretProvider : ISecretProvider
{
    ITokenProvider _tokenProvider;

    public KeyVaultSecretProvider(ITokenProvider tokenProvider)
    {
        _tokenProvider = tokenProvider;
    }

    public string GetSecret(string secretName)
    {
        var KeyVaultUrl = ConfigurationManager.AppSettings[Constants.KEYVAULT_ENDPOINT];
        var subscriptionKey = ConfigurationManager.AppSettings[Constants.KEYVAULT_SUBSCRIPTION_KEY];

        string responseFromServer = "";

        var requestedSecretUrl = $"{KeyVaultUrl}{secretName}";

        var secretWebRequest = (HttpWebRequest)WebRequest.Create(requestedSecretUrl);

        var accessToken = _tokenProvider.GetKeyVaultToken();

        secretWebRequest.Method = "GET";

        secretWebRequest.Headers.Add("authorization:" + accessToken);
        secretWebRequest.Headers.Add("cache-control:no-cache");
        secretWebRequest.Headers.Add("Ocp-Apim-Subscription-Key:" + subscriptionKey);

        using (WebResponse response = secretWebRequest.GetResponse())
        {
            using (var dataStream = response.GetResponseStream())
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    responseFromServer = reader.ReadToEnd();
                    reader.Close();
                }

                dataStream.Close();
            }

            response.Close();
            response.Dispose();
        }


        JToken secret = JObject.Parse(responseFromServer);

        var secretValue = secret.SelectToken("Secret").ToString();

        return secretValue;
    }
}

1 Ответ

0 голосов
/ 20 сентября 2018

Один класс должен реализовывать оба интерфейса.Обе обязанности взаимосвязаны, поэтому соберите их в один класс.В этом нет ничего плохого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...