Obtaining and setting custom attributes between privacyidea and simplesamlphp


We are implementing an application named Zivver. Zivver requires the use of a few attributes that we need to fetch from the AD (behind Privacyidea) and feed them into simplesamlphp. The reference I have is for adfs : https://docs.zivver.com/nl/manuals/sso/microsoft-adfs.html, but there is an okta example as well. We have setup succesfully ( I think ;-)) the connection between simplesamlphp and zivver.

But we fail to get the attributes:

  • LDAP Attribute : ObjectGUID – Outgoing Claim Type : https://zivver.com/SAML/Attributes/ZivverAccountKey
  • LDAP Attribute : E-Mail Addresses – Outgoing Claim Type : E-Mail Address

How can I map the objectGUID to “https://zivver.com[…]”? How do I get them in privacyidea, when I add them to my objects, I only get a { referenced instead of the objectGUID.

And perhaps someone also knows how we can map those attributes back into saml so that it forwards them to Zivver. The email address currently looks like an hash when I Try to authenticate to the application.

Thanks in advance,
hat: for my customer :slight_smile:

Which version of privacyIDEA server and of the privacyIDEA simpleSAML Plugin are you using?

You can add additional fields to the attribute mapping in your LDAP resolver (like “objectGUID”: “objectGUI”).

The SAML plugin uses the /validate/samlcheck endpoint.
In my case the response would look like this:

"jsonrpc": "2.0",
"signature": "12077405501122846328410580115358292216873387714536930480117467034837077699544420068114075749216262678673921076335540692024128392075509703400054127035329145723607028397295609951012578506141921797852621376542037163365586631786750843928970418687982963260018529792499197668524228430132281393893999215618192304452169380033169028099976034298859172326481592119715083200550439715210704924525537653602347317139938377501720746691550233866304315658927570930434647763733089408545846259040058589138021375030769977367966953177016380998549110944495074171388169315133523388786677547047216148106046380143122813281839710017849256581480",
"detail": {
    "message": "matching 1 tokens",
    "type": "spass",
    "serial": "PISP00010A27",
    "otplen": 6,
    "threadid": 140246336042752
"versionnumber": "2.23.4",
"version": "privacyIDEA 2.23.4",
"result": {
    "status": true,
    "value": {
        "attributes": {
            "username": "kölbel",
            "realm": "testfoo",
            "resolver": "testfoo",
            "mobile": "+4915129601417,+4915129601416",
            "objectGUID": "30d0b95e-2a32-4a28-9ac9-3e9e0eed828c",
            "phone": "",
            "groups": [
                "CN=TOken USer,CN=Users,DC=testfoo,DC=intranet",
                "CN=Domain Admins,CN=Users,DC=testfoo,DC=intranet"
            "surname": "Kölbel",
            "givenname": "Cornelius",
            "email": "a@example.com; b@example.com"
        "auth": true
"time": 1550760593.679706,
"id": 1

Then you can map the contents of “value”->“attributes” to SAML attributes.
But first you should verify, that you get the right response, when calling the /validate/samlcheck endpoint.

Hi Corne,

We are currently using:

privacyidea-all/now 2.22.1-1xenial
together with:
privacyidea-simplesamlphp/now 2.22.1-1xenial

I hadded the Attribute mapping in the ldap resolver, we have the following there:

{ “username”: “sAMAccountName”, “phone” : “telephoneNumber”, “mobile” : “mobile”, “email” : “mail”, “surname” : “sn”, “givenname” : “givenName”, “displayname” : “displayName”, “objectGUID” : “objectGUID” }

But somehow, that generates a { for objectGUID.

How can I Call the /validate/samlcheck endpoint? is that on the privacyidea server?

It is on the privacyIDEA server. You can have a look at this https://privacyidea.readthedocs.io/en/latest/modules/api/validate.html#post--validate-samlcheck

As @Mipronimo said, you can call the endpoint on your privacyIDEA system. For simplicity you can do a GET Request in your browser and take a look at the JSON response.

From 2.22 to 2.23 there were several LDAP changes, so chances are good, that 2.23 can handle the objectGUID, while 2.22 can not.

Before upgrading your existing, productive installation, you could also install a test system with 2.23.4 to check, if everything works our fine in your environment.

I just checked the difference between the two git tags:

git diff v2.22.1 v2.23.4 -- privacyidea/lib/resolvers/LDAPIdResolver.py 

which shows that the actually are the relevant changes for the objectGUID:

 @@ -489,7 +509,11 @@ class IdResolver (UserIdResolver):
             for map_k, map_v in self.userinfo.items():
                 if ldap_k == map_v:
                     if ldap_k == "objectGUID":
-                        ret[map_k] = ldap_v[0]
+                        # An objectGUID should be no list, since it is unique
+                        if isinstance(ldap_v, basestring):
+                            ret[map_k] = ldap_v.strip("{").strip("}")
+                        else:
+                            raise Exception("The LDAP returns an objectGUID, that is no string: {0!s}".format(type(ldap_v)))
                     elif type(ldap_v) == list and map_k not in self.multivalueattributes:
                         # lists that are not in self.multivalueattributes return first value
                         # as a string. Multi-value-attributes are returned as a list
@@ -529,12 +553,28 @@ class IdResolver (UserIdResolver):
         if len(self.loginname_attribute) > 1:
             loginname_filter = u""
             for l_attribute in self.loginname_attribute:
-                loginname_filter += u"({!s}={!s})".format(l_attribute.strip(),
-                                                          login_name)
+                # Special case if we have a guid
+                try:
+                    if l_attribute.lower() == "objectguid":
+                        search_login_name = trim_objectGUID(login_name)
+                    else:
+                        search_login_name = login_name
+                    loginname_filter += u"({!s}={!s})".format(l_attribute.strip(),
+                                                              search_login_name)
+                except ValueError:
+                    # This happens if we have a self.loginname_attribute like ["sAMAccountName","objectGUID"],
+                    # the user logs in with his sAMAccountName, which can
+                    # not be transformed to a UUID
+                    log.debug(u"Can not transform {0!s} to a objectGUID.".format(login_name))
             loginname_filter = u"|" + loginname_filter
+            if self.loginname_attribute[0].lower() == "objectguid":
+                search_login_name = trim_objectGUID(login_name)
+            else:
+                search_login_name = login_name
             loginname_filter = u"{!s}={!s}".format(self.loginname_attribute[0],
-                                                   login_name)
+                                                   search_login_name)
         log.debug("login name filter: {!r}".format(loginname_filter))

Ah great! I will poke at it on monday again to see whether I can get the results that I expect.
Can I “apply” the diff without breaking things, or should we test and plan for the update?

I would not recommend applying the diffs seperately!
Update to 2.23.4.

Hi Cornelius,

We have recently updated the application and it seems that we can get the objectGUID now. I also hacked around a bit (i dont find simplesaml that easy to use) and I can access the Zivver application now as well.


1 Like