I want to get a ConnectionString from an instance of SqlConnectionStringBuilder as a String.
This seems simple, and should be as easy as this:
String conString = builder.ConnectionString;
However the String that SqlConnectionStringBuilder gives up doesn't include the Password field/value. I'm guessing this is some sort of security feature, is there a way to force Password to be included in the String?
Looking at this further I'm thinking this may have something to do with ConnectionManager. What I am trying to do is modify the ConnectionString for a Package, changing the Initial Catalog.
Below is my code, the point that builder's connection string is passed back into connectionManager's the Password is lost...
public void DataTransfer(String sourceConnection, String destConnection, String pkgLocation)
{
Package pkg;
Application app;
DTSExecResult pkgResults;
try
{
app = new Application();
pkg = app.LoadPackage(pkgLocation, null);
foreach (ConnectionManager connectionManager in pkg.Connections)
{
SqlConnectionStringBuilder builder;
switch (connectionManager.Name)
{
case "SourceConnection":
builder = new SqlConnectionStringBuilder(sourceConnection) { PersistSecurityInfo = true };
builder.Remove("Initial Catalog");
builder.Add("Initial Catalog", "StagingArea");
connectionManager.ConnectionString = builder.ConnectionString.ToString();
connectionManager.ConnectionString += ";Provider=SQLNCLI;Auto Translate=false;";
Debug.WriteLine(connectionManager.ConnectionString.ToString());
break;
case "DestinationConnection":
builder = new SqlConnectionStringBuilder(sourceConnection) { PersistSecurityInfo = true };
builder.Remove("Initial Catalog");
builder.Add("Initial Catalog", "StagingArea");
connectionManager.ConnectionString = builder.ConnectionString.ToString();
connectionManager.ConnectionString += ";Provider=SQLNCLI;Auto Translate=false;";
Debug.WriteLine(connectionManager.ConnectionString.ToString());
break;
}
}
pkgResults = pkg.Execute();
}
catch (Exception e)
{
throw;
}
Console.WriteLine(pkgResults.ToString());
}
Set PersistSecurityInfo to True before setting other properties in the SqlConnectionStringBuilder : D
I need to rename this a little maybe, as the question is different now, but here is my solution:
The first part of this question was answered correctly by #madd0. The ConnectionString does contain the Password field.
The second part was solved with formatting code is below:
public void DataTransfer(String sourceConnection, String destConnection, String pkgLocation)
{
Package pkg;
Application app;
DTSExecResult pkgResults;
try
{
app = new Application();
pkg = app.LoadPackage(pkgLocation, null);
foreach (ConnectionManager connectionManager in pkg.Connections)
{
SqlConnectionStringBuilder builder;
switch (connectionManager.Name)
{
case "SourceConnection":
builder = new SqlConnectionStringBuilder(sourceConnection) { PersistSecurityInfo = true };
builder.Remove("Initial Catalog");
builder.Add("Initial Catalog", "StagingArea");
var sourceCon = builder.ConnectionString + ";Provider=SQLNCLI;Auto Translate=false;";
//Added spaces to retain password!!!
sourceCon = sourceCon.Replace(";", "; ");
connectionManager.ConnectionString = sourceCon;
Debug.WriteLine(connectionManager.ConnectionString.ToString());
break;
case "DestinationConnection":
builder = new SqlConnectionStringBuilder(sourceConnection) { PersistSecurityInfo = true };
builder.Remove("Initial Catalog");
builder.Add("Initial Catalog", "StagingArea");
var destCon = builder.ConnectionString + ";Provider=SQLNCLI;Auto Translate=false;";
//Added spaces to retain password!!!
destCon = destCon.Replace(";", "; ");
connectionManager.ConnectionString = destCon;
Debug.WriteLine(connectionManager.ConnectionString.ToString());
break;
}
}
pkgResults = pkg.Execute();
}
catch (Exception e)
{
throw;
}
Console.WriteLine(pkgResults.ToString());
}
I played about with the ConnectionStrings and noticed after a while that the original String had spaces between each property.
Running 2 tests I found that without spaces the Password was lost...
connectionManager.ConnectionString = destCon;
Test 1: No Spaces:
When destCon = Data Source=xxx.xxx.xxx.xxx;Initial Catalog=StagingArea;User ID=*****;Password=*****;Provider=SQLNCLI;Auto Translate=false;
Then connectionManager.ConnectionString = Data Source=xxx.xxx.xxx.xxx;User ID=*****;Initial Catalog=StagingArea;Provider=SQLNCLI;Auto Translate=false;
Test 2: Spaces:
When destCon = Data Source=xxx.xxx.xxx.xxx; Initial Catalog=StagingArea; User ID=*****; Password=*****; Provider=SQLNCLI; Auto Translate=false;
Then connectionManager.ConnectionString = Data Source=xxx.xxx.xxx.xxx; Initial Catalog=StagingArea; User ID=*****; Password=*****; Provider=SQLNCLI; Auto Translate=false;
No idea why this happens, but without spaces the ordering is adjusted and the Password field is lost.
Related
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.
I'm trying to read in a SQL script in a C# console app. I'm having issues as the file route that it's generating always starts in the bin folder of the project.
public static void ApiResources(IConfiguration config, string testUrlExtension)
{
try
{
var azureDatabaseUrl = String.Format(config["SqlDatabase:BaseUrl"], $"test{testUrlExtension}");
SqlConnectionStringBuilder connBuilder = new SqlConnectionStringBuilder();
connBuilder.DataSource = azureDatabaseUrl;
connBuilder.UserID = config["SqlDatabase:ZupaKeyReleaseUserName"];
connBuilder.Password = config["SqlDatabase:ZupaKeyReleasePassword"];
connBuilder.InitialCatalog = "zupaauthentication";
using (SqlConnection connection = new SqlConnection(connBuilder.ConnectionString))
{
using (SqlCommand command = connection.CreateCommand())
{
connection.Open();
var GetLocalPathToProject = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Split("Zupa.ReleaseDeploymentAutoConfigure")[0];
var routeToApiResourseSqlScript = $"{GetLocalPathToProject}Zupa.ReleaseDeploymentAutoConfigure\\Zupa.ReleaseDeploymentAutoConfigure\\Sql\\Scripts\\";
var apiResourcesFileName = "AddApiResorces.sql";
var fullPathToSqlScript = $"{routeToApiResourseSqlScript}{apiResourcesFileName}";
command.CommandText = File.ReadAllText(fullPathToSqlScript);
command.ExecuteNonQuery();
connection.Close();
}
}
}
catch (SqlException e)
{
Console.WriteLine(e.InnerException);
}
}
The error I'm receiving is as follows:
Something went wrong try configuring the release again.
System.IO.IOException: The filename, directory name, or volume label syntax is incorrect. :
'C:\Zupa_Source_Code\Zupa.ReleaseDeploymentAutoConfigure\Zupa.ReleaseDeploymentAutoConfigure\bin\Debug\netcoreapp3.1\file:\C:\Zupa_Source_Code\Zupa.ReleaseDeploymentAutoConfigure\Zupa.ReleaseDeploymentAutoConfigure\Sql\Scripts\AddApiResorces.sql'
The correct path is being added to the end of the bin directory which is
file:\C:\Zupa_Source_Code\Zupa.ReleaseDeploymentAutoConfigure\Zupa.ReleaseDeploymentAutoConfigure\Sql\Scripts\AddApiResorces.sql
Change "CodeBase" in this line
var GetLocalPathToProject = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Split("Zupa.ReleaseDeploymentAutoConfigure")[0];
to be Location:
var GetLocalPathToProject = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).Split("Zupa.ReleaseDeploymentAutoConfigure")[0];
i wish detect lines changed of the defferent versions of a file in perforce my problem is that when i tried to get the different versions of the file i get always the last version how can i proceed to get the different versions
String password = "*****";
String ws_client = "****";
Repository rep;
P4Server ps = new P4Server(conStr, user, password, ws_client);
Server server = new Server(new ServerAddress(conStr));
rep = new Repository(server);
rep.Connection.UserName = user;
Options options = new Options();
Console.WriteLine(options.ToString());
Client c = new Client();
options["Password"] = password;
rep.Connection.Client = new Client();
rep.Connection.Connect(options);
rep.Connection.Login(password, options);
Console.WriteLine(rep.ToString());
string text1="";
string text2="";
P4Command cmd = new P4Command(ps);
string[]cmdargs= new string[1];
cmdargs[0] = "";
Console.WriteLine(cmd.ToString());
Console.WriteLine(ps.ToString());
Console.WriteLine(server.ToString());
// *********************************************************************
#region mrigla2 using filehistory class
FileSpec filespecs = new FileSpec(FileSpec.DepotSpec("//obms/Dot-NET/Main/FixDepthSource/SLC_FDS/clsFixEventsSource.vb").DepotPath, Revision.Head);
Options opt = new Options();
opt.Add("-m", "");
IList<FileHistory> filehistories = new List<FileHistory>();
filehistories = rep.GetFileHistory(new Options(), filespecs);
if (filehistories != null)
{
foreach (FileHistory fh in filehistories)
{
string p = fh.DepotPath.Path;
string dpath = "//obms/Dot-NET/Main/FixDepthSource/SLC_FDS/clsFixEventsSource.vb";
if (p==dpath)
{
Console.WriteLine("Client name:" + fh.ClientName);
Console.WriteLine("Description:" + fh.Description);
Console.WriteLine("username:" + fh.UserName);
Console.WriteLine("Date:" + fh.Date);
Console.WriteLine("changelist:" + fh.ChangelistId);
directoriesfile.Filedirectory fsd = Program.getpaths(p, ps);
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine("******************revision:" + fh.Revision+"**********************");
if (fh.Revision == 6)
{ text1 = System.IO.File.ReadAllText(fsd.localPath); }
if (fh.Revision == 5)
{text2 = System.IO.File.ReadAllText(fsd.localPath); }
Console.BackgroundColor = ConsoleColor.Black;
affichcontentFile(fsd.depotPath, ps, fsd.localPath);
Console.WriteLine("Action:" + fh.Action);
}
}
}
To get the history of the contents of a file, use 'p4 annotate'.
To get the history of a file (but not its contents), use 'p4 filelog'.
To get the differences between two specified versions of a file, use 'p4 diff2'.
Putting together 'p4 filelog' (to figure out which versions correspond to which changes) and 'p4 diff2' (to compute the differences between two versions) will get you much useful information.
Or do what I do: don't do any of these things, and install P4V, and use 'Time Lapse View'. It's a beautiful visual tool that makes exploring a file's history simple.
FileSpec fso = new FileSpec(FileSpec.DepotSpec(fsd.depotPath).DepotPath, Revision.Head);
IList<FileSpec> fsos = new List<FileSpec>();
fsos.Add(fso);
Options opts = new Options();
opts.Add("-a", "");
IList<FileAnnotation> fas = rep.GetFileAnnotations(fsos, opts);
foreach (FileAnnotation fa in fas)
{
Console.BackgroundColor = ConsoleColor.Yellow;
lines5+= fa.Line;
Console.BackgroundColor = ConsoleColor.Black;
}
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.
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]);