00001 #include "CondCore/DBCommon/interface/DecodingKey.h"
00002 #include "CondCore/DBCommon/interface/FileUtils.h"
00003 #include "CondCore/DBCommon/interface/Exception.h"
00004 #include "XMLAuthenticationService.h"
00005 #include "CoralCommon/AuthenticationCredentials.h"
00006 #include "CoralCommon/Cipher.h"
00007 #include "RelationalAccess/AuthenticationServiceException.h"
00008 #include "SealKernel/PropertyManager.h"
00009 #include "SealKernel/MessageStream.h"
00010 #include "xercesc/parsers/XercesDOMParser.hpp"
00011 #include "xercesc/framework/MemBufInputSource.hpp"
00012 #include "xercesc/dom/DOM.hpp"
00013 #include "xercesc/sax/HandlerBase.hpp"
00014 #include "xercesc/util/XMLString.hpp"
00015 #include "xercesc/util/PlatformUtils.hpp"
00016 #include <memory>
00017 #include <cstdlib>
00018 #include <fstream>
00019 #include <sys/stat.h>
00020 #include <fcntl.h>
00021 #include <boost/filesystem.hpp>
00022
00023 static std::string XML_AUTHENTICATION_FILE("authentication.xml");
00024
00025 DEFINE_SEAL_COMPONENT ( cond::XMLAuthenticationService::XMLAuthenticationService, "COND/Services/XMLAuthenticationService")
00026
00027 namespace cond {
00028
00029 namespace XMLAuthenticationService {
00030
00031 class CallbackForInputFileName {
00032 public:
00033 explicit CallbackForInputFileName( cond::XMLAuthenticationService::XMLAuthenticationService& authenticationService )
00034 : m_authenticationService( authenticationService )
00035 {
00036 }
00037
00038 void operator() ( const seal::PropertyBase& p )
00039 {
00040 std::string fileName = boost::any_cast< std::string >( p.get() );
00041 m_authenticationService.setInputFileName( fileName );
00042 }
00043 private:
00044 cond::XMLAuthenticationService::XMLAuthenticationService& m_authenticationService;
00045 };
00046
00047 }
00048 }
00049
00050 cond::XMLAuthenticationService::DataSourceEntry::DataSourceEntry( const std::string& serviceName,
00051 const std::string& connectionName ):
00052 m_serviceName( serviceName ),
00053 m_connectionName( connectionName ),
00054 m_default( new coral::AuthenticationCredentials( serviceName ) ),
00055 m_data()
00056 {}
00057
00058 cond::XMLAuthenticationService::DataSourceEntry::~DataSourceEntry()
00059 {
00060 delete m_default;
00061 for ( std::map< std::string, coral::AuthenticationCredentials* >::iterator iData = m_data.begin();
00062 iData != m_data.end(); ++iData )
00063 delete iData->second;
00064 }
00065
00066 void
00067 cond::XMLAuthenticationService::DataSourceEntry::appendCredentialItem( const std::string& item,
00068 const std::string& value )
00069 {
00070 m_default->registerItem( item, value );
00071 }
00072
00073 void
00074 cond::XMLAuthenticationService::DataSourceEntry::appendCredentialItemForRole( const std::string& item,
00075 const std::string& value,
00076 const std::string& role )
00077 {
00078 std::map< std::string, coral::AuthenticationCredentials* >::iterator iRole = m_data.find( role );
00079 if ( iRole == m_data.end() ) {
00080 iRole = m_data.insert( std::make_pair( role, new coral::AuthenticationCredentials( m_serviceName ) ) ).first;
00081 }
00082 iRole->second->registerItem( item, value );
00083 }
00084
00085 const coral::IAuthenticationCredentials&
00086 cond::XMLAuthenticationService::DataSourceEntry::credentials() const
00087 {
00088 return *m_default;
00089 }
00090
00091 const coral::IAuthenticationCredentials&
00092 cond::XMLAuthenticationService::DataSourceEntry::credentials( const std::string& role ) const
00093 {
00094 std::map< std::string, coral::AuthenticationCredentials* >::const_iterator iRole = m_data.find( role );
00095 if ( iRole == m_data.end() )
00096 throw coral::UnknownRoleException( m_serviceName,
00097 m_connectionName,
00098 role );
00099 return *( iRole->second );
00100 }
00101
00102 cond::XMLAuthenticationService::XMLAuthenticationService::XMLAuthenticationService( seal::Context* c )
00103 : seal::Service( c, classContextKey() ),
00104 m_isInitialized( false ),
00105 m_inputFileName( "" ),
00106 m_data()
00107 {
00108 propertyManager()->declareProperty( "AuthenticationFile",
00109 m_inputFileName,
00110 XML_AUTHENTICATION_FILE,
00111 "The input file with the authentication data",
00112 cond::XMLAuthenticationService::CallbackForInputFileName( *this ) );
00113 }
00114
00115 cond::XMLAuthenticationService::XMLAuthenticationService::XMLAuthenticationService( seal::Context* c,
00116 const std::string& key )
00117 : seal::Service( c, key ),
00118 m_isInitialized( false ),
00119 m_inputFileName( "" ),
00120 m_data()
00121 {
00122 propertyManager()->declareProperty( "AuthenticationFile",
00123 m_inputFileName,
00124 XML_AUTHENTICATION_FILE,
00125 "The input file with the authentication data",
00126 cond::XMLAuthenticationService::CallbackForInputFileName( *this ) );
00127 }
00128
00129 cond::XMLAuthenticationService::XMLAuthenticationService::~XMLAuthenticationService()
00130 {
00131 for ( std::map< std::string, cond::XMLAuthenticationService::DataSourceEntry* >::iterator iConnection = m_data.begin();
00132 iConnection != m_data.end(); ++iConnection ) delete iConnection->second;
00133 }
00134
00135 void
00136 cond::XMLAuthenticationService::XMLAuthenticationService::setInputFileName( const std::string& inputFileName )
00137 {
00138 m_inputFileName = inputFileName;
00139 reset();
00140 }
00141
00142 bool
00143 cond::XMLAuthenticationService::XMLAuthenticationService::processFile( const std::string& inputFileName )
00144 {
00145 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00146 log << seal::Msg::Debug << "Processing file \""<< inputFileName<<"\"" << seal::flush;
00147 bool result = true;
00148
00149 cond::FileReader inputFile;
00150 std::string cont("");
00151 try{
00152 inputFile.read(inputFileName);
00153 cont = inputFile.content();
00154 } catch (const cond::Exception& exc){
00155 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00156 log << seal::Msg::Error << exc.what() << seal::flush;
00157 return false;
00158 }
00159
00160
00161 boost::filesystem::path filePath( inputFileName );
00162 std::string name = filePath.leaf();
00163 if(name!=XML_AUTHENTICATION_FILE){
00164 cond::DecodingKey key;
00165 try{
00166 key.readUserKeyString(cont);
00167
00168 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00169 log << seal::Msg::Debug << "Decoding content of file \""<< key.dataSource()<<"\"" << seal::flush;
00170
00171 cond::FileReader dataFile;
00172 dataFile.read(key.dataSource());
00173 cont = dataFile.content();
00174 cont = coral::Cipher::decode(cont,key.key());
00175 } catch (const cond::Exception& exc){
00176 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00177 log << seal::Msg::Error << exc.what() << seal::flush;
00178 return false;
00179 }
00180
00181 } else {
00182 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00183 log << seal::Msg::Debug << "Authentication file is expected standard XML."<< seal::flush;
00184 }
00185
00186 xercesc::MemBufInputSource* memBufInputSource = 0;
00187
00188 try
00189 {
00190 xercesc::XercesDOMParser parser;
00191 parser.setValidationScheme( xercesc::XercesDOMParser::Val_Always );
00192 parser.setDoNamespaces( true );
00193
00194 xercesc::HandlerBase errorHandler;
00195 parser.setErrorHandler( &errorHandler );
00196
00197
00198 const char* bufferId="InMemoryDocument";
00199 const char* buffer = cont.c_str();
00200
00201 memBufInputSource = new xercesc::MemBufInputSource( (const XMLByte*)buffer,strlen(buffer),bufferId,false );
00202
00203 parser.parse(*memBufInputSource);
00204
00205 xercesc::DOMDocument* document = parser.getDocument();
00206
00207 XMLCh tempStr[20];
00208 xercesc::XMLString::transcode( "connection", tempStr, 19);
00209
00210 xercesc::DOMNodeList* connectionList = document->getElementsByTagName( tempStr );
00211
00212 if ( connectionList )
00213 {
00214 XMLSize_t numberOfConnections = connectionList->getLength();
00215
00216 for ( XMLSize_t iConnection = 0; iConnection < numberOfConnections; ++iConnection )
00217 {
00218 xercesc::DOMNode* connectionNode = connectionList->item( iConnection );
00219
00220 if ( connectionNode )
00221 {
00222 char* connectionName = xercesc::XMLString::transcode( connectionNode->getAttributes()->item( 0 )->getNodeValue() );
00223 std::string sConnectionName = connectionName;
00224 xercesc::XMLString::release( &connectionName );
00225
00226
00227 cond::XMLAuthenticationService::DataSourceEntry* credential = 0;
00228 std::map< std::string, cond::XMLAuthenticationService::DataSourceEntry* >::iterator iConnection = m_data.find( sConnectionName );
00229 if ( iConnection != m_data.end() ) {
00230 credential = iConnection->second;
00231
00232 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00233 log << seal::Msg::Warning << "Credential parameters for connection string \""
00234 << sConnectionName
00235 << "\" have already been defined. Only new elements are appended, while existing will be ignored."
00236 << seal::flush;
00237 }
00238 else {
00239 credential = new cond::XMLAuthenticationService::DataSourceEntry( this->name(), sConnectionName );
00240 m_data.insert( std::make_pair( sConnectionName, credential ) );
00241 }
00242
00243 xercesc::DOMNodeList* parameterList = connectionNode->getChildNodes();
00244
00245 if ( parameterList )
00246 {
00247 XMLSize_t numberOfParameters = parameterList->getLength();
00248
00249 for ( XMLSize_t iParameter = 0; iParameter < numberOfParameters; ++iParameter )
00250 {
00251 xercesc::DOMNode* parameterNode = parameterList->item( iParameter );
00252
00253 if ( parameterNode && parameterNode->getNodeType() == xercesc::DOMNode::ELEMENT_NODE )
00254 {
00255 char* nodeName = xercesc::XMLString::transcode( parameterNode->getNodeName() );
00256 std::string sNodeName = nodeName;
00257 xercesc::XMLString::release( &nodeName );
00258
00259 if ( sNodeName == "parameter" ) {
00260 char* parameterName = xercesc::XMLString::transcode( parameterNode->getAttributes()->item( 0 )->getNodeValue() );
00261 std::string sParameterName = parameterName;
00262 xercesc::XMLString::release( ¶meterName );
00263 char* parameterValue = xercesc::XMLString::transcode( parameterNode->getAttributes()->item( 1 )->getNodeValue() );
00264 std::string sParameterValue = parameterValue;
00265 xercesc::XMLString::release( ¶meterValue );
00266
00267 credential->appendCredentialItem( sParameterName, sParameterValue );
00268 }
00269 else if ( sNodeName == "role" ) {
00270 char* roleName = xercesc::XMLString::transcode( parameterNode->getAttributes()->item( 0 )->getNodeValue() );
00271 std::string sRoleName = roleName;
00272 xercesc::XMLString::release( &roleName );
00273
00274
00275 xercesc::DOMNodeList* roleParameterList = parameterNode->getChildNodes();
00276
00277
00278 if ( roleParameterList )
00279 {
00280 XMLSize_t numberOfRoleParameters = roleParameterList->getLength();
00281
00282 for ( XMLSize_t iRoleParameter = 0; iRoleParameter < numberOfRoleParameters; ++iRoleParameter )
00283 {
00284 xercesc::DOMNode* roleParameterNode = roleParameterList->item( iRoleParameter );
00285 if ( roleParameterNode && roleParameterNode->getNodeType() == xercesc::DOMNode::ELEMENT_NODE )
00286 {
00287 char* roleNodeName = xercesc::XMLString::transcode( roleParameterNode->getNodeName() );
00288 std::string sRoleNodeName = roleNodeName;
00289 xercesc::XMLString::release( &roleNodeName );
00290
00291 if ( sRoleNodeName == "parameter" ) {
00292 char* roleParameterName = xercesc::XMLString::transcode( roleParameterNode->getAttributes()->item( 0 )->getNodeValue() );
00293 std::string sRoleParameterName = roleParameterName;
00294 xercesc::XMLString::release( &roleParameterName );
00295 char* roleParameterValue = xercesc::XMLString::transcode( roleParameterNode->getAttributes()->item( 1 )->getNodeValue() );
00296 std::string sRoleParameterValue = roleParameterValue;
00297 xercesc::XMLString::release( &roleParameterValue );
00298
00299 credential->appendCredentialItemForRole( sRoleParameterName, sRoleParameterValue, sRoleName );
00300 }
00301 }
00302 }
00303 }
00304 }
00305 }
00306 }
00307 }
00308 }
00309 }
00310 }
00311
00312 parser.reset();
00313 }
00314 catch ( const xercesc::XMLException& toCatch )
00315 {
00316 char* message = xercesc::XMLString::transcode( toCatch.getMessage() );
00317 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00318 log << seal::Msg::Error << message << seal::flush;
00319 xercesc::XMLString::release( &message );
00320 result = false;
00321 }
00322 catch ( const xercesc::DOMException& toCatch )
00323 {
00324 char* message = xercesc::XMLString::transcode( toCatch.msg );
00325 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00326 log << seal::Msg::Error << message << seal::flush;
00327 xercesc::XMLString::release( &message );
00328 result = false;
00329 }
00330 catch ( const xercesc::SAXException& toCatch )
00331 {
00332 char* message = xercesc::XMLString::transcode( toCatch.getMessage() );
00333 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00334 log << seal::Msg::Error << message << seal::flush;
00335 xercesc::XMLString::release( &message );
00336 result = false;
00337 }
00338 catch (...){
00339 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00340 log << seal::Msg::Error << "Unexpected Exception parsing file \"" << inputFileName << "\"" << seal::flush;
00341 result = false;
00342 }
00343 if(memBufInputSource) delete memBufInputSource;
00344 return result;
00345 }
00346
00347
00348 bool
00349 cond::XMLAuthenticationService::XMLAuthenticationService::initialize()
00350 {
00351 std::set< std::string > inputFileNames = this->verifyFileName();
00352 if ( inputFileNames.empty() )
00353 {
00354 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00355 log << seal::Msg::Error << "Could not open \"" << m_inputFileName << "\" for reading" << seal::flush;
00356 return false;
00357 }
00358
00359 try
00360 {
00361 xercesc::XMLPlatformUtils::Initialize();
00362 }
00363 catch ( const xercesc::XMLException& toCatch )
00364 {
00365 char* message = xercesc::XMLString::transcode( toCatch.getMessage() );
00366 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00367 log << seal::Msg::Error << message << seal::flush;
00368 xercesc::XMLString::release( &message );
00369 return false;
00370 }
00371
00372 bool result = false;
00373 for ( std::set< std::string >::const_reverse_iterator iFileName = inputFileNames.rbegin();
00374 iFileName != inputFileNames.rend(); ++iFileName ) {
00375 if ( this->processFile( *iFileName ) ) {
00376 result = true;
00377 }
00378 }
00379
00380 xercesc::XMLPlatformUtils::Terminate();
00381
00382 m_isInitialized = result;
00383 if(!m_isInitialized) reset();
00384 return result;
00385 }
00386
00387 void cond::XMLAuthenticationService::XMLAuthenticationService::reset(){
00388 for ( std::map< std::string, cond::XMLAuthenticationService::DataSourceEntry* >::iterator iConnection = m_data.begin();
00389 iConnection != m_data.end(); ++iConnection ) delete iConnection->second;
00390 m_data.clear();
00391 m_isInitialized = false;
00392 }
00393
00394
00395
00396 const coral::IAuthenticationCredentials&
00397 cond::XMLAuthenticationService::XMLAuthenticationService::credentials( const std::string& connectionString ) const
00398 {
00399 boost::mutex::scoped_lock lock(m_mutexLock);
00400 if ( ! m_isInitialized ) {
00401 const_cast< cond::XMLAuthenticationService::XMLAuthenticationService* >( this )->initialize();
00402 }
00403 std::map< std::string, cond::XMLAuthenticationService::DataSourceEntry* >::const_iterator iConnection = m_data.find( connectionString );
00404 if ( iConnection == m_data.end() )
00405 throw coral::UnknownConnectionException( this->name(), connectionString );
00406 return iConnection->second->credentials();
00407 }
00408
00409
00410 const coral::IAuthenticationCredentials&
00411 cond::XMLAuthenticationService::XMLAuthenticationService::credentials( const std::string& connectionString,
00412 const std::string& role ) const
00413 {
00414 boost::mutex::scoped_lock lock(m_mutexLock);
00415 if ( ! m_isInitialized ) {
00416 const_cast< cond::XMLAuthenticationService::XMLAuthenticationService* >( this )->initialize();
00417 }
00418 std::map< std::string, cond::XMLAuthenticationService::DataSourceEntry* >::const_iterator iConnection = m_data.find( connectionString );
00419 if ( iConnection == m_data.end() )
00420 throw coral::UnknownConnectionException( this->name(), connectionString );
00421 return iConnection->second->credentials( role );
00422 }
00423
00424
00425 std::set< std::string >
00426 cond::XMLAuthenticationService::XMLAuthenticationService::verifyFileName()
00427 {
00428
00429 {
00430 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00431 log << seal::Msg::Debug << "Verifying file name: \"" << m_inputFileName << "\"." << seal::flush;
00432 }
00433
00434 std::set< std::string > fileNames;
00435
00436
00437 boost::filesystem::path filePath( m_inputFileName );
00438 if ( boost::filesystem::exists( m_inputFileName ) ) {
00439 if(boost::filesystem::is_directory( m_inputFileName )){
00440 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00441 log << seal::Msg::Error << "Provided path \"" << m_inputFileName << "\" is a directory." << seal::flush;
00442 return fileNames;
00443 }
00444 boost::filesystem::path& fullPath = filePath.normalize();
00445 fileNames.insert( fullPath.string() );
00446 if(filePath.is_complete()) return fileNames;
00447 }
00448
00449
00450 const char* thePathVariable = ::getenv( "CORAL_AUTH_PATH" );
00451 if ( ! thePathVariable ) return fileNames;
00452 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00453 log << seal::Msg::Debug << "File \"" << m_inputFileName << "\" not found in the current directory. Trying in the search path." << seal::flush;
00454
00455 std::string searchPath(thePathVariable);
00456 if(boost::filesystem::exists(searchPath)){
00457 if(!boost::filesystem::is_directory( searchPath )){
00458 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00459 log << seal::Msg::Error << "Search path \"" << searchPath << "\" is not a directory." << seal::flush;
00460 return fileNames;
00461 }
00462 boost::filesystem::path fullPath( searchPath );
00463 fullPath /= filePath;
00464 fileNames.insert( fullPath.string() );
00465 } else {
00466 seal::MessageStream log( this, this->name(),seal::Msg::Verbose );
00467 log << seal::Msg::Error << "Search path \"" << searchPath << "\" does not exist." << seal::flush;
00468 return fileNames;
00469 }
00470
00471 return fileNames;
00472 }