.Net пул соединений, вызывающий сбой входа в систему после изменения пароля SQL Server - PullRequest
0 голосов
/ 09 мая 2018

В наших конфигурационных файлах есть строки подключения, которые не содержат паролей.

Data Source=OurDataSource;Initial Catalog=OurCatalog;Integrated Security=False;UID=OurUser;Encrypt=True;TrustServerCertificate=False;

В нашем коде пароль загружается из сервиса и добавляется следующим образом:

var connectionString = ConfigurationManager.ConnectionStrings["ourCS"].ConnectionString;
var builder = new SqlConnectionStringBuilder(connectionString);
var credential = GetPassword(builder.UserID);
builder.Password = credential.Password;
var connectionString = builder.ConnectionString;
using (var db = new SqlConnection(connectionString))
{
    // Execute our query
}

Служба паролей меняет пароль каждые несколько месяцев, и недавно после смены пароля мы начали получать сообщения об ошибках входа в систему ниже и учетная запись заблокирована.

Login failed for user 'OurUser'. Reason: Password did not match that for the login provided.

Мое исследование указывает на проблемы с пулом соединений, у которого все еще есть открытые соединения, которые пытаются аутентифицироваться на базе данных и блокировать ее.

Вся наша связь с БД осуществляется с использованием приведенных выше операторов, которые должны закрывать соединение при вызове dispose. Однако после декомпиляции System.Data.SqlClient.SqlConnection кажется, что метод dispose не закрывает соединение.

public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        // using CloseHandle and UnmapViewOfFile - no exposure
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private void Dispose(bool disposing) {
            if (disposing) {
               // Nothing to do here
                ;
            }
            if (pMemMap != IntPtr.Zero) {
                NativeMethods.UnmapViewOfFile(pMemMap);
                pMemMap = IntPtr.Zero;
            }
            if (hMemMap != IntPtr.Zero) {
                NativeMethods.CloseHandle(hMemMap);
                hMemMap = IntPtr.Zero;
            }
            active = false;
        }

        ~SqlDebugContext() {
                Dispose(false);
        }

Кто-нибудь сталкивался с этой проблемой и ее решением? На данный момент он указывает на необходимость вызова соединения следующим образом, поскольку не похоже, что это делает Dispose.

using (var db = new SqlConnection(connectionString))
{
    // Execute our query
db.Close();
}

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

Приведенный выше код должен располагать SqlConnection и создавать новое соединение каждый раз, когда устанавливается соединение с базой данных. Строка подключения, используемая для первого подключения, нигде не кэшируется, и создается новая переменная SqlConnection с передаваемой ей переменной connectionString.

Судя по описанным вами симптомам, метод GetPassword не всегда возвращает правильную комбинацию имени пользователя и пароля.

Возможно, что это проблема синхронизации, подобная описанной @DanGuzman, когда функция GetPassword возвращает правильный пароль, но пароль изменяется до создания SqlConnection. Это объясняет периодически регистрируемые успехи и неудачи при входе в систему.

0 голосов
/ 10 мая 2018

Я действительно нашел ответ. У меня есть клиентский log4net appender, который получает строку подключения и добавляет пароль от службы.

Проблема была в том, что я получал пароль в конструкторе нашего пользовательского приложения, и конструктор вызывался только при запуске приложения: D. Поэтому мне пришлось перенести поиск пароля в переопределенном методе добавления.

<log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="RepositoryAppender" />
    </root>
    <appender name="RepositoryAppender" type="MyAppender, MyLibrary">
      <threshold value="ALL" />
      <bufferSize value="1" />
    </appender>
</log4net>
0 голосов
/ 09 мая 2018

Удаление пулированного соединения просто возвращает его в пул. Поскольку каждый пул соединений представляет собой отдельную строку соединения, новый пул будет создаваться при наличии строки соединения при использовании нового пароля.

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

Если смена пароля выполняется вручную (например, «ALTER LOGIN»), а затем служба настроена с новым паролем, решение может состоять в том, чтобы изменить пароль в коде службы, используя статический SqlConnection.ChangePassword метод. Я думаю, что это уменьшит проблему, если существует только один экземпляр службы.

...