diff options
| author | Mili Verma <mili.verma@isode.com> | 2015-07-08 15:27:52 (GMT) |
|---|---|---|
| committer | Mili Verma <mili.verma@isode.com> | 2015-07-08 15:33:09 (GMT) |
| commit | 58bb58557368c520e8a9368fcacff8d22466e759 (patch) | |
| tree | bfd8bb3b93ab771482fe46e1d558f4ad399bdaa1 | |
| parent | 0e6beadc1b4427e8ab5109e52872f99a5f85c3d8 (diff) | |
| download | swift-58bb58557368c520e8a9368fcacff8d22466e759.zip swift-58bb58557368c520e8a9368fcacff8d22466e759.tar.bz2 | |
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
| -rw-r--r-- | Swiften/Client/ClientOptions.h | 7 | ||||
| -rw-r--r-- | Swiften/Client/ClientSession.cpp | 41 | ||||
| -rw-r--r-- | Swiften/Client/ClientSession.h | 14 | ||||
| -rw-r--r-- | Swiften/Client/CoreClient.cpp | 2 | ||||
| -rw-r--r-- | Swiften/SASL/WindowsGSSAPIClientAuthenticator.cpp | 5 | ||||
| -rw-r--r-- | Swiften/SASL/WindowsGSSAPIClientAuthenticator.h | 2 |
6 files changed, 67 insertions, 4 deletions
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 | |||
| @@ -36,10 +36,11 @@ namespace Swift { | |||
| 36 | useTLS(UseTLSWhenAvailable), | 36 | useTLS(UseTLSWhenAvailable), |
| 37 | allowPLAINWithoutTLS(false), | 37 | allowPLAINWithoutTLS(false), |
| 38 | useStreamResumption(false), | 38 | useStreamResumption(false), |
| 39 | forgetPassword(false), | 39 | forgetPassword(false), |
| 40 | useAcks(true), | 40 | useAcks(true), |
| 41 | singleSignOn(false), | ||
| 41 | manualHostname(""), | 42 | manualHostname(""), |
| 42 | manualPort(-1), | 43 | manualPort(-1), |
| 43 | proxyType(SystemConfiguredProxy), | 44 | proxyType(SystemConfiguredProxy), |
| 44 | manualProxyHostname(""), | 45 | manualProxyHostname(""), |
| 45 | manualProxyPort(-1), | 46 | manualProxyPort(-1), |
| @@ -91,10 +92,16 @@ namespace Swift { | |||
| 91 | * Default: true | 92 | * Default: true |
| 92 | */ | 93 | */ |
| 93 | bool useAcks; | 94 | bool useAcks; |
| 94 | 95 | ||
| 95 | /** | 96 | /** |
| 97 | * Use Single Sign On. | ||
| 98 | * Default: false | ||
| 99 | */ | ||
| 100 | bool singleSignOn; | ||
| 101 | |||
| 102 | /** | ||
| 96 | * The hostname to connect to. | 103 | * The hostname to connect to. |
| 97 | * Leave this empty for standard XMPP connection, based on the JID domain. | 104 | * Leave this empty for standard XMPP connection, based on the JID domain. |
| 98 | */ | 105 | */ |
| 99 | std::string manualHostname; | 106 | std::string manualHostname; |
| 100 | 107 | ||
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,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2010-2014 Isode Limited. | 2 | * Copyright (c) 2010-2015 Isode Limited. |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * See the COPYING file for more information. | 4 | * See the COPYING file for more information. |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <Swiften/Client/ClientSession.h> | 7 | #include <Swiften/Client/ClientSession.h> |
| @@ -45,10 +45,11 @@ | |||
| 45 | #include <Swiften/TLS/CertificateTrustChecker.h> | 45 | #include <Swiften/TLS/CertificateTrustChecker.h> |
| 46 | #include <Swiften/TLS/ServerIdentityVerifier.h> | 46 | #include <Swiften/TLS/ServerIdentityVerifier.h> |
| 47 | 47 | ||
| 48 | #ifdef SWIFTEN_PLATFORM_WIN32 | 48 | #ifdef SWIFTEN_PLATFORM_WIN32 |
| 49 | #include <Swiften/Base/WindowsRegistry.h> | 49 | #include <Swiften/Base/WindowsRegistry.h> |
| 50 | #include <Swiften/SASL/WindowsGSSAPIClientAuthenticator.h> | ||
| 50 | #endif | 51 | #endif |
| 51 | 52 | ||
| 52 | #define CHECK_STATE_OR_RETURN(a) \ | 53 | #define CHECK_STATE_OR_RETURN(a) \ |
| 53 | if (!checkState(a)) { return; } | 54 | if (!checkState(a)) { return; } |
| 54 | 55 | ||
| @@ -71,11 +72,13 @@ ClientSession::ClientSession( | |||
| 71 | needSessionStart(false), | 72 | needSessionStart(false), |
| 72 | needResourceBind(false), | 73 | needResourceBind(false), |
| 73 | needAcking(false), | 74 | needAcking(false), |
| 74 | rosterVersioningSupported(false), | 75 | rosterVersioningSupported(false), |
| 75 | authenticator(NULL), | 76 | authenticator(NULL), |
| 76 | certificateTrustChecker(NULL) { | 77 | certificateTrustChecker(NULL), |
| 78 | singleSignOn(false), | ||
| 79 | authenticationPort(-1) { | ||
| 77 | #ifdef SWIFTEN_PLATFORM_WIN32 | 80 | #ifdef SWIFTEN_PLATFORM_WIN32 |
| 78 | if (WindowsRegistry::isFIPSEnabled()) { | 81 | if (WindowsRegistry::isFIPSEnabled()) { |
| 79 | SWIFT_LOG(info) << "Windows is running in FIPS-140 mode. Some authentication methods will be unavailable." << std::endl; | 82 | SWIFT_LOG(info) << "Windows is running in FIPS-140 mode. Some authentication methods will be unavailable." << std::endl; |
| 80 | } | 83 | } |
| 81 | #endif | 84 | #endif |
| @@ -202,10 +205,36 @@ void ClientSession::handleElement(boost::shared_ptr<ToplevelElement> element) { | |||
| 202 | else if (useStreamCompression && stream->supportsZLibCompression() && streamFeatures->hasCompressionMethod("zlib")) { | 205 | else if (useStreamCompression && stream->supportsZLibCompression() && streamFeatures->hasCompressionMethod("zlib")) { |
| 203 | state = Compressing; | 206 | state = Compressing; |
| 204 | stream->writeElement(boost::make_shared<CompressRequest>("zlib")); | 207 | stream->writeElement(boost::make_shared<CompressRequest>("zlib")); |
| 205 | } | 208 | } |
| 206 | else if (streamFeatures->hasAuthenticationMechanisms()) { | 209 | else if (streamFeatures->hasAuthenticationMechanisms()) { |
| 210 | #ifdef SWIFTEN_PLATFORM_WIN32 | ||
| 211 | if (singleSignOn) { | ||
| 212 | const boost::optional<std::string> authenticationHostname = streamFeatures->getAuthenticationHostname(); | ||
| 213 | bool gssapiSupported = streamFeatures->hasAuthenticationMechanism("GSSAPI") && authenticationHostname && !authenticationHostname->empty(); | ||
| 214 | |||
| 215 | if (!gssapiSupported) { | ||
| 216 | finishSession(Error::NoSupportedAuthMechanismsError); | ||
| 217 | } | ||
| 218 | else { | ||
| 219 | WindowsGSSAPIClientAuthenticator* gssapiAuthenticator = new WindowsGSSAPIClientAuthenticator(*authenticationHostname, localJID.getDomain(), authenticationPort); | ||
| 220 | boost::shared_ptr<Error> error = boost::make_shared<Error>(Error::AuthenticationFailedError); | ||
| 221 | |||
| 222 | authenticator = gssapiAuthenticator; | ||
| 223 | |||
| 224 | if (!gssapiAuthenticator->isError()) { | ||
| 225 | state = Authenticating; | ||
| 226 | stream->writeElement(boost::make_shared<AuthRequest>(authenticator->getName(), authenticator->getResponse())); | ||
| 227 | } | ||
| 228 | else { | ||
| 229 | error->errorCode = gssapiAuthenticator->getErrorCode(); | ||
| 230 | finishSession(error); | ||
| 231 | } | ||
| 232 | } | ||
| 233 | } | ||
| 234 | else | ||
| 235 | #endif | ||
| 207 | if (stream->hasTLSCertificate()) { | 236 | if (stream->hasTLSCertificate()) { |
| 208 | if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) { | 237 | if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) { |
| 209 | authenticator = new EXTERNALClientAuthenticator(); | 238 | authenticator = new EXTERNALClientAuthenticator(); |
| 210 | state = Authenticating; | 239 | state = Authenticating; |
| 211 | stream->writeElement(boost::make_shared<AuthRequest>("EXTERNAL", createSafeByteArray(""))); | 240 | stream->writeElement(boost::make_shared<AuthRequest>("EXTERNAL", createSafeByteArray(""))); |
| @@ -296,10 +325,18 @@ void ClientSession::handleElement(boost::shared_ptr<ToplevelElement> element) { | |||
| 296 | CHECK_STATE_OR_RETURN(Authenticating); | 325 | CHECK_STATE_OR_RETURN(Authenticating); |
| 297 | assert(authenticator); | 326 | assert(authenticator); |
| 298 | if (authenticator->setChallenge(challenge->getValue())) { | 327 | if (authenticator->setChallenge(challenge->getValue())) { |
| 299 | stream->writeElement(boost::make_shared<AuthResponse>(authenticator->getResponse())); | 328 | stream->writeElement(boost::make_shared<AuthResponse>(authenticator->getResponse())); |
| 300 | } | 329 | } |
| 330 | #ifdef SWIFTEN_PLATFORM_WIN32 | ||
| 331 | else if (WindowsGSSAPIClientAuthenticator* gssapiAuthenticator = dynamic_cast<WindowsGSSAPIClientAuthenticator*>(authenticator)) { | ||
| 332 | boost::shared_ptr<Error> error = boost::make_shared<Error>(Error::AuthenticationFailedError); | ||
| 333 | |||
| 334 | error->errorCode = gssapiAuthenticator->getErrorCode(); | ||
| 335 | finishSession(error); | ||
| 336 | } | ||
| 337 | #endif | ||
| 301 | else { | 338 | else { |
| 302 | finishSession(Error::AuthenticationFailedError); | 339 | finishSession(Error::AuthenticationFailedError); |
| 303 | } | 340 | } |
| 304 | } | 341 | } |
| 305 | else if (AuthSuccess* authSuccess = dynamic_cast<AuthSuccess*>(element.get())) { | 342 | else if (AuthSuccess* authSuccess = dynamic_cast<AuthSuccess*>(element.get())) { |
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 | |||
| @@ -124,10 +124,22 @@ namespace Swift { | |||
| 124 | 124 | ||
| 125 | void setCertificateTrustChecker(CertificateTrustChecker* checker) { | 125 | void setCertificateTrustChecker(CertificateTrustChecker* checker) { |
| 126 | certificateTrustChecker = checker; | 126 | certificateTrustChecker = checker; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | void setSingleSignOn(bool b) { | ||
| 130 | singleSignOn = b; | ||
| 131 | } | ||
| 132 | |||
| 133 | /** | ||
| 134 | * Sets the port number used in Kerberos authentication | ||
| 135 | * Does not affect network connectivity. | ||
| 136 | */ | ||
| 137 | void setAuthenticationPort(int i) { | ||
| 138 | authenticationPort = i; | ||
| 139 | } | ||
| 140 | |||
| 129 | public: | 141 | public: |
| 130 | boost::signal<void ()> onNeedCredentials; | 142 | boost::signal<void ()> onNeedCredentials; |
| 131 | boost::signal<void ()> onInitialized; | 143 | boost::signal<void ()> onInitialized; |
| 132 | boost::signal<void (boost::shared_ptr<Swift::Error>)> onFinished; | 144 | boost::signal<void (boost::shared_ptr<Swift::Error>)> onFinished; |
| 133 | boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaReceived; | 145 | boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaReceived; |
| @@ -181,7 +193,9 @@ namespace Swift { | |||
| 181 | ClientAuthenticator* authenticator; | 193 | ClientAuthenticator* authenticator; |
| 182 | boost::shared_ptr<StanzaAckRequester> stanzaAckRequester_; | 194 | boost::shared_ptr<StanzaAckRequester> stanzaAckRequester_; |
| 183 | boost::shared_ptr<StanzaAckResponder> stanzaAckResponder_; | 195 | boost::shared_ptr<StanzaAckResponder> stanzaAckResponder_; |
| 184 | boost::shared_ptr<Swift::Error> error_; | 196 | boost::shared_ptr<Swift::Error> error_; |
| 185 | CertificateTrustChecker* certificateTrustChecker; | 197 | CertificateTrustChecker* certificateTrustChecker; |
| 198 | bool singleSignOn; | ||
| 199 | int authenticationPort; | ||
| 186 | }; | 200 | }; |
| 187 | } | 201 | } |
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 | |||
| @@ -150,10 +150,12 @@ void CoreClient::connect(const ClientOptions& o) { | |||
| 150 | void CoreClient::bindSessionToStream() { | 150 | void CoreClient::bindSessionToStream() { |
| 151 | session_ = ClientSession::create(jid_, sessionStream_, networkFactories->getIDNConverter(), networkFactories->getCryptoProvider()); | 151 | session_ = ClientSession::create(jid_, sessionStream_, networkFactories->getIDNConverter(), networkFactories->getCryptoProvider()); |
| 152 | session_->setCertificateTrustChecker(certificateTrustChecker); | 152 | session_->setCertificateTrustChecker(certificateTrustChecker); |
| 153 | session_->setUseStreamCompression(options.useStreamCompression); | 153 | session_->setUseStreamCompression(options.useStreamCompression); |
| 154 | session_->setAllowPLAINOverNonTLS(options.allowPLAINWithoutTLS); | 154 | session_->setAllowPLAINOverNonTLS(options.allowPLAINWithoutTLS); |
| 155 | session_->setSingleSignOn(options.singleSignOn); | ||
| 156 | session_->setAuthenticationPort(options.manualPort); | ||
| 155 | switch(options.useTLS) { | 157 | switch(options.useTLS) { |
| 156 | case ClientOptions::UseTLSWhenAvailable: | 158 | case ClientOptions::UseTLSWhenAvailable: |
| 157 | session_->setUseTLS(ClientSession::UseTLSWhenAvailable); | 159 | session_->setUseTLS(ClientSession::UseTLSWhenAvailable); |
| 158 | break; | 160 | break; |
| 159 | case ClientOptions::NeverUseTLS: | 161 | case ClientOptions::NeverUseTLS: |
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 | |||
| @@ -12,13 +12,16 @@ | |||
| 12 | 12 | ||
| 13 | #define SECURITY_LAYER_NONE 1 | 13 | #define SECURITY_LAYER_NONE 1 |
| 14 | 14 | ||
| 15 | namespace Swift { | 15 | namespace Swift { |
| 16 | 16 | ||
| 17 | WindowsGSSAPIClientAuthenticator::WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname) : ClientAuthenticator("GSSAPI"), step_(BuildingSecurityContext), error_(false), haveCredentialsHandle_(false), haveContextHandle_(false), haveCompleteContext_(false) { | 17 | WindowsGSSAPIClientAuthenticator::WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname, int port) : ClientAuthenticator("GSSAPI"), step_(BuildingSecurityContext), error_(false), haveCredentialsHandle_(false), haveContextHandle_(false), haveCompleteContext_(false) { |
| 18 | WindowsServicePrincipalName servicePrincipalName(domainname); | 18 | WindowsServicePrincipalName servicePrincipalName(domainname); |
| 19 | servicePrincipalName.setInstanceName(hostname); | 19 | servicePrincipalName.setInstanceName(hostname); |
| 20 | if ((port != -1) && (port != 5222)) { | ||
| 21 | servicePrincipalName.setInstancePort(port); | ||
| 22 | } | ||
| 20 | servicePrincipalNameString_ = servicePrincipalName.toString(); | 23 | servicePrincipalNameString_ = servicePrincipalName.toString(); |
| 21 | 24 | ||
| 22 | errorCode_ = acquireCredentialsHandle(&credentialsHandle_); | 25 | errorCode_ = acquireCredentialsHandle(&credentialsHandle_); |
| 23 | if (isError()) { | 26 | if (isError()) { |
| 24 | return; | 27 | return; |
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 | |||
| @@ -18,11 +18,11 @@ | |||
| 18 | #include <Swiften/SASL/ClientAuthenticator.h> | 18 | #include <Swiften/SASL/ClientAuthenticator.h> |
| 19 | 19 | ||
| 20 | namespace Swift { | 20 | namespace Swift { |
| 21 | class SWIFTEN_API WindowsGSSAPIClientAuthenticator : public ClientAuthenticator { | 21 | class SWIFTEN_API WindowsGSSAPIClientAuthenticator : public ClientAuthenticator { |
| 22 | public: | 22 | public: |
| 23 | WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname); | 23 | WindowsGSSAPIClientAuthenticator(const std::string& hostname, const std::string& domainname, int port); |
| 24 | 24 | ||
| 25 | ~WindowsGSSAPIClientAuthenticator(); | 25 | ~WindowsGSSAPIClientAuthenticator(); |
| 26 | 26 | ||
| 27 | virtual boost::optional<SafeByteArray> getResponse() const; | 27 | virtual boost::optional<SafeByteArray> getResponse() const; |
| 28 | virtual bool setChallenge(const boost::optional<std::vector<unsigned char> >&); | 28 | virtual bool setChallenge(const boost::optional<std::vector<unsigned char> >&); |
Swift