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