Git Product home page Git Product logo

scim2's Introduction

Maven Central Javadocs Build Status

UnboundID SCIM 2 SDK for Java

SCIM, or System for Cross-domain Identity Management, is an IETF standard that defines an extensible schema mechanism and REST API for managing users and other identity data. SCIM is used by a variety of vendors โ€” including GitHub, Salesforce, Microsoft, Cisco, Sailpoint, and Ping Identity โ€” for a variety of purposes, including user provisioning, directory services, attribute exchange, and more.

The UnboundID SCIM 2 SDK for Java provides a powerful and flexible set of APIs for interacting with SCIM service providers and resources. Use it to build applications and servers that interoperate with SCIM servers such as the PingDirectory Server.

The SCIM 2 SDK consists of the following components:

Component name What it is Who needs it
scim2-sdk-client The SCIM 2 client API. SCIM client developers.
scim2-ubid-extensions Model classes representing UnboundID extensions to the SCIM standard. This component is subject to API changes and should be considered experimental. SCIM client developers using features specific to UnboundID servers.
scim2-sdk-server Classes for use by SCIM 2 service providers. SCIM service provider implementers.
scim2-sdk-common Shared model, exception, and utility classes. Included as a transitive dependency of all of the above.

How to get it

The SCIM 2 SDK is available from Maven Central and can be included in your product like any other Maven dependency. Check Maven Central for the latest available version of SCIM 2 SDK dependencies.

For general-purpose clients:

<dependency>
  <groupId>com.unboundid.product.scim2</groupId>
  <artifactId>scim2-sdk-client</artifactId>
  <version>VERSION</version>
</dependency>

For clients using UnboundID-specific features:

<dependency>
  <groupId>com.unboundid.product.scim2</groupId>
  <artifactId>scim2-ubid-extensions</artifactId>
  <version>VERSION</version>
</dependency>

You may also download SCIM 2 SDK builds from the Releases page.

How to use it

The UnboundID SCIM 2 SDK requires Java 11 or greater.

The primary point of entry for a client is the ScimService class, which represents a SCIM service provider, such as the PingDirectory Server. This class acts as a wrapper for a JAX-RS client instance, providing methods for building and making requests.

Other classes provide facilities for selecting attributes by path, building query filters, and working with JSON documents. SCIM resources returned from a service provider can either be represented as POJOs or using an API based on the Jackson tree model.

import com.unboundid.scim2.client.ScimService;
import com.unboundid.scim2.common.exceptions.ScimException;
import com.unboundid.scim2.common.types.UserResource;
import com.unboundid.scim2.common.types.Name;
import com.unboundid.scim2.common.types.Email;
import com.unboundid.scim2.common.GenericScimResource;
import com.unboundid.scim2.common.messages.ListResponse;
import com.unboundid.scim2.common.filters.Filter;

// Create a ScimService
Client client = ClientBuilder.newClient().register(OAuth2ClientSupport.feature("..bearerToken.."));
WebTarget target = client.target("https://example.com/scim/v2");
ScimService scimService = new ScimService(target);

// Create a user
UserResource user = new UserResource();
user.setUserName("babs");
user.setPassword("secret");
Name name = new Name()
  .setGivenName("Barbara")
  .setFamilyName("Jensen");
user.setName(name);
Email email = new Email()
  .setType("home")
  .setPrimary(true)
  .setValue("[email protected]");
user.setEmails(email);
user = scimService.create("Users", user);

// Retrieve the user as a UserResource and replace with a modified instance using PUT
user = scimService.retrieve("Users", user.getId(), UserResource.class);
user.setDisplayName("Babs");
user = scimService.replace(user);

// Retrieve the user as a GenericScimResource and replace with a modified instance using PUT
GenericScimResource genericUser =
    scimService.retrieve("Users", user.getId(), GenericScimResource.class);
genericUser.replace("displayName", "Babs Jensen");
genericUser = scimService.replaceRequest(genericUser).invoke();

// Perform a partial modification of the user using PATCH
scimService.modifyRequest("Users", user.getId())
           .replaceValue("displayName", "Babs")
           .invoke(GenericScimResource.class);

// Perform a password change using PATCH
scimService.modifyRequest("Users", user.getId())
           .replaceValue("password", "new-password")
           .invoke(GenericScimResource.class);

