From 58bb58557368c520e8a9368fcacff8d22466e759 Mon Sep 17 00:00:00 2001 From: Mili Verma Date: Wed, 8 Jul 2015 16:27:52 +0100 Subject: Use GSSAPI when SSO is used This patch uses the GSSAPI authenticator on Windows if the server advertises it and the client requests it. (The user is not able to request it in the UI yet) Also sends the manual port to the GSSAPI authenticator to construct the SPN if a non-default port is used. Test-information: Tested on Windows using WIP code. Tested both on TLS & without. Unit tests pass. Change-Id: I9a9ad9604fe084d5fb2003b7a91174a9512e2eec diff --git a/Swiften/Client/ClientOptions.h b/Swiften/Client/ClientOptions.h index 25393e4..c09b987 100644 --- a/Swiften/Client/ClientOptions.h +++ b/Swiften/Client/ClientOptions.h @@ -38,6 +38,7 @@ namespace Swift { useStreamResumption(false), forgetPassword(false), useAcks(true), + singleSignOn(false), manualHostname(""), manualPort(-1), proxyType(SystemConfiguredProxy), @@ -93,6 +94,12 @@ namespace Swift { bool useAcks; /** + * Use Single Sign On. + * Default: false + */ + bool singleSignOn; + + /** * The hostname to connect to. * Leave this empty for standard XMPP connection, based on the JID domain. */ diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index 26b89c4..52b8cfb 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Isode Limited. + * Copyright (c) 2010-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -47,6 +47,7 @@ #ifdef SWIFTEN_PLATFORM_WIN32 #include +#include #endif #define CHECK_STATE_OR_RETURN(a) \ @@ -73,7 +74,9 @@ ClientSession::ClientSession( needAcking(false), rosterVersioningSupported(false), authenticator(NULL), - certificateTrustChecker(NULL) { + certificateTrustChecker(NULL), + singleSignOn(false), + authenticationPort(-1) { #ifdef SWIFTEN_PLATFORM_WIN32 if (WindowsRegistry::isFIPSEnabled()) { SWIFT_LOG(info) << "Windows is running in FIPS-140 mode. Some authentication methods will be unavailable." << std::endl; @@ -204,6 +207,32 @@ void ClientSession::handleElement(boost::shared_ptr element) { stream->writeElement(boost::make_shared("zlib")); } else if (streamFeatures->hasAuthenticationMechanisms()) { +#ifdef SWIFTEN_PLATFORM_WIN32 + if (singleSignOn) { + const boost::optional authenticationHostname = streamFeatures->getAuthenticationHostname(); + bool gssapiSupported = streamFeatures->hasAuthenticationMechanism("GSSAPI") && authenticationHostname && !authenticationHostname->empty(); + + if (!gssapiSupported) { + finishSession(Error::NoSupportedAuthMechanismsError); + } + else { + WindowsGSSAPIClientAuthenticator* gssapiAuthenticator = new WindowsGSSAPIClientAuthenticator(*authenticationHostname, localJID.getDomain(), authenticationPort); + boost::shared_ptr error = boost::make_shared(Error::AuthenticationFailedError); + + authenticator = gssapiAuthenticator; + + if (!gssapiAuthenticator->isError()) { + state = Authenticating; + stream->writeElement(boost::make_shared(authenticator->getName(), authenticator->getResponse())); + } + else { + error->errorCode = gssapiAuthenticator->getErrorCode(); + finishSession(error); + } + } + } + else +#endif if (stream->hasTLSCertificate()) { if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) { authenticator = new EXTERNALClientAuthenticator(); @@ -298,6 +327,14 @@ void ClientSession::handleElement(boost::shared_ptr element) { if (authenticator->setChallenge(challenge->getValue())) { stream->writeElement(boost::make_shared(authenticator->getResponse())); } +#ifdef SWIFTEN_PLATFORM_WIN32 + else if (WindowsGSSAPIClientAuthenticator* gssapiAuthenticator = dynamic_cast(authenticator)) { + boost::shared_ptr error = boost::make_shared(Error::AuthenticationFailedError); + + error->errorCode = gssapiAuthenticator->getErrorCode(); + finishSession(error); + } +#endif else { finishSession(Error::AuthenticationFailedError); } diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h index 9bbc3f2..c4b6abe 100644 --- a/Swiften/Client/ClientSession.h +++ b/Swiften/Client/ClientSession.h @@ -126,6 +126,18 @@ namespace Swift { certificateTrustChecker = checker; } + void setSingleSignOn(bool b) { + singleSignOn = b; + } + + /** + * Sets the port number used in Kerberos authentication + * Does not affect network connectivity. + */ + void setAuthenticationPort(int i) { + authenticationPort = i; + } + public: boost::signal onNeedCredentials; boost::signal onInitialized; @@ -183,5 +195,7 @@ namespace Swift { boost::shared_ptr stanzaAckResponder_; boost::shared_ptr error_; CertificateTrustChecker* certificateTrustChecker; + bool singleSignOn; + int authenticationPort; }; } diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index baebd4a..b1a375b 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -152,6 +152,8 @@ void CoreClient::bindSessionToStream() { session_->setCertificateTrustChecker(certificateTrustChecker); session_->setUseStreamCompression(options.useStreamCompression); session_->setAllowPLAINOverNonTLS(options.allowPLAINWithoutTLS); + session_->setSingleSignOn(options.singleSignOn); + session_->setAuthenticationPort(options.manualPort); switch(options.useTLS) { case ClientOptions::UseTLSWhenAvailable: session_->setUseTLS(ClientSession::UseTLSWhenAvailable); diff --git a/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp b/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp index 7423243..f602bff 100644 --- a/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp +++ b/Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp @@ -14,9 +14,12 @@ namespace Swift { -WindowsGSSAPIClientAuthenticator::WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname) : ClientAuthenticator("GSSAPI"), step_(BuildingSecurityContext), error_(false), haveCredentialsHandle_(false), haveContextHandle_(false), haveCompleteContext_(false) { +WindowsGSSAPIClientAuthenticator::WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname, int port) : ClientAuthenticator("GSSAPI"), step_(BuildingSecurityContext), error_(false), haveCredentialsHandle_(false), haveContextHandle_(false), haveCompleteContext_(false) { WindowsServicePrincipalName servicePrincipalName(domainname); servicePrincipalName.setInstanceName(hostname); + if ((port != -1) && (port != 5222)) { + servicePrincipalName.setInstancePort(port); + } servicePrincipalNameString_ = servicePrincipalName.toString(); errorCode_ = acquireCredentialsHandle(&credentialsHandle_); diff --git a/Swiften/SASL/WindowsGSSAPIClientAuthenticator.h b/Swiften/SASL/WindowsGSSAPIClientAuthenticator.h index d046999..f772b71 100644 --- a/Swiften/SASL/WindowsGSSAPIClientAuthenticator.h +++ b/Swiften/SASL/WindowsGSSAPIClientAuthenticator.h @@ -20,7 +20,7 @@ namespace Swift { class SWIFTEN_API WindowsGSSAPIClientAuthenticator : public ClientAuthenticator { public: - WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname); + WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname, int port); ~WindowsGSSAPIClientAuthenticator(); -- cgit v0.10.2-6-g49f6