]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Add vgauth smoketest
authorOliver Kurth <okurth@vmware.com>
Fri, 15 Sep 2017 18:23:32 +0000 (11:23 -0700)
committerOliver Kurth <okurth@vmware.com>
Fri, 15 Sep 2017 18:23:32 +0000 (11:23 -0700)
Provide the vgauth smoketest so open-vm-tools builders
can validate VGAUthservice.

open-vm-tools/configure.ac
open-vm-tools/vgauth/Makefile.am
open-vm-tools/vgauth/test/Makefile.am [new file with mode: 0644]
open-vm-tools/vgauth/test/README.txt [new file with mode: 0644]
open-vm-tools/vgauth/test/main.c [new file with mode: 0644]

index 363c76d977ed77cf0196fa9b10c5ec73ed81e159..117cf97657eeb18c00fdb34156cd28110c068b47 100644 (file)
@@ -1531,6 +1531,7 @@ AC_CONFIG_FILES([                      \
    vgauth/lib/Makefile                 \
    namespacetool/Makefile              \
    vgauth/cli/Makefile                 \
+   vgauth/test/Makefile                 \
    vgauth/service/Makefile             \
    libguestlib/Makefile                \
    libguestlib/vmguestlib.pc           \
index e246dcdedbe1c973a355391e306ad1a69070c485..22d92efc6cdf5613402f084508da869ec50d83d7 100644 (file)
@@ -19,3 +19,4 @@ SUBDIRS =
 SUBDIRS += lib
 SUBDIRS += cli
 SUBDIRS += service
+SUBDIRS += test
diff --git a/open-vm-tools/vgauth/test/Makefile.am b/open-vm-tools/vgauth/test/Makefile.am
new file mode 100644 (file)
index 0000000..92259a7
--- /dev/null
@@ -0,0 +1,45 @@
+################################################################################
+### Copyright (C) 2014-2017 VMware, Inc.  All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+################################################################################
+
+bin_PROGRAMS = vmware-vgauth-smoketest
+
+vmware_vgauth_smoketest_SOURCES =
+vmware_vgauth_smoketest_SOURCES += main.c
+
+vmware_vgauth_smoketest_CPPFLAGS =
+vmware_vgauth_smoketest_CPPFLAGS += -DVMTOOLS_USE_GLIB
+vmware_vgauth_smoketest_CPPFLAGS += @GLIB2_CPPFLAGS@
+vmware_vgauth_smoketest_CPPFLAGS += -I$(top_srcdir)/libvmtools
+vmware_vgauth_smoketest_CPPFLAGS += -I$(top_srcdir)/vgauth/public
+vmware_vgauth_smoketest_CPPFLAGS += -I$(top_srcdir)/vgauth/common
+
+vmware_vgauth_smoketest_LDADD =
+vmware_vgauth_smoketest_LDADD += @VMTOOLS_LIBS@
+vmware_vgauth_smoketest_LDADD += @GLIB2_LIBS@
+vmware_vgauth_smoketest_LDADD += @GTHREAD_LIBS@
+vmware_vgauth_smoketest_LDADD += @SSL_LIBS@
+vmware_vgauth_smoketest_LDADD += ../lib/libvgauth.la
+
+if HAVE_ICU
+   vmware_vgauth_smoketest_LDADD += @ICU_LIBS@
+   vmware_vgauth_smoketest_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS)     \
+                            $(LIBTOOLFLAGS) --mode=link $(CXX)       \
+                            $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+                            $(LDFLAGS) -o $@
+else
+   vmware_vgauth_smoketest_LINK = $(LINK)
+endif
diff --git a/open-vm-tools/vgauth/test/README.txt b/open-vm-tools/vgauth/test/README.txt
new file mode 100644 (file)
index 0000000..ae1d8a4
--- /dev/null
@@ -0,0 +1,37 @@
+ *    The VGAuthService smoke test.
+ *
+ *    This does some very basic vgauth effort to verify that it
+ *    properly validates SAML tokens.  This verifies that vgauth
+ *    was built and installed properly.
+ *
+ *    This uses a built-in SAML token with a 1000 year lifetime,
+ *    to avoid any issues with the XML security library on the signing
+ *    side.
+ *
+ *    This test must be run as root on the same system as VGAuthService.
+ *    This test should only be run in a test environment, since it
+ *    will clear out any existing aliases.
+ *
+ *    To use:
+ *    - start VGAuthService (/usr/bin/VGAuithService -s )
+ *    - run the smoketest
+ *
+ *
+ *    Steps:
+ *    - clear out any existing aliases
+ *    - add an alias using the built-in cert
+ *    - validate the SAML token
+ *
+ *    Possible reasons for failure:
+ *    - VGAuthService wasn't started
+ *    - VGAuthService failed to start up properly
+ *       - unable to find support files (schemas)
+ *       - unable to access various files/directories
+ *       - parts of xmlsec1 missing (openssl crypto lib missing)
+ *       - SAML verification failed to init (xmlsec1 build issues)
+ *    - token fails to validate
+ *       - this test was run after 12/18/3015
+ *       - xmlsec1-config lies about how xmlsec1 was built
+ *          some packages leave out -DXMLSEC_NO_SIZE_T,
+ *          which can make some data structures a different size
+ *          than in the library
diff --git a/open-vm-tools/vgauth/test/main.c b/open-vm-tools/vgauth/test/main.c
new file mode 100644 (file)
index 0000000..eb89017
--- /dev/null
@@ -0,0 +1,489 @@
+/*********************************************************
+ * Copyright (C) 2016-2017 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file main.c
+ *
+ *    The VGAuthService smoke test.
+ *
+ *    This does some very basic vgauth effort to verify that it
+ *    properly validates SAML tokens.
+ *
+ *    This uses a built-in SAML token with a 1000 year lifetime,
+ *    to avoid any issues with the XML security library on the signing
+ *    side.
+ *
+ *    This test must be run as root on the same system as VGAuthService.
+ *    This test should only be run in a test environment, since it
+ *    will clear out any existing aliases.
+ *
+ *    Steps:
+ *    - clear out any existing aliases
+ *    - add an alias using the built-in cert
+ *    - validate the SAML token
+ *
+ *    Possible reasons for failure:
+ *    - VGAuthService wasn't started
+ *    - VGAuthService failed to start up properly
+ *       - unable to find support files (schemas)
+ *       - unable to access various files/directories
+ *       - parts of xmlsec1 missing (openssl crypto lib missing)
+ *       - SAML verification failed to init (xmlsec1 build issues)
+ *    - token fails to validate
+ *       - this test was run after 12/18/3015
+ *       - xmlsec1-config lies about how xmlsec1 was built
+ *          some packages leave out -DXMLSEC_NO_SIZE_T,
+ *          which can make some data structures a different size
+ *          than in the library
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <errno.h>
+#endif
+#include <glib.h>
+
+#include "VGAuthBasicDefs.h"
+#include "VGAuthAlias.h"
+#include "VGAuthAuthentication.h"
+#include "VGAuthCommon.h"
+#include "VGAuthError.h"
+#include "VGAuthLog.h"
+#include "VGAuthUtil.h"
+
+static gchar *appName;
+
+#define ALIAS_USER_NAME    "root"
+#define SUBJECT_NAME       "SmokeSubject"
+#define COMMENT            "Smoke comment"
+
+#define MAKE_PEM_FROM_BASE64(base64) \
+   "-----BEGIN CERTIFICATE-----\n"   \
+   base64                            \
+   "-----END CERTIFICATE-----\n"
+/*
+ * Self-signed smoketest cert.
+ *
+ * Not Before: Aug 16 22:29:21 2016 GMT
+ * Not After : Dec 18 22:29:21 3015 GMT
+ *
+ */
+#define SMOKETEST_CERT_BASE64 \
+"MIIDZTCCAk2gAwIBAgIJALuLD4JnajhkMA0GCSqGSIb3DQEBBQUAMEgxCzAJBgNV\n" \
+"BAYTAlhYMRMwEQYDVQQIDApTbW9rZVN0YXRlMRIwEAYDVQQHDAlTbW9rZUNpdHkx\n" \
+"EDAOBgNVBAoMB1Ntb2tlQ28wIBcNMTYwODE2MjIyOTIxWhgPMzAxNTEyMTgyMjI5\n" \
+"MjFaMEgxCzAJBgNVBAYTAlhYMRMwEQYDVQQIDApTbW9rZVN0YXRlMRIwEAYDVQQH\n" \
+"DAlTbW9rZUNpdHkxEDAOBgNVBAoMB1Ntb2tlQ28wggEiMA0GCSqGSIb3DQEBAQUA\n" \
+"A4IBDwAwggEKAoIBAQDcRD+tNhOwxtEDDhnwQ94Qn+eEI4Nh6zXBP5CfnbMIHYo0\n" \
+"1tzxLWOaJsN8/WoHy2cbeQkXGiGHpzuJIndhkL3XZpRdKTLIw95EVJkChYJi8ZUl\n" \
+"LnaLIPsG1bpVOSuf+0qGcRyoItXBlvvYMZ5JAdUncHYnJ2NAbvqZVIH0sSafupzv\n" \
+"w5txeQ7ufIcCzHYzSIFiX82CVMq/xuSQULVAZXoIfjNqMlwhYQn/EiSFb+y3kUa+\n" \
+"xDzNWNyzv4H+7/6C+qz2KxTUbBEKT/lsuIVYVJ5R+1vZ2MnGkqsz8ELttXk0tAK+\n" \
+"pfUAg7ugOhpF2rdvNOt4874Kkdj8a2It/JKqN3kBAgMBAAGjUDBOMB0GA1UdDgQW\n" \
+"BBR9OuZuejgPVz64LWnhOfO1d6u0dTAfBgNVHSMEGDAWgBR9OuZuejgPVz64LWnh\n" \
+"OfO1d6u0dTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCZ91zS4zKZ\n" \
+"uQv5rXn/zJtJ7d1pWnywh26n5bBlNQS3N7nAQPG5fvK2MB2rztE45Anq056YcYL7\n" \
+"TTDDDPz9dGndThGyusHbzO/lV7UHCQUzMr0joItxrQoX7/4OPBMyARBLAE5wRa85\n" \
+"uXm0D/Z6AAKJLz30yaQ+kBwTlIVhJFFhQv2zGZ3vB7CN0zNAZ/4s6lo+ejHj4Dhc\n" \
+"PFsUDwWnqqp9iqZMX3vxp3BEuxUsSzXtuwBytvWcS/6i1LUl41obD4RNxZ3llQTN\n" \
+"+uXVUFTTt0NgCbMJq5G8Nz4ziyjgxT94tB/AMwRmJzPSvew3vGMFhF7Fm0Z3Oxn5\n" \
+"kWMiikdSCME8\n"
+
+
+const char *smoketestPEMCert = MAKE_PEM_FROM_BASE64(SMOKETEST_CERT_BASE64);
+
+const char *smoketestBase64Cert = SMOKETEST_CERT_BASE64;
+
+/*
+ * Token
+ */
+
+static const gchar *token =
+"<saml:Assertion xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"_b07b804c-7c29-ea16-7300-4f3d6f7928ac\" IssueInstant=\"2004-12-05T09:22:05Z\" Version=\"2.0\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
+"<saml:Issuer>https://sso.eng.vmware.com</saml:Issuer>\n"
+"<ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">\n"
+"<ds:SignedInfo>\n"
+"<ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>\n"
+"<ds:SignatureMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\"/>\n"
+"<ds:Reference URI=\"#_b07b804c-7c29-ea16-7300-4f3d6f7928ac\">\n"
+"<ds:Transforms>\n"
+"<ds:Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/>\n"
+"</ds:Transforms>\n"
+"<ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"/>\n"
+"<ds:DigestValue>w0kRFhuuzMenlkrfZttAweUTHcyRsQtHRn2L01Rmsa4=</ds:DigestValue>\n"
+"</ds:Reference>\n"
+"</ds:SignedInfo>\n"
+"<ds:SignatureValue>B54Qp2fO+YyMPK/6gYzCDigLZdOO3vEu8getiKB4a8s14ySoH6aQtq/RjgNSW8jr\n"
+"yNox9NRxc8ipBXC/noF8UBw6sUPpxsifMabWdMb9XvoZKufdDDrYKxQ4LwGjKF9y\n"
+"i2dO/Saw8kZ8CQKYvbNt0KkMqbQZNtDtM6AVAobWXuZioYyphQSJ6YZVwJnLh6wv\n"
+"sI0DgBqjFI91pID4n4N4SZq+tr2u8wcepnSIcmFNZ+BVdy7TKnjqTnjaDCG0Y0Uk\n"
+"P5wtWOAVpqTGMmTDpVwAtKfs089tDw/doGds+FIAXd6oR2eECo9j7SOm0i0V9pEn\n"
+"/nIe1Di7JNVJfl9V+g/bfA==</ds:SignatureValue>\n"
+"<ds:KeyInfo>\n"
+"<ds:X509Data>\n"
+"<ds:X509Certificate>MIIDZTCCAk2gAwIBAgIJALuLD4JnajhkMA0GCSqGSIb3DQEBBQUAMEgxCzAJBgNV\n"
+"BAYTAlhYMRMwEQYDVQQIDApTbW9rZVN0YXRlMRIwEAYDVQQHDAlTbW9rZUNpdHkx\n"
+"EDAOBgNVBAoMB1Ntb2tlQ28wIBcNMTYwODE2MjIyOTIxWhgPMzAxNTEyMTgyMjI5\n"
+"MjFaMEgxCzAJBgNVBAYTAlhYMRMwEQYDVQQIDApTbW9rZVN0YXRlMRIwEAYDVQQH\n"
+"DAlTbW9rZUNpdHkxEDAOBgNVBAoMB1Ntb2tlQ28wggEiMA0GCSqGSIb3DQEBAQUA\n"
+"A4IBDwAwggEKAoIBAQDcRD+tNhOwxtEDDhnwQ94Qn+eEI4Nh6zXBP5CfnbMIHYo0\n"
+"1tzxLWOaJsN8/WoHy2cbeQkXGiGHpzuJIndhkL3XZpRdKTLIw95EVJkChYJi8ZUl\n"
+"LnaLIPsG1bpVOSuf+0qGcRyoItXBlvvYMZ5JAdUncHYnJ2NAbvqZVIH0sSafupzv\n"
+"w5txeQ7ufIcCzHYzSIFiX82CVMq/xuSQULVAZXoIfjNqMlwhYQn/EiSFb+y3kUa+\n"
+"xDzNWNyzv4H+7/6C+qz2KxTUbBEKT/lsuIVYVJ5R+1vZ2MnGkqsz8ELttXk0tAK+\n"
+"pfUAg7ugOhpF2rdvNOt4874Kkdj8a2It/JKqN3kBAgMBAAGjUDBOMB0GA1UdDgQW\n"
+"BBR9OuZuejgPVz64LWnhOfO1d6u0dTAfBgNVHSMEGDAWgBR9OuZuejgPVz64LWnh\n"
+"OfO1d6u0dTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCZ91zS4zKZ\n"
+"uQv5rXn/zJtJ7d1pWnywh26n5bBlNQS3N7nAQPG5fvK2MB2rztE45Anq056YcYL7\n"
+"TTDDDPz9dGndThGyusHbzO/lV7UHCQUzMr0joItxrQoX7/4OPBMyARBLAE5wRa85\n"
+"uXm0D/Z6AAKJLz30yaQ+kBwTlIVhJFFhQv2zGZ3vB7CN0zNAZ/4s6lo+ejHj4Dhc\n"
+"PFsUDwWnqqp9iqZMX3vxp3BEuxUsSzXtuwBytvWcS/6i1LUl41obD4RNxZ3llQTN\n"
+"+uXVUFTTt0NgCbMJq5G8Nz4ziyjgxT94tB/AMwRmJzPSvew3vGMFhF7Fm0Z3Oxn5\n"
+"kWMiikdSCME8\n"
+"</ds:X509Certificate>\n"
+"</ds:X509Data>\n"
+"</ds:KeyInfo>\n"
+"</ds:Signature><saml:Subject>\n"
+"<saml:NameID Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\">SmokeSubject</saml:NameID>\n"
+"<saml:SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\">\n"
+"<saml:SubjectConfirmationData NotOnOrAfter=\"2116-07-23T23:29:34.677406Z\"/>\n"
+"</saml:SubjectConfirmation>\n"
+"</saml:Subject>\n"
+"<saml:Conditions NotBefore=\"2016-08-16T23:29:34.677402Z\" NotOnOrAfter=\"2116-07-23T23:29:34.677229Z\">\n"
+"<saml:AudienceRestriction>\n"
+"<saml:Audience>https://sp.example.com/SAML2</saml:Audience></saml:AudienceRestriction>\n"
+"</saml:Conditions>\n"
+"<saml:AuthnStatement AuthnInstant=\"2004-12-05T09:22:00Z\" SessionIndex=\"b07b804c-7c29-ea16-7300-4f3d6f7928ac\">\n"
+"<saml:AuthnContext>\n"
+"<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>\n"
+"</saml:AuthnContext>\n"
+"</saml:AuthnStatement>\n"
+"<saml:AttributeStatement>\n"
+"<saml:Attribute FriendlyName=\"eduPersonAffiliation\" Name=\"urn:oid:1.3.6.1.4.1.5923.1.1.1.1\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:uri\" xmlns:x500=\"urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500\" x500:Encoding=\"LDAP\">\n"
+"<saml:AttributeValue xsi:type=\"xs:string\">member</saml:AttributeValue>\n"
+"<saml:AttributeValue xsi:type=\"xs:string\">staff</saml:AttributeValue>\n"
+"</saml:Attribute>\n"
+"</saml:AttributeStatement>\n"
+"</saml:Assertion>\n"
+;
+
+
+/*
+ ******************************************************************************
+ * Usage --                                                              */ /**
+ *
+ * Usage message for smoke test
+ *
+ ******************************************************************************
+ */
+
+static void
+Usage(void)
+{
+   fprintf(stderr, "Usage: %s\n", appName);
+   exit(-1);
+}
+
+
+/*
+ ******************************************************************************
+ * Log --                                                                */ /**
+ *
+ * Error message logging function.
+ *
+ * @param[in]     logDomain   The glib logging domain, which is set by the
+ *                            various glib components and vgauth itself.
+ * @param[in]     logLevel    The severity of the message.
+ * @param[in]     msg         The error message.
+ * @param[in]     userData    Any userData specified in the call to
+ *                            VGAuth_SetLogHandler() (unused)
+ *
+ ******************************************************************************
+ */
+
+static void
+Log(const char *logDomain,
+    int logLevel,
+    const char *msg,
+    void *userData)
+{
+   g_printerr("%s[%d]: %s", logDomain, logLevel, msg);
+}
+
+
+/*
+ ******************************************************************************
+ * CleanAliases --                                                       */ /**
+ *
+ * Clears out the alias store for the given user, and the map file.
+ *
+ * @param[in]  ctx        VGAuth context
+ * @param[in]  userName   The user whose alias store is to be cleaned.
+ *
+ * @return A SAMl token on success, NULL failure.
+ *
+ ******************************************************************************
+ */
+
+static VGAuthError
+CleanAliases(VGAuthContext *ctx,
+             const gchar *userName)
+{
+   VGAuthError err;
+   int num;
+   int i;
+   VGAuthMappedAlias *maList;
+   VGAuthUserAlias *uaList;
+
+   // clear out mapped aliaes
+   err = VGAuth_QueryMappedAliases(ctx, 0, NULL, &num, &maList);
+   if (err != VGAUTH_E_OK) {
+      g_printerr("VGAuth_QueryMappedAliases() failed "VGAUTHERR_FMT64"\n",
+                 err);
+      return err;
+   }
+
+   for (i = 0; i < num; i++) {
+      err = VGAuth_RemoveAliasByCert(ctx, maList[i].userName,
+                                     maList[i].pemCert, 0, NULL);
+      if (err != VGAUTH_E_OK) {
+         g_printerr("VGAuth_RemoveAliasByCert() failed "VGAUTHERR_FMT64"\n",
+                    err);
+         return err;
+      }
+   }
+   VGAuth_FreeMappedAliasList(num, maList);
+   err = VGAuth_QueryMappedAliases(ctx, 0, NULL, &num, &maList);
+   if (err != VGAUTH_E_OK || num != 0) {
+         g_printerr("sitll have mapped aliases or "
+                    "VGAuth_QueryMappedAliases() failed "VGAUTHERR_FMT64"\n",
+                    err);
+         return err;
+   }
+
+   // clear out user aliases
+   err = VGAuth_QueryUserAliases(ctx, userName, 0, NULL,
+                                 &num, &uaList);
+   if (err != VGAUTH_E_OK) {
+      g_printerr("VGAuth_QueryUserAliases() failed "VGAUTHERR_FMT64"\n",
+                 err);
+      return err;
+   }
+   for (i = 0; i < num; i++) {
+      err = VGAuth_RemoveAliasByCert(ctx, userName,
+                                     uaList[i].pemCert, 0, NULL);
+      if (err != VGAUTH_E_OK) {
+         g_printerr("VGAuth_RemoveAliasByCert() failed "VGAUTHERR_FMT64"\n",
+                    err);
+         return err;
+      }
+   }
+
+   err = VGAuth_QueryUserAliases(ctx, userName, 0, NULL,
+                                 &num, &uaList);
+   if (err != VGAUTH_E_OK || num != 0) {
+      g_printerr("aliases left or VGAuth_QueryUserAliases() failed "
+                 VGAUTHERR_FMT64"\n",
+                 err);
+      return err;
+   }
+
+   return err;
+}
+
+
+/*
+ ******************************************************************************
+ * AddAlias --                                                           */ /**
+ *
+ * Generates a SAMl token with a given Subject.
+ *
+ * @param[in]  ctx        VGAuth context
+ * @param[in]  cert       The certificate for the alias.
+ * @param[in]  user       The user whose alias store is to be updated.
+ * @param[in]  subject    The Subject for the alias.
+ * @param[in]  comment    The Comment for the alias.
+ *
+ * @return A SAMl token on success, NULL failure.
+ *
+ ******************************************************************************
+ */
+
+static VGAuthError
+AddAlias(VGAuthContext *ctx,
+         const gchar *cert,
+         const gchar *user,
+         const gchar *subject,
+         const gchar *comment)
+{
+   VGAuthError err;
+   VGAuthAliasInfo ai;
+
+   ai.subject.type = VGAUTH_SUBJECT_NAMED;
+   ai.subject.val.name = (gchar *)subject;
+   ai.comment = (gchar *)comment;
+   err = VGAuth_AddAlias(ctx, user, FALSE, cert, &ai, 0, NULL);
+   if (err != VGAUTH_E_OK) {
+      g_printerr("VGAuth_AddAlias() failed "VGAUTHERR_FMT64"\n",
+                 err);
+      return err;
+   }
+
+   return err;
+}
+
+
+/*
+ ******************************************************************************
+ * ValidateToken --                                                      */ /**
+ *
+ * Validates a SAMl token.
+ *
+ * @param[in]  ctx        VGAuth context
+ * @param[in]  userName   The user associated with the token.
+ * @param[in]  token      A SAML token.
+ *
+ * @return VGAUTH_E_OK on success, an error on failure.
+ *
+ ******************************************************************************
+ */
+
+static VGAuthError
+ValidateToken(VGAuthContext *ctx,
+              const gchar *userName,
+              const gchar *token)
+{
+   VGAuthError err;
+   VGAuthExtraParams extraParams[1];
+   VGAuthUserHandle *userHandle = NULL;
+   VGAuthAliasInfo *retAi = NULL;
+   char *retSamlSubject = NULL;
+   char *retUserName = NULL;
+
+   /*
+    * Use info-only -- its all we need.
+    */
+   extraParams[0].name = VGAUTH_PARAM_VALIDATE_INFO_ONLY;
+   extraParams[0].value = VGAUTH_PARAM_VALUE_TRUE;
+   err = VGAuth_ValidateSamlBearerToken(ctx,
+                                        token,
+                                        userName,
+                                        1,
+                                        extraParams,
+                                        &userHandle);
+   if (VGAUTH_E_OK != err) {
+      g_printerr("Failed to validate token");
+      goto done;
+   }
+
+   err = VGAuth_UserHandleUsername(ctx, userHandle, &retUserName);
+   if (VGAUTH_E_OK != err) {
+      g_printerr("Failed to get username off handle");
+      goto done;
+   }
+   err = VGAuth_UserHandleSamlData(ctx,
+                                   userHandle,
+                                   &retSamlSubject,
+                                   &retAi);
+   if (VGAUTH_E_OK != err) {
+      g_printerr("Failed to get SAML subject data off handle");
+      goto done;
+   }
+   printf("Token details: user: %s (expected %s) subject: %s (expected %s)\n",
+          retUserName, ALIAS_USER_NAME, retSamlSubject, SUBJECT_NAME);
+
+done:
+   VGAuth_UserHandleFree(userHandle);
+   g_free(retUserName);
+   g_free(retSamlSubject);
+   VGAuth_FreeAliasInfo(retAi);
+   return err;
+}
+
+
+/*
+ ******************************************************************************
+ * main --                                                               */ /**
+ *
+ * Main entry point.
+ *
+ * @param[in]  argc        Number of command line arguments.
+ * @param[in]  argv        The command line arguments.
+ *
+ * @return 0 if the operation ran successfully, -1 if there was an error during
+ *         execution.
+ *
+ ******************************************************************************
+ */
+
+int
+main(int argc,
+     char *argv[])
+{
+   VGAuthError err;
+   VGAuthContext *ctx;
+
+   appName = g_path_get_basename(argv[0]);
+   if (argc != 1) {
+      Usage();
+   }
+
+   VGAuth_SetLogHandler(Log, NULL, 0, NULL);
+
+   err = VGAuth_Init(appName, 0, NULL, &ctx);
+   if (VGAUTH_E_OK != err) {
+      g_printerr("Failed to init VGAuth");
+      return -1;
+   }
+
+   // make sure we start with a clean slate
+   err = CleanAliases(ctx, ALIAS_USER_NAME);
+   if (VGAUTH_E_OK != err) {
+      g_printerr("Failed to clean alias store");
+      return -1;
+   }
+
+   err = AddAlias(ctx, smoketestPEMCert,
+                  ALIAS_USER_NAME, SUBJECT_NAME, COMMENT);
+   if (VGAUTH_E_OK != err) {
+      g_printerr("Failed to add alias");
+      return -1;
+   }
+
+   err = ValidateToken(ctx, ALIAS_USER_NAME, token);
+   if (VGAUTH_E_OK != err) {
+      g_printerr("Failed to validate SAML token");
+      return -1;
+   }
+
+   printf("PASSED!\n");
+
+   // make sure we end with a clean slate
+   err = CleanAliases(ctx, ALIAS_USER_NAME);
+   if (VGAUTH_E_OK != err) {
+      g_printerr("Failed to clean alias store");
+      return -1;
+   }
+
+   VGAuth_Shutdown(ctx);
+   g_free(appName);
+   return 0;
+}