// Search for users with the same last name as our user
ListResponse<UserResource> searchResponse =
  scimService.searchRequest("Users")
        .filter(Filter.eq("name.familyName", user.getName().getFamilyName()).toString())
        .page(1, 5)
        .attributes("name")
        .invoke(UserResource.class);

For detailed information about using the SCIM 2 SDK, including more examples, please see the wiki.

Nullability Annotations

As of version 3.1.0, the SCIM 2 SDK provides the com.unboundid.scim2.common.annotations.Nullable and com.unboundid.scim2.common.annotations.NotNull annotations for all input parameters, member variables, and method return values. This is designed to provide insight when invoking SCIM SDK library methods, help interface with languages like Kotlin (which has built-in null types for variables), and to help applications become less prone to nullability problems. These annotations can be leveraged by IDE tools to help validate objects that are given to and received from the SCIM SDK library. To configure/integrate this into your environment, view the documentation of your IDE of choice. Some popular choices are linked below:

Reporting issues

Please report bug reports and enhancement requests through this project's issue tracker. See the contribution guidelines for more information.

License

The UnboundID SCIM2 SDK is available under three licenses: the GNU General Public License version 2 (GPLv2), the GNU Lesser General Public License version 2.1 (LGPLv2.1), and a free-right-to-use license created by UnboundID Corp. See the LICENSE file for more info.

scim2's People

Contributors

bertold avatar braveulysses avatar bskinny avatar continuousintegrationunboundid avatar coulbeck avatar dbrowski avatar dependabot[bot] avatar digitalperk avatar dirmgr avatar dvernon-uid avatar henryrecker-unboundid avatar kenneth-ping avatar kolehey avatar kqarryzada avatar lance-purple-unboundid avatar nprager avatar psarkarping avatar richardcardona avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

scim2's Issues

Query parameters set through RequestBuilder.queryParam(...) are ignored when using .search

Arbitrary query parameters set via RequestBuilder.queryParam(...) are ignored when used in conjunction with a search via POST.

Adding something like

      service.searchRequest("Users").
          filter(filter).
          queryParam(expectedKey, expectedValue).
          invokePost(UserResource.class);

to EndpointTestCase.testQueryParams() should reproduce this.

Note that there isn't actually an implementation yet. For the client to set these parameters, logic needs to be added to SearchRequestBuilder.invoke(boolean, SearchResultHandler<T>, Class<T>), similar to the existing logic there for handling arbitrary headers. Then, support will need to be added to the server component, in DotSearchFilter, I assume.

Get HTTP status code from invoke method

Is there a way to get http status code from invoke method?

retrieveRequest(USERS_ENDPOINT, id).invoke(UserResource.class);

This method above will return the response in UserResource object..I'd like to also get HTTP status code from the response as well.

Thanks

patchOp.apply puts added enterprise fields under wrong path

When applying a patch add operation for an enterprise field (namely department), patchOp.apply puts the added department as a field in an object under they key "User" in an object which sits under the key "urn:ietf:params:scim:schemas:extension:enterprise:2.0". The department should actually be added as a field in an object under the key "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User".

For example say we have a user resource:

{
  "schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" ],
  "externalId" : "externalId-1",
  "meta" : {
    "resourceType" : "User"
  },
  "userName" : "user1",
  "name" : {
    "familyName" : "Young",
    "givenName" : "Joy"
  },
  "displayName" : "Joy Young",
  "active" : true,
  "emails" : [ {
    "value" : "[email protected]",
    "type" : "work",
    "primary" : true
  }, {
    "value" : "[email protected]",
    "type" : "work",
    "primary" : false
  } ],
  "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" : {
    "department" : null,
    "manager" : null
  }
}

This is parsed into a UserResource object.

We then parse the following patch operation:

{
  "schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
  "Operations" : [ {
    "op" : "add",
    "path" : "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.department",
    "value" : "Department A"
  }, {
    "op" : "replace",
    "path" : "name.familyName",
    "value" : "Smith"
  } ]
}

We turn the UserResource into a generic scim resource by calling asGenericScimResource() on it. We then apply the patch operation by passing the generic scim resource to the patch op's apply method.

The result of this is the following:

