Kerberos authentication

Jan Safranek <[email protected]> Thu, 06 Mar 2014 16:39:23 +0100
Newsgroups gmane.network.open-pegasus.general
Message-ID <[email protected]>
I've implemented SPNEGO-based authentication into Pegasus client and
server, as described in RFC 4559. This RFC is used in WS-MAN world,
especially on Microsoft Windows and it fits WBEM pretty nicely - it's
just HTTP, after all.

There already are some non-compilable leftovers of Kerberos
authentication spread across current Pegasus sources (look for #ifdef
PEGASUS_KERBEROS_AUTHENTICATION). Are these parts still used? Were they
ever working?

My implementation introduces PEGASUS_SPNEGO_AUTHENTICATION, so it can be
easily compared with PEGASUS_KERBEROS_AUTHENTICATION code. I've checked
that it works on Linux (Fedora 20) with MIT Kerberos, but any GSSAPI
implementation should work.

Still, there is lot of work to do:

1. If the old PEGASUS_KERBEROS_AUTHENTICATION code is not working/used,
it should be removed.

2. If I look at the old PEGASUS_KERBEROS_AUTHENTICATION code, I can see
that after the initial authentication, the actual HTTP data were
encrypted into WWW-Authenticate: and Authorize: headers using Kerberos.
Is it really needed? Pegasus already supports HTTPS for confidentiality,
in my opinion we do not need another style of encryption.

3. There should be probably some setting to set Kerberos service name
and set path to keytab file, currently it's taken from environment
variable. What is the process of introducing new configuration options?

4. The implementation uses GSSAPI, as described by RFC 2743. If there is
a platform, which uses different API for Kerberos,
Pegasus/Common/Kerberos.cpp should be split into platform-independent
part + implementations for each platform. Can someone check if all the
platform Pegasus supports have some sort of GSSAPI? Especially MS Windows.

5. I was not able to enable tracing in Pegasus Client library. How to do
it? It would be nice to have some debug logs to see how the
authentication proceeds on the client side.

See the preliminary version of my patch attached (apply to current CVS
HEAD). It is not final version, I will update it based on your feedback
and answers to 1. - 5.

Jan
kerberos-1.patch (text/x-patch, 47.5 KB)
commit 10197be0aa6d0715044336f3e78d14de097c80a4
Author: Jan Safranek <[email protected]>
Date:   Thu Feb 27 14:06:04 2014 +0100

    Implement GSSAPI.

diff --git a/env_var_Linux.status b/env_var_Linux.status
index ecc1fe6..d41ccf0 100644
--- a/env_var_Linux.status
+++ b/env_var_Linux.status
@@ -6,6 +6,8 @@ PEGASUS_ENABLE_MAKE_INSTALL = yes
 #OPENSSL_BIN=
 #PEGASUS_PLATFORM=
 
+PEGASUS_SPNEGO_AUTHENTICATION=yes
+
 PEGASUS_OVERRIDE_PRODUCT_ID=yes
 PEGASUS_OVERRIDE_DEFAULT_RELEASE_DIRS=yes
 PEGASUS_PRODUCT_NAME="OpenPegasus"
diff --git a/mak/config-linux.mak b/mak/config-linux.mak
index 73e3da2..6b07885 100644
--- a/mak/config-linux.mak
+++ b/mak/config-linux.mak
@@ -41,6 +41,8 @@ PEGASUS_PLATFORM_LINUX_GENERIC_GNU = 1
 DEFINES += -DPEGASUS_PLATFORM_LINUX_GENERIC_GNU
 DEFINES += -DPEGASUS_PLATFORM_$(PEGASUS_PLATFORM)
 
+PEGASUS_SPNEGO_AUTHENTICATION=true
+
 #########################################################################
 ##
 ## Platform specific compile options controlled by environment variables
diff --git a/mak/config.mak b/mak/config.mak
index 3e8b740..a34f28b 100644
--- a/mak/config.mak
+++ b/mak/config.mak
@@ -1414,6 +1414,21 @@ endif
 
 ##==============================================================================
 ##
+## PEGASUS_SPNEGO_AUTHENTICATION
+##
+##==============================================================================
+
+ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    # Compile in the code required for PAM authentication
+    # and compile out the code that uses the password file.
+    DEFINES += -DPEGASUS_SPNEGO_AUTHENTICATION
+
+    # Link with MIT Kerberos
+    SYS_LIBS += -lgssapi_krb5
+endif
+
+##==============================================================================
+##
 ## PEGASUS_USE_PAM_STANDALONE_PROC
 ##
 ##==============================================================================
