diff --git a/README.md b/README.md
index 16e58bd4200609a3288799e51f02cf327492d721..4c9d1db592700bbd253ac4fccd2ff1ce3ff726aa 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,43 @@ A comma-separated list of _Fully Qualified Attribute Names_
 
 ### voms_user
 
+user DN
+
+### voms_user_ca
+
+user CA
+
+### voms_server
+
+server DN
+
+### voms_server_ca
+
+server CA
+
+### voms_vo
+
+VO name
+
+### voms_server_uri
+
+VOMS server URI
+
+### voms_not_before
+
+not-before
+
+### voms_not_after
+
+not-after
+
+### voms_generic_attributes
+
+generic attributes
+
+### voms_serial
+
+serial number
 
 ## Testing
 
diff --git a/src/ngx_http_voms_module.cpp b/src/ngx_http_voms_module.cpp
index 7cfdebbc9c12142efed42334a8df6f0cf8a17784..8611c8d35caf736d81c2b6fd4854f4150423f47f 100644
--- a/src/ngx_http_voms_module.cpp
+++ b/src/ngx_http_voms_module.cpp
@@ -63,29 +63,110 @@ ngx_module_t ngx_http_voms_module = {
 
 static std::unique_ptr<vomsdata> vomsdata_ptr;
 
-static ngx_int_t get_voms_fqans(  //
-    ngx_http_request_t* r,
-    ngx_http_variable_value_t* v,
-    uintptr_t data);
-static ngx_int_t get_voms_user(  //
+static ngx_int_t generic_getter(  //
     ngx_http_request_t* r,
     ngx_http_variable_value_t* v,
     uintptr_t data);
 
+using getter_t = std::string(VomsAc const& voms);
+static getter_t get_voms_user;
+static getter_t get_voms_user_ca;
+static getter_t get_voms_fqans;
+static getter_t get_voms_server;
+static getter_t get_voms_server_ca;
+static getter_t get_voms_vo;
+static getter_t get_voms_server_uri;
+static getter_t get_voms_not_before;
+static getter_t get_voms_not_after;
+static getter_t get_voms_generic_attributes;
+static getter_t get_voms_serial;
+
 static ngx_http_variable_t variables[] = {
+    {
+        ngx_string("voms_user"),
+        NULL,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_user),
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
+    {
+        ngx_string("voms_user_ca"),
+        NULL,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_user_ca),
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
     {
         ngx_string("voms_fqans"),
         NULL,
-        get_voms_fqans,
-        0,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_fqans),
         NGX_HTTP_VAR_NOCACHEABLE,
         0  //
     },
     {
-        ngx_string("voms_user"),
+        ngx_string("voms_server"),
+        NULL,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_server),
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
+    {
+        ngx_string("voms_server_ca"),
         NULL,
-        get_voms_user,
-        0,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_server_ca),
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
+    {
+        ngx_string("voms_vo"),
+        NULL,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_vo),
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
+    {
+        ngx_string("voms_server_uri"),
+        NULL,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_server_uri),
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
+    {
+        ngx_string("voms_not_before"),
+        NULL,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_not_before),
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
+    {
+        ngx_string("voms_not_after"),
+        NULL,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_not_after),
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
+    {
+        ngx_string("voms_generic_attributes"),
+        NULL,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_generic_attributes),
+        NGX_HTTP_VAR_NOCACHEABLE,
+        0  //
+    },
+    {
+        ngx_string("voms_serial"),
+        NULL,
+        generic_getter,
+        reinterpret_cast<uintptr_t>(&get_voms_serial),
         NGX_HTTP_VAR_NOCACHEABLE,
         0  //
     },
@@ -200,11 +281,11 @@ static MaybeVomsAc const& get_voms_ac(ngx_http_request_t* r)
   return *acp;
 }
 
