0

In the SCIM core schema there is a simple multivalued attribute "photos" defined to hold the urls of a user's photos.

In the UnboundID Data Store config directory the scim-resources.xml file has the following commented out under the User resource:

<!-- Mapping must be defined to use this attribute
<attribute name="photos" schema="urn:scim:schemas:core:1.0"
           readOnly="false" required="false">
  <description>URL of photos of the User</description>
  <simpleMultiValued childName="photo" dataType="string">
    <canonicalValue name="photo"/>
    <canonicalValue name="thumbnail"/>
  </simpleMultiValued>
</attribute>
-->

Further down in the spec is an example output:

"photos": [
  {
    "value": "https://photos.example.com/profilephoto/72930000000Ccne/F",
    "type": "photo"
  },
  {
    "value": "https://photos.example.com/profilephoto/72930000000Ccne/T",
    "type": "thumbnail"
  }
],

I have User entries with the jpegPhoto attribute populated. Questions:

  1. Does UnboundID already have an endpoint defined to access these photos? I don't want just the encoded binary string value of jpegPhoto
  2. If such an endpoint exists (or I create one), do I then need to write a transformation class and reference it in a <subMapping> child element of the <canonicalValue> elements?

If how to do this is documented somewhere I haven't been able to find it.

Any guidance appreciated.

Grant

GBC
  • 35
  • 6

2 Answers2

1

Since the SCIM photos attribute refers to an array of external URLs to the photos, you could create a Data Store virtual attribute which maps in SCIM to an array of URLs that reference a hosted servlet to retrieve the photo(s). There is no existing server endpoint for returning jpegPhoto attributes from an ldap entry and you've said you don't want the base64-encoded binary data via SCIM.

An HTTP Servlet Extension which returns photos would ideally accept the same credentials as the SCIM user for authentication and perform an LDAP search as the SCIM user that will honor ACI access control for the jpegPhoto attribute, e.g.

GET https://server:8443/photosEndpoint/{entryUUID}[/attribute-option]
Authorization: <scim user credentials>

Since jpegPhoto is a multi-value attribute, if there is one (or the first, if many) jpegPhoto attributes, this can return an img/jpeg content-type entity. It looks like you're attempting to select from multiple photos using a qualifier, e.g. /F for full size? and /T for thumbnail but there is no way to tell multi-values attribute values apart in LDAP without an attribute option, e,g,

jpegPhoto returned via /photosEndpoint/{entryUUID}
jpegPhoto;size=fullsize returned via /photosEndpoint/{entryUUID}[/fullsize | /F]
jpegPhoto;size=thumbnail returned via /photosEndpoint/{entryUUID}[/thumbnail | /T]

The servlet could also be written to handle multiple photos by returning them in a multi-part MIME response with a jpegPhoto per part. The part names would include the attribute options, if available. One downside is this kind response would not render easily in a browser.

Overall this is a nice-to-have idea but some amount of work in practice. UnboundID support might be able to help.

Richard
  • 11
  • 1
  • Thanks Richard. I'm not so much concerned with returning/selecting from multiple photos (yet!) but if there was an existing endpoint and the required change to the SCIM resources.xml. I've got something working which I detail in an answer below. – GBC Sep 09 '15 at 00:33
0

As a starting point I wrote a simple servlet to return the first value of jpegPhoto (if present) as an image/png via an LDAP query against the uid. I then wrote a simple transform class to return the relevant photo URL based on the uid:

import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.scim.schema.AttributeDescriptor;
import com.unboundid.scim.sdk.SCIMAttributeValue;
import com.unboundid.util.ByteString;

public class PhotoTransform extends com.unboundid.scim.ldap.Transformation {

@Override
public String toLDAPFilterValue(String scimFilterValue) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public ASN1OctetString toLDAPValue(AttributeDescriptor descriptor, SCIMAttributeValue value) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public SCIMAttributeValue toSCIMValue(AttributeDescriptor descriptor, ByteString value) {
    return SCIMAttributeValue.createStringValue("http://localhost:4567/photo/" + value.stringValue());
}

I then referenced the class in the SCIM resources.xml passing the uid as the LDAP attribute:

<attribute name="photos" schema="urn:scim:schemas:core:1.0"
           readOnly="false" required="false">
  <description>URL of photos of the User</description>
  <simpleMultiValued childName="photo" dataType="string">
    <canonicalValue name="photoUrl">
            <subMapping name="value" ldapAttribute="uid"
                    transform="com.example.scim.PhotoTransform">
            </subMapping>
    </canonicalValue>
    <canonicalValue name="thumbnail"/>
  </simpleMultiValued>
</attribute>

and a SCIM query (against the reference implementation)

curl 'http://localhost:8080/Users?filter=userName%20eq%20%22jsmith%22' -u bjensen:password

now returns:

{
"totalResults" : 1,
"itemsPerPage" : 1,
"startIndex" : 1,
"schemas" : ["urn:scim:schemas:core:1.0", "urn:scim:schemas:extension:enterprise:1.0"],
"Resources" : [{
        "name" : {
            "formatted" : "Mr. John Smith",
            "familyName" : "Smith",
            "givenName" : "John"
        },
        "phoneNumbers" : [{
                "value" : "tel:555-555-1256",
                "type" : "work"
            }
        ],
        "userName" : "jsmith",
        "emails" : [{
                "value" : "jsmith@example.com",
                "type" : "work"
            }
        ],
        "photos" : [{
                "value" : "http://localhost:4567/photo/jsmith",
                "type" : "photoUrl"
            }
        ],
        "id" : "fb4134dc-0a93-476a-964a-c29847f3bf79",
        "meta" : {
            "created" : "2015-09-09T00:17:12.768Z",
            "lastModified" : "2015-09-09T00:17:12.768Z",
            "location" : "http://localhost:8080/v1/Users/fb4134dc-0a93-476a-964a-c29847f3bf79",
            "version" : "\"20150909001712.768Z\""
        }
    }]
}
GBC
  • 35
  • 6