{
  "schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" ],
  "externalId" : "externalId-1",
  "meta" : {
    "resourceType" : "User"
  },
  "userName" : "user1",
  "name" : {
    "familyName" : "Smith",
    "givenName" : "Joy"
  },
  "displayName" : "Joy Young",
  "active" : true,
  "emails" : [ {
    "value" : "[email protected]",
    "type" : "work",
    "primary" : true
  }, {
    "value" : "[email protected]",
    "type" : "work",
    "primary" : false
  } ],
  "urn:ietf:params:scim:schemas:extension:enterprise:2.0" : {
    "User" : {
      "department" : "Department A"
    }
  },
  "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" : {
    "department" : null,
    "manager" : null
  }
}

As you can see, the department under the proper scim structure remains as null. An erroneous "urn:ietf:params:scim:schemas:extension:enterprise:2.0" field has been added with the new department under a key "User". This appears to be incorrect behaviour.

Value filter in Path can omit closing square bracket character

A Path with a value filter is considered valid if it omits the closing ] character, though such a Path should be considered invalid. This is something that @dvernon-uid noticed some time ago.

Example:

{  
   "colors": [  
      "red",
      "green",
      "blue"
   ]
}

The path colors[value eq \"blue\"] is valid, as expected, but so is colors[value eq \"blue\".

update jackson - remote code execution vulnerability

per the output of owasp's dependency-check-maven plugin, used in a library which uses scim2-sdk-client:

One or more dependencies were identified with known vulnerabilities in <artifact>:

jackson-databind-2.7.4.jar (com.fasterxml.jackson.core:jackson-databind:2.7.4, cpe:/a:fasterxml:jackson-databind:2.7.4, cpe:/a:fasterxml:jackson:2.7.4) : CVE-2018-14719, CVE-2018-1000873, CVE-2017-7525, CVE-2018-7489, CVE-2018-14721, CVE-2018-14720, CVE-2018-5968, CVE-2017-15095, CVE-2017-17485, CVE-2018-19362, CVE-2018-19361, CVE-2018-19360
guava-18.0.jar (cpe:/a:google:guava:18.0, com.google.guava:guava:18.0) : CVE-2018-10237

at least one of these (2018-7489) seems to be a remote code execution exploit. Please update your dependencies when possible.

Should EntepriseUserExtension not extend UserResource ?

I am new to Scim, so if I ask some noob question, apologize in advance.
Why does EnterpriseUserExtension not extend UserResource ? Its shown as a child on simplecloud.info.

Secondly if I am implementing a ScimServer (listening to updates from some IdP), then how am I supposed to get extensionValues as explained in
https://github.com/pingidentity/scim2/wiki/working-with-scim-resources#obtaining-extension-attributes

The above link seems to be polling the server to get more info, but what if the request is to update an attribute that belongs to the Extension schema across multiple users ?

Authorization Header set on WebTarget interface ignored

To start with, Thank you for all the hard work. This library is pretty amazing and very easy to use for SCIM client implementation.

Bug Details:
I'd like to set the Authorization headers on the WebTarget object passed during ScimService creation like this:
Client client = ClientBuilder.newClient();
WebTarget target = client.target(url);
target.request().header("Authorization", "Basic test123")
ScimService service = new ScimService(target);
service.create("/Users", scimResource);

However, the auth header doesn't make it all the way to the headers set in CreateRequestBuilder class. Only way I was able to bypass this was do this:
CreateRequestBuilder requestBuilder = scimService.createRequest("Users", scimResource);
requestBuilder.header("Authorization", "Basic test123"));
requestBuilder.invoke();

Because of this, I am unable to use the helper classes on ScimService and having to mock requestBuilder stuff in my tests that are absolutely unnecessary and is an implementation detail that I don't need to worry about. Let me know if you need any other information.

Cannot parse filter: not(age eq 21)

Attempting to parse the filter not(age eq 21) fails with this stack trace:

com.unboundid.scim2.common.exceptions.BadRequestException: Invalid comparison value at position 11: Unexpected character (')' (code 41)): Expected space separating root-level values
 at [Source: com.unboundid.scim2.common.utils.Parser$StringReader@35847a59; line: 1, column: 4]

    at com.unboundid.scim2.common.exceptions.BadRequestException.invalidFilter(BadRequestException.java:137)
    at com.unboundid.scim2.common.utils.Parser.readFilter(Parser.java:633)
    at com.unboundid.scim2.common.utils.Parser.parseFilter(Parser.java:161)
    at com.unboundid.scim2.common.filters.Filter.fromString(Filter.java:1189)

It works fine if my filter looks like: not(age eq 21 ) (with a space between the 21 and the closing parenthesis).