-static ngx_int_t get_voms_fqans(ngx_http_request_t* r,
+static ngx_int_t generic_getter(ngx_http_request_t* r,
                                 ngx_http_variable_value_t* v,
-                                uintptr_t)
+                                uintptr_t data)
 {
-  ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "%s", __FUNCTION__);
+  ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "%s", __func__);
 
   v->not_found = 1;
   v->valid = 0;
@@ -216,52 +297,89 @@ static ngx_int_t get_voms_fqans(ngx_http_request_t* r,
     return NGX_OK;
   }
 
-  auto fqans = boost::algorithm::join(ac->fqan, ",");
+  using getter_p = std::string (*)(VomsAc const& voms);
+  auto getter = reinterpret_cast<getter_p>(data);
+  std::string const value = getter(*ac);
 
-  auto data = static_cast<u_char*>(ngx_pnalloc(r->pool, fqans.size()));
-  if (!data) {
+  auto buffer = static_cast<u_char*>(ngx_pnalloc(r->pool, value.size()));
+  if (!buffer) {
     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pnalloc() failed");
     return NGX_OK;
   }
-  ngx_memcpy(data, fqans.c_str(), fqans.size());
+  ngx_memcpy(buffer, value.c_str(), value.size());
 
-  v->data = data;
-  v->len = fqans.size();
+  v->data = buffer;
+  v->len = value.size();
   v->valid = 1;
   v->not_found = 0;
   v->no_cacheable = 0;
   return NGX_OK;
 }
 
-static ngx_int_t get_voms_user(ngx_http_request_t* r,
-                               ngx_http_variable_value_t* v,
-                               uintptr_t)
+std::string get_voms_user(VomsAc const& ac)
 {
-  ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "%s", __FUNCTION__);
+  return ac.user;
+}
 
-  v->not_found = 1;
-  v->valid = 0;
+std::string get_voms_user_ca(VomsAc const& ac)
+{
+  return ac.userca;
+}
 
-  auto& ac = get_voms_ac(r);
+std::string get_voms_fqans(VomsAc const& ac)
+{
+  return boost::algorithm::join(ac.fqan, ",");
+}
 
-  if (!ac) {
-    ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "get_voms_ac() failed");
-    return NGX_OK;
-  }
+std::string get_voms_server(VomsAc const& ac)
+{
+  return ac.server;
+}
 
-  auto const& user = ac->user;
+std::string get_voms_server_ca(VomsAc const& ac)
+{
+  return ac.serverca;
+}
 
-  auto data = static_cast<u_char*>(ngx_pnalloc(r->pool, user.size()));
-  if (!data) {
-    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pnalloc() failed");
-    return NGX_OK;
-  }
-  ngx_memcpy(data, user.c_str(), user.size());
+std::string get_voms_vo(VomsAc const& ac)
+{
+  return ac.voname;
+}
 
-  v->data = data;
-  v->len = user.size();
-  v->valid = 1;
-  v->not_found = 0;
-  v->no_cacheable = 0;
-  return NGX_OK;
+std::string get_voms_server_uri(VomsAc const& ac)
+{
+  return ac.uri;
+}
+
+std::string get_voms_not_before(VomsAc const& ac)
+{
+  return ac.date1;
+}
+
+std::string get_voms_not_after(VomsAc const& ac)
+{
+  return ac.date2;
+}
+
+// struct attribute {
+//   std::string name;      /*!< attribute's group */
+//   std::string qualifier; /*!< attribute's qualifier */
+//   std::string value;     /*!< attribute's value */
+// };
+
+// struct attributelist {
+//   std::string grantor;               /*!< Who granted these attributes. */
+//   std::vector<attribute> attributes; /*!< The attributes themselves.    */
+// };
+
+std::string get_voms_generic_attributes(VomsAc const& ac)
+{
+  // the GetAttributes method is not declared const
+  auto const attributes = const_cast<VomsAc&>(ac).GetAttributes();
+  return {};
+}
+
+std::string get_voms_serial(VomsAc const& ac)
+{
+  return ac.serial;
 }