+AM_CONDITIONAL([VMTOOLS_FS_VGAUTH_HOST_VERIFICATION],[true])
+if test "$enable_vgauth" = "yes"; then
+ echo "Enabling vgauth host verification"
+ CPPFLAGS="$CPPFLAGS -DVMTOOLS_FS_VGAUTH_HOST_VERIFICATION"
+fi
###
}
+/**
+ * Sends vix capabilites.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx Unused.
+ * @param[in] set Whether capabilities are being set.
+ * @param[in] data Unused.
+ *
+ * @return List of capabilities.
+ */
+
+static GArray *
+VixCapabilitiesCb(gpointer src,
+ ToolsAppCtx *ctx,
+ gboolean set,
+ gpointer data)
+{
+ const ToolsAppCapability caps[] = {
+ { TOOLS_CAP_NEW, NULL, CAP_HOST_VERIFIED_SAML_TOKEN, 1},
+ };
+
+ return VMTools_WrapArray(caps, sizeof *caps, ARRAYSIZE(caps));
+}
/**
};
ToolsPluginSignalCb sigs[] = {
{ TOOLS_CORE_SIG_SHUTDOWN, VixShutdown, ®Data },
+ { TOOLS_CORE_SIG_CAPABILITIES, VixCapabilitiesCb, NULL }
};
ToolsAppReg regs[] = {
{ TOOLS_APP_GUESTRPC, VMTools_WrapArray(rpcs, sizeof *rpcs, ARRAYSIZE(rpcs)) },
VixError GuestAuthSAMLAuthenticateAndImpersonate(
char const *obfuscatedNamePassword,
Bool loadUserProfile,
+ Bool hostVerified,
void **userToken);
void GuestAuthUnimpersonate();
}
#if SUPPORT_VGAUTH
case VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN:
+ case VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN_HOST_VERIFIED:
{
VixCommandSAMLToken *samlStruct =
(VixCommandSAMLToken *) credentialField;
#if SUPPORT_VGAUTH
else if ((VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN == credentialType)
+ || (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN_HOST_VERIFIED == credentialType)
) {
if (GuestAuthEnabled()) {
+ Bool hostVerified =
+ (credentialType == VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN_HOST_VERIFIED)
+ ? TRUE : FALSE;
err = GuestAuthSAMLAuthenticateAndImpersonate(obfuscatedNamePassword,
loadUserProfile,
+ hostVerified,
userToken);
} else {
err = VIX_E_NOT_SUPPORTED;
GuestAuthSAMLAuthenticateAndImpersonate(
char const *obfuscatedNamePassword, // IN
Bool loadUserProfile, // IN
+ Bool hostVerified, // IN
void **userToken) // OUT
{
#if SUPPORT_VGAUTH
VGAuthError vgErr;
VGAuthUserHandle *newHandle = NULL;
VGAuthExtraParams extraParams[1];
+ VGAuthExtraParams hostVerfiedParams[1];
Bool impersonated = FALSE;
extraParams[0].name = VGAUTH_PARAM_LOAD_USER_PROFILE;
goto done;
}
+ hostVerfiedParams[0].name = VGAUTH_PARAM_SAML_HOST_VERIFIED;
+ hostVerfiedParams[0].value = hostVerified ? VGAUTH_PARAM_VALUE_TRUE :
+ VGAUTH_PARAM_VALUE_FALSE;
vgErr = VGAuth_ValidateSamlBearerToken(ctx,
token,
username,
- 0, NULL,
+ (int)ARRAYSIZE(hostVerfiedParams),
+ hostVerfiedParams,
&newHandle);
#if ALLOW_LOCAL_SYSTEM_IMPERSONATION_BYPASS
/*
#define VGAUTH_COMMENT_ELEMENT_NAME "comment"
#define VGAUTH_ALIAS_ELEMENT_NAME "alias"
#define VGAUTH_VALIDATE_ONLY_ELEMENT_NAME "validateOnly"
+#define VGAUTH_HOST_VERIFIED_ELEMENT_NAME "hostVerified"
/*
* Complex types
* SAML token, and does not create an access token on Windows. This
* flag is ignored on *ix.
*
+ * If hostVerified is set, then the service will skip the signature
+ * check in the SAML token.
+ *
* Request:
* SAML token
* user
* validateOnly (bool)
+ * hostVerified (bool)
* =>
* user
* token (empty for non-Windows)
"<"VGAUTH_SAMLTOKEN_ELEMENT_NAME">%s</"VGAUTH_SAMLTOKEN_ELEMENT_NAME">" \
"<"VGAUTH_USERNAME_ELEMENT_NAME">%s</"VGAUTH_USERNAME_ELEMENT_NAME">" \
"<"VGAUTH_VALIDATE_ONLY_ELEMENT_NAME">%s</"VGAUTH_VALIDATE_ONLY_ELEMENT_NAME">" \
+ "<"VGAUTH_HOST_VERIFIED_ELEMENT_NAME">%s</"VGAUTH_HOST_VERIFIED_ELEMENT_NAME">" \
VGAUTH_REQUEST_FORMAT_END
/* clang-format off */
VGAuthError VGAuth_SendValidateSamlBearerTokenRequest(VGAuthContext *ctx,
gboolean validateOnly,
+ gboolean hostVerified,
const char *samlToken,
const char *userName,
VGAuthUserHandle **userHandle);
* @a handle cannot be used for impersonation or ticket
* creation.
*
+ * VGAUTH_PARAM_SAML_HOST_VERIFIED, which must have the value
+ * VGAUTH_PARAM_VALUE_TRUE or VGAUTH_PARAM_VALUE_FALSE.
+ * If set, the SAML token has been verified by the host
+ * and this service will skip that step when validating.
+ *
* @param[in] ctx The VGAuthContext.
* @param[in] samlToken The SAML token to be validated.
* @param[in] userName The user to authenticate as. Optional.
VGAuthError err;
VGAuthUserHandle *newHandle = NULL;
gboolean validateOnly;
+ gboolean hostVerified;
/*
* arg check
if (VGAUTH_E_OK != err) {
return err;
}
+ err = VGAuthGetBoolExtraParam(numExtraParams, extraParams,
+ VGAUTH_PARAM_SAML_HOST_VERIFIED,
+ FALSE,
+ &hostVerified);
+ if (VGAUTH_E_OK != err) {
+ return err;
+ }
err = VGAuth_SendValidateSamlBearerTokenRequest(ctx,
validateOnly,
+ hostVerified,
samlToken,
userName,
&newHandle);
VGAuthError
VGAuth_SendValidateSamlBearerTokenRequest(VGAuthContext *ctx,
gboolean validateOnly,
+ gboolean hostVerified,
const char *samlToken,
const char *userName,
VGAuthUserHandle **userHandle)
ctx->comm.sequenceNumber,
samlToken,
userName ? userName : "",
- validateOnly ? "1" : "0");
+ validateOnly ? "1" : "0",
+ hostVerified ? "1" : "0");
err = VGAuth_CommSendData(ctx, packet);
if (VGAUTH_E_OK != err) {
#define VGAUTH_PARAM_VALIDATE_INFO_ONLY "validateInfoOnly"
+# define VGAUTH_PARAM_SAML_HOST_VERIFIED "hostVerified"
VGAuthError VGAuth_ValidateSamlBearerToken(VGAuthContext *ctx,
const char *samlToken,
PARSE_STATE_USERHANDLESAMLINFO,
PARSE_STATE_USERHANDLESAMLSUBJECT,
PARSE_STATE_SAML_VALIDATE_ONLY,
+ PARSE_STATE_SAML_HOST_VERIFIED,
} ProtoParseState;
/*
gchar *samlToken;
gchar *userName;
gboolean validateOnly;
+ gboolean hostVerified;
} validateSamlBToken;
} reqData;
Log("username '%s'\n", req->reqData.validateSamlBToken.userName);
Log("validate Only '%s'\n",
req->reqData.validateSamlBToken.validateOnly ? "TRUE" : "FALSE");
+ Log("hostVerified '%s'\n",
+ req->reqData.validateSamlBToken.hostVerified ? "TRUE" : "FALSE");
break;
default:
Warning("Unknown request type -- no request specific data\n");
req->parseState = PARSE_STATE_SAMLTOKEN;
} else if (g_strcmp0(elementName, VGAUTH_VALIDATE_ONLY_ELEMENT_NAME) == 0) {
req->parseState = PARSE_STATE_SAML_VALIDATE_ONLY;
+ } else if (g_strcmp0(elementName, VGAUTH_HOST_VERIFIED_ELEMENT_NAME) == 0) {
+ req->parseState = PARSE_STATE_SAML_HOST_VERIFIED;
} else if (g_strcmp0(elementName, VGAUTH_ALIASINFO_ELEMENT_NAME) == 0) {
req->parseState = PARSE_STATE_ALIASINFO;
} else if (g_strcmp0(elementName, VGAUTH_SUBJECT_ELEMENT_NAME) == 0) {
case PARSE_STATE_TOKEN:
case PARSE_STATE_SAMLTOKEN:
case PARSE_STATE_SAML_VALIDATE_ONLY:
+ case PARSE_STATE_SAML_HOST_VERIFIED:
case PARSE_STATE_USERHANDLEINFO:
req->parseState = PARSE_STATE_REQUEST;
break;
iVal = atoi(val);
req->reqData.validateSamlBToken.validateOnly = (iVal) ? TRUE : FALSE;
break;
+ case PARSE_STATE_SAML_HOST_VERIFIED:
+
+ if (req->reqType != PROTO_REQUEST_VALIDATE_SAML_BEARER_TOKEN) {
+ g_set_error(error, G_MARKUP_ERROR_PARSE, VGAUTH_E_INVALID_ARGUMENT,
+ "Found hostVerified option in req type %d",
+ req->reqType);
+ goto done;
+ }
+ iVal = atoi(val);
+ req->reqData.validateSamlBToken.hostVerified = (iVal) ? TRUE : FALSE;
+ break;
case PARSE_STATE_USERHANDLETYPE:
{
ServiceValidationResultsType t = VALIDATION_RESULTS_TYPE_UNKNOWN;
*/
err = SAML_VerifyBearerTokenAndChain(req->reqData.validateSamlBToken.samlToken,
req->reqData.validateSamlBToken.userName,
+ req->reqData.validateSamlBToken.hostVerified,
&userName,
&subjectName,
&ai);
static bool SAMLCheckAudience(const XMLCh *audience);
static bool SAMLCheckSignature(DOMDocument *doc,
+ gboolean hostVerified,
vector<string> &certs);
static bool SAMLCheckReference(const DOMDocument *doc, DSIGSignature *sig);
SAMLTokenData token;
err = SAMLVerifyAssertion(xmlText,
+ FALSE, // use original mode
token, certs);
if (VGAUTH_E_OK != err) {
return err;
*
* @param[in] xmlText The text of the SAML assertion.
* @param[in] userName Optional username to authenticate as.
+ * @param[in] hostVerified If true, skip signature verification.
* @param[out] userNameOut The user that the token has authenticated as.
* @param[out] subjNameOut The subject in the token.
* @param[out] verifySi The subjectInfo associated with the entry
VGAuthError
SAML_VerifyBearerTokenAndChain(const char *xmlText,
const char *userName,
+ gboolean hostVerified,
char **userNameOut,
char **subjNameOut,
ServiceAliasInfo **verifyAi)
int i;
err = SAMLVerifyAssertion(xmlText,
+ hostVerified,
token, certs);
if (VGAUTH_E_OK != err) {
return err;
* certs.
*
* @param[in] xmlText
+ * @param[in] hostVerified If true, skip signature verification.
* @param[out] token The interesting bits extracted from the xmlText.
* @param[out] certs If the SAML assertion is verified, then this will
* contain the certificate chain for the issuer.
VGAuthError
SAMLVerifyAssertion(const char *xmlText,
+ gboolean hostVerified,
SAMLTokenData &token,
vector<string> &certs)
{
}
if (!SAMLCheckSignature(doc,
+ hostVerified,
certs)) {
return VGAUTH_E_AUTHENTICATION_DENIED;
}
* from that, then checks that the signature is valid.
*
* @param[in] doc The document of which to check the signature.
+ * @param[in] hostVerified If true, skip signature verification.
* @param[out] certs The base64 encoded certificates present in the
* signature.
*
static bool
SAMLCheckSignature(DOMDocument *doc,
+ gboolean hostVerified,
vector<string> &certs)
{
DOMElement *sigElem = SAMLFindChildByName(doc->getDocumentElement(),
__FUNCTION__);
return false;
}
+ if (hostVerified) {
+ Debug("hostVerified is set, skipping signtaure check");
+ } else {
const XSECCryptoX509 *x509 = keyInfo->getCertificateCryptoItem(0);
ASSERT(NULL != x509);
return false;
}
+ }
for (int i = 0; i < keyInfo->getCertificateListSize(); i++) {
const XSECCryptoX509 *cert = keyInfo->getCertificateCryptoItem(i);
certs.push_back(string(cert->getDEREncodingSB().rawCharBuffer()));
* Verifies the signature on an XML document.
*
* @param[in] doc Parsed XML document.
+ * @param[in] hostVerified If set, signature verifcation can be skipped.
* @param[out] numCerts Number of certs in the token.
* @param[out] certChain Certs in the token. Caller should g_free() array and
* contents.
static gboolean
VerifySignature(xmlDocPtr doc,
+ gboolean hostVerified,
int *numCerts,
gchar ***certChain)
{
goto done;
}
+ if (hostVerified) {
+ // XXX add a check that the sig is replaced with the expected value
+ g_debug("%s: token is hostVerified, skipping signature check",
+ __FUNCTION__);
+ goto verified;
+ }
/*
* Create a signature context with the key manager
goto done;
}
+verified:
retCode = TRUE;
*numCerts = num;
*certChain = certList;
gboolean
SAML_VerifySignature(xmlDocPtr doc,
+ gboolean hostVerified,
int *numCerts,
gchar ***certChain)
{
return VerifySignature(doc,
+ hostVerified,
numCerts,
certChain);
}
* Parses the XML, then verifies Subject, Conditions and Signature.
*
* @param[in] token Text of SAML token.
+ * @param[in] hostVerfied If true, the signature check can be skipped.
* @param[out] subject Subject of SAML token, Caller must g_free().
* @param[out] numCerts Number of certs in the token.
* @param[out] certChain Certs in the token. Caller should g_free()
static gboolean
VerifySAMLToken(const gchar *token,
+ gboolean hostVerified,
gchar **subject,
int *numCerts,
gchar ***certChain)
#endif
bRet = VerifySignature(doc,
+ hostVerified,
numCerts, certChain);
if (FALSE == bRet) {
g_warning("Failed to verify Signature\n");
}
+// XXX remove this? hostVerified can be tested just fine with the 'real'
+// API, the test-only shortcut may be overkill. Though once this is
+// out of dev, we could add the extra param to SAML_VerifyBearerToken()
+// and fix all the test calls.
+
+/*
+ ******************************************************************************
+ * SAML_VerifyBearerTokenEx -- */ /**
+ *
+ * Determines whether the SAML bearer token can be used to authenticate.
+ * A token consists of a single SAML assertion.
+ *
+ * This is currently only used from the test code.
+ *
+ * @param[in] xmlText The text of the SAML assertion.
+ * @param[in] userName Optional username to authenticate as.
+ * @param[in] hostVerified If set, then the signature verification will
+ * be skipped.
+ * @param[out] userNameOut The user that the token has authenticated as.
+ * @param[out] subjNameOut The subject in the token. Caller must g_free().
+ * @param[out] verifyAi The alias info associated with the entry
+ * in the alias store used to verify the
+ * SAML cert.
+ *
+ * @return VGAUTH_E_OK on success, VGAuthError on failure
+ *
+ ******************************************************************************
+ */
+
+VGAuthError
+SAML_VerifyBearerTokenEx(const char *xmlText,
+ const char *userName, // UNUSED
+ gboolean hostVerified,
+ char **userNameOut, // UNUSED
+ char **subjNameOut,
+ ServiceAliasInfo **verifyAi) // UNUSED
+{
+ gboolean ret;
+ gchar **certChain = NULL;
+ int num = 0;
+
+ ret = VerifySAMLToken(xmlText,
+ hostVerified,
+ subjNameOut,
+ &num,
+ &certChain);
+
+ // clean up -- this code doesn't look at the chain
+ FreeCertArray(num, certChain);
+
+ return (ret == TRUE) ? VGAUTH_E_OK : VGAUTH_E_AUTHENTICATION_DENIED;
+}
/*
int num = 0;
ret = VerifySAMLToken(xmlText,
+ FALSE, // XXX keep original to minimze test changes
subjNameOut,
&num,
&certChain);
*
* @param[in] xmlText The text of the SAML assertion.
* @param[in] userName Optional username to authenticate as.
+ * @param[in] hostVerified If true, skip signature verification.
* @param[out] userNameOut The user that the token has authenticated as.
* @param[out] subjNameOut The subject in the token. Caller must g_free().
* @param[out] verifyAi The alias info associated with the entry
VGAuthError
SAML_VerifyBearerTokenAndChain(const char *xmlText,
const char *userName,
+ gboolean hostVerified,
char **userNameOut,
char **subjNameOut,
ServiceAliasInfo **verifyAi)
*verifyAi = NULL;
bRet = VerifySAMLToken(xmlText,
+ hostVerified,
subjNameOut,
&num,
&certChain);
auto_ptr<XMLGrammarPool> SAMLCreateAndPopulateGrammarPool();
VGAuthError SAMLVerifyAssertion(const char *xmlText,
+ gboolean hostVerified,
SAMLTokenData &token,
vector<string> &certs);
#endif // ifndef _SAMLINT_H_
VGAuthError SAML_Init(void);
/* clang-format off */
+VGAuthError SAML_VerifyBearerTokenEx(const char *xmlText,
+ const char *userName,
+ gboolean hostVerified,
+ char **userNameOut,
+ char **subjectNameOut,
+ ServiceAliasInfo **verifyAi);
VGAuthError SAML_VerifyBearerToken(const char *xmlText,
const char *userName,
char **userNameOut,
ServiceAliasInfo **verifyAi);
VGAuthError SAML_VerifyBearerTokenAndChain(const char *xmlText,
const char *userName,
+ gboolean hostVerified,
char **userNameOut,
char **subjectNameOut,
ServiceAliasInfo **verifyAi);