Jira: DS-14604

simplify client extension to work with not-quite-compliant servers

As SCIM2 is a relatively young specification, many implementations still have quirks which must be worked around. Removing the 'final' modifier from the builder classes and allowing protected access to the relevant methods greatly makes it much simpler to keep a client compatible with many servers by extending the builders with the necessary workarounds.

I've opened PR #101 to highlight the particular methods giving me trouble, but there may be more which could benefit from this.

Make the SCIM compatible Jackson JSON mapper understand SCIM POJOs better

POJOs currently have to extend BaseScimResource to get the behavior of expecting the SCIM common attributes (schemas, id, externalId, and meta). We should make the SCIM compatible Jackson JSON mapper always ignore these if the POJO didn't define them.

BaseScimResource currently ignores unknown attributes. This should also be changed to throw an error if the attribute is unknown.

Incorrect parsing of scim filter

The filter:
displayName sw \"e\" and displayName sw \"f\" and displayName sw \"g\" or nickName sw \"a\"
parsed with Filter.fromString(filter) results in
image

The offending part is in yellow, that shouldn't be there.

The expected behaviour would be the one of parsing (note the brackets):
(displayName sw \"e\" and displayName sw \"f\" and displayName sw \"g\") or nickName sw \"a\"
image

PatchRequest should not extend BaseScimResource

Describe the bug
per RFC7644 section 3.5.2, urn:ietf:params:scim:api:messages:2.0:PatchOp does not have the elements "meta", "id", and "externalId". Sending requests with these parameters can cause issues when targeting a strict server. Currently these values are sent as e.g. "id": null even when not set

Expected behavior
Sent patch requests do not have the "meta", "id", and "externalId" elements.

Additional context
https://github.com/pingidentity/scim2/blob/master/scim2-sdk-common/src/main/java/com/unboundid/scim2/common/messages/PatchRequest.java#L38

Compliance to SCIM 2 section 2.5

The client SDK seem to incorrectly interprete section 2.5 of the core standard, which states:

When a resource is expressed in
JSON format, unassigned attributes, although they are defined in
schema, MAY be omitted for compactness.

This "MAY" expresses according to RFC2119 that the server implementation is allowed to either omit the attribute or to send an empty value.

However, when talking to servers which return empty attributes, e.g. empty "display" attributes, we get the infamous UnrecognizedPropertyException exception.

ScimService should allow PUT URI to be specified

The ScimService class should provide a replace(...) method that takes a URI. Otherwise, it's difficult for client code to handle APIs in which the resource to be replaced via PUT cannot first be retrieved via GET. (A password change API, for example.)

I'll submit a pull request for this.

Duplicated class com.unboundid.scim2.common.utils.Version

Hi,
We have a problem with Maven build process with duplicated class: com.unboundid.scim2.common.utils.Version
This class is duplicated in all in libraries: scim2-sdk-common, scim2-sdk-client and scim2-sdk-server.

Best regards,
Dominik

Group Resource in common/types

Is your feature request related to a problem? Please describe.
Currently, there is no support for the /Groups endpoint resource defined in RFC 7643 section 4.2. Having this object available would be useful to clients.

Describe the solution you'd like
an object extending BaseScimResource with the schema urn:ietf:params:scim:schemas:core:2.0:Group available in the common types package

Describe alternatives you've considered
The object can be maintained within code which uses the client library, but upstream support is preferable for de-duplication of effort

GenericScimResource.replaceValue() seems to handle Dates

It looks like it is parsing the Date to a String twice.

Consider this adding this test method to GenericScimResourceObjectTest.java:

  @Test
  public void testDates() throws ScimException {
    String path1 = "path1";
    Date date1 = new Date(9482087542L);
    String date1String = "1970-04-20T17:54:47.542Z";

    //date1 and date1String are equivalent
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    df.setTimeZone(TimeZone.getTimeZone("UTC"));
    Assert.assertEquals(df.format(date1),date1String);

    String expected = "{\n" +
            "  \"path1\" : \"1970-04-20T17:54:47.542Z\"\n" +
            "}";
    GenericScimResource gsr = new GenericScimResource();
    gsr.replaceValue(path1, date1String);
    Assert.assertEquals(gsr.toString(),expected);

    //replacing a Date value should be equivalent to replacing date as String value
    gsr.replaceValue(path1, date1);
    Assert.assertEquals(gsr.toString(),expected);
  }

As written, this test will fail. It seems replaceValue(String path,Date value) generates this:

{
  "path1" : "\"1970-04-20T17:54:47.542Z\""
}

instead of this:

{
  "path1" : "1970-04-20T17:54:47.542Z"
}

The workaround of course, is to just avoid the variants of replaceValue() in GenericScimResource that deal with java.util.Date.

Migrate this repository to the Ping Identity organization

UnboundID has been acquired by Ping Identity and all public repositories in the UnboundID GitHub organization will be migrated to the Ping Identity organization. The migration should happen this weekend (March 4โ€“5, 2017).

All repository history, issues, pull requests, releases, and settings should be migrated. URIs will change, but GitHub should automatically redirect the old URIs to the new ones. See https://help.github.com/articles/about-repository-transfers/ for more information.

[scim2-sdk-client] ResponseProcessingException on primitive email response

per RFC 7643 section 2.4, a SCIM2 multi-valued attribute can contain either primitive or complex values (although "service providers SHOULD canonicalize the value returned", it isn't required). However, receiving a primitive valued email address (as returned by WSO2 identity server 5.6.0) results in:

javax.ws.rs.client.ResponseProcessingException: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.unboundid.scim2.common.types.Email: no String-argument constructor/factory method to deserialize from String value ('[email protected]')
 at [Source: org.glassfish.jersey.message.internal.EntityInputStream@3febffc9; line: 1, column: 140] (through reference chain: com.unboundid.scim2.common.types.UserResource["emails"]->java.util.ArrayList[0])
	at com.unboundid.scim2.client.requests.SearchRequestBuilder.invoke(SearchRequestBuilder.java:323)
	at com.unboundid.scim2.client.requests.SearchRequestBuilder.invoke(SearchRequestBuilder.java:155)
	at com.pti.impression.service.PiecesUserService.search(PiecesUserService.java:111)
	at com.pti.impression.service.PiecesUserService.findByUsername(PiecesUserService.java:115)
	at com.pti.impression.controller.UiController.user(UiController.java:77)
	at com.pti.impression.controller.UiController$$FastClassBySpringCGLIB$$28ae0e53.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:669)
	at com.pti.impression.controller.UiController$$EnhancerBySpringCGLIB$$54abf8d5.user(<generated>)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.unboundid.scim2.common.types.Email: no String-argument constructor/factory method to deserialize from String value ('[email protected]')
 at [Source: org.glassfish.jersey.message.internal.EntityInputStream@3febffc9; line: 1, column: 140] (through reference chain: com.unboundid.scim2.common.types.UserResource["emails"]->java.util.ArrayList[0])
	at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270)
	at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1456)
	at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1012)
	at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:370)
	at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:315)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1283)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:159)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:150)
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:287)
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:259)
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26)
	at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:504)
	at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:104)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
	at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3786)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2115)
	at com.fasterxml.jackson.core.JsonParser.readValueAs(JsonParser.java:1627)
	at com.unboundid.scim2.client.requests.SearchRequestBuilder.invoke(SearchRequestBuilder.java:295)
	... 107 common frames omitted

