diff --git a/extensions/auth/nsAuthGSSAPI.cpp b/extensions/auth/nsAuthGSSAPI.cpp index 32071f2435..299f2c68b2 100644 --- a/extensions/auth/nsAuthGSSAPI.cpp +++ b/extensions/auth/nsAuthGSSAPI.cpp @@ -288,8 +288,6 @@ nsAuthGSSAPI::nsAuthGSSAPI(pType package) LOG(("entering nsAuthGSSAPI::nsAuthGSSAPI()\n")); - mComplete = false; - if (!gssLibrary && NS_FAILED(gssInit())) return; @@ -340,6 +338,8 @@ nsAuthGSSAPI::Reset() } mCtx = GSS_C_NO_CONTEXT; mComplete = false; + mDelegationRequested = false; + mDelegationSupported = false; } /* static */ void @@ -386,6 +386,7 @@ nsAuthGSSAPI::GetNextToken(const void *inToken, { OM_uint32 major_status, minor_status; OM_uint32 req_flags = 0; + OM_uint32 ret_flags = 0; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; gss_buffer_t in_token_ptr = GSS_C_NO_BUFFER; @@ -402,8 +403,22 @@ nsAuthGSSAPI::GetNextToken(const void *inToken, if (mComplete) Reset(); - if (mServiceFlags & REQ_DELEGATE) + // Two-phase delegation logic + // Phase 1: Try authentication without delegation first + // Phase 2: Only retry with delegation if server supports it (ret_flags) + bool delegationConfigured = (mServiceFlags & REQ_DELEGATE) != 0; + + if (delegationConfigured) { + if (!mDelegationRequested) { + // First attempt: don't request delegation yet + LOG(("First auth attempt without delegation")); + mDelegationRequested = true; + } else if (mDelegationSupported) { + // Second attempt: server supports delegation, now request it + LOG(("Retrying auth with delegation - server supports it")); req_flags |= GSS_C_DELEG_FLAG; + } + } if (mServiceFlags & REQ_MUTUAL_AUTH) req_flags |= GSS_C_MUTUAL_FLAG; @@ -469,7 +484,7 @@ nsAuthGSSAPI::GetNextToken(const void *inToken, in_token_ptr, nullptr, &output_token, - nullptr, + &ret_flags, nullptr); if (GSS_ERROR(major_status)) { @@ -478,6 +493,27 @@ nsAuthGSSAPI::GetNextToken(const void *inToken, rv = NS_ERROR_FAILURE; goto end; } + // Check if server supports delegation (OK-AS-DELEGATE equivalent) + if (delegationConfigured && !mDelegationSupported && + (ret_flags & GSS_C_DELEG_FLAG)) { + LOG(("Server supports delegation (GSS_C_DELEG_FLAG in ret_flags)")); + + // If we completed without requesting delegation, but server supports it, + // we need to restart with delegation + if (major_status == GSS_S_COMPLETE && !(req_flags & GSS_C_DELEG_FLAG)) { + LOG(("Restarting authentication to request delegation")); + Reset(); + + // These flags get cleared by Reset(). + // Set them again to make sure the next call sets GSS_C_DELEG_FLAG + mDelegationRequested = true; + mDelegationSupported = true; + + gss_release_name_ptr(&minor_status, &server); + return GetNextToken(inToken, inTokenLen, outToken, outTokenLen); + } + } + if (major_status == GSS_S_COMPLETE) { // Mark ourselves as being complete, so that if we're called again // we know to start afresh. diff --git a/extensions/auth/nsAuthGSSAPI.h b/extensions/auth/nsAuthGSSAPI.h index cce9d17c7d..421f48015f 100644 --- a/extensions/auth/nsAuthGSSAPI.h +++ b/extensions/auth/nsAuthGSSAPI.h @@ -54,9 +54,11 @@ private: gss_ctx_id_t mCtx; gss_OID mMechOID; nsCString mServiceName; - uint32_t mServiceFlags; + uint32_t mServiceFlags = REQ_DEFAULT; nsString mUsername; - bool mComplete; + bool mComplete = false; + bool mDelegationRequested = false; + bool mDelegationSupported = false; }; #endif /* nsAuthGSSAPI_h__ */