summaryrefslogtreecommitdiffstats
path: root/mailnews/addrbook/src/nsAbLDAPListenerBase.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2019-11-03 00:17:46 -0400
committerMatt A. Tobin <email@mattatobin.com>2019-11-03 00:17:46 -0400
commit302bf1b523012e11b60425d6eee1221ebc2724eb (patch)
treeb191a895f8716efcbe42f454f37597a545a6f421 /mailnews/addrbook/src/nsAbLDAPListenerBase.cpp
parent21b3f6247403c06f85e1f45d219f87549862198f (diff)
downloadUXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.gz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.lz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.tar.xz
UXP-302bf1b523012e11b60425d6eee1221ebc2724eb.zip
Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1
Diffstat (limited to 'mailnews/addrbook/src/nsAbLDAPListenerBase.cpp')
-rw-r--r--mailnews/addrbook/src/nsAbLDAPListenerBase.cpp358
1 files changed, 358 insertions, 0 deletions
diff --git a/mailnews/addrbook/src/nsAbLDAPListenerBase.cpp b/mailnews/addrbook/src/nsAbLDAPListenerBase.cpp
new file mode 100644
index 000000000..e5465a7f5
--- /dev/null
+++ b/mailnews/addrbook/src/nsAbLDAPListenerBase.cpp
@@ -0,0 +1,358 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsAbLDAPListenerBase.h"
+#include "nsIWindowWatcher.h"
+#include "nsIWindowMediator.h"
+#include "mozIDOMWindow.h"
+#include "nsIAuthPrompt.h"
+#include "nsIStringBundle.h"
+#include "nsILDAPMessage.h"
+#include "nsILDAPErrors.h"
+#include "nsILoginManager.h"
+#include "nsILoginInfo.h"
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsMemory.h"
+#include "mozilla/Services.h"
+
+using namespace mozilla;
+
+nsAbLDAPListenerBase::nsAbLDAPListenerBase(nsILDAPURL* url,
+ nsILDAPConnection* connection,
+ const nsACString &login,
+ const int32_t timeOut) :
+ mDirectoryUrl(url), mConnection(connection), mLogin(login),
+ mTimeOut(timeOut), mBound(false), mInitialized(false),
+ mLock("nsAbLDAPListenerBase.mLock")
+{
+}
+
+nsAbLDAPListenerBase::~nsAbLDAPListenerBase()
+{
+}
+
+nsresult nsAbLDAPListenerBase::Initiate()
+{
+ if (!mConnection || !mDirectoryUrl)
+ return NS_ERROR_NULL_POINTER;
+
+ if (mInitialized)
+ return NS_OK;
+
+ mInitialized = true;
+
+ return NS_OK;
+}
+
+// If something fails in this function, we must call InitFailed() so that the
+// derived class (and listener) knows to cancel what its doing as there is
+// a problem.
+NS_IMETHODIMP nsAbLDAPListenerBase::OnLDAPInit(nsILDAPConnection *aConn, nsresult aStatus)
+{
+ if (!mConnection || !mDirectoryUrl)
+ {
+ InitFailed();
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ nsresult rv;
+ nsString passwd;
+
+ // Make sure that the Init() worked properly
+ if (NS_FAILED(aStatus))
+ {
+ InitFailed();
+ return NS_OK;
+ }
+
+ // If mLogin is set, we're expected to use it to get a password.
+ //
+ if (!mLogin.IsEmpty() && !mSaslMechanism.EqualsLiteral("GSSAPI"))
+ {
+ // get the string bundle service
+ //
+ nsCOMPtr<nsIStringBundleService> stringBundleSvc =
+ mozilla::services::GetStringBundleService();
+ if (!stringBundleSvc)
+ {
+ NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
+ " error getting string bundle service");
+ InitFailed();
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ // get the LDAP string bundle
+ //
+ nsCOMPtr<nsIStringBundle> ldapBundle;
+ rv = stringBundleSvc->CreateBundle("chrome://mozldap/locale/ldap.properties",
+ getter_AddRefs(ldapBundle));
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit(): error creating string"
+ "bundle chrome://mozldap/locale/ldap.properties");
+ InitFailed();
+ return rv;
+ }
+
+ // get the title for the authentication prompt
+ //
+ nsString authPromptTitle;
+ rv = ldapBundle->GetStringFromName(u"authPromptTitle",
+ getter_Copies(authPromptTitle));
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit(): error getting"
+ "'authPromptTitle' string from bundle "
+ "chrome://mozldap/locale/ldap.properties");
+ InitFailed();
+ return rv;
+ }
+
+ // get the host name for the auth prompt
+ //
+ nsAutoCString host;
+ rv = mDirectoryUrl->GetAsciiHost(host);
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit(): error getting ascii host"
+ "name from directory url");
+ InitFailed();
+ return rv;
+ }
+
+ // hostTemp is only necessary to work around a code-generation
+ // bug in egcs 1.1.2 (the version of gcc that comes with Red Hat 6.2),
+ // which is the default compiler for Mozilla on linux at the moment.
+ //
+ NS_ConvertASCIItoUTF16 hostTemp(host);
+ const char16_t *hostArray[1] = { hostTemp.get() };
+
+ // format the hostname into the authprompt text string
+ //
+ nsString authPromptText;
+ rv = ldapBundle->FormatStringFromName(u"authPromptText",
+ hostArray,
+ sizeof(hostArray) / sizeof(const char16_t *),
+ getter_Copies(authPromptText));
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
+ "error getting 'authPromptText' string from bundle "
+ "chrome://mozldap/locale/ldap.properties");
+ InitFailed();
+ return rv;
+ }
+
+ // get the window mediator service, so we can get an auth prompter
+ //
+ nsCOMPtr<nsIWindowMediator> windowMediator =
+ do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
+ " couldn't get window mediator service.");
+ InitFailed();
+ return rv;
+ }
+
+ // get the addressbook window, as it will be used to parent the auth
+ // prompter dialog
+ //
+ nsCOMPtr<mozIDOMWindowProxy> window;
+ rv = windowMediator->GetMostRecentWindow(nullptr,
+ getter_AddRefs(window));
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
+ " error getting most recent window");
+ InitFailed();
+ return rv;
+ }
+
+ // get the window watcher service, so we can get an auth prompter
+ //
+ nsCOMPtr<nsIWindowWatcher> windowWatcherSvc =
+ do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPListenerBase::OnLDAPInit():"
+ " couldn't get window watcher service.");
+ InitFailed();
+ return rv;
+ }
+
+ // get the auth prompter itself
+ //
+ nsCOMPtr<nsIAuthPrompt> authPrompter;
+ rv = windowWatcherSvc->GetNewAuthPrompter(window,
+ getter_AddRefs(authPrompter));
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit():"
+ " error getting auth prompter");
+ InitFailed();
+ return rv;
+ }
+
+ // get authentication password, prompting the user if necessary
+ //
+ // we're going to use the URL spec of the server as the "realm" for
+ // wallet to remember the password by / for.
+
+ // Get the specification
+ nsCString spec;
+ rv = mDirectoryUrl->GetSpec(spec);
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit():"
+ " error getting directory url spec");
+ InitFailed();
+ return rv;
+ }
+
+ bool status;
+ rv = authPrompter->PromptPassword(authPromptTitle.get(),
+ authPromptText.get(),
+ NS_ConvertUTF8toUTF16(spec).get(),
+ nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
+ getter_Copies(passwd),
+ &status);
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): failed to prompt for"
+ " password");
+ InitFailed();
+ return rv;
+ }
+ else if (!status)
+ {
+ InitFailed(true);
+ return NS_OK;
+ }
+ }
+
+ // Initiate the LDAP operation
+ mOperation = do_CreateInstance(NS_LDAPOPERATION_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): failed to create ldap operation");
+ InitFailed();
+ return rv;
+ }
+
+ rv = mOperation->Init(mConnection, this, nullptr);
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): failed to Initialise operation");
+ InitFailed();
+ return rv;
+ }
+
+ // Try non-password mechanisms first
+ if (mSaslMechanism.EqualsLiteral("GSSAPI"))
+ {
+ nsAutoCString service;
+ rv = mDirectoryUrl->GetAsciiHost(service);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ service.Insert(NS_LITERAL_CSTRING("ldap@"), 0);
+
+ nsCOMPtr<nsIAuthModule> authModule =
+ do_CreateInstance(NS_AUTH_MODULE_CONTRACTID_PREFIX "sasl-gssapi", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = mOperation->SaslBind(service, mSaslMechanism, authModule);
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): "
+ "failed to perform GSSAPI bind");
+ mOperation = nullptr; // Break Listener -> Operation -> Listener ref cycle
+ InitFailed();
+ }
+ return rv;
+ }
+
+ // Bind
+ rv = mOperation->SimpleBind(NS_ConvertUTF16toUTF8(passwd));
+ if (NS_FAILED(rv))
+ {
+ NS_ERROR("nsAbLDAPMessageBase::OnLDAPInit(): failed to perform bind operation");
+ mOperation = nullptr; // Break Listener->Operation->Listener reference cycle
+ InitFailed();
+ }
+ return rv;
+}
+
+nsresult nsAbLDAPListenerBase::OnLDAPMessageBind(nsILDAPMessage *aMessage)
+{
+ if (mBound)
+ return NS_OK;
+
+ // see whether the bind actually succeeded
+ //
+ int32_t errCode;
+ nsresult rv = aMessage->GetErrorCode(&errCode);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (errCode != nsILDAPErrors::SUCCESS)
+ {
+ // if the login failed, tell the wallet to forget this password
+ //
+ if (errCode == nsILDAPErrors::INAPPROPRIATE_AUTH ||
+ errCode == nsILDAPErrors::INVALID_CREDENTIALS)
+ {
+ // Login failed, so try again - but first remove the existing login(s)
+ // so that the user gets prompted. This may not be the best way of doing
+ // things, we need to review that later.
+
+ nsCOMPtr<nsILoginManager> loginMgr =
+ do_GetService(NS_LOGINMANAGER_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCString spec;
+ rv = mDirectoryUrl->GetSpec(spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCString prePath;
+ rv = mDirectoryUrl->GetPrePath(prePath);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t count;
+ nsILoginInfo** logins;
+
+ rv = loginMgr->FindLogins(&count, NS_ConvertUTF8toUTF16(prePath),
+ EmptyString(),
+ NS_ConvertUTF8toUTF16(spec), &logins);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Typically there should only be one-login stored for this url, however,
+ // just in case there isn't.
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ rv = loginMgr->RemoveLogin(logins[i]);
+ if (NS_FAILED(rv))
+ {
+ NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(count, logins);
+ return rv;
+ }
+ }
+ NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(count, logins);
+
+ // XXX We should probably pop up an error dialog telling
+ // the user that the login failed here, rather than just bringing
+ // up the password dialog again, which is what calling OnLDAPInit()
+ // does.
+ return OnLDAPInit(nullptr, NS_OK);
+ }
+
+ // Don't know how to handle this, so use the message error code in
+ // the failure return value so we hopefully get it back to the UI.
+ return NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_LDAP, errCode);
+ }
+
+ mBound = true;
+ return DoTask();
+}