1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ldapuserprofilebe.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_extensions.hxx"
34 #include "ldapuserprofilebe.hxx"
35 #include "ldapuserprofilelayer.hxx"
36 #include <osl/file.hxx>
37 #include <osl/module.hxx>
38 #include <osl/process.h>
39 #include <rtl/ustrbuf.hxx>
40 #include <rtl/byteseq.h>
42 #ifndef INCLUDED_RTL_INSTANCE_HXX_
43 #include <rtl/instance.hxx>
45 #include <com/sun/star/beans/NamedValue.hpp>
46 #include <osl/security.hxx>
48 //==============================================================================
49 namespace extensions
{ namespace config
{ namespace ldap
{
52 static void checkIOError(
53 osl::File::RC aErrorCode
,
54 const rtl::OUString
& aFileUrl
)
58 case osl::File::E_None
: // got it
65 rtl::OUStringBuffer sMsg
;
66 sMsg
.appendAscii("LdapUserProfileBe: Cannot Read Meta-Configuration file:");
67 sMsg
.append(aFileUrl
);
68 throw backend::BackendSetupException(sMsg
.makeStringAndClear(),
74 //------------------------------------------------------------------------------
76 static rtl::OUString
getCurrentModuleDirectory() // URL excluding terminating slash
78 rtl::OUString aFileURL
;
79 if ( !osl::Module::getUrlFromAddress((void*)&getCurrentModuleDirectory
,aFileURL
) )
81 OSL_TRACE(false, "Cannot locate current module - using executable instead");
83 OSL_VERIFY(osl_Process_E_None
== osl_getExecutableFile(&aFileURL
.pData
));
86 OSL_ENSURE(0 < aFileURL
.lastIndexOf('/'), "Cannot find directory for module URL");
88 return aFileURL
.copy(0, aFileURL
.lastIndexOf('/') );
91 //------------------------------------------------------------------------------
92 LdapUserProfileBe::LdapUserProfileBe( const uno::Reference
<uno::XComponentContext
>& xContext
)
93 // throw (backend::BackendAccessException, backend::BackendSetupException, RuntimeException)
94 : LdapProfileMutexHolder(),
96 mFactory(xContext
->getServiceManager(),uno::UNO_QUERY_THROW
),
98 mLdapSource( new LdapUserProfileSource
),
102 LdapDefinition aDefinition
;
104 // This whole rigmarole is to prevent an infinite recursion where reading
105 // the configuration for the backend would create another instance of the
106 // backend, which would try and read the configuration which would...
108 osl::Mutex
& aInitMutex
= rtl::Static
< osl::Mutex
, LdapUserProfileBe
>::get();
109 osl::MutexGuard
aInitGuard(aInitMutex
);
111 static bool bReentrantCall
; // = false
112 OSL_ENSURE(!bReentrantCall
, "configuration: Ldap Backend constructor called reentrantly - probably a registration error.");
118 bReentrantCall
= true ;
119 if (! readLdapConfiguration(aDefinition
) )
121 throw backend::BackendSetupException(
122 rtl::OUString::createFromAscii("LdapUserProfileBe- LDAP not configured"),
126 bReentrantCall
= false ;
128 catch (uno::Exception
&)
130 bReentrantCall
= false;
138 mLdapSource
->mConnection
.loadModule();
139 mLdapSource
->mConnection
.connectSimple(aDefinition
);
141 mUserDN
= mLdapSource
->mConnection
.findUserDn(
142 rtl::OUStringToOString(mLoggedOnUser
, RTL_TEXTENCODING_ASCII_US
));
144 catch (lang::IllegalArgumentException
& exception
)
146 throw backend::BackendSetupException(exception
.Message
, NULL
,
147 uno::makeAny(exception
)) ;
149 catch (ldap::LdapConnectionException
& exception
)
151 throw backend::CannotConnectException(exception
.Message
, NULL
,
152 uno::makeAny(exception
)) ;
154 catch(ldap::LdapGenericException
& exception
)
156 mapGenericException(exception
) ;
159 initializeMappingTable(
160 rtl::OStringToOUString(aDefinition
.mMapping
,
161 RTL_TEXTENCODING_ASCII_US
));
163 OSL_POSTCOND(mLdapSource
->mConnection
.isConnected(),"Erroneously constructed a LdapUserProfileBackend without a LDAP connection");
165 //------------------------------------------------------------------------------
166 LdapUserProfileBe::~LdapUserProfileBe()
169 //------------------------------------------------------------------------------
171 void LdapUserProfileBe::initializeMappingTable(const rtl::OUString
& aFileMapName
)
173 rtl::OUString aMappingFileUrl
= getMappingFileUrl(aFileMapName
);
175 osl::File
aFile (aMappingFileUrl
);
176 checkIOError( aFile
.open(OpenFlag_Read
), aMappingFileUrl
);
178 sal_uInt64 nFileLength
= 0;
179 checkIOError( aFile
.getSize(nFileLength
), aMappingFileUrl
);
181 sal_uInt32 nDataLength
= sal_uInt32(nFileLength
);
182 if (nDataLength
!= nFileLength
)
184 throw backend::BackendSetupException(rtl::OUString::createFromAscii
185 ("LdapUserProfileBe - can not read entire Mapping File: too big"),
191 RawBuffer(sal_Size size
) : data(rtl_allocateMemory(size
)) {}
192 ~RawBuffer() { rtl_freeMemory(data
); }
196 RawBuffer
buffer( nDataLength
);
198 sal_uInt64 nRead
= 0;
199 osl::File::RC result
= aFile
.read (static_cast<sal_uInt8
*>(buffer
.data
), nDataLength
, nRead
);
200 if (result
!= osl::File::E_None
)
202 checkIOError( result
, aMappingFileUrl
);
203 OSL_ASSERT(!"unreached");
206 if (nRead
!= nDataLength
)
208 throw backend::BackendSetupException(rtl::OUString::createFromAscii
209 ("LdapUserProfileBe - can not read entire Mapping File"),
213 rtl::OString
aStrBuffer ( static_cast<char*>(buffer
.data
), sal_uInt32(nDataLength
) );
214 mLdapSource
->mProfileMap
.source(aStrBuffer
);
217 //------------------------------------------------------------------------------
219 static const rtl::OUString
kMappingFileSuffix(RTL_CONSTASCII_USTRINGPARAM(
222 static const rtl::OUString
kMappingUrl(
223 RTL_CONSTASCII_USTRINGPARAM("/modules/com.sun.star.configuration/bootstrap/LdapMappingUrl"));
226 static const sal_Unicode kPathSeparator
= '/' ;
227 static const rtl::OUString
kBootstrapContextSingletonName(
228 RTL_CONSTASCII_USTRINGPARAM(
229 "/singletons/com.sun.star.configuration.bootstrap.theBootstrapContext"));
231 rtl::OUString
LdapUserProfileBe::getMappingFileUrl(const rtl::OUString
& aFileMapName
) const
233 uno::Any aContext
= mContext
->getValueByName(kBootstrapContextSingletonName
);
234 uno::Reference
<uno::XComponentContext
> aBootStrapContext
;
236 rtl::OUString aFileUrl
;
237 if (aContext
>>= aBootStrapContext
)
238 aBootStrapContext
->getValueByName(kMappingUrl
) >>= aFileUrl
;
240 if (aFileUrl
.getLength() == 0 )
243 static const rtl::OUString
kMappingDirectory(RTL_CONSTASCII_USTRINGPARAM( "/share/registry/ldap"));
245 rtl::OUString aModuleUrl
= getCurrentModuleDirectory();
246 sal_Int32 nIndex
= aModuleUrl
.lastIndexOf('/');
249 throw backend::BackendSetupException(rtl::OUString::createFromAscii
250 ("LdapUserProfileBe - can not access Mapping File"),
253 rtl::OUString aMappingFileUrl
= aModuleUrl
.copy(0, nIndex
);
254 aMappingFileUrl
+= kMappingDirectory
;
255 aFileUrl
= aMappingFileUrl
;
257 throw backend::BackendSetupException(rtl::OUString::createFromAscii
258 ("LdapUserProfileBe - can not locate Mapping File"),
263 rtl::OUStringBuffer
sFileBuffer(aFileUrl
);
264 sFileBuffer
.append(kPathSeparator
);
265 sFileBuffer
.append (aFileMapName
);
266 sFileBuffer
.append(kMappingFileSuffix
);
267 return sFileBuffer
.makeStringAndClear();
269 //------------------------------------------------------------------------------
270 void LdapUserProfileBe::mapGenericException(ldap::LdapGenericException
& aException
)
271 throw (backend::InsufficientAccessRightsException
,
272 backend::ConnectionLostException
,
273 backend::BackendAccessException
)
275 switch (aException
.ErrorCode
)
277 case LDAP_INSUFFICIENT_ACCESS
:
278 throw backend::InsufficientAccessRightsException(aException
.Message
,
279 NULL
, uno::makeAny(aException
)) ;
281 case LDAP_SERVER_DOWN
:
282 case LDAP_CONNECT_ERROR
:
283 throw backend::ConnectionLostException(aException
.Message
, NULL
,
284 uno::makeAny(aException
)) ;
286 throw backend::BackendAccessException(aException
.Message
, NULL
,
287 uno::makeAny(aException
)) ;
290 //------------------------------------------------------------------------------
292 bool LdapUserProfileBe::readLdapConfiguration(LdapDefinition
& aDefinition
)
294 const rtl::OUString
kConfigurationProviderService( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.ConfigurationProvider")) ;
295 const rtl::OUString
kReadOnlyViewService( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.ConfigurationAccess")) ;
296 const rtl::OUString
kComponent( RTL_CONSTASCII_USTRINGPARAM("org.openoffice.LDAP/UserDirectory"));
297 const rtl::OUString
kServerDefiniton(RTL_CONSTASCII_USTRINGPARAM ("ServerDefinition"));
298 const rtl::OUString
kServer(RTL_CONSTASCII_USTRINGPARAM ("Server"));
299 const rtl::OUString
kPort(RTL_CONSTASCII_USTRINGPARAM("Port"));
300 const rtl::OUString
kBaseDN(RTL_CONSTASCII_USTRINGPARAM("BaseDN"));
301 const rtl::OUString
kUser(RTL_CONSTASCII_USTRINGPARAM("SearchUser"));
302 const rtl::OUString
kPassword(RTL_CONSTASCII_USTRINGPARAM("SearchPassword"));
303 const rtl::OUString
kUserObjectClass(RTL_CONSTASCII_USTRINGPARAM("UserObjectClass"));
304 const rtl::OUString
kUserUniqueAttr(RTL_CONSTASCII_USTRINGPARAM("UserUniqueAttribute"));
305 const rtl::OUString
kMapping(RTL_CONSTASCII_USTRINGPARAM("Mapping"));
306 const rtl::OString
kDefaultMappingFile("oo-ldap");
308 uno::Reference
< XInterface
> xIface
;
311 uno::Reference
< lang::XMultiServiceFactory
> xCfgProvider(
312 mFactory
->createInstance(kConfigurationProviderService
),
314 OSL_ENSURE(xCfgProvider
.is(),"LdapUserProfileBe: could not create the configuration provider");
315 if (!xCfgProvider
.is())
318 css::beans::NamedValue
aPath(rtl::OUString::createFromAscii("nodepath"), uno::makeAny(kComponent
) );
320 uno::Sequence
< uno::Any
> aArgs(1);
323 xIface
= xCfgProvider
->createInstanceWithArguments(kReadOnlyViewService
, aArgs
);
325 uno::Reference
<container::XNameAccess
> xAccess(xIface
, uno::UNO_QUERY_THROW
);
326 xAccess
->getByName(kServerDefiniton
) >>= xIface
;
328 uno::Reference
<container::XNameAccess
> xChildAccess(xIface
, uno::UNO_QUERY_THROW
);
330 if (!getLdapStringParam(xChildAccess
, kServer
, aDefinition
.mServer
))
332 if (!getLdapStringParam(xChildAccess
, kBaseDN
, aDefinition
.mBaseDN
))
336 xChildAccess
->getByName(kPort
) >>= aDefinition
.mPort
;
337 if (aDefinition
.mPort
== 0)
340 if (!getLdapStringParam(xAccess
, kUserObjectClass
, aDefinition
.mUserObjectClass
))
342 if (!getLdapStringParam(xAccess
, kUserUniqueAttr
, aDefinition
.mUserUniqueAttr
))
345 getLdapStringParam(xAccess
, kUser
, aDefinition
.mAnonUser
);
346 getLdapStringParam(xAccess
, kPassword
, aDefinition
.mAnonCredentials
);
348 if (!getLdapStringParam(xAccess
, kMapping
, aDefinition
.mMapping
))
349 aDefinition
.mMapping
= kDefaultMappingFile
;
351 catch (uno::Exception
& e
)
353 OSL_TRACE("LdapUserProfileBackend: access to configuration data failed: %s",
354 rtl::OUStringToOString( e
.Message
, RTL_TEXTENCODING_ASCII_US
).getStr() );
358 osl::Security aSecurityContext
;
359 if (!aSecurityContext
.getUserName(mLoggedOnUser
))
360 OSL_TRACE("LdapUserProfileBackend - could not get Logged on user from system");
362 sal_Int32 nIndex
= mLoggedOnUser
.indexOf('/');
364 mLoggedOnUser
= mLoggedOnUser
.copy(nIndex
+1);
367 OSL_TRACE("Logged on user is %s", rtl::OUStringToOString(mLoggedOnUser
,RTL_TEXTENCODING_ASCII_US
).getStr());
372 //------------------------------------------------------------------------------
373 bool LdapUserProfileBe::getLdapStringParam(
374 uno::Reference
<container::XNameAccess
>& xAccess
,
375 const rtl::OUString
& aLdapSetting
,
376 rtl::OString
& aServerParameter
)
378 rtl::OUString sParam
;
379 xAccess
->getByName(aLdapSetting
) >>= sParam
;
380 aServerParameter
= rtl::OUStringToOString(sParam
, RTL_TEXTENCODING_ASCII_US
);
382 return aServerParameter
.getLength() != 0;
384 //------------------------------------------------------------------------------
385 uno::Reference
<backend::XLayer
> SAL_CALL
LdapUserProfileBe::getLayer(
386 const rtl::OUString
& /*aComponent*/, const rtl::OUString
& /*aTimestamp*/)
387 throw (backend::BackendAccessException
, lang::IllegalArgumentException
,uno::RuntimeException
)
389 OSL_PRECOND(mLdapSource
->mConnection
.isConnected(), "LdapUserProfileBackend invoked without a connection");
390 if (!mLdapSource
->mConnection
.isConnected())
393 const rtl::OString kModificationAttribute
= "modifyTimeStamp";
395 rtl::OString aTimeStamp
= mLdapSource
->mConnection
.
396 getSingleAttribute( mUserDN
, kModificationAttribute
);
398 return new LdapUserProfileLayer(
399 mFactory
, mLoggedOnUser
, mLdapSource
,
400 rtl::OStringToOUString(aTimeStamp
, RTL_TEXTENCODING_ASCII_US
));
403 //------------------------------------------------------------------------------
404 uno::Reference
<backend::XUpdatableLayer
> SAL_CALL
405 LdapUserProfileBe::getUpdatableLayer(const rtl::OUString
& /*aComponent*/)
406 throw (backend::BackendAccessException
,lang::NoSupportException
,
407 lang::IllegalArgumentException
,uno::RuntimeException
)
409 throw lang::NoSupportException(
410 rtl::OUString::createFromAscii(
411 "LdapUserProfileBe: No Update Operation allowed, Read Only access"),
414 //------------------------------------------------------------------------------
415 rtl::OUString SAL_CALL
LdapUserProfileBe::getLdapUserProfileBeName(void) {
416 return rtl::OUString::createFromAscii("com.sun.star.comp.configuration.backend.LdapUserProfileBe") ;
418 //------------------------------------------------------------------------------
420 rtl::OUString SAL_CALL
LdapUserProfileBe::getImplementationName(void)
421 throw (uno::RuntimeException
)
423 return getLdapUserProfileBeName() ;
425 //------------------------------------------------------------------------------
427 uno::Sequence
<rtl::OUString
> SAL_CALL
LdapUserProfileBe::getLdapUserProfileBeServiceNames(void)
429 uno::Sequence
<rtl::OUString
> aServices(2) ;
430 aServices
[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.backend.LdapUserProfileBe")) ;
431 aServices
[1] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.backend.PlatformBackend")) ;
435 //------------------------------------------------------------------------------
437 sal_Bool SAL_CALL
LdapUserProfileBe::supportsService(const rtl::OUString
& aServiceName
)
438 throw (uno::RuntimeException
)
440 uno::Sequence
< rtl::OUString
> const svc
= getLdapUserProfileBeServiceNames();
442 for(sal_Int32 i
= 0; i
< svc
.getLength(); ++i
)
443 if(svc
[i
] == aServiceName
)
448 //------------------------------------------------------------------------------
450 uno::Sequence
<rtl::OUString
>
451 SAL_CALL
LdapUserProfileBe::getSupportedServiceNames(void)
452 throw (uno::RuntimeException
)
454 return getLdapUserProfileBeServiceNames() ;
456 // ---------------------------------------------------------------------------------------
458 // ---------------------------------------------------------------------------------------