Get user and password from ConnectionStringSettings - c#

How can I get the user and password from such a connectionString in the app.config with a .NET function?
Of course I could read that string and get the value after the ID= and Password=.
<connectionStrings>
<add name="MyConString" connectionString="Data Source=(local);Initial Catalog=MyDatabase;Persist Security Info=True;User ID=MyUsername Password=MyPassword;Connect providerName="System.Data.SqlClient"/>
</connectionStrings>

use the ConnectionBuilderClass
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder("Your connection string");
string password = builder.Password;
together with the
string connString = ConfigurationManager.ConnectionStrings["MyConString"].ConnectionString;
to achieve this.

If you need a more generic approach for parsing the connection string (one that doesn't deal with the specifics of one database provider) you can also use
System.Data.Common.DbConnectionStringBuilder
which is a base class for other classes like SqlConnectionStringBuilder etc.
You can create an instance of DbConnectionStringBuilder and in my case I needed to have one configurable connection string that I could get information from -- regardless of the database provider type. A few options if you need this flexibility -- you could create the appropriate ConnectionStringBuilder for your provider as others have suggested -- this would likely be required for most cases where provider-specific properties are needed.
Or if you want to read just a couple generic properties, you could use DbConnectionStringBuilder if you just need the user id and password for example.
This sample should work for ANY connection string that includes user id and password.
DbConnectionStringBuilder db = new DbConnectionStringBuilder();
db.ConnectionString = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
var username = db["User Id"].ToString();
var password = db["Password"].ToString();

SqlConnectionStringBuilder con = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString);
string myUser = con.UserID;
string myPass = con.Password;

var builder = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["MyConString"].ConnectionString)
var user = builder.UserID;
var password = builder.Password;

You can get the connection string from the following
SqlConnectionStringBuilder yourconn = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString);
string password = yourconn.Password;
You can then get the substring you are looking for .

Just to add a bit to Tomas Walek's answer.
This approach would work only if "User ID" in the connection string is capitalized correctly. Oracle provider accepted "User Id" OK, but SqlConnectionStringBuilder did not work.
public static class DbConnectionFactory
{
public static ConnectionStringSettings AppConnectionSettings = ConfigurationManager.ConnectionStrings["{A connection string name}"];
public static SqlConnectionStringBuilder AppConnBuilder = new SqlConnectionStringBuilder(AppConnectionSettings.ConnectionString);
public static string DbUserID
{
get
{
return AppConnBuilder.UserID;
}
set { }
}
}

add a reference to System.Configuration and then use:
using System.Configuration;
string MyDBConnection = ConfigurationManager.ConnectionStrings["MyDBConnection"].ConnectionString;
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(MyDBConnection);
string UserID = builder.UserID;
string Password = builder.Password;
string ServerName = builder.DataSource;
string DatabaseName = builder.InitialCatalog;

public static string GetConnectionSettings(string searchSetting )
{
var con = ConfigurationManager.ConnectionStrings["yourConnectionHere"]‌​.ConnectionString;
String[] myString = con.Split(';');
Dictionary<string, string> dict = new Dictionary<string, string>();
for (int i = 0; i < myString.Count(); i++)
{
String[] con3 = myString[i].Split('='); dict.Add(con3[0], con3[1]);
}
return dict[searchSetting];
}
for searchSetting you can use what you want "User Is" or password.

another way is to use regular expression (which I did), with a more forgiving pattern, to handle different ways a user id could be provided on the connection string:
public static string GetUserIdFromConnectionString(string connectionString)
{
return new Regex("USER\\s+ID\\=\\s*?(?<UserId>\\w+)",
RegexOptions.IgnoreCase)
.Match(connectionString)
.Groups["UserId"]
?.Value;
}