the result returned by curl, which it's trying to parse, is:
{"totalResults":1,"startIndex":1,"itemsPerPage":1,"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],"Resources":[{"emails":["[email protected]"],"meta":{"created":"2018-07-13T14:11:57Z","lastModified":"2018-07-13T14:11:57Z"},"name":{"givenName":"admin","familyName":"admin"},"groups":[{"display":"Application/local-8443"}],"id":"fd650662-a0fc-4095-a88a-c4d9203b3e67","userName":"admin"}]}

Can Server `utils` be safely extracted to facilitate non-JAX-RS implementations

Hi! First of all, Thanks for this amazing library!

I'm looking to use this library to implement a SCIM service on top of an existing Spring application. A lot of the tooling in com.unboundid.scim2.server.utils package (i.e., ResourcePreparer, SchemaChecker, etc.) seem really useful for my effort. However, it seems that to leverage these utilities I need to add an unnecessary dependency on JAX-RS. So, is there any way we can separate these server utilities from this constraint?

Please correct me if I'm wrong, but it seems that ResourceTypeDefinition#fromJaxRsResource, which relies on javax.ws.rs.Path annotation, is the the sole blocker here, as many other server utilities import the class, either directly or indirectly. Could we resolve this by moving the factory to a separate utility class (e.g., ServerUtils)?

update SchemaChecker Javadoc to clarify usage

SchemaChecker implementation does not conform to SCIM2.0 standard with regards to ignoring\asserting fields with mutability type READ_ONLY or IMMUTABLE

SCIM Protocol Specification 3.5.1. Replacing with PUT

immutable If one or more values are already set for the attribute,
the input value(s) MUST match, or HTTP status code 400 SHOULD be
returned with a "scimType" error code of "mutability". If the
service provider has no existing values, the new value(s) SHALL be
applied.
readOnly Any values provided SHALL be ignored.

SCIM Protocol Specification 3.3. Creating Resources

In the request body, attributes whose mutability is "readOnly"
(see Sections 2.2 and 7 of [RFC7643]) SHALL be ignored.

Expected behavior:
ReadOnly fields specified in request's body are ignored, as stated in the specification.
Values of immutable fields in the request are checked against the actual values.

Actual behavior:
The SchemaChecker fails with BadRequestException

com.unboundid.scim2.common.exceptions.BadRequestException: Attribute id is read-only, Attribute meta is read-only, Attribute meta.created is read-only, Attribute meta.location is read-only, Attribute meta.resourceType is read-only
        at com.unboundid.scim2.common.exceptions.BadRequestException.mutability(BadRequestException.java:173)

Steps to reproduce:

  1. Issue a GET request
  2. Copy the response body
  3. Send it again in a PUT request

This is causing a lot of problems as the workaround requires removing the offending fields before the validation and performing the checks by hand.

@braveulysses @digitalperk Can anything be done with this issue?

Schemas are not sent and parsed correctly

When retrieving all schemas (running the test testGetSchemas within EndpointTestCase.java) you will get the following:

{ "schemas" : [ "urn:ietf:params:scim:api:messages:2.0:ListResponse" ], "totalResults" : 2, "Resources" : [ { "schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:Schema" ], "id" : "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", "name" : "EnterpriseUser", ....

However looking at sample in RFC7643 chapter 8.7.1 you will find a simple array of schemas.

[ { "id" : "urn:ietf:params:scim:schemas:core:2.0:User", "name" : "User", "description" : "User Account", "attributes" : [ { "name" : "userName", "type" : "string", "multiValued" : false, "description" : "Unique identifier for the User, typically used by the user to directly authenticate to the service provider. Each User MUST include a non-empty userName value. This identifier MUST be unique across the service provider's entire set of Users. REQUIRED.", "required" : true, "caseExact" : false, "mutability" : "readWrite", "returned" : "default", "uniqueness" : "ser ....

When retrieving all schemas from a SCIM provider that only provides the array of schemas, the client will generate an Exception.

CreateRequestBuilder class throws ProcessingException

/**

  • Invoke the SCIM create request.
  • @param The type of object to return.
  • @param cls The Java class object used to determine the type to return.
  • @return The successfully modified SCIM resource.
  • @throws ScimException If an error occurred.
    */
    public C invoke(final Class cls) throws ScimException
    {
    Response response = buildRequest().post(
    Entity.entity(resource, getContentType()));
    try
    {
    if(response.getStatusInfo().getFamily() ==
    Response.Status.Family.SUCCESSFUL)
    {
    return response.readEntity(cls);
    }
    else
    {
    throw toScimException(response);
    }
    }
    finally
    {
    response.close();
    }
    }

I expect this method to throw ScimException as defined in its documentation but since the actual post is outside of the try catch, the ProcessingException from JAXRS makes it back to the calling method. Is this working as designed?

ReplaceOperation with an empty-array value is rejected unnecessarily

Problem behavior
The library rejects payloads that are valid according to RFC 7644, Sec. 3.5.2.3. Replace Operation. Specifically, it rejects Operations whose value is the empty array []:

      if(value == null || value.isNull() ||
           ((value.isArray() || value.isObject()) && value.size() == 0))
       {
         throw BadRequestException.invalidSyntax(
             "value field must not be null or an empty container");
       }

PatchOperation.java#L305

Why this is important
Okta sends the following payload which fails to be deserialized:

{
    "schemas": [
        "urn:ietf:params:scim:api:messages:2.0:PatchOp"
    ],
    "Operations": [
        {
            "op": "replace",
            "path": "members",
            "value": []
        }
    ]
}

Historical context
The code doing this validation was merged in #26.

Suggested resolution
Change the check in PatchOperation.java to:

      if(value == null || value.isNull() ||
           (value.isObject() && value.size() == 0))
       {
         throw BadRequestException.invalidSyntax(
             "value field must not be null or an empty object");
       }

issue with scimChecker functionality

we have defined the GroupResource schemas(some attributes have been omitted):
@Schema(id="urn:ietf:params:scim:schemas:core:2.0:Group",
name="Group",
description="Group")
public class GroupResource extends BaseScimResource {
@Attribute(description="A list of members of the Group.",
isCaseExact=false,
mutability=AttributeDefinition.Mutability.READ_WRITE,
multiValueClass = Member.class,
returned=AttributeDefinition.Returned.DEFAULT)
private List members;
}

since the members attribute has READWRITE mutablity, i think it should be valid if we do replace with below input resource:
{
"schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:Group" ],
"members" : [ {
"value" : "member1"
} ]
}

but currently it will not pass the schema check, the exception is shown below:
com.unboundid.scim2.common.exceptions.BadRequestException: Attribute members[0].value is immutable and value(s) may not be replaced

it seems that schemaChecker is failing because the sub-attributes of Member like value are described as immutable.

The same exception will be thrown for patch request with members replacement operation, for example:
{
"schemas" : [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ],
"Operations" : [ {
"op" : "replace",
"path" : "members",
"value" : [ {
"value" : "member1"
} ]
} ]
}

the class members definition is shown below:
public class Member {

@Attribute(description = "Identifier of the member of this Group.", isCaseExact = false, mutability = AttributeDefinition.Mutability.IMMUTABLE, returned = AttributeDefinition.Returned.DEFAULT, uniqueness = AttributeDefinition.Uniqueness.NONE)
private String value;

@Attribute(description = "The URI corresponding to a SCIM resource that is a member of this Group.", isCaseExact = false, referenceTypes = {
		"User",
		"Group" }, mutability = AttributeDefinition.Mutability.IMMUTABLE, returned = AttributeDefinition.Returned.DEFAULT, uniqueness = AttributeDefinition.Uniqueness.NONE)
private String $ref;

@Attribute(description = "A label indicating the type of resource e.g., 'User' or 'Group'.", isCaseExact = false, mutability = AttributeDefinition.Mutability.IMMUTABLE, returned = AttributeDefinition.Returned.DEFAULT, uniqueness = AttributeDefinition.Uniqueness.NONE)
private String type;

}

Define interface for attribute models that implement getType(), getPrimary(), etc.

This is an enhancement request. Would it be possible to add an interface for those model classes that represent a complex attribute with typical sub-attributes like "type" and "primary"?

To provide an example of how this would be useful, a client developer or tester might want to write a single method to select an attribute from a collection where "type" == "home".

ErrorResponse status should be string

Hey,

According to SCIM v2 spec, the "status" field of an error message should contain the status code represented a string (don't ask me why),

Will you accept a patch that fixes this?

p.s: It makes sense to keep the status code in the ErrorResponse class as int but just serialize it back as string via ToStringSerializer Jackson serializer

Thanks.

duplicate class "com.unboundid.scim2.common.utils.Version" betwen scim2-sdk-client and scim2-sdk-common

When attempting to build a fat jar which uses the scim2-sdk-client library, maven gives the following warning:

[WARNING] scim2-sdk-client-2.1.3.jar, scim2-sdk-common-2.1.3.jar define 1 overlapping classes:
[WARNING]   - com.unboundid.scim2.common.utils.Version
[WARNING] maven-shade-plugin has detected that some class files are
[WARNING] present in two or more JARs. When this happens, only one
[WARNING] single version of the class is copied to the uber jar.
[WARNING] Usually this is not harmful and you can skip these warnings,
[WARNING] otherwise try to manually exclude artifacts based on
[WARNING] mvn dependency:tree -Ddetail=true and the above output.
[WARNING] See http://maven.apache.org/plugins/maven-shade-plugin/

When classes have naming conflicts, it is undefined which is loaded. While it looks like the file is identical between them, this leaves an opening for issues if they do diverge.

Since scim2-sdk-client imports scim2-sdk-common, the class can just be deleted from scim2-sdk-client.

scim2-sdk-common declares too many dependencies

The module scim2-sdk-common declares unused dependencies, as reported by mvn dependency:analyze:

[INFO] --- maven-dependency-plugin:2.8:analyze (default-cli) @ scim2-sdk-common ---
[WARNING] Used undeclared dependencies found:
[WARNING]    com.fasterxml.jackson.core:jackson-core:jar:2.7.4:compile
[WARNING]    com.fasterxml.jackson.core:jackson-annotations:jar:2.7.0:compile
[WARNING]    com.fasterxml.jackson.core:jackson-databind:jar:2.7.4:compile
[WARNING] Unused declared dependencies found:
[WARNING]    com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.7.4:compile
[WARNING]    com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:sources:2.7.4:compile
[WARNING]    com.google.guava:guava:jar:sources:18.0:compile
[WARNING]    com.fasterxml.jackson.core:jackson-core:jar:sources:2.7.4:compile

Guava is only used for tests, com.fasterxml.jackson.jaxrs isn't actually used and source artifacts aren't needed either, so dependencies can be simplified to:

<dependencies>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${com.fasterxml.jackson.version}</version>
  </dependency>
  <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
    <scope>test</scope>
  </dependency>
</dependencies>

JsonUtils.replaceValue fails when given null value

Describe the bug
When a function which calls JsonUtils.replaceValue is given a null, an NullPointerException is thrown by UpdatingNodeVisitor when attempting to deepCopy() that null.

To Reproduce
construct a GenericScimResource x and call x.setSchemaUrns(null).

Expected behavior
the Schemas element is removed from the resource

Additional context
This can be necessary to construct a PATCH operation on an overall Group object, in which you don't want to edit the schema URNs.

Model classes in scim2-sdk-common cannot be deserialized if attribute includes non-standard sub-attribute

The types in scim2-sdk-common cannot be used to deserialize SCIM attributes that do not strictly correspond to the SCIM 2 spec's User schema; Jackson will throw an UnrecognizedPropertyException if such an attribute contains a non-standard sub-attribute. Consider annotating these classes such that Jackson will tolerate unrecognized fields. I would argue that if any schema violation enforcement is desired, it should manifest at some other point during processing, not during deserialization.

I encountered this using com.unboundid.scim2.common.types.Email. I'm assuming that the issue is generalizable to other classes in the same package.

Example

I have test code that looks something like this:

GenericScimResource resource = scimClient.retrieve(uri, GenericScimResource.class);
assertNotNull(resource.getValues("emails", Email.class));

It fails with an UnrecognizedPropertyException:

Failure Cause: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "verified" (class com.unboundid.scim2.common.types.Email), not marked as ignorable (4 known properties: "value", "display", "primary", "type"]) at [Source: N/A; line: -1, column: -1] (through reference chain: com.unboundid.scim2.common.types.Email["verified"]) com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51) com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:817) com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:954) com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1315) com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1293) com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:249) com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136) com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:1408) com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:858) com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:876) com.fasterxml.jackson.databind.ObjectReader.treeToValue(ObjectReader.java:1363) com.unboundid.scim2.common.GenericScimResource.getValues(GenericScimResource.java:334) com.unboundid.scim2.common.GenericScimResource.getValues(GenericScimResource.java:307) ...

Add methods to replace and remove values from an multi-valued attribute using POJOs

Currently, to remove and/or replace values of a multi-valued attribute, you will have to provide a path to the remove and replace methods. This is often inconvenient since the getters return POJOs and it will be much easier to just remove and/or replace using one of the returned instances instead of constructing a filter. This allows for quick object manipulation like:

List<Address> addresses = resource.getValues("addresses", Address.class);
for(Address address : addresses)
{
  if(address.zipCode().equals("78750"))
  {
    resource.removeValues("addresses", address);
  }
}

This applies to the *ScimResource as well as the ModifyRequestBuilder classes.

Ignoring unknown fields?

Hey guys,

Question, we have under the 'meta' section some extra fields, when retrieving a resource we get:

java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "foo" (class com.unboundid.scim2.common.types.Meta), not marked as ignorable (5 known properties: "resourceType", "location", "lastModified", "created", "version"])

We do have in our schema a description of these fields but I guess the library doesn't consult with the schema rather just try to deserialize the Meta.class object,

Is there any way to ignore unknown fields or make the retrieve be aware of them somehow?

Another option would be to extends the resources to fit to our own needs and override the 'Meta' object (in case you are willing to make the Meta class not a final one)

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.