diff --git a/src/Pegasus/Client/CIMClientRep.cpp b/src/Pegasus/Client/CIMClientRep.cpp
index 5933235..1031d45 100644
--- a/src/Pegasus/Client/CIMClientRep.cpp
+++ b/src/Pegasus/Client/CIMClientRep.cpp
@@ -84,6 +84,8 @@ void CIMClientRep::_connect(bool binaryRequest, bool binaryResponse)
 {
     ClientTrace::setup();
 
+    _authenticator.setHost(_connectHost);
+
     //
     // Create response decoder:
     //
diff --git a/src/Pegasus/Client/ClientAuthenticator.cpp b/src/Pegasus/Client/ClientAuthenticator.cpp
index 62a797b..f3bbbab 100644
--- a/src/Pegasus/Client/ClientAuthenticator.cpp
+++ b/src/Pegasus/Client/ClientAuthenticator.cpp
@@ -67,6 +67,11 @@ static const String BASIC_AUTH_HEADER = "Authorization: Basic ";
 static const String DIGEST_AUTH_HEADER = "Authorization: Digest ";
 
 /**
+    Constant representing the Negotiate authentication header.
+*/
+static const String NEGOTIATE_AUTH_HEADER = "Authorization: Negotiate ";
+
+/**
     Constant representing the local authentication header.
 */
 static const String LOCAL_AUTH_HEADER = "PegasusAuthorization: Local";
@@ -83,6 +88,9 @@ ClientAuthenticator::~ClientAuthenticator()
 
 void ClientAuthenticator::clear()
 {
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    _session.reset(new KerberosClientSession(String::EMPTY));
+#endif
     _requestMessage.reset();
     _userName.clear();
     _password.clear();
@@ -100,6 +108,7 @@ Boolean ClientAuthenticator::checkResponseHeaderForChallenge(
     //
     const char* authHeader;
     String authType;
+    String authChallenge;
     String authRealm;
 
     if (!HTTPMessage::lookupHeader(
@@ -108,66 +117,83 @@ Boolean ClientAuthenticator::checkResponseHeaderForChallenge(
         return false;
     }
 
-    if (_challengeReceived)
-    {
-        // Do not respond to a challenge more than once
-        return false;
-    }
-    else
-    {
-       _challengeReceived = true;
+   //
+   // Parse the authentication challenge header
+   //
+   if (!_parseAuthHeader(authHeader, authType, authChallenge))
+   {
+       throw InvalidAuthHeader();
+   }
 
-       //
-       // Parse the authentication challenge header
-       //
-       if (!_parseAuthHeader(authHeader, authType, authRealm))
-       {
-           throw InvalidAuthHeader();
-       }
+   if (String::equal(authType, "Local"))
+   {
+       _authType = ClientAuthenticator::LOCAL;
+       authRealm = _parseBasicRealm(authChallenge);
+       if (authRealm.size() == 0)
+           return false;
+   }
+   else if ( String::equal(authType, "Basic"))
+   {
+       _authType = ClientAuthenticator::BASIC;
+       authRealm = _parseBasicRealm(authChallenge);
+       if (authRealm.size() == 0)
+           return false;
+   }
+   else if ( String::equal(authType, "Digest"))
+   {
+       _authType = ClientAuthenticator::DIGEST;
+   }
+   else if ( String::equal(authType, "Negotiate"))
+   {
+       _authType = ClientAuthenticator::NEGOTIATE;
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+       _session->parseChallenge(authChallenge);
+#endif
+   }
+   else
+   {
+       throw InvalidAuthHeader();
+   }
 
-       if (String::equal(authType, "Local"))
-       {
-           _authType = ClientAuthenticator::LOCAL;
-       }
-       else if ( String::equal(authType, "Basic"))
+   if (_challengeReceived)
+   {
+       // Do not respond to a challenge more than once.
+       // Only Negotiate authentication can take multiple roundtrips,
+       // but stop it when the server returns empty challenge.
+       if (_authType != ClientAuthenticator::NEGOTIATE
+               || authChallenge.size() == 0)
        {
-           _authType = ClientAuthenticator::BASIC;
-       }
-       else if ( String::equal(authType, "Digest"))
-       {
-           _authType = ClientAuthenticator::DIGEST;
-       }
-       else
-       {
-           throw InvalidAuthHeader();
+           return false;
        }
+   }
 
-       if (_authType == ClientAuthenticator::LOCAL)
-       {
-           String filePath = authRealm;
-           FileSystem::translateSlashes(filePath);
+   _challengeReceived = true;
 
-           // Check whether the directory is a valid pre-defined directory.
-           //
-           Uint32 index = filePath.reverseFind('/');
+   if (_authType == ClientAuthenticator::LOCAL)
+   {
+       String filePath = authRealm;
+       FileSystem::translateSlashes(filePath);
 
-           if (index != PEG_NOT_FOUND)
+       // Check whether the directory is a valid pre-defined directory.
+       //
+       Uint32 index = filePath.reverseFind('/');
+
+       if (index != PEG_NOT_FOUND)
+       {
+           String dirName = filePath.subString(0,index);
+
+           if (!String::equal(dirName, String(PEGASUS_LOCAL_AUTH_DIR)))
            {
-               String dirName = filePath.subString(0,index);
-
-               if (!String::equal(dirName, String(PEGASUS_LOCAL_AUTH_DIR)))
-               {
-                   // Refuse to respond to the challenge when the file is
-                   // not in the expected directory
-                   return false;
-               }
+               // Refuse to respond to the challenge when the file is
+               // not in the expected directory
+               return false;
            }
-
-           _localAuthFile = authRealm;
        }
 
-       return true;
+       _localAuthFile = authRealm;
    }
+
+   return true;
 }
 
 
@@ -230,6 +256,13 @@ String ClientAuthenticator::buildRequestAuthHeader()
         //    }
             break;
 
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+        case ClientAuthenticator::NEGOTIATE:
+            challengeResponse = NEGOTIATE_AUTH_HEADER;
+            challengeResponse.append(_session->buildRequestAuthData());
+            break;
+#endif
+
         case ClientAuthenticator::LOCAL:
 
             challengeResponse = LOCAL_AUTH_HEADER;
@@ -303,11 +336,19 @@ void ClientAuthenticator::setPassword(const String& password)
     _password = password;
 }
 
+void ClientAuthenticator::setHost(const String& host)
+{
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    _session.reset(new KerberosClientSession(host));
+#endif
+}
+
 void ClientAuthenticator::setAuthType(ClientAuthenticator::AuthType type)
 {
     PEGASUS_ASSERT( (type == ClientAuthenticator::BASIC) ||
          (type == ClientAuthenticator::DIGEST) ||
          (type == ClientAuthenticator::LOCAL) ||
+         (type == ClientAuthenticator::NEGOTIATE) ||
          (type == ClientAuthenticator::NONE) );
 
     _authType = type;
@@ -395,7 +436,7 @@ String ClientAuthenticator::_buildLocalAuthResponse()
 Boolean ClientAuthenticator::_parseAuthHeader(
     const char* authHeader,
     String& authType,
-    String& authRealm)
+    String& authChallenge)
 {
     //
     // Skip the white spaces in the begining of the header
@@ -415,29 +456,42 @@ Boolean ClientAuthenticator::_parseAuthHeader(
         return false;
     }
 
-    //
-    // Ignore the start quote
-    //
-    _getSubStringUptoMarker(&authHeader, CHAR_QUOTE);
-
+    // skip any spaces between authentication type and data
+    while (*authHeader && isspace(*authHeader))
+    {
+        ++authHeader;
+    }
 
-    //
-    // Get the realm ending with a quote
-    //
-    String realm = _getSubStringUptoMarker(&authHeader, CHAR_QUOTE);
+    // the rest is challenge
+    String challenge(authHeader);
 
-    if (!realm.size())
+    // There must be challenge in the header.
+    // Except Negotiate authentication, where the first 401 Unauthorized
+    // has no challenge.
+    if (!challenge.size() && !String::equal(type, "Negotiate"))
     {
         return false;
     }
 
     authType = type;
 
-    authRealm = realm;
+    authChallenge= challenge;
 
     return true;
 }
 
+String ClientAuthenticator::_parseBasicRealm(const String &challenge)
+{
+    CString str = challenge.getCString();
+    const char *challengeStr = str;
+    //
+    // Ignore everything up to the start quote
+    //
+    _getSubStringUptoMarker(&challengeStr, CHAR_QUOTE);
+    String realm = _getSubStringUptoMarker(&challengeStr, CHAR_QUOTE);
+
+    return realm;
+}
 
 String ClientAuthenticator::_getSubStringUptoMarker(
     const char** line,
diff --git a/src/Pegasus/Client/ClientAuthenticator.h b/src/Pegasus/Client/ClientAuthenticator.h
index f29a79e..cdf7f12 100644
--- a/src/Pegasus/Client/ClientAuthenticator.h
+++ b/src/Pegasus/Client/ClientAuthenticator.h
@@ -37,6 +37,9 @@
 #include <Pegasus/Common/HTTPMessage.h>
 #include <Pegasus/Client/Linkage.h>
 
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+#include <Pegasus/Common/Kerberos.h>
+#endif
 
 PEGASUS_NAMESPACE_BEGIN
 
@@ -47,7 +50,7 @@ class PEGASUS_CLIENT_LINKAGE ClientAuthenticator
 {
 public:
 
-    enum AuthType { NONE, BASIC, DIGEST, LOCAL };
+    enum AuthType { NONE, BASIC, DIGEST, LOCAL, NEGOTIATE };
 
     /** Constuctor. */
     ClientAuthenticator();
@@ -100,6 +103,10 @@ public:
     */
     void setPassword(const String& password);
 
+    /** Set the hostname
+    */
+    void setHost(const String& host);
+
     /** Set the authentication type
     */
     void setAuthType(AuthType type);
@@ -119,6 +126,9 @@ private:
         String& authType,
         String& authRealm);
 
+    /** Parse realm name out of realm="<realm>" */
+    String _parseBasicRealm(const String &challenge);
+
     String _getSubStringUptoMarker(
         const char** line,
         char marker);
@@ -134,6 +144,10 @@ private:
     String _localAuthFileContent;
 
     AuthType _authType;
+
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    AutoPtr<KerberosClientSession> _session;
+#endif
 };
 
 PEGASUS_NAMESPACE_END
diff --git a/src/Pegasus/Common/AuthenticationInfo.h b/src/Pegasus/Common/AuthenticationInfo.h
index 36f468a..31f084b 100644
--- a/src/Pegasus/Common/AuthenticationInfo.h
+++ b/src/Pegasus/Common/AuthenticationInfo.h
@@ -43,6 +43,11 @@
 #include <Pegasus/Common/CIMKerberosSecurityAssociation.h>
 #endif
 
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+// TODO: write proper CIMKerberosSecurityAssociation with opaque types
+#include <Pegasus/Common/Kerberos.h>
+#endif //PEGASUS_SPNEGO_AUTHENTICATION
+
 PEGASUS_NAMESPACE_BEGIN
 
 /**
@@ -322,6 +327,15 @@ public:
     }
 #endif
 
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    /** Get GSSAPI context for this connection. */
+    SharedPtr<KerberosServerSession> getKerberosSession()
+    {
+        CheckRep(_rep);
+        return _rep->getKerberosSession();
+    }
+#endif //PEGASUS_SPNEGO_AUTHENTICATION
+
     Array<SSLCertificateInfo*> getClientCertificateChain()
     {
         CheckRep(_rep);
diff --git a/src/Pegasus/Common/AuthenticationInfoRep.cpp b/src/Pegasus/Common/AuthenticationInfoRep.cpp
index 5ba37d4..d00bacd 100644
--- a/src/Pegasus/Common/AuthenticationInfoRep.cpp
+++ b/src/Pegasus/Common/AuthenticationInfoRep.cpp
@@ -52,7 +52,9 @@ AuthenticationInfoRep::AuthenticationInfoRep()
 {
     PEG_METHOD_ENTER(
         TRC_AUTHENTICATION, "AuthenticationInfoRep::AuthenticationInfoRep");
-
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+      _session.reset(new KerberosServerSession());
+#endif
     PEG_METHOD_EXIT();
 }
 
@@ -77,7 +79,7 @@ AuthenticationInfoRep::~AuthenticationInfoRep()
             FileSystem::removeFile(_localAuthFilePath);
         }
     }
-       
+
     PEG_METHOD_EXIT();
 }
 
diff --git a/src/Pegasus/Common/AuthenticationInfoRep.h b/src/Pegasus/Common/AuthenticationInfoRep.h
index 0743452..ab1fa39 100644
--- a/src/Pegasus/Common/AuthenticationInfoRep.h
+++ b/src/Pegasus/Common/AuthenticationInfoRep.h
@@ -44,6 +44,10 @@
 #include <Pegasus/Common/CIMKerberosSecurityAssociation.h>
 #endif
 
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+#include <Pegasus/Common/Kerberos.h>
+#endif //PEGASUS_SPNEGO_AUTHENTICATION
+
 PEGASUS_NAMESPACE_BEGIN
 
 class AuthenticationInfo;
@@ -147,6 +151,15 @@ public:
     void setSecurityAssociation();
 #endif
 
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    /** Get GSSAPI context for this connection. */
+    SharedPtr<KerberosServerSession> getKerberosSession()
+    {
+        return _session;
+    }
+
+#endif //PEGASUS_SPNEGO_AUTHENTICATION
+
     Array<SSLCertificateInfo*> getClientCertificateChain()
     {
         return _clientCertificate;
@@ -214,6 +227,9 @@ private:
 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
     AutoPtr<CIMKerberosSecurityAssociation> _securityAssoc;//PEP101
 #endif
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    SharedPtr<KerberosServerSession> _session;
+#endif //PEGASUS_SPNEGO_AUTHENTICATION
     Boolean _wasRemotePrivilegedUserAccessChecked;
 
     Array<SSLCertificateInfo*> _clientCertificate;
diff --git a/src/Pegasus/Common/Kerberos.cpp b/src/Pegasus/Common/Kerberos.cpp
new file mode 100644
index 0000000..fd775bc
--- /dev/null
+++ b/src/Pegasus/Common/Kerberos.cpp
@@ -0,0 +1,358 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%/////////////////////////////////////////////////////////////////////////////
+
+#include <Pegasus/Common/Config.h>
+#include "Kerberos.h"
+#include "Tracer.h"
+#include "Base64.h"
+
+PEGASUS_NAMESPACE_BEGIN
+
+static const char KERBEROS_GET_NAME_FAILED_KEY [] =
+    "Common.Kerberos KERBEROS_GET_NAME_FAILURE";
+
+static const char KERBEROS_GET_NAME_FAILED[] =
+    "Cannot read user name for Kerberos request.";
+
+static const char KERBEROS_GET_NAME_RELEASE_FAILED_KEY [] =
+    "Common.Kerberos KERBEROS_GET_NAME_RELEASE_FAILURE";
+
+static const char KERBEROS_GET_NAME_RELEASE_FAILED[] =
+    "Cannot release user name for Kerberos request.";
+
+static const char KERBEROS_GET_NAME_SUCCESS_KEY [] =
+    "Common.Kerberos KERBEROS_GET_NAME_RELEASE_SUCCESS";
+
+static const char KERBEROS_GET_NAME_SUCCESS[] =
+    "Got user name $0 from Kerberos request.";
+
+static const char KERBEROS_SERVICE_NAME[] = "HTTP@";
+
+
+static gss_OID_desc gss_mech_spnego = {
+        6,
+        (char *)"\x2b\x06\x01\x05\x05\x02"
+};
+
+String getKerberosError(uint32_t major, uint32_t minor)
+{
+    gss_buffer_desc text;
+    uint32_t maj, min;
+    uint32_t msg_ctx = 0;
+
+    bool first = true;
+    String msg;
+    do {
+        maj = gss_display_status(&min, major, GSS_C_GSS_CODE, GSS_C_NO_OID,
+                &msg_ctx, &text);
+        if (maj != GSS_S_COMPLETE)
+            return msg;
+        if (!first)
+            msg.append(", ");
+        msg.append((const char*)text.value, text.length);
+        first = false;
+    } while (msg_ctx != 0);
+
+    do {
+        maj = gss_display_status(&min, minor, GSS_C_MECH_CODE, GSS_C_NO_OID,
+                &msg_ctx, &text);
+        if (maj != GSS_S_COMPLETE)
+            return msg;
+        if (!first)
+            msg.append(", ");
+        msg.append((const char*)text.value, text.length);
+        first = false;
+    } while (msg_ctx != 0);
+
+    return msg;
+}
+
+KerberosServerSession::KerberosServerSession()
+    : _challenge(String::EMPTY)
+{
+    PEG_METHOD_ENTER(
+        TRC_AUTHENTICATION, "KerberosServerSession::KerberosServerSession");
+
+    _ctx = GSS_C_NO_CONTEXT;
+
+    PEG_METHOD_EXIT();
+}
+
+KerberosServerSession::~KerberosServerSession()
+{
+    PEG_METHOD_ENTER(
+        TRC_AUTHENTICATION, "KerberosServerSession::~KerberosServerSession");
+    uint32_t min;
+    gss_delete_sec_context(&min, &_ctx, GSS_C_NO_BUFFER);
+    PEG_METHOD_EXIT();
+}
+
+KerberosAuthenticationStatus KerberosServerSession::authenticate(
+            const String &authorization, String &userName)
+{
+    PEG_METHOD_ENTER(
+        TRC_AUTHENTICATION, "KerberosServerSession::authenticate");
+
+    // decode the authorization data
+    Buffer data;
+    data.append((const char*) authorization.getCString(), authorization.size());
+    Buffer decodedData = Base64::decode( data );
+
+    // collect GSSAPI input and output arguments
+    uint32_t flags = 0, maj, min = 0;
+    gss_name_t client = GSS_C_NO_NAME;
+    gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
+    input.value = decodedData.getContentPtr();
+    input.length = decodedData.size();
+
+    maj = gss_accept_sec_context(
+                        &min,
+                        &_ctx,
+                        GSS_C_NO_CREDENTIAL,
+                        &input,
+                        GSS_C_NO_CHANNEL_BINDINGS,
+                        &client,
+                        NULL,
+                        &output,
+                        &flags,
+                        NULL,
+                        NULL);
+
+    userName = parseUserName(client);
+
+    KerberosAuthenticationStatus status;
+
+    if (GSS_ERROR(maj))
+    {
+        // reset the GSSAPI context, in case the user tries it again
+        _ctx = GSS_C_NO_CONTEXT;
+        // no challenge in the next HTTP response
+        _challenge = String::EMPTY;
+
+        // TODO: log the gssapi error message
+        status = KERBEROS_FAILED;
+    }
+    else
+    {
+        // no error so far
+        // remember the challenge to send (already base64-encoded)
+        if (output.length > 0)
+        {
+            Buffer outputBuf((const char*) output.value, output.length);
+            Buffer encodedBuf = Base64::encode(outputBuf);
+            _challenge.assign(encodedBuf.getData(), encodedBuf.size());
+            gss_release_buffer(&min, &output);
+        }
+        else
+        {
+            // no challenge in the next HTTP response
+            _challenge = String::EMPTY;
+        }
+
+        if (maj == GSS_S_COMPLETE)
+            status = KERBEROS_SUCCESS;
+        else
+            status = KERBEROS_CONTINUE;
+    }
+
+    PEG_METHOD_EXIT();
+    return status;
+}
+
+String KerberosServerSession::parseUserName(gss_name_t client)
+{
+    PEG_METHOD_ENTER(
+         TRC_AUTHENTICATION, "KerberosServerSession::parseUserName");
+
+    uint32_t maj, min;
+    gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
+    gss_OID oid;
+
+    maj = gss_display_name(&min, client, &output, &oid);
+    if (maj != GSS_S_COMPLETE)
+    {
+        Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER,
+            Logger::INFORMATION,
+            MessageLoaderParms(
+                    KERBEROS_GET_NAME_FAILED_KEY,
+                    KERBEROS_GET_NAME_FAILED));
+        PEG_METHOD_EXIT();
+        return String::EMPTY;
+    }
+
+    String userName((const char*) output.value, (unsigned int) output.length);
+
+    Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER,
+        Logger::TRACE,
+        MessageLoaderParms(
+                KERBEROS_GET_NAME_SUCCESS_KEY,
+                KERBEROS_GET_NAME_SUCCESS, userName));
+
+    maj = gss_release_name(&min, &client);
+    if (maj != GSS_S_COMPLETE)
+    {
+        Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER,
+            Logger::INFORMATION,
+            MessageLoaderParms(
+                    KERBEROS_GET_NAME_RELEASE_FAILED_KEY,
+                    KERBEROS_GET_NAME_RELEASE_FAILED));
+    }
+
+    PEG_METHOD_EXIT();
+    return userName;
+}
+
+
+
+
+
+
+KerberosClientSession::KerberosClientSession(String hostname)
+    : _challenge(String::EMPTY)
+{
+    PEG_METHOD_ENTER(
+        TRC_AUTHENTICATION, "KerberosClientSession::KerberosClientSession");
+
+    _ctx = GSS_C_NO_CONTEXT;
+
+    // translate hostname to gss_name_t (HTTP@<hostname>)
+    gss_buffer_desc input;
+    Buffer buf(KERBEROS_SERVICE_NAME, sizeof(KERBEROS_SERVICE_NAME)-1);
+    buf.append(hostname.getCString(), hostname.size()+1);
+    input.value = buf.getContentPtr();
+    input.length = buf.size();
+
+    uint32_t min=0, maj;
+    maj = gss_import_name(&min, &input, GSS_C_NT_HOSTBASED_SERVICE, &_service);
+    if (GSS_ERROR(maj))
+    {
+        String msg = getKerberosError(maj, min);
+        MessageLoaderParms parms(
+            "Common.Kerberos."
+                "KERBEROS_CLIENT_SESSION_FAILED_TO_INITIALIZE",
+            "Client authentication handler for Kerberos failed to "
+                "initialize properly: %s.", (const char *) msg.getCString());
+        Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::SEVERE,
+            parms);
+        throw Exception(parms);
+    }
+    PEG_METHOD_EXIT();
+}
+
+KerberosClientSession::~KerberosClientSession()
+{
+    PEG_METHOD_ENTER(
+        TRC_AUTHENTICATION, "KerberosClientSession::~KerberosClientSession");
+
+    uint32_t min;
+    gss_delete_sec_context(&min, &_ctx, GSS_C_NO_BUFFER);
+    gss_release_name(&min, &_service);
+
+    PEG_METHOD_EXIT();
+}
+
+/**
+ * Return <data> for 'WWW-Authenticate: Negotiate <data>' header,
+ * already base64 encoded.
+ * @return The data for WWW-Authenticate header.
+ */
+String KerberosClientSession::buildRequestAuthData()
+{
+    PEG_METHOD_ENTER(
+        TRC_AUTHENTICATION, "KerberosClientSession::buildRequestAuthData");
+
+    // decode previous challenge from base64
+
+    gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
+    if (_challenge.size() > 0)
+    {
+        Buffer data;
+        data.append((const char*) _challenge.getCString(), _challenge.size());
+        Buffer decodedData = Base64::decode( data );
+        input.value = decodedData.getContentPtr();
+        input.length = decodedData.size();
+    }
+
+    // collect GSSAPI input and output arguments
+    uint32_t flags = 0, maj, min = 0;
+    gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
+
+    maj = gss_init_sec_context(
+            &min,
+            GSS_C_NO_CREDENTIAL,
+            &_ctx,
+            _service,
+            /*GSS_C_NULL_OID, */ &gss_mech_spnego,
+            0,
+            0,
+            GSS_C_NO_CHANNEL_BINDINGS,
+            &input,
+            NULL,
+            &output,
+            &flags,
+            NULL);
+
+    String authentication;
+    if (GSS_ERROR(maj))
+    {
+        // reset the GSSAPI context and challenge
+        _ctx = GSS_C_NO_CONTEXT;
+        _challenge = String::EMPTY;
+
+        String msg = getKerberosError(maj, min);
+        PEG_TRACE((TRC_AUTHENTICATION, Tracer::LEVEL1,
+                "KerberosClientSession::buildRequestAuthData GSSAPI error %s",
+                (const char *) msg.getCString()));
+    }
+    else
+    {
+        // no error so far
+        if (output.length > 0)
+        {
+            Buffer outputBuf((const char*) output.value, output.length);
+            Buffer encodedBuf = Base64::encode(outputBuf);
+            authentication.assign(encodedBuf.getData(), encodedBuf.size());
+            gss_release_buffer(&min, &output);
+            PEG_TRACE((TRC_AUTHENTICATION, Tracer::LEVEL1,
+                    "KerberosClientSession::buildRequestAuthData"
+                    " sending response %s\n",
+                    (const char*) authentication.getCString()));
+        }
+    }
+
+    PEG_METHOD_EXIT();
+    return authentication;
+}
+
+PEGASUS_NAMESPACE_END
+
+
diff --git a/src/Pegasus/Common/Kerberos.h b/src/Pegasus/Common/Kerberos.h
new file mode 100644
index 0000000..c513019
--- /dev/null
+++ b/src/Pegasus/Common/Kerberos.h
@@ -0,0 +1,144 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%////////////////////////////////////////////////////////////////////////////
+
+#ifndef Pegasus_Kerberos_h
+#define Pegasus_Kerberos_h
+
+#include <Pegasus/Common/Config.h>
+#include <Pegasus/Common/Linkage.h>
+#include <Pegasus/Common/String.h>
+
+#include <gssapi/gssapi.h>
+
+PEGASUS_NAMESPACE_BEGIN
+
+enum KerberosAuthenticationStatus
+{
+    /** User is authenticated. */
+    KERBEROS_SUCCESS,
+    /** Authentication is in progress, 401 Unauthorized with a challenge
+     *  should be sent. */
+    KERBEROS_CONTINUE,
+    /** User failed to authenticate. */
+    KERBEROS_FAILED
+};
+
+/**
+ * This class keeps status of ongoing GSSAPI/Kerberos authentication.
+ * It processes Authorization: header from HTTP requests and helps to compose
+ * WWW-Authentication header in responses.
+ */
+class PEGASUS_COMMON_LINKAGE KerberosServerSession
+{
+public:
+    KerberosServerSession();
+    virtual ~KerberosServerSession();
+
+    /**
+     * Perform authentication of Authorization: Negotiate <data>' header.
+     * @param authorization - The <data> from Authorization: header, base64
+     * encoded.
+     * @param userName - output parameter, authenticated user name or empty
+     * string, if the name is not known yet.
+     * @return Status of the authentication process.
+     */
+    KerberosAuthenticationStatus authenticate(
+            const String &authorization, String &userName);
+
+    /**
+     * Get challenge for next WWW-Authenticate: Negotiate <challenge>.
+     */
+    String getChallenge()
+    {
+        return _challenge;
+    }
+
+
+private:
+    /** GSSAPI context */
+    gss_ctx_id_t _ctx;
+    /** Challenge to be sent in next 401 Unauthorized or 200 OK response.*/
+    String   _challenge;
+
+    /**
+     * Parse user name out of gss_name_t.
+     */
+    String parseUserName(gss_name_t client);
+
+
+};
+
+/**
+ * This class keeps status of ongoing GSSAPI/Kerberos authentication.
+ * It processes WWW-Authenticate: header from HTTP responses and helps to
+ * compose Authroization header in requests.
+ */
+class PEGASUS_COMMON_LINKAGE KerberosClientSession
+{
+public:
+    /**
+     * Create new client session.
+     * @param hostname - Fully qualified domain name of the server, it's needed
+     * to compose correct service identity.
+     */
+    KerberosClientSession(String hostname);
+    virtual ~KerberosClientSession();
+
+    /**
+     * Return <data> for 'WWW-Authenticate: Negotiate <data>' header,
+     * already base64 encoded.
+     * @return The data for WWW-Authenticate header.
+     */
+    String buildRequestAuthData();
+
+    /**
+     * Parse Authorization: Negotiate <challenge> header.
+     * @param challenge - the challenge, base64 encoded.
+     */
+    void parseChallenge(const String &challenge)
+    {
+        _challenge = challenge;
+    }
+
+private:
+    /** GSSAPI context */
+    gss_ctx_id_t _ctx;
+    /** Data from the last Authorization: Negotiate <challenge> header,
+     *  base64 encoded.*/
+    String   _challenge;
+
+    /** Remote service name. */
+    gss_name_t _service;
+};
+
+PEGASUS_NAMESPACE_END
+
+#endif //Pegasus_Kerberos_h
diff --git a/src/Pegasus/Common/Makefile b/src/Pegasus/Common/Makefile
index 15de543..c491fa9 100644
--- a/src/Pegasus/Common/Makefile
+++ b/src/Pegasus/Common/Makefile
@@ -281,5 +281,10 @@ ifeq ($(OS_TYPE),windows)
     endif
 endif
 
