1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "cppuhelper/factory.hxx"
29 
30 #include "com/sun/star/lang/XMultiServiceFactory.hpp"
31 #include "com/sun/star/task/NoMasterException.hpp"
32 #include "com/sun/star/task/XInteractionHandler.hpp"
33 #include "com/sun/star/task/XMasterPasswordHandling.hpp"
34 #include "com/sun/star/task/XPasswordContainer.hpp"
35 #include "com/sun/star/task/XUrlContainer.hpp"
36 #include "com/sun/star/ucb/AuthenticationRequest.hpp"
37 #include "com/sun/star/ucb/URLAuthenticationRequest.hpp"
38 #include "com/sun/star/ucb/XInteractionSupplyAuthentication.hpp"
39 #include "com/sun/star/ucb/XInteractionSupplyAuthentication2.hpp"
40 
41 #include "passwordcontainer.hxx"
42 
43 using namespace com::sun::star;
44 
45 namespace {
46 
47 //=========================================================================
48 bool fillContinuation(
49     bool bUseSystemCredentials,
50     const ucb::AuthenticationRequest & rRequest,
51     const task::UrlRecord & aRec,
52     const uno::Reference< ucb::XInteractionSupplyAuthentication > &
53         xSupplyAuthentication,
54     const uno::Reference< ucb::XInteractionSupplyAuthentication2 > &
55         xSupplyAuthentication2,
56     bool bCanUseSystemCredentials,
57     bool bCheckForEqualPasswords )
58 {
59     if ( bUseSystemCredentials )
60     {
61         // "use system creds" record found.
62         // Wants client that we use it?
63         if ( xSupplyAuthentication2.is() && bCanUseSystemCredentials )
64         {
65             xSupplyAuthentication2->setUseSystemCredentials( sal_True );
66             return true;
67         }
68         return false;
69     }
70     else if (aRec.UserList.getLength() != 0)
71     {
72         if (aRec.UserList[0].Passwords.getLength() == 0)
73         {
74             // Password sequence can be empty, for instance if master
75             // password was not given (e.g. master pw dialog canceled)
76             // pw container does not throw NoMasterException in this case.
77             // bug???
78             return false;
79         }
80 
81         // "user/pass" record found.
82         if (!bCheckForEqualPasswords || !rRequest.HasPassword
83             || rRequest.Password != aRec.UserList[0].Passwords[0]) // failed login attempt?
84         {
85             if (xSupplyAuthentication->canSetUserName())
86                 xSupplyAuthentication->
87                     setUserName(aRec.UserList[0].UserName.getStr());
88 
89             if (xSupplyAuthentication->canSetPassword())
90                 xSupplyAuthentication->
91                     setPassword(aRec.UserList[0].Passwords[0].getStr());
92             if (aRec.UserList[0].Passwords.getLength() > 1)
93             {
94                 if (rRequest.HasRealm)
95                 {
96                     if (xSupplyAuthentication->canSetRealm())
97                         xSupplyAuthentication->
98                             setRealm(aRec.UserList[0].Passwords[1].
99                                 getStr());
100                 }
101                 else if (xSupplyAuthentication->canSetAccount())
102                     xSupplyAuthentication->
103                         setAccount(aRec.UserList[0].Passwords[1].
104                             getStr());
105             }
106 
107             if ( xSupplyAuthentication2.is() && bCanUseSystemCredentials )
108                 xSupplyAuthentication2->setUseSystemCredentials( sal_False );
109 
110             return true;
111         }
112     }
113     return false;
114 }
115 
116 } // namespace
117 
118 namespace uui {
119 
120 //=========================================================================
121 PasswordContainerHelper::PasswordContainerHelper(
122     uno::Reference< lang::XMultiServiceFactory > const & xServiceFactory )
123 {
124     OSL_ENSURE(xServiceFactory.is(), "no service factory given!");
125     if (xServiceFactory.is())
126         try
127         {
128             m_xPasswordContainer
129                 = uno::Reference< task::XPasswordContainer >(
130                       xServiceFactory->
131                           createInstance(
132                               rtl::OUString(
133                                   RTL_CONSTASCII_USTRINGPARAM(
134                                      "com.sun.star.task.PasswordContainer"))),
135                       uno::UNO_QUERY);
136         }
137         catch (uno::Exception const &)
138         {}
139     OSL_ENSURE(m_xPasswordContainer.is(),
140                "unable to instanciate password container service");
141 }
142 
143 //=========================================================================
144 bool PasswordContainerHelper::handleAuthenticationRequest(
145     ucb::AuthenticationRequest const & rRequest,
146     uno::Reference< ucb::XInteractionSupplyAuthentication > const &
147         xSupplyAuthentication,
148     rtl::OUString const & rURL,
149     uno::Reference< task::XInteractionHandler > const & xIH )
150         SAL_THROW((uno::RuntimeException))
151 {
152     // Is continuation even a XInteractionSupplyAuthentication2, which
153     // is derived from XInteractionSupplyAuthentication?
154     uno::Reference< ucb::XInteractionSupplyAuthentication2 >
155         xSupplyAuthentication2(xSupplyAuthentication, uno::UNO_QUERY);
156 
157     sal_Bool bCanUseSystemCredentials = sal_False;
158     if (xSupplyAuthentication2.is())
159     {
160         sal_Bool bDefaultUseSystemCredentials;
161         bCanUseSystemCredentials
162             =  xSupplyAuthentication2->canUseSystemCredentials(
163                 bDefaultUseSystemCredentials );
164     }
165 
166     uno::Reference< task::XPasswordContainer > xContainer(
167         m_xPasswordContainer );
168     uno::Reference< task::XUrlContainer > xUrlContainer(
169         m_xPasswordContainer, uno::UNO_QUERY );
170     OSL_ENSURE( xUrlContainer.is(), "Got no XUrlContainer!" );
171 
172     if ( !xContainer.is() || !xUrlContainer.is() )
173         return false;
174 
175     if ( bCanUseSystemCredentials )
176     {
177         // Runtime / Persistent info avail for current auth request?
178 
179         rtl::OUString aResult = xUrlContainer->findUrl(
180             rURL.getLength() ? rURL : rRequest.ServerName );
181         if ( aResult.getLength() > 0 )
182         {
183             if ( fillContinuation( true,
184                                    rRequest,
185                                    task::UrlRecord(),
186                                    xSupplyAuthentication,
187                                    xSupplyAuthentication2,
188                                    bCanUseSystemCredentials,
189                                    false ) )
190             {
191                 return true;
192             }
193         }
194     }
195 
196     // xContainer works with userName passwdSequences pairs:
197     if (rRequest.HasUserName && rRequest.HasPassword)
198     {
199         try
200         {
201             if (rRequest.UserName.getLength() == 0)
202             {
203                 task::UrlRecord aRec;
204                 if ( rURL.getLength() )
205                     aRec = xContainer->find(rURL, xIH);
206 
207                 if ( aRec.UserList.getLength() == 0 )
208                 {
209                     // compat: try server name.
210                     aRec = xContainer->find(rRequest.ServerName, xIH);
211                 }
212 
213                 if ( fillContinuation( false,
214                                        rRequest,
215                                        aRec,
216                                        xSupplyAuthentication,
217                                        xSupplyAuthentication2,
218                                        bCanUseSystemCredentials,
219                                        false ) )
220                 {
221                     return true;
222                 }
223             }
224             else
225             {
226                 task::UrlRecord aRec;
227                 if ( rURL.getLength() )
228                     aRec = xContainer->findForName(
229                         rURL, rRequest.UserName, xIH);
230 
231                 if ( aRec.UserList.getLength() == 0 )
232                 {
233                     // compat: try server name.
234                     aRec = xContainer->findForName(
235                         rRequest.ServerName, rRequest.UserName, xIH);
236                 }
237 
238                 if ( fillContinuation( false,
239                                        rRequest,
240                                        aRec,
241                                        xSupplyAuthentication,
242                                        xSupplyAuthentication2,
243                                        bCanUseSystemCredentials,
244                                        true ) )
245                 {
246                     return true;
247                 }
248             }
249         }
250         catch (task::NoMasterException const &)
251         {} // user did not enter master password
252     }
253     return false;
254 }
255 
256 //=========================================================================
257 bool PasswordContainerHelper::addRecord(
258     rtl::OUString const & rURL,
259     rtl::OUString const & rUsername,
260     uno::Sequence< rtl::OUString > const & rPasswords,
261     uno::Reference< task::XInteractionHandler > const & xIH,
262     bool bPersist )
263         SAL_THROW((uno::RuntimeException))
264 {
265     try
266     {
267         if ( rUsername.getLength() )
268         {
269             OSL_ENSURE( m_xPasswordContainer.is(),
270                         "Got no XPasswordContainer!" );
271             if ( !m_xPasswordContainer.is() )
272                 return false;
273 
274             if ( bPersist )
275             {
276                 uno::Reference< task::XMasterPasswordHandling > xMPH(
277                     m_xPasswordContainer, uno::UNO_QUERY_THROW );
278 
279                 // If persistent storing of passwords is not yet
280                 // allowed, enable it.
281                 if ( !xMPH->isPersistentStoringAllowed() )
282                     xMPH->allowPersistentStoring( sal_True );
283 
284                 m_xPasswordContainer->addPersistent( rURL,
285                                                      rUsername,
286                                                      rPasswords,
287                                                      xIH );
288             }
289             else
290                 m_xPasswordContainer->add( rURL,
291                                            rUsername,
292                                            rPasswords,
293                                            xIH );
294         }
295         else
296         {
297             uno::Reference< task::XUrlContainer >
298                 xContainer( m_xPasswordContainer, uno::UNO_QUERY );
299             OSL_ENSURE( xContainer.is(), "Got no XUrlContainer!" );
300             if ( !xContainer.is() )
301                 return false;
302 
303             xContainer->addUrl( rURL, bPersist );
304         }
305     }
306     catch ( task::NoMasterException const & )
307     {
308         // user did not enter master password
309         return false;
310     }
311     return true;
312 }
313 
314 //=========================================================================
315 //=========================================================================
316 //=========================================================================
317 
318 PasswordContainerInteractionHandler::PasswordContainerInteractionHandler(
319     const uno::Reference< lang::XMultiServiceFactory >& xSMgr )
320 : m_aPwContainerHelper( xSMgr )
321 {
322 }
323 
324 //=========================================================================
325 // virtual
326 PasswordContainerInteractionHandler::~PasswordContainerInteractionHandler()
327 {
328 }
329 
330 //=========================================================================
331 //
332 // XServiceInfo methods.
333 //
334 //=========================================================================
335 
336 // virtual
337 ::rtl::OUString SAL_CALL
338 PasswordContainerInteractionHandler::getImplementationName()
339     throw ( uno::RuntimeException )
340 {
341     return getImplementationName_Static();
342 }
343 
344 //=========================================================================
345 // virtual
346 sal_Bool SAL_CALL
347 PasswordContainerInteractionHandler::supportsService(
348         const ::rtl::OUString& ServiceName )
349     throw ( uno::RuntimeException )
350 {
351     uno::Sequence< rtl::OUString > aSNL = getSupportedServiceNames();
352     const rtl::OUString * pArray = aSNL.getConstArray();
353     for ( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
354     {
355         if ( pArray[ i ] == ServiceName )
356             return sal_True;
357     }
358     return sal_False;
359 }
360 
361 //=========================================================================
362 // virtual
363 uno::Sequence< ::rtl::OUString > SAL_CALL
364 PasswordContainerInteractionHandler::getSupportedServiceNames()
365     throw ( uno::RuntimeException )
366 {
367     return getSupportedServiceNames_Static();
368 }
369 
370 //=========================================================================
371 // static
372 rtl::OUString
373 PasswordContainerInteractionHandler::getImplementationName_Static()
374 {
375     return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
376         "com.sun.star.comp.uui.PasswordContainerInteractionHandler" ) );
377 }
378 
379 //=========================================================================
380 // static
381 uno::Sequence< rtl::OUString >
382 PasswordContainerInteractionHandler::getSupportedServiceNames_Static()
383 {
384     uno::Sequence< rtl::OUString > aSNS( 1 );
385     aSNS.getArray()[ 0 ]
386         = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
387             "com.sun.star.task.PasswordContainerInteractionHandler" ) );
388     return aSNS;
389 }
390 
391 //=========================================================================
392 //
393 // XInteractionHandler methods.
394 //
395 //=========================================================================
396 
397 // virtual
398 void SAL_CALL
399 PasswordContainerInteractionHandler::handle(
400         const uno::Reference< task::XInteractionRequest >& rRequest )
401     throw ( uno::RuntimeException )
402 {
403     if ( !rRequest.is() )
404         return;
405 
406     uno::Any aAnyRequest( rRequest->getRequest() );
407 
408     ucb::AuthenticationRequest aAuthenticationRequest;
409     if ( !( aAnyRequest >>= aAuthenticationRequest ) )
410         return;
411 
412     rtl::OUString aURL;
413     ucb::URLAuthenticationRequest aURLAuthenticationRequest;
414     if ( aAnyRequest >>= aURLAuthenticationRequest )
415         aURL = aURLAuthenticationRequest.URL;
416 
417     uno::Sequence< uno::Reference< task::XInteractionContinuation > >
418         rContinuations = rRequest->getContinuations();
419 
420     uno::Reference< ucb::XInteractionSupplyAuthentication >
421         xSupplyAuthentication;
422 
423     for ( sal_Int32 i = 0; i < rContinuations.getLength(); ++i )
424     {
425         xSupplyAuthentication
426             = uno::Reference< ucb::XInteractionSupplyAuthentication >(
427                 rContinuations[i], uno::UNO_QUERY );
428         if( xSupplyAuthentication.is() )
429             break;
430     }
431 
432     if ( !xSupplyAuthentication.is() )
433         return;
434 
435     // Try to obatin credentials from password container.
436     if ( m_aPwContainerHelper.
437              handleAuthenticationRequest( aAuthenticationRequest,
438                                           xSupplyAuthentication,
439                                           aURL,
440                                           // @@@ FIXME: this not able to
441                                           // handle master pw request!
442                                           // master pw request is never
443                                           // solvable without UI!
444                                           this ) )
445     {
446         // successfully handled
447         xSupplyAuthentication->select();
448     }
449 }
450 
451 //=========================================================================
452 //
453 // Service factory implementation.
454 //
455 //=========================================================================
456 
457 static uno::Reference< uno::XInterface > SAL_CALL
458 PasswordContainerInteractionHandler_CreateInstance(
459         const uno::Reference< lang::XMultiServiceFactory> & rSMgr )
460     throw( uno::Exception )
461 {
462     lang::XServiceInfo * pX = static_cast< lang::XServiceInfo * >(
463         new PasswordContainerInteractionHandler( rSMgr ) );
464     return uno::Reference< uno::XInterface >::query( pX );
465 }
466 
467 //=========================================================================
468 // static
469 uno::Reference< lang::XSingleServiceFactory >
470 PasswordContainerInteractionHandler::createServiceFactory(
471     const uno::Reference< lang::XMultiServiceFactory >& rxServiceMgr )
472 {
473     return uno::Reference< lang::XSingleServiceFactory >(
474         cppu::createOneInstanceFactory(
475             rxServiceMgr,
476             PasswordContainerInteractionHandler::getImplementationName_Static(),
477             PasswordContainerInteractionHandler_CreateInstance,
478             PasswordContainerInteractionHandler::getSupportedServiceNames_Static() ) );
479 }
480 
481 } // namespace uui
482