Monday, August 10, 2009

Override the connection string in IBatis.Net

Like many software developers, I built one too many data access layers. Don’t get me wrong – I’m really happy with ADO.Net and it’s capabilities. I just don’t want to write the same code snippets over and over. I’ve also gone the code-generation route using multiple tools like CodeSmith and even the Guidance Automation Toolkit. I’m a big fan of NHibernate and I’m looking forward to using it again in the future.

On my current project, we’re using IBatis.Net’s DataMapper.

For this project though, there was a slight twist. For security reasons, the connection string is encrypted - but not using the facilities to encrypt sections of the config file.  For whatever the reason, it is what it is.

Now, normally you would define your data sources in the SqlMap.config file. It would look something like this:

   1: <databases>



   2:     <provider name="sqlServer2.0"/>



   3:     <dataSource name="centralDb"



   4:         connectionString="server=(local); catalog=central;integrated security=true;persist security info=false;"



   5: </database>




This, of course, is not an encrypted connection string. It turns out that using an encrypted connection string with IBatis.Net really isn’t that difficult. We’ll start with out SqlMap.Config file.



Our SqlMap.config file



The only purpose of our file is to indicate that type of provider that we’ll be using. Notice that connection string contains information directing people to look elsewhere for it.







   1: <database>



   2: <provider name="sqlServer2.0">



   3: <datasource name="centralDb" connectionstring=" -- uses encrypted string from config file --">



   4: </database>







EncryptedDataSource



We have a custom DataSource that is responsible for retrieving the encrypted connection string, decrypting it and making it available.



EncryptedDataSource.cs





   1: public class EncryptedDataSource : DataSource 



   2: { 



   3:     private IDataSource _innerDataSource; 



   4:     private string _connectionString; 



   5:     private object _lock = new object(); 



   6:     



   7:     /// The data source. 



   8:     public EncryptedDataSource(IDataSource dataSource) 



   9:     { 



  10:         _innerDataSource = dataSource; 



  11:     } 



  12:     



  13:     private void Initialize() 



  14:     { 



  15:         string encryptedConnectionString = ...; 



  16:     



  17:         if (string.IsNullOrEmpty(encryptedConnectionString)) 



  18:         { 



  19:             throw new ConfigurationErrorsException( 



  20:             "The encrypted connection string could not be located within the configuration file. Please check the configuration file."); 



  21:         } 



  22:         this._connectionString = ...; // decrypt key 



  23:     } 



  24:     



  25:     public override string ConnectionString 



  26:     { 



  27:         get 



  28:         { 



  29:             if (string.IsNullOrEmpty(this._connectionString)) 



  30:             { 



  31:                 lock (_lock) 



  32:                 { 



  33:                     if (string.IsNullOrEmpty(this._connectionString)) this.Initialize(); 



  34:                 } 



  35:             } 



  36:         



  37:             return this._connectionString; 



  38:         } 



  39:         set 



  40:         { 



  41:             this._connectionString = value; 



  42:         } 



  43:     } 



  44:     



  45:     /// 



  46:     /// The provider to use for this data source. 



  47:     /// 



  48:     public override IDbProvider DbProvider 



  49:     { 



  50:         get 



  51:         { 



  52:             return this._innerDataSource.DbProvider; 



  53:         } 



  54:         set 



  55:         { 



  56:             this._innerDataSource.DbProvider = value; 



  57:         } 



  58:     } 



  59: } 




Mapper.cs



We initialize our mapper as you would expect but we reset the DataSource with an instance of our EncryptedDataSource class. The constructor of the EncryptedDataSource accepts the data source that was built as part of the initialization. This way we can return it whenever the framework asks for information about the configured provider.






   1: protected static void InitMapper() 



   2: { 



   3:     ConfigureHandler handler = new ConfigureHandler(Configure); 



   4:     DomSqlMapBuilder builder = new DomSqlMapBuilder(); 



   5:     ISqlMapper mapper = builder.ConfigureAndWatch(_sqlMapFile,handler); 



   6:     Debug.Assert(null != mapper); 



   7:     mapper.DataSource = new EncryptedDataSource(mapper.DataSource); 



   8:     _mapper = mapper; 



   9: } 


No comments:

Post a Comment