+ifeq ($(PEGASUS_SPNEGO_AUTHENTICATION),true)
+    SOURCES += Kerberos.cpp
+endif
+
+
 include $(ROOT)/mak/dynamic-library.mak
 # DO NOT DELETE
diff --git a/src/Pegasus/Config/SecurityPropertyOwner.cpp b/src/Pegasus/Config/SecurityPropertyOwner.cpp
index a7d8e92..0c44268 100644
--- a/src/Pegasus/Config/SecurityPropertyOwner.cpp
+++ b/src/Pegasus/Config/SecurityPropertyOwner.cpp
@@ -607,6 +607,9 @@ Boolean SecurityPropertyOwner::isValid(
 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
             || String::equal(value, "Kerberos")
 #endif
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+            || String::equal(value, "Kerberos")
+#endif
         )
         {
             retVal = true;
diff --git a/src/Pegasus/Security/Authentication/AuthenticationManager.cpp b/src/Pegasus/Security/Authentication/AuthenticationManager.cpp
index 75defe6..3107c19 100644
--- a/src/Pegasus/Security/Authentication/AuthenticationManager.cpp
+++ b/src/Pegasus/Security/Authentication/AuthenticationManager.cpp
@@ -46,7 +46,9 @@
 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
 #include "KerberosAuthenticationHandler.h"
 #endif
-
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+#include "KerberosAuthenticationHandler.h"
+#endif
 
 PEGASUS_USING_STD;
 
@@ -156,6 +158,13 @@ AuthenticationStatus AuthenticationManager::performHttpAuthentication(
         authStatus = _httpAuthHandler->authenticate(cookie, authInfo);
     }
 #endif
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    else if ( String::equalNoCase(authType, "Negotiate") &&
+              String::equal(_httpAuthType, "Kerberos") )
+    {
+        authStatus = _httpAuthHandler->authenticate(cookie, authInfo);
+    }
+#endif
     // FUTURE: Add code to check for "Digest" when digest
     // authentication is implemented.
 
@@ -277,8 +286,13 @@ String AuthenticationManager::getPegasusAuthResponseHeader(
 String AuthenticationManager::getHttpAuthResponseHeader(
     AuthenticationInfo* authInfo)
 #else
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+String AuthenticationManager::getHttpAuthResponseHeader(
+    AuthenticationInfo* authInfo)
+#else
 String AuthenticationManager::getHttpAuthResponseHeader()
 #endif
+#endif
 {
     PEG_METHOD_ENTER(TRC_AUTHENTICATION,
         "AuthenticationManager::getHttpAuthResponseHeader()");
@@ -287,9 +301,13 @@ String AuthenticationManager::getHttpAuthResponseHeader()
     String respHeader = _httpAuthHandler->getAuthResponseHeader(
         String::EMPTY, String::EMPTY, authInfo);
 #else
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    String respHeader = _httpAuthHandler->getAuthResponseHeader(
+        String::EMPTY, String::EMPTY, authInfo);
+#else
     String respHeader = _httpAuthHandler->getAuthResponseHeader();
 #endif
-
+#endif
     PEG_METHOD_EXIT();
     return respHeader;
 }
@@ -358,6 +376,12 @@ Authenticator* AuthenticationManager::_getHttpAuthHandler()
         }
     }
 #endif
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    if ( String::equal(_httpAuthType, "Kerberos") )
+    {
+        handler.reset((Authenticator* ) new KerberosAuthenticationHandler( ));
+    }
+#endif
     // FUTURE: uncomment these line when Digest authentication
     // is implemented.
     //