Extension method to get "User Id" from connectionString in DbConnection:
using System;
using System.Data.Common;
using System.Text.RegularExpressions;
namespace DemoProject.Helpers
{
public static class DbConnectionExtensions
{
public static string GetUserId(this DbConnection connection)
{
const string userIdPattern1 = "User[ ]*Id";
const string userIdPattern2 = "UID";
var connectionString = connection.ConnectionString;
foreach (var item in connectionString.Split(';'))
{
var index = item.IndexOf('=');
if (index == -1)
continue;
var property = item.Substring(0, index).Trim();
if (Regex.IsMatch(property, userIdPattern1, RegexOptions.IgnoreCase) ||
Regex.IsMatch(property, userIdPattern2, RegexOptions.IgnoreCase))
{
var userId = item.Substring(index + 1).Trim();
return userId;
}
}
throw new Exception("Couldn't find \"User Id\" in connectionString");
}
}
}
Example #1 of using:
using DemoProject.Helpers;
using Oracle.ManagedDataAccess.Client;
namespace DemoProject
{
class Program
{
static void Main(string[] args)
{
const string connectionString = "Data Source=(DESCRIPTION=" +
"(ADDRESS=(PROTOCOL=TCP)(HOST=oracle19c-vm)(PORT=1521))" +
"(CONNECT_DATA=(SERVICE_NAME=ORCLPDB1)));" +
"User Id=JOHN;" +
"Password=pwd123";
var connection = new OracleConnection(connectionString);
var userId = connection.GetUserId();
}
}
}
Example #2 of using:
using DemoProject.Helpers;
using Npgsql;
namespace DemoProject
{
class Program
{
static void Main(string[] args)
{
const string connectionString = "Server=postgre-vm;" +
"User Id=JOHN;" +
"Password=pwd123;" +
"Database=DEV1";
var connection = new NpgsqlConnection(connectionString);
var userId = connection.GetUserId();
}
}
}
Also you can add the 2nd extension method to get the password

var connString = ConfigurationManager.ConnectionStrings["MyConString"].ConnectionString;
var tokens = connString.Split(';');
string userId;
string password;
for(var i = 0; i < tokens.Length; i++) {
var token = tokens[i];
if(token.StartsWith("User ID"))
userId = token.Substring(token.IndexOf("=") + 1);
if(token.StartsWith("Password"))
password = token.Substring(token.IndexOf("=") + 1);
}

