pingidentity / scim2

The UnboundID SCIM 2.0 SDK for Java
176 stars 72 forks source link

Include both core and extension schema in application/scim+json representation #151

Closed michel-zedler closed 3 years ago

michel-zedler commented 3 years ago

Use Case: I need to extend the core user schema with some additional attributes.

In the com.unboundid.scim2.server.annotations.ResourceType annotation I can specify: schema=com.unboundid.scim2.common.types.UserResource requiredSchemaExtensions = my.custom.UserExtension then the /Schemas endpoint will correctly expose both schemas and the /ResourceTypes endpoint will correctly reference both schemas: "schema": "urn:ietf:params:scim:schemas:core:2.0:User", "schemaExtensions": [ { "schema": "urn:ietf:params:scim:schemas:extension:mycustom:2.0:User", "required": true } ],

I understand from the Enterprise User Extension Representation example in https://tools.ietf.org/html/rfc7643#section-8.3 that the schemas attribute must reference all relevant schemas but I seem to be unable to achieve this with the current SDK.

When I have my.custom.UserExtension extend BaseScimResource and return my.custom.UserExtension or ListResponse in a GET response
schemas it will only reference the schema extension (urn:ietf:params:scim:schemas:extension:mycustom:2.0:User and not urn:ietf:params:scim:schemas:core:2.0:User). Also this does not allow me to expose any core attributes in the response.

Currently I could have my.custom.UserExtension extend com.unboundid.scim2.common.types.UserResource but that would redefine all core attributes in the schema extension.

I would like to be able to extend com.unboundid.scim2.common.types.UserResource, have the GET response reference both schemas (urn:ietf:params:scim:schemas:extension:mycustom:2.0:User and not urn:ietf:params:scim:schemas:core:2.0:User) and urn:ietf:params:scim:schemas:extension:mycustom:2.0:User schema exposed by /Schemas be clean of attributes inherited from the com.unboundid.scim2.common.types.UserResource.

michel-zedler commented 3 years ago

Java class extension is the wrong approach, instead it can be achieved by using com.unboundid.scim2.common.BaseScimResource#setExtension e.g. on a UserResource object instance - then the com.fasterxml.jackson.databind.ObjectMapper provided by com.unboundid.scim2.common.utils.JsonUtils#createObjectMapper will to the trick.

iinuwa commented 3 years ago

@michel-zedler, do you mind giving more information about this? I have set the extension on a UserResource, but I can only see the schema URN showing up in the schemasUrn" field; I don't see the urn:ietf:params:scim:schemas:extension:enterprise:2.0:User field populated with the values I set.

michel-zedler commented 3 years ago

@iinuwa I needed to register the ObjectMapper provided as JAX-RS provider for application/scim+json:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.unboundid.scim2.common.utils.ApiConstants;
import com.unboundid.scim2.common.utils.JsonUtils;

import javax.ws.rs.Produces;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

@Provider
@Produces({ApiConstants.MEDIA_TYPE_SCIM})
class JacksonScimConfig implements ContextResolver<ObjectMapper> {

    ObjectMapper mapper = JsonUtils.createObjectMapper();

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }
}
iinuwa commented 3 years ago

Ah, ok. Thanks!

Your post made me realize that I was doing that already and that the ObjectMapper I registered wasn't being used. A couple of searches on StackOverflow led me to this answer that showed me I needed to remove the jersey-media-json-binding dependency generated by the Grizzly project archetype that I used in order for it to work.

Here's how I'm doing it (stolen from example in scim2-server-sdk tests):

final ResourceConfig config = new ResourceConfig();
// ...
JacksonJsonProvider provider =
        new JacksonJsonProvider(JsonUtils.createObjectMapper());
provider.configure(JaxRSFeature.ALLOW_EMPTY_INPUT, false);
config.register(provider);

All is well, thank you!