User authentication with DAAB

Topics: Data Access Application Block
Dec 22, 2008 at 12:25 PM
Edited Dec 22, 2008 at 12:27 PM

Hi everyone.

I'm using Enteprise library as a foundation for my business application for over 2yrs. All that time I worked with Sql server 2005 where I used integrated security to authenticate users on my database. Now, I need to change database to IBM Informix 11 which doesn't have integrated security.

So, I need to have a login screen to ask for username & password. Username & password should then be used to connect on my Informix database. I can't just provide userID & password in app.config file since I'll have hundreds of users and I need to differentiate themat database level for security and auditing purposes.

I have no idea atm how to implement user login in my app which is built over DAAB. Any suggestion will be appreciated.

Thanks.

Dec 28, 2008 at 8:45 AM
You can either create a DbConnection and modify its ConnectionString property accordingly everytime you would execute a DbCommand or modify the EntLib source code which would accept a connection string when creating a Database object.


Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 29, 2008 at 7:35 AM

Well, the first suggestion isn't doable since I already have thousands of calls to database in my solution. Second approach is doable but I'm reluctant in changing EntLib, it's more difficult upgrading that way. I'm actually puzzled that this scenario isn't better covered with DAAB. I tought it's common scenario.

Anyway how about this solution: I can create my own provider like this and use it instead of an original provider:

  [DatabaseAssembler(typeof(InformixAssembler))]
public class InformixDatabase : Database
{
public InformixDatabase(string connectionString)
: base(AddUserNamePass(connectionString), IfxFactory.Instance)
{
}

protected override void DeriveParameters(DbCommand discoveryCommand)
{
IfxCommandBuilder.DeriveParameters((IfxCommand)discoveryCommand);
}

private static string AddUserNamePass(string connectionString)
{
return string.Format(connectionString, Session.User, Session.Pass);
}
}

Dec 29, 2008 at 10:53 AM
That would be a better approach.


Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com
Feb 6, 2009 at 7:49 AM

Hello SrdjanNjiric,

I was pointed to this thread, as i want to achieve the similar result. Only difference being i want to use SQL Server.

I went through your code and would like to implement the similar way. However, i am at loss as to where did IfxFactory.Instance and Session would come from? Is this something Informix specific.

Any idea, what would i use if i am sticking to default SQL Server provider. Any pointers are hugely appreciated.

Regards,
Nitin Sontakke.

Feb 6, 2009 at 8:07 AM

Hi.

Actually, Factory class somes from ADO.NET so every data provider should have one implemented. For SQL server it's this one:

System.Data.SqlClient.SqlClientFactory.Instance

Session class is my static class. It has User and Pass string properties that need to be filled before first call to database. I'm using dialog form to ask user for those. 

I hope it helps.

Feb 6, 2009 at 8:53 AM

Yes. It did.

 

With a bit of tricking (and an unfortunate “hard-cording”) I did manage to connect to SQL Server using SQL Authentication.

 

You are right. It’s such a common scenario. I hope this is taken care in a bit more graceful manner in next version of EL.

 

Thanks for all your help. I appreciate.

 

Regards,

Nitin Sontakke.

Feb 16, 2009 at 4:14 AM

Hello SrdjanNjiric

 

Looks like I need your help again. There are two things I am still struggling to reconcile with. Your input will be helpful.

 

1/ In your implementation, where the connection string is coming from? May be you have kept it in app.config. However, I am struggling to read the DAAB related sections from app.config programmatically in my implementation of EL code. Basically, I aim to keep something like “uid={0};pwd={1}” in app.config and place other info at run time. The reason I want to keep it in EL generated config itself is then I can encrypt it.

 

2/ In your code, addUserNamePass is private static, how do you manage to access your custom Session object within that is beyond me. Please help. I aim to replace it with my own currentUser object which will hold userId and password. (It's identical to your Session object!)

 

Needless to mention, any input from AvanadeSupport is welcome too.

 

Regards,

Nitin Sontakke.

Feb 16, 2009 at 8:07 AM

Hello,

 

Looks like I manage to figure it out. Here are the code snippets for others to refer as well.

 

1/ First created a class which is derived from Database class:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.Practices.EnterpriseLibrary.Data;

using Microsoft.Practices.EnterpriseLibrary.Common;

using System.Data.Common;

using System.Data.SqlClient;

 

namespace ELData

{

  public class SADatabase : Database

  {

    public SADatabase(String connectionString)

      : base(connectionString, System.Data.SqlClient.SqlClientFactory.Instance)

    {

    }

 

    protected override void DeriveParameters(DbCommand discoveryCommand)

  { SqlCommandBuilder.DeriveParameters((SqlCommand)discoveryCommand); }

  }

}

 

2/ Then created a custom Data Access Layer for further abstraction. Here I implemented the stuff which reads from EL config file.

 

using System;

using Microsoft.Practices.EnterpriseLibrary.Common;

using Microsoft.Practices.EnterpriseLibrary.Data;

using Microsoft.Practices.EnterpriseLibrary.Data.Configuration;

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

using System.Configuration;

 

namespace ELData

{

  class DAL

  {

    public static SADatabase CreateDatabse(String userId, String password)

    {

      return new SADatabase(String.Format(getConnectionString(""), userId, password));

    }

 

    public static SADatabase CreateDatabse(String sectionName, String userId, String password)

    {

      return new SADatabase(String.Format(getConnectionString(sectionName), userId, password));

    }

 

    private static String getConnectionString(String sectionName)

    {

      IConfigurationSource csf = ConfigurationSourceFactory.Create();

      if (sectionName == String.Empty)

      {

        DatabaseSettings dbs = (DatabaseSettings)csf.GetSection("dataConfiguration");

        sectionName = dbs.DefaultDatabase;

      }

      String cn = String.Empty;

      System.Configuration.ConnectionStringsSection css = (ConnectionStringsSection)(csf.GetSection("connectionStrings"));

      foreach (ConnectionStringSettings cns in css.ConnectionStrings)

      { if (cns.Name == sectionName) { cn = cns.ConnectionString; break; } }

      return cn;

    }

 

  }

}

 

3/ Wrote a simple client app, to test the functioning:

 

    private void cmdTest_Click(object sender, EventArgs e)

    {

      SADatabase db = DAL.CreateDatabse("userId", "password");

      MessageBox.Show(db.ExecuteScalar(CommandType.Text, "SELECT DB_Name()").ToString());

    }

 

Please review. Any comments for improvement of code are most welcome. Thank you.

 

Feb 18, 2009 at 8:02 AM

Hi.

>1/ In your implementation, where the connection string is coming from? May be you have kept it in app.config. However, I am struggling to read the DAAB related sections from app.config programmatically in my implementation of EL code. Basically, I aim to keep >something like “uid={0};pwd={1}” in app.config and place other info at run time. The reason I want to keep it in EL generated config itself is then I can encrypt it.

App.config, yes.

>2/ In your code, addUserNamePass is private static, how do you manage to access your custom Session object within that is beyond me. Please help. I aim to replace it with my own currentUser object which will hold userId and password. (It's identical to your >Session object!)

If my method is private static it still can use all public static classes and methods. My Database class shares the same namespace as my Session object. 

I don't understand what you solved with creating DAL class. DAAB intent is to provide data access abstraction but your class limits you to one database class SADatabase. If you want to have pieces of connection string outside of app.config than it's easy to expand method addUserNamePass to insert additional elements into connection string and you get all other benefits of using DAAB. Right now you're just not using it at all.

Hope it helps.