string connectionString = ConfigurationManager.ConnectionStrings["MyConString"].ConnectionString;
var tokens = connectionString.Split(';').Select(n => n.Split('=');
string userId = tokens.First(n => n[0].Equals("User ID").Select(n => n[1]);
string password = tokens.First(n => n[0].Equals("Password").Select(n => n[1]);

Related

How to pass ConnectionString parameters with variables?

I have a ConnectionString and I want to pass it values (DataSource, Database, User ID, Password) with values from a .txt file and I need to read them, then pass them to the connectionString but I'm very confused how should I do this.
In my program I have a Helper Class to return the connectionString
public static class Helper
{
public static string ConnectionString(string name)
{
return ConfigurationManager.ConnectionStrings[name].ConnectionString;
}
}
This is how I call the connectionString so I can access the database data
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(Helper.ConnectionString("Hotel")))
{
connection.Execute($"INSERT INTO dbo.Registos_Cancelados(Nome, Telemovel, Data) VALUES(#Nome, #Telemovel, #Data)", new { Nome = nome, Telemovel = telemovel, Data = data });
}
I have a text file with the values
"DataSourceName"
"DataBaseName"
"User IDName"
"PasswordName"
And I want them in the connection string.
<connectionStrings>
<add name="Hotel" connectionString="DataSource="DataSourceName";Database="DatabaseName";User Id="UserIdName";Password="PasswordName""
providerName="System.Data.SqlClient" />
</connectionStrings>
You're using SqlClient, so: your best bet here is SqlConnectionStringBuilder:
var cb = new SqlConnectionStringBuilder(theBaseString);
cb.DataSource = dataSourceName;
cb.InitialCatalog = dataBaseName;
cb.UserID = userId;
cb.Password = password;
var connectionString = cb.ConnectionString;
If you don't have a template string (theBaseString), just use new SqlConnectionStringBuilder() instead.
The advantage of using SqlConnectionStringBuilder here is that it knows all about the escaping rules for non-trivial values, reserved characters, etc.
You can format your connection string like below to pass the necessary values like dbname later.
<connectionStrings>
<add name="Hotel" connectionString="DataSource={0};Database={1};User Id={2};Password={3}"
providerName="System.Data.SqlClient" />
</connectionStrings>
After that in your Helper class, return the formatted connection string with the values that you read from txt file.
public static string ConnectionString(string name)
{
var dataSourceName = "...";
var dbName = "...";
var userId = "...";
var password = "...";
var connectionString = ConfigurationManager.ConnectionStrings[name].ConnectionString;
return string.Format(connectionString, dataSourceName, dbName, userId, password);
}

External Control of System or Configuration Setting (CWE ID 15)

We had security threat issue when scanning applications in Veracode. Got "External Control of System or Configuration Setting (CWE ID 15)".
Scan reported for using (var connection = new SqlConnection(connectionString))
we are checking whether "SQLConnectionExists" by passing connection string,
string sqlConnString = SqlHelper.GetSQLConnectionString(input.ServerName, dbName, isWinAuth, input.UserName, input.Password);
if (!DBUtil.CheckSQLConnectionExists(sqlConnString))
{
_ValidationMessage += "Database Unreachable \n";
isValid = false;
}
public static bool CheckSQLConnectionExists(string connectionString)
{
bool isExist = false;
try
{
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
connection.Close();
isExist = true;
}
}
catch (Exception ex)
{
Logger.Instance.Log(LogLevel.EXCEPTION, "CheckSQLConnectionExists Exception : " + ex.Message);
}
return isExist;
}
public static string GetSQLConnectionString(string servername, string db, bool isWinAuth, string username, string password)
{
System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder();
builder["Data Source"] = servername;
builder["Initial Catalog"] = db;
if (isWinAuth)
{
builder["Integrated Security"] = "SSPI";
builder["Trusted_Connection"] = "Yes";
}
else
{
builder["Persist Security Info"] = false;
builder["User ID"] = username;
builder["Password"] = password;
}
return builder.ConnectionString;
}
In this line using (var connection = new SqlConnection(connectionString)) we got error in security scan. Could you please some one provide suggestions to resolve this Veracode error.
Veracode detects input.ServerName, input.UserName and input.Password to be user-controlled which is a risk.
Ensure validation is implemented - if possible, compare against a whitelist or known predefined server names. Also, check if the entered (injected) Min Pool Size is larger than expected. Use framework classes such as the one that you used SqlConnectionStringBuilder
Propose this check as a mitigation afterwards.

Reading from .dbf with dBASE IV

When trying to read a .dbf file with the Control Panel -> Region -> Administrative -> Region Settings = "English (UK)" system settings, Russian characters are read in an unknown encoding. But if this option is switched Region Settings = "Russian (Russia)", then the characters are read correctly. The options I tried are:
Modified connection options with a private constant string SOURCE_CONNECTION_STRING = "Provider = Microsoft.Jet.OLEDB.4.0; Advanced properties = dBASE; Data source = {0};"; to a private constant string SOURCE_CONNECTION_STRING = "Provider = Microsoft.Jet.OLEDB.4.0; Advanced properties = 'dBASE IV; character set = 1251; HDR = Yes; FMT = delimited"; Data Source = {0}; ";, but it did not help.
Use solution method:
private string Decode(string input)
{
Encoding fromEncoding = Encoding.GetEncoding("cp850");
Encoding toEncoding = Encoding.GetEncoding(866);
string returnValue = toEncoding.GetString(fromEncoding.GetBytes(input));
return returnValue;
}
Method 2, using explicit decoding, helped me. I would like to know if I can somehow set the encoding I expect explicitly in the settings of the "OleDbConnection" class or in some other way?
Here is an example of a received line from a .dbf file - ÇóÔ«¡«¼¡Ù®
«¬ÓÒú.
DBF File
Class Example:
class DbfReader
{
private const string COUNT_ATTRIBUTE_NAME = "count";
private const string ROW_ELEMENT_NAME = "r";
private const string MappedTableName = "SOCRBASE";
private const string SOURCE_CONNECTION_STRING = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Extended Properties='dBASE IV;characterset=1251;HDR=Yes;FMT=Delimited'; " +
"Data Source={0};";
private static readonly string TableName = "socrbase";
private static readonly string GetCountQuery = $"select count(1) from [{TableName}]";
private static readonly List<string> Columns = new List<string> { "level", "scname", "socrname", "kod_t_st" };
private static string SelectQuery => $"select [level], [scname], [socrname], [kod_t_st] from [{TableName}]";
public void Convert(string dataSourceFolder)
{
using (var srcConn = new OleDbConnection(string.Format(SOURCE_CONNECTION_STRING, dataSourceFolder)))
{
srcConn.Open();
Exception exception = null;
try
{
var xmlFilePath = GetTableFileName(dataSourceFolder, TableName);
Directory.CreateDirectory(Path.GetDirectoryName(xmlFilePath));
var xml = new XmlTextWriter(xmlFilePath, Encoding.UTF8);
xml.WriteStartDocument();
var reader = new OleDbCommand(SelectQuery, srcConn).ExecuteReader();
xml.WriteStartElement(MappedTableName);
xml.WriteAttributeString(COUNT_ATTRIBUTE_NAME, ((int)new OleDbCommand(GetCountQuery, srcConn).ExecuteScalar()).ToString());
while (reader.Read())
{
xml.WriteStartElement(ROW_ELEMENT_NAME);
foreach (var column in Columns)
{
xml.WriteStartElement(column);
var value = reader[column].ToString();
var decodeValue = Decode(value);
xml.WriteCData(value);
xml.WriteEndElement();
}
xml.WriteEndElement();
}
xml.WriteEndElement();
xml.WriteEndDocument();
xml.Close();
Console.WriteLine("XML has been created");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
private string Decode(string input)
{
Encoding fromEncoding = Encoding.GetEncoding("cp850");
Encoding toEncoding = Encoding.GetEncoding(866);
string returnValue = toEncoding.GetString(fromEncoding.GetBytes(input));
return returnValue;
}
private string GetTableFileName(string dataSourceFolder, string tableName)
{
return Path.Combine(dataSourceFolder, "xml", $"{tableName}.xml");
}
}

The type initializer for 'NameSpace.Settings' threw an exception

I've a very simple class that I've added method GetConnectionString(). After adding it whenever any value is accesses from the Settings class it throws an exception The type initializer for 'NameSpace.Settings' threw an exception. As soon as I remove GetConnectionString() program works fine.
using System.Data.EntityClient;
using System.Data.SqlClient;
namespace CRM {
static class Settings {
public static bool userAuthenticated = false;
public static string userGroup = "";
public static Klienci currentlySelectedClient;
public static string sqlDataConnectionDetailsCRM = GetConnectionString();
public static string GetConnectionString() {
string connection = "";
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
sqlBuilder.InitialCatalog = dbInitialCatalog;
sqlBuilder.DataSource = dbServer;
sqlBuilder.IntegratedSecurity = false;
sqlBuilder.UserID = dbUserName;
sqlBuilder.Password = dbPasswWord;
sqlBuilder.MultipleActiveResultSets = true;
EntityConnectionStringBuilder entity = new EntityConnectionStringBuilder();
entity.Metadata = #"res://*/Data.System.csdl|res://*/Data.System.ssdl|res://*/Data.System.msl";
entity.Provider = "System.Data.SqlClient";
entity.ProviderConnectionString = sqlBuilder.ToString();
connection = entity.ToString();
return connection;
}
}
}
If I comment out sqlBuilder and entity. It works fine..
public static string GetConnectionString() {
string connection = "";
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
//sqlBuilder.InitialCatalog = dbInitialCatalog;
//sqlBuilder.DataSource = dbServer;
//sqlBuilder.IntegratedSecurity = false;
//sqlBuilder.UserID = dbUserName;
//sqlBuilder.Password = dbPasswWord;
//sqlBuilder.MultipleActiveResultSets = true;
EntityConnectionStringBuilder entity = new EntityConnectionStringBuilder();
//entity.Metadata = #"res://*/Data.System.csdl|res://*/Data.System.ssdl|res://*/Data.System.msl";
//entity.Provider = "System.Data.SqlClient";
//entity.ProviderConnectionString = sqlBuilder.ToString();
connection = entity.ToString();
return connection;
}
What's going on? It seems fine to me..
Edit:
InnerException:
exception = "System.ArgumentNullException: Value cannot be
null.\r\nParameter name: Initial Catalog\r\n at
System.Data.SqlClient.SqlConnectionStringBuilder.set_InitialCatalog(String
value)\r\n at CRM.Settings.GetConnectionString() in
C:\Projects\Project.C.S...
While public static string dbInitialCatalog = "BazaCRM"; is set in Settings class.
The order of the fields being initialized is not guaranteed. What's going on here is that the sqlDataConnectionDetailsCRM is being initialized before the dbInitialCatalog field.
If you change those other static fields to be const it should fix it.
Or a better way might be to just removed your public static field, and retrieve the connection string from the method, or you might also like to investigate the Lazy<T> class, and use that to build the connection string the first time it's needed.
According to your error the value of dbInitialCatalog seems to be null, so the connection string builder is throwing an error. Because this is inside the static constructor of a class, the type itself can't be loaded and the whole thing fails.
Have you tried manually supplying the connection string yourself?

Get Connection String Without Password Value in C#

I try create method for get the connection string value but without value for password, or show password like * character. I need used it in logging.
I use ConnectionStringBuilder for Oracle, SqlServer.
Anyway, another way -better- to implement it ? Maybe more generic . And what it happens it ProviderName is empty...
public static string GetConnectionStringWithouPassword(this ConnectionStringSettings cs)
{
if (cs == null || string.IsNullOrEmpty(cs.ConnectionString)) return null;
if (cs.ProviderName.ToLower().Equals("Oracle.DataAccess.Client".ToLower()))
{
var builderOra = new Oracle.DataAccess.Client.OracleConnectionStringBuilder(cs.ConnectionString);
return "";
}
if (cs.ProviderName.ToLower().Equals("System.Data.SqlClient".ToLower()))
{
var builderSql = new SqlConnectionStringBuilder(cs.ConnectionString);
return "";
}
return null;
}
//
public static string ObtenerCadenasConexion()
{
var sb = new StringBuilder();
ConnectionStringSettingsCollection settings = ConfigurationManager.ConnectionStrings;
if (settings != null)
{
foreach (ConnectionStringSettings cs in settings)
{
sb.AppendLine("Name: " + cs.Name);
sb.AppendLine("ProviderName: " + cs.ProviderName);
sb.AppendLine("ConnectionString: " + cs.GetConnectionStringWithouPassword() + Environment.NewLine);
}
}
return sb.ToString();
}
check this one: DbConnectionStringBuilder Class
you can use the Remove method, no magic parsing required:
for example, from that MSDN page:
static void Main()
{
DbConnectionStringBuilder builder = new
DbConnectionStringBuilder();
builder.ConnectionString =
#"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\Demo.mdb;" +
"Jet OLEDB:System Database=system.mdw;";
// Try to remove an existing item.
TryRemove(builder, "Provider");
// Try to remove a nonexistent item.
TryRemove(builder, "User ID");
// Try to remove an existing item,
// demonstrating that the search isn't
// case sensitive.
TryRemove(builder, "DATA SOURCE");
Console.ReadLine();
}
static void TryRemove(DbConnectionStringBuilder builder, string itemToRemove)
{
if (builder.Remove(itemToRemove))
{
Console.WriteLine(#"Removed '{0}'", itemToRemove);
}
else
{
Console.WriteLine(#"Unable to remove '{0}'", itemToRemove);
}
Console.WriteLine(builder.ConnectionString);
}
Check the Connection.PersistSecurityInfo property, you may drop this information as soon as the connection is created automatically.

Categories