You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by bd...@apache.org on 2023/09/06 15:08:48 UTC
[directory-scimple] branch quarkus-example created (now 0bf86117)
This is an automated email from the ASF dual-hosted git repository.
bdemers pushed a change to branch quarkus-example
in repository https://gitbox.apache.org/repos/asf/directory-scimple.git
at 0bf86117 Adds Quarkus example and ITs
This branch includes the following new commits:
new 0bf86117 Adds Quarkus example and ITs
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[directory-scimple] 01/01: Adds Quarkus example and ITs
Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
bdemers pushed a commit to branch quarkus-example
in repository https://gitbox.apache.org/repos/asf/directory-scimple.git
commit 0bf86117726659693d739ae1f1dc29c8247f91c6
Author: Brian Demers <bd...@apache.org>
AuthorDate: Fri Sep 1 17:00:02 2023 -0400
Adds Quarkus example and ITs
All of the ITs are wrapped and executed via `@QuarkusIntegrationTest`, this allows the tests to be executed in a more friendly Quarkus way (and would also work for native images)
NOTE: Native images do not currently work, we need to figure out what classes are needed at runtime and configure them (this could also benifit, non-quarkus users of native-image)
---
scim-server-examples/scim-server-quarkus/README.md | 20 +++
scim-server-examples/scim-server-quarkus/pom.xml | 139 +++++++++++++++
.../scim/example/quarkus/QuarkusApplication.java | 53 ++++++
.../quarkus/extensions/LuckyNumberExtension.java | 62 +++++++
.../quarkus/service/InMemoryGroupService.java | 139 +++++++++++++++
.../quarkus/service/InMemorySelfResolverImpl.java | 37 ++++
.../quarkus/service/InMemoryUserService.java | 187 +++++++++++++++++++++
.../scim/example/quarkus/QuarkusGroupsIT.java | 41 +++++
.../example/quarkus/QuarkusResourceTypesIT.java | 41 +++++
.../scim/example/quarkus/QuarkusSchemasIT.java | 41 +++++
.../quarkus/QuarkusServiceProviderConfigIT.java | 41 +++++
.../scim/example/quarkus/QuarkusUsersIT.java | 41 +++++
12 files changed, 842 insertions(+)
diff --git a/scim-server-examples/scim-server-quarkus/README.md b/scim-server-examples/scim-server-quarkus/README.md
new file mode 100644
index 00000000..3fee83f8
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/README.md
@@ -0,0 +1,20 @@
+Apache Directory SCIMple Quarkus Example
+==========================================
+
+This example project demo's how to:
+
+* Add a custom SCIM Extension
+* Manage Users and Groups (in memory)
+
+Use this as a starter point on how to integrate Apache Directory SCIMple into your own project.
+
+Run: `mvn quarkus:dev` and then access one of the endpoints:
+
+```bash
+# httpie
+http :8080/v2/Users
+
+# curl
+curl localhost:8080/v2/Users
+```
+n
diff --git a/scim-server-examples/scim-server-quarkus/pom.xml b/scim-server-examples/scim-server-quarkus/pom.xml
new file mode 100644
index 00000000..eb7dbe52
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/pom.xml
@@ -0,0 +1,139 @@
+<!-- Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.directory.scimple</groupId>
+ <artifactId>scim-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../..</relativePath>
+ </parent>
+
+ <artifactId>scim-server-quarkus</artifactId>
+ <name>SCIMple - Server - Examples - Quarkus</name>
+
+ <properties>
+ <module.name>org.apache.directory.scim.example.quarkus</module.name>
+ <version.quarkus>3.3.1</version.quarkus>
+ <max.jdk.version>17</max.jdk.version>
+ <!-- disable discovery of tests in other jars, tests are wrapped directly in this project to run with Quarkus -->
+ <dependenciesToScan></dependenciesToScan>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus.platform</groupId>
+ <artifactId>quarkus-bom</artifactId>
+ <version>${version.quarkus}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <!-- quarkus uses an older version of antlr, forced in via the bom -->
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr4-runtime</artifactId>
+ <version>${version.antlr4}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>jakarta.servlet</groupId>
+ <artifactId>jakarta.servlet-api</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-arc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-resteasy</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-resteasy-jackson</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>jakarta.ws.rs</groupId>
+ <artifactId>jakarta.ws.rs-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.inject</groupId>
+ <artifactId>jakarta.inject-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.annotation</groupId>
+ <artifactId>jakarta.annotation-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.enterprise</groupId>
+ <artifactId>jakarta.enterprise.cdi-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.scimple</groupId>
+ <artifactId>scim-server</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-junit5</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>rest-assured</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.scimple</groupId>
+ <artifactId>scim-compliance-tests</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.quarkus.platform</groupId>
+ <artifactId>quarkus-maven-plugin</artifactId>
+ <version>${version.quarkus}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <goals>
+ <goal>build</goal>
+ <goal>generate-code</goal>
+ <goal>generate-code-tests</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/QuarkusApplication.java b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/QuarkusApplication.java
new file mode 100644
index 00000000..7be3d9f9
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/QuarkusApplication.java
@@ -0,0 +1,53 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+
+* http://www.apache.org/licenses/LICENSE-2.0
+
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.directory.scim.example.quarkus;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.inject.Produces;
+import jakarta.ws.rs.ApplicationPath;
+import org.apache.directory.scim.server.configuration.ServerConfiguration;
+
+import java.util.Set;
+
+import jakarta.ws.rs.core.Application;
+import org.apache.directory.scim.server.rest.ScimResourceHelper;
+
+import static org.apache.directory.scim.spec.schema.ServiceProviderConfiguration.AuthenticationSchema.oauthBearer;
+
+@ApplicationPath("v2")
+@ApplicationScoped
+public class QuarkusApplication extends Application {
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ return ScimResourceHelper.scimpleFeatureAndResourceClasses();
+ }
+
+ @Produces
+ ServerConfiguration serverConfiguration() {
+ return new ServerConfiguration()
+ // Set any unique configuration bits
+ .setId("scimple-quarkus-example")
+ .setDocumentationUri("https://github.com/apache/directory-scimple")
+ // set the auth scheme too
+ .addAuthenticationSchema(oauthBearer());
+ }
+
+}
diff --git a/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/extensions/LuckyNumberExtension.java b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/extensions/LuckyNumberExtension.java
new file mode 100644
index 00000000..8ab27289
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/extensions/LuckyNumberExtension.java
@@ -0,0 +1,62 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+
+* http://www.apache.org/licenses/LICENSE-2.0
+
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.directory.scim.example.quarkus.extensions;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlRootElement;
+
+import lombok.Data;
+import org.apache.directory.scim.spec.annotation.ScimAttribute;
+import org.apache.directory.scim.spec.annotation.ScimExtensionType;
+import org.apache.directory.scim.spec.resources.ScimExtension;
+import org.apache.directory.scim.spec.schema.Schema;
+
+/**
+ * Allows a User's lucky number to be passed as part of the User's entry via
+ * the SCIM protocol.
+ *
+ * @author Chris Harm <crh5255@psu.edu>
+ */
+@XmlRootElement( name = "LuckyNumberExtension", namespace = "http://www.psu.edu/schemas/psu-scim" )
+@XmlAccessorType(XmlAccessType.NONE)
+@Data
+@ScimExtensionType(id = LuckyNumberExtension.SCHEMA_URN, description="Lucky Numbers", name="LuckyNumbers", required=true)
+public class LuckyNumberExtension implements ScimExtension {
+
+ public static final String SCHEMA_URN = "urn:mem:params:scim:schemas:extension:LuckyNumberExtension";
+
+ @ScimAttribute(returned=Schema.Attribute.Returned.DEFAULT, required=true)
+ @XmlElement
+ private long luckyNumber;
+
+ /**
+ * Provides the URN associated with this extension which, as defined by the
+ * SCIM specification is the extension's unique identifier.
+ *
+ * @return The extension's URN.
+ */
+ @Override
+ public String getUrn() {
+ return SCHEMA_URN;
+ }
+
+}
diff --git a/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryGroupService.java b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryGroupService.java
new file mode 100644
index 00000000..486d0845
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryGroupService.java
@@ -0,0 +1,139 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+
+* http://www.apache.org/licenses/LICENSE-2.0
+
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.directory.scim.example.quarkus.service;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.core.Response;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
+import org.apache.directory.scim.server.exception.UnableToUpdateResourceException;
+import org.apache.directory.scim.core.repository.Repository;
+import org.apache.directory.scim.core.repository.UpdateRequest;
+import org.apache.directory.scim.spec.filter.FilterExpressions;
+import org.apache.directory.scim.spec.filter.FilterResponse;
+import org.apache.directory.scim.spec.filter.Filter;
+import org.apache.directory.scim.spec.filter.PageRequest;
+import org.apache.directory.scim.spec.filter.SortRequest;
+import org.apache.directory.scim.spec.resources.ScimExtension;
+import org.apache.directory.scim.spec.resources.ScimGroup;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Named;
+import org.apache.directory.scim.core.schema.SchemaRegistry;
+
+@Named
+@ApplicationScoped
+public class InMemoryGroupService implements Repository<ScimGroup> {
+
+ private final Map<String, ScimGroup> groups = new HashMap<>();
+
+ private SchemaRegistry schemaRegistry;
+
+ @Inject
+ public InMemoryGroupService(SchemaRegistry schemaRegistry) {
+ this.schemaRegistry = schemaRegistry;
+ }
+
+ protected InMemoryGroupService() {}
+
+ @PostConstruct
+ public void init() {
+ ScimGroup group = new ScimGroup();
+ group.setId(UUID.randomUUID().toString());
+ group.setDisplayName("example-group");
+ group.setExternalId("example-group");
+ groups.put(group.getId(), group);
+ }
+
+ @Override
+ public Class<ScimGroup> getResourceClass() {
+ return ScimGroup.class;
+ }
+
+ @Override
+ public ScimGroup create(ScimGroup resource) throws UnableToCreateResourceException {
+ String id = UUID.randomUUID().toString();
+
+ // if the external ID is not set, use the displayName instead
+ if (StringUtils.isEmpty(resource.getExternalId())) {
+ resource.setExternalId(resource.getDisplayName());
+ }
+
+ // check to make sure the group doesn't already exist
+ boolean existingGroupFound = groups.values().stream()
+ .anyMatch(group -> resource.getExternalId().equals(group.getExternalId()));
+ if (existingGroupFound) {
+ // HTTP leaking into data layer
+ throw new UnableToCreateResourceException(Response.Status.CONFLICT, "Group '" + resource.getExternalId() + "' already exists.");
+ }
+
+ resource.setId(id);
+ groups.put(id, resource);
+ return resource;
+ }
+
+ @Override
+ public ScimGroup update(UpdateRequest<ScimGroup> updateRequest) throws UnableToUpdateResourceException {
+ String id = updateRequest.getId();
+ ScimGroup resource = updateRequest.getResource();
+ groups.put(id, resource);
+ return resource;
+ }
+
+ @Override
+ public ScimGroup get(String id) {
+ return groups.get(id);
+ }
+
+ @Override
+ public void delete(String id) {
+ groups.remove(id);
+ }
+
+ @Override
+ public FilterResponse<ScimGroup> find(Filter filter, PageRequest pageRequest, SortRequest sortRequest) {
+ long count = pageRequest.getCount() != null ? pageRequest.getCount() : groups.size();
+ long startIndex = pageRequest.getStartIndex() != null
+ ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
+ : 0;
+
+ List<ScimGroup> result = groups.values().stream()
+ .skip(startIndex)
+ .limit(count)
+ .filter(FilterExpressions.inMemory(filter, schemaRegistry.getSchema(ScimGroup.SCHEMA_URI)))
+ .collect(Collectors.toList());
+
+ return new FilterResponse<>(result, pageRequest, result.size());
+ }
+
+ @Override
+ public List<Class<? extends ScimExtension>> getExtensionList() {
+ return Collections.emptyList();
+ }
+
+}
diff --git a/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemorySelfResolverImpl.java b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemorySelfResolverImpl.java
new file mode 100644
index 00000000..87ab36cf
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemorySelfResolverImpl.java
@@ -0,0 +1,37 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+
+* http://www.apache.org/licenses/LICENSE-2.0
+
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.directory.scim.example.quarkus.service;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import org.apache.directory.scim.server.exception.UnableToResolveIdResourceException;
+import org.apache.directory.scim.core.repository.SelfIdResolver;
+
+import java.security.Principal;
+
+import jakarta.ws.rs.core.Response.Status;
+
+@ApplicationScoped
+public class InMemorySelfResolverImpl implements SelfIdResolver {
+
+ @Override
+ public String resolveToInternalId(Principal principal) throws UnableToResolveIdResourceException {
+ throw new UnableToResolveIdResourceException(Status.NOT_IMPLEMENTED, "Caller Principal not available");
+ }
+}
diff --git a/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryUserService.java b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryUserService.java
new file mode 100644
index 00000000..154ca57d
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/src/main/java/org/apache/directory/scim/example/quarkus/service/InMemoryUserService.java
@@ -0,0 +1,187 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+
+* http://www.apache.org/licenses/LICENSE-2.0
+
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+package org.apache.directory.scim.example.quarkus.service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+
+import jakarta.ws.rs.core.Response;
+import org.apache.directory.scim.example.quarkus.extensions.LuckyNumberExtension;
+import org.apache.directory.scim.server.exception.UnableToCreateResourceException;
+import org.apache.directory.scim.server.exception.UnableToUpdateResourceException;
+import org.apache.directory.scim.core.repository.Repository;
+import org.apache.directory.scim.core.repository.UpdateRequest;
+import org.apache.directory.scim.spec.extension.EnterpriseExtension;
+import org.apache.directory.scim.spec.filter.FilterExpressions;
+import org.apache.directory.scim.spec.filter.FilterResponse;
+import org.apache.directory.scim.spec.filter.Filter;
+import org.apache.directory.scim.spec.filter.PageRequest;
+import org.apache.directory.scim.spec.filter.SortRequest;
+import org.apache.directory.scim.spec.resources.*;
+import org.apache.directory.scim.core.schema.SchemaRegistry;
+
+/**
+ * Creates a singleton (effectively) Repository<ScimUser> with a memory-based
+ * persistence layer.
+ *
+ * @author Chris Harm <crh5255@psu.edu>
+ */
+@Named
+@ApplicationScoped
+public class InMemoryUserService implements Repository<ScimUser> {
+
+ static final String DEFAULT_USER_ID = UUID.randomUUID().toString();
+ static final String DEFAULT_USER_EXTERNAL_ID = "e" + DEFAULT_USER_ID;
+ static final String DEFAULT_USER_DISPLAY_NAME = "User " + DEFAULT_USER_ID;
+ static final String DEFAULT_USER_EMAIL_VALUE = "e1@example.com";
+ static final String DEFAULT_USER_EMAIL_TYPE = "work";
+ static final int DEFAULT_USER_LUCKY_NUMBER = 7;
+
+ private final Map<String, ScimUser> users = new HashMap<>();
+
+ private SchemaRegistry schemaRegistry;
+
+ @Inject
+ public InMemoryUserService(SchemaRegistry schemaRegistry) {
+ this.schemaRegistry = schemaRegistry;
+ }
+
+ protected InMemoryUserService() {}
+
+ @PostConstruct
+ public void init() {
+ ScimUser user = new ScimUser();
+ user.setId(DEFAULT_USER_ID);
+ user.setExternalId(DEFAULT_USER_EXTERNAL_ID);
+ user.setUserName(DEFAULT_USER_EXTERNAL_ID);
+ user.setDisplayName(DEFAULT_USER_DISPLAY_NAME);
+ user.setName(new Name()
+ .setGivenName("Tester")
+ .setFamilyName("McTest"));
+ Email email = new Email();
+ email.setDisplay(DEFAULT_USER_EMAIL_VALUE);
+ email.setValue(DEFAULT_USER_EMAIL_VALUE);
+ email.setType(DEFAULT_USER_EMAIL_TYPE);
+ email.setPrimary(true);
+ user.setEmails(List.of(email));
+
+ LuckyNumberExtension luckyNumberExtension = new LuckyNumberExtension();
+ luckyNumberExtension.setLuckyNumber(DEFAULT_USER_LUCKY_NUMBER);
+
+ user.addExtension(luckyNumberExtension);
+
+ EnterpriseExtension enterpriseExtension = new EnterpriseExtension();
+ enterpriseExtension.setEmployeeNumber("12345");
+ EnterpriseExtension.Manager manager = new EnterpriseExtension.Manager();
+ manager.setValue("bulkId:qwerty");
+ enterpriseExtension.setManager(manager);
+ user.addExtension(enterpriseExtension);
+
+ users.put(user.getId(), user);
+ }
+
+ @Override
+ public Class<ScimUser> getResourceClass() {
+ return ScimUser.class;
+ }
+
+ /**
+ * @see Repository#create(ScimResource)
+ */
+ @Override
+ public ScimUser create(ScimUser resource) throws UnableToCreateResourceException {
+ String id = UUID.randomUUID().toString();
+
+ // check to make sure the user doesn't already exist
+ boolean existingUserFound = users.values().stream()
+ .anyMatch(user -> user.getUserName().equals(resource.getUserName()));
+ if (existingUserFound) {
+ // HTTP leaking into data layer
+ throw new UnableToCreateResourceException(Response.Status.CONFLICT, "User '" + resource.getUserName() + "' already exists.");
+ }
+
+ resource.setId(id);
+ users.put(id, resource);
+ return resource;
+ }
+
+ /**
+ * @see Repository#update(UpdateRequest)
+ */
+ @Override
+ public ScimUser update(UpdateRequest<ScimUser> updateRequest) throws UnableToUpdateResourceException {
+ String id = updateRequest.getId();
+ ScimUser resource = updateRequest.getResource();
+ users.put(id, resource);
+ return resource;
+ }
+
+ /**
+ * @see Repository#get(java.lang.String)
+ */
+ @Override
+ public ScimUser get(String id) {
+ return users.get(id);
+ }
+
+ /**
+ * @see Repository#delete(java.lang.String)
+ */
+ @Override
+ public void delete(String id) {
+ users.remove(id);
+ }
+
+ /**
+ * @see Repository#find(Filter, PageRequest, SortRequest)
+ */
+ @Override
+ public FilterResponse<ScimUser> find(Filter filter, PageRequest pageRequest, SortRequest sortRequest) {
+
+ long count = pageRequest.getCount() != null ? pageRequest.getCount() : users.size();
+ long startIndex = pageRequest.getStartIndex() != null
+ ? pageRequest.getStartIndex() - 1 // SCIM is 1-based indexed
+ : 0;
+
+ List<ScimUser> result = users.values().stream()
+ .skip(startIndex)
+ .limit(count)
+ .filter(FilterExpressions.inMemory(filter, schemaRegistry.getSchema(ScimUser.SCHEMA_URI)))
+ .collect(Collectors.toList());
+
+ return new FilterResponse<>(result, pageRequest, result.size());
+ }
+
+ /**
+ * @see Repository#getExtensionList()
+ */
+ @Override
+ public List<Class<? extends ScimExtension>> getExtensionList() {
+ return List.of(LuckyNumberExtension.class, EnterpriseExtension.class);
+ }
+}
diff --git a/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusGroupsIT.java b/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusGroupsIT.java
new file mode 100644
index 00000000..221caa37
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusGroupsIT.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.directory.scim.example.quarkus;
+
+import io.quarkus.test.common.http.TestHTTPResource;
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+import org.apache.directory.scim.compliance.tests.GroupsIT;
+
+import java.net.URI;
+
+/**
+ * Wraps GroupsIT in a Quarkus friendly runner.
+ */
+@QuarkusIntegrationTest
+public class QuarkusGroupsIT extends GroupsIT {
+
+ @TestHTTPResource("/v2")
+ URI uri;
+
+ @Override
+ protected URI uri() {
+ return uri;
+ }
+}
diff --git a/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusResourceTypesIT.java b/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusResourceTypesIT.java
new file mode 100644
index 00000000..5238cb7d
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusResourceTypesIT.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.directory.scim.example.quarkus;
+
+import io.quarkus.test.common.http.TestHTTPResource;
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+import org.apache.directory.scim.compliance.tests.ResourceTypesIT;
+
+import java.net.URI;
+
+/**
+ * Wraps ResourceTypesIT in a Quarkus friendly runner.
+ */
+@QuarkusIntegrationTest
+public class QuarkusResourceTypesIT extends ResourceTypesIT {
+
+ @TestHTTPResource("/v2")
+ URI uri;
+
+ @Override
+ protected URI uri() {
+ return uri;
+ }
+}
diff --git a/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusSchemasIT.java b/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusSchemasIT.java
new file mode 100644
index 00000000..057dbcb6
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusSchemasIT.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.directory.scim.example.quarkus;
+
+import io.quarkus.test.common.http.TestHTTPResource;
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+import org.apache.directory.scim.compliance.tests.SchemasIT;
+
+import java.net.URI;
+
+/**
+ * Wraps SchemasIT in a Quarkus friendly runner.
+ */
+@QuarkusIntegrationTest
+public class QuarkusSchemasIT extends SchemasIT {
+
+ @TestHTTPResource("/v2")
+ URI uri;
+
+ @Override
+ protected URI uri() {
+ return uri;
+ }
+}
diff --git a/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusServiceProviderConfigIT.java b/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusServiceProviderConfigIT.java
new file mode 100644
index 00000000..0e7de8d1
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusServiceProviderConfigIT.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.directory.scim.example.quarkus;
+
+import io.quarkus.test.common.http.TestHTTPResource;
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+import org.apache.directory.scim.compliance.tests.ServiceProviderConfigIT;
+
+import java.net.URI;
+
+/**
+ * Wraps ServiceProviderConfigIT in a Quarkus friendly runner.
+ */
+@QuarkusIntegrationTest
+public class QuarkusServiceProviderConfigIT extends ServiceProviderConfigIT {
+
+ @TestHTTPResource("/v2")
+ URI uri;
+
+ @Override
+ protected URI uri() {
+ return uri;
+ }
+}
diff --git a/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusUsersIT.java b/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusUsersIT.java
new file mode 100644
index 00000000..2f3b17c0
--- /dev/null
+++ b/scim-server-examples/scim-server-quarkus/src/test/java/org/apache/directory/scim/example/quarkus/QuarkusUsersIT.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.directory.scim.example.quarkus;
+
+import io.quarkus.test.common.http.TestHTTPResource;
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+import org.apache.directory.scim.compliance.tests.UsersIT;
+
+import java.net.URI;
+
+/**
+ * Wraps UsersIT in a Quarkus friendly runner.
+ */
+@QuarkusIntegrationTest
+public class QuarkusUsersIT extends UsersIT {
+
+ @TestHTTPResource("/v2")
+ URI uri;
+
+ @Override
+ protected URI uri() {
+ return uri;
+ }
+}