diff --git a/src/Pegasus/Security/Authentication/AuthenticationManager.h b/src/Pegasus/Security/Authentication/AuthenticationManager.h
index 4c4bdf5..8bae851 100644
--- a/src/Pegasus/Security/Authentication/AuthenticationManager.h
+++ b/src/Pegasus/Security/Authentication/AuthenticationManager.h
@@ -41,6 +41,9 @@
 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
 #include <Pegasus/Common/AuthenticationInfo.h>
 #endif
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+#include <Pegasus/Common/AuthenticationInfo.h>
+#endif
 
 PEGASUS_NAMESPACE_BEGIN
 
@@ -104,11 +107,16 @@ public:
         @return String containing the authentication challenge
     */
 #ifdef PEGASUS_KERBEROS_AUTHENTICATION
-    String AuthenticationManager::getHttpAuthResponseHeader(
+    String getHttpAuthResponseHeader(
+        AuthenticationInfo* authInfo = 0);
+#else
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+    String getHttpAuthResponseHeader(
         AuthenticationInfo* authInfo = 0);
 #else
     String getHttpAuthResponseHeader();
 #endif
+#endif
 
     static Boolean isRemotePrivilegedUserAccessAllowed(
         String & userName);
diff --git a/src/Pegasus/Security/Authentication/KerberosAuthenticationHandler.cpp b/src/Pegasus/Security/Authentication/KerberosAuthenticationHandler.cpp
new file mode 100644
index 0000000..d6bc8f2
--- /dev/null
+++ b/src/Pegasus/Security/Authentication/KerberosAuthenticationHandler.cpp
@@ -0,0 +1,165 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%/////////////////////////////////////////////////////////////////////////////
+
+#include <Pegasus/Common/AuditLogger.h>
+#include <Pegasus/Common/Logger.h>
+#include <Pegasus/Common/Tracer.h>
+
+#include "KerberosAuthenticationHandler.h"
+#include <Pegasus/Common/Base64.h>
+//PEGASUS_USING_STD;
+
+PEGASUS_NAMESPACE_BEGIN
+
+
+static const char KERBEROS_AUTHENTICATION_FAILED_KEY [] =
+    "Security.Authentication.KerberosAuthenticationHandler."
+        "BASIC_AUTHENTICATION_FAILURE";
+
+static const char KERBEROS_AUTHENTICATION_FAILED[] =
+    "Authentication failed for user $0 from client IP address $1.";
+
+static const char KERBEROS_AUTHENTICATION_SUCCESS_KEY [] =
+    "Security.Authentication.KerberosAuthenticationHandler."
+        "BASIC_AUTHENTICATION_FAILURE";
+
+static const char KERBEROS_AUTHENTICATION_SUCCESS[] =
+    "Authentication succeeded for user $0 from client IP address $1.";
+
+static const char KERBEROS_AUTHENTICATION_CONTINUE_KEY [] =
+    "Security.Authentication.KerberosAuthenticationHandler."
+        "BASIC_AUTHENTICATION_FAILURE";
+
+static const char KERBEROS_AUTHENTICATION_CONTINUE[] =
+    "Authentication continues for user $0 from client IP address $1.";
+
+static const String KERBEROS_AUTHENTICATION_CHALLENGE_HEADER =
+    "WWW-Authenticate: Negotiate ";
+
+KerberosAuthenticationHandler::KerberosAuthenticationHandler()
+{
+    PEG_METHOD_ENTER(TRC_AUTHENTICATION,
+       "KerberosAuthenticationHandler::KerberosAuthenticationHandler()");
+
+    PEG_METHOD_EXIT();
+}
+
+KerberosAuthenticationHandler::~KerberosAuthenticationHandler()
+{
+    PEG_METHOD_ENTER(TRC_AUTHENTICATION,
+        "KerberosAuthenticationHandler::~KerberosAuthenticationHandler()");
+
+    PEG_METHOD_EXIT();
+}
+
+AuthenticationStatus KerberosAuthenticationHandler::authenticate(
+    const String& authHeader,
+    AuthenticationInfo* authInfo)
+{
+    PEG_METHOD_ENTER(TRC_AUTHENTICATION,
+        "KerberosAuthenticationHandler::authenticate()");
+
+    SharedPtr<KerberosServerSession> session = authInfo->getKerberosSession();
+    String userName;
+    KerberosAuthenticationStatus status = session->authenticate(authHeader,
+            userName);
+
+    if (userName != String::EMPTY)
+        authInfo->setAuthenticatedUser(userName);
+
+    bool authenticated = false;
+    switch(status)
+    {
+    case KERBEROS_SUCCESS:
+        // authentication finished successfully, audit it
+        PEG_AUDIT_LOG(logBasicAuthentication(
+            userName,
+            authInfo->getIpAddress(),
+            true));
+
+        Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER,
+            Logger::TRACE,
+            MessageLoaderParms(
+                    KERBEROS_AUTHENTICATION_SUCCESS_KEY,
+                    KERBEROS_AUTHENTICATION_SUCCESS, userName, authInfo->getIpAddress()));
+        authenticated = true;
+        break;
+
+    case KERBEROS_CONTINUE:
+        Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER,
+            Logger::TRACE,
+            MessageLoaderParms(
+                    KERBEROS_AUTHENTICATION_CONTINUE_KEY,
+                    KERBEROS_AUTHENTICATION_CONTINUE, userName, authInfo->getIpAddress()));
+        break;
+
+    case KERBEROS_FAILED:
+        String userName = authInfo->getAuthenticatedUser();
+        // audit the failure
+        PEG_AUDIT_LOG(logBasicAuthentication(
+                userName,
+                authInfo->getIpAddress(),
+                false));
+        break;
+    }
+
+    PEG_METHOD_EXIT();
+    return AuthenticationStatus(authenticated);
+}
+
+AuthenticationStatus KerberosAuthenticationHandler::validateUser(
+    const String& userName,
+    AuthenticationInfo* authInfo)
+{
+    return true;
+}
+
+String KerberosAuthenticationHandler::getAuthResponseHeader(
+    const String& authType,
+    const String& userName,
+    AuthenticationInfo* authInfo)
+{
+    PEG_METHOD_ENTER(TRC_AUTHENTICATION,
+        "KerberosAuthenticationHandler::getAuthResponseHeader()");
+
+    String authResp = KERBEROS_AUTHENTICATION_CHALLENGE_HEADER;
+    SharedPtr<KerberosServerSession> session = authInfo->getKerberosSession();
+    String challenge = session->getChallenge();
+    authResp.append(challenge);
+    PEG_TRACE((TRC_AUTHENTICATION, Tracer::LEVEL1,
+            "getAuthResponseHeader returning: %s",
+            (const char*)authResp.getCString()));
+
+    PEG_METHOD_EXIT();
+    return authResp;
+}
+
+PEGASUS_NAMESPACE_END
diff --git a/src/Pegasus/Security/Authentication/KerberosAuthenticationHandler.h b/src/Pegasus/Security/Authentication/KerberosAuthenticationHandler.h
new file mode 100644
index 0000000..75196e3
--- /dev/null
+++ b/src/Pegasus/Security/Authentication/KerberosAuthenticationHandler.h
@@ -0,0 +1,101 @@
+//%LICENSE////////////////////////////////////////////////////////////////
+//
+// Licensed to The Open Group (TOG) under one or more contributor license
+// agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
+// this work for additional information regarding copyright ownership.
+// Each contributor licenses this file to you under the OpenPegasus Open
+// Source License; you may not use this file except in compliance with the
+// License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+//%/////////////////////////////////////////////////////////////////////////////
+
+#ifndef Pegasus_KerberosAuthenticationHandler_h
+#define Pegasus_KerberosAuthenticationHandler_h
+
+#include <Pegasus/Common/Config.h>
+#include <Pegasus/Common/String.h>
+#include <Pegasus/Common/AutoPtr.h>
+
+#include <Pegasus/Security/Authentication/Linkage.h>
+#include "Authenticator.h"
+
+PEGASUS_NAMESPACE_BEGIN
+
+/**
+    This class implements the AuthenticationHandler for SPNEGO authenticator,
+    as described in RFC 4559.  It extends the Authenticator and provides the
+    implementation (using MIT Kerberos).
+*/
+
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+
+class PEGASUS_SECURITY_LINKAGE KerberosAuthenticationHandler
+    : public Authenticator
+{
+public:
+
+    /** Constructors  */
+    KerberosAuthenticationHandler();
+
+    /** Destructor  */
+    ~KerberosAuthenticationHandler();
+
+    /** Verify the authentication of the user passed in the authorization
+        header.
+        @param authHeader String containing the Authorization header
+        @param authInfo Reference to AuthenticationInfo object
+        @return AuthenticationStatus holding http status code and error detail
+    */
+    AuthenticationStatus authenticate(
+        const String& authHeader,
+        AuthenticationInfo* authInfo);
+
+    /** Construct and return the Pegasus Local authentication challenge header
+        @param authType String containing the HTTP authentication type
+        @param userName String containing the user name
+        @param authInfo Reference to AuthenticationInfo object
+        @return A string containing the authentication challenge header.
+    */
+    String getAuthResponseHeader(
+        const String& authType = String::EMPTY,
+        const String& userName = String::EMPTY,
+        AuthenticationInfo* authInfo = 0);
+
+    /**
+        Verify whether the user is valid.
+        @param userName String containing the user name
+        @param authInfo reference to AuthenticationInfo object that holds the
+        authentication information for the given connection.
+        @return AuthenticationStatus holding http status code and error detail
+    */
+    AuthenticationStatus validateUser(
+        const String& userName,
+        AuthenticationInfo* authInfo = 0);
+
+};
+
+PEGASUS_NAMESPACE_END
+
+#endif
+
+#endif /* Pegasus_KerberosAuthenticationHandler_h*/
diff --git a/src/Pegasus/Security/Authentication/Makefile b/src/Pegasus/Security/Authentication/Makefile
index 71de2c1..c8a4b45 100644
--- a/src/Pegasus/Security/Authentication/Makefile
+++ b/src/Pegasus/Security/Authentication/Makefile
@@ -60,7 +60,8 @@ SOURCES = \
     SecureBasicAuthenticator.cpp \
     PAMBasicAuthenticator.cpp \
     BasicAuthenticationHandler.cpp \
-    AuthenticationManager.cpp
+    AuthenticationManager.cpp \
+    KerberosAuthenticationHandler.cpp
 
 # Special code calling pam_end in class AuthHandle only required
 # with session based authentication mechanism
diff --git a/src/Pegasus/Server/HTTPAuthenticatorDelegator.cpp b/src/Pegasus/Server/HTTPAuthenticatorDelegator.cpp
index 6dc0b2e..758b323 100644
--- a/src/Pegasus/Server/HTTPAuthenticatorDelegator.cpp
+++ b/src/Pegasus/Server/HTTPAuthenticatorDelegator.cpp
@@ -1116,9 +1116,21 @@ void HTTPAuthenticatorDelegator::handleHTTPMessage(
                         _authenticationManager->getHttpAuthResponseHeader(
                             httpMessage->authInfo);
 #else
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+                    // Kerberos authentication needs access to the
+                    // AuthenticationInfo object for this session in
+                    // order to set up the reference to the
+                    // CIMKerberosSecurityAssociation object for this
+                    // session.
+
+                    String authResp =
+                        _authenticationManager->getHttpAuthResponseHeader(
+                            httpMessage->authInfo);
+#else
                     String authResp =
                         _authenticationManager->getHttpAuthResponseHeader();
 #endif
+#endif
                     if (authResp.size() > 0)
                     {
                         if (authStatus.doChallenge())
@@ -1417,9 +1429,15 @@ void HTTPAuthenticatorDelegator::handleHTTPMessage(
             _authenticationManager->getHttpAuthResponseHeader(
                 httpMessage->authInfo);
 #else
+#ifdef PEGASUS_SPNEGO_AUTHENTICATION
+        String authResp =
+            _authenticationManager->getHttpAuthResponseHeader(
+                httpMessage->authInfo);
+#else
         String authResp =
             _authenticationManager->getHttpAuthResponseHeader();
 #endif
+#endif
 
         if (authResp.size() > 0)
         {