001/*
002 * (C) Copyright 2015 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 */
018
019package org.nuxeo.scim.server.jaxrs;
020
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.List;
024
025import javax.ws.rs.GET;
026import javax.ws.rs.Path;
027import javax.ws.rs.PathParam;
028import javax.ws.rs.Produces;
029import javax.ws.rs.WebApplicationException;
030import javax.ws.rs.core.Context;
031import javax.ws.rs.core.HttpHeaders;
032import javax.ws.rs.core.MediaType;
033import javax.ws.rs.core.Response;
034
035import org.nuxeo.ecm.webengine.model.Template;
036import org.nuxeo.ecm.webengine.model.WebObject;
037import org.nuxeo.ecm.webengine.model.exceptions.WebResourceNotFoundException;
038import org.nuxeo.ecm.webengine.model.exceptions.WebSecurityException;
039import org.nuxeo.ecm.webengine.model.impl.ModuleRoot;
040
041import com.unboundid.scim.data.AuthenticationScheme;
042import com.unboundid.scim.data.BulkConfig;
043import com.unboundid.scim.data.ChangePasswordConfig;
044import com.unboundid.scim.data.FilterConfig;
045import com.unboundid.scim.data.PatchConfig;
046import com.unboundid.scim.data.ServiceProviderConfig;
047import com.unboundid.scim.data.SortConfig;
048import com.unboundid.scim.data.XmlDataFormatConfig;
049import com.unboundid.scim.schema.CoreSchema;
050
051/**
052 * The root entry for the WebEngine module.
053 *
054 * @author tiry
055 * @since 7.4
056 */
057@Path("/scim/v1")
058@Produces("text/html;charset=UTF-8")
059@WebObject(type = "SCIMRoot")
060public class SCIMRoot extends ModuleRoot {
061
062    @Path("/Users")
063    public Object doGetUsersResource() {
064        return newObject("users");
065    }
066
067    @Path("/Users.json")
068    public Object doGetUsersJsonResource() {
069        return newObject("users", MediaType.APPLICATION_JSON_TYPE);
070    }
071
072    @Path("/Users.xml")
073    public Object doGetUsersXmlResource() {
074        return newObject("users", MediaType.APPLICATION_XML_TYPE);
075    }
076
077    @Path("/Groups")
078    public Object doGetGroups() {
079        return newObject("groups");
080    }
081
082    @Path("/Groups.json")
083    public Object doGetGroupsAsJson() {
084        return newObject("groups", MediaType.APPLICATION_JSON_TYPE);
085    }
086
087    @Path("/Groups.xml")
088    public Object doGetGroupsAsJXml() {
089        return newObject("groups", MediaType.APPLICATION_XML_TYPE);
090    }
091
092    protected Object getSchema(String schemaName, String format) {
093
094        String viewName = "user-schema";
095
096        if (schemaName.equalsIgnoreCase("users")) {
097            viewName = "user-schema";
098        } else if (schemaName.equalsIgnoreCase("groups")) {
099            viewName = "group-schema";
100        }
101
102        Template tmpl = getView(viewName + "." + format);
103        return tmpl;
104    }
105
106    @GET
107    @Path("/Schemas/{schemaName}")
108    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML + "; qs=0.9" })
109    public Object getSchema(@PathParam("schemaName") String schemaName, @Context HttpHeaders headers) {
110
111        List<String> accepted = headers.getRequestHeader("Accept");
112
113        if (accepted.contains(MediaType.APPLICATION_JSON)) {
114            return getSchema(schemaName, "json");
115        }
116        return getSchema(schemaName, "xml");
117    }
118
119    @GET
120    @Path("/Schemas/{schemaName}.json")
121    @Produces({ MediaType.APPLICATION_JSON })
122    public Object getSchemaAsJson(@PathParam("schemaName") String schemaName) {
123        return getSchema(schemaName, "json");
124    }
125
126    @GET
127    @Path("/Schemas/{schemaName}.xml")
128    @Produces({ MediaType.APPLICATION_XML })
129    public Object getSchemaAsXml(@PathParam("schemaName") String schemaName) {
130        return getSchema(schemaName, "xml");
131    }
132
133    @GET
134    @Path("/ServiceProviderConfigs")
135    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML + "; qs=0.9" })
136    public ServiceProviderConfig getConfig() {
137
138        ServiceProviderConfig config = new ServiceProviderConfig(CoreSchema.SERVICE_PROVIDER_CONFIG_SCHEMA_DESCRIPTOR);
139
140        config.setId("Nuxeo");
141        config.setExternalId("Nuxeo");
142
143        // auth config
144        Collection<AuthenticationScheme> authSchemes = new ArrayList<>();
145        authSchemes.add(AuthenticationScheme.createBasic(true));
146        config.setAuthenticationSchemes(authSchemes);
147
148        // Filter
149        FilterConfig filterConfig = new FilterConfig(true, 1000);
150        config.setFilterConfig(filterConfig);
151
152        // Bulk Config : for now
153        BulkConfig bulkConfig = new BulkConfig(false, 0, 0);
154        config.setBulkConfig(bulkConfig);
155
156        // Pwd
157        ChangePasswordConfig changePasswordConfig = new ChangePasswordConfig(false);
158        config.setChangePasswordConfig(changePasswordConfig);
159
160        config.setPatchConfig(new PatchConfig(false));
161
162        config.setSortConfig(new SortConfig(true));
163
164        config.setXmlDataFormatConfig(new XmlDataFormatConfig(true));
165
166        return config;
167    }
168
169    @Override
170    public Object handleError(WebApplicationException e) {
171        if (e instanceof WebSecurityException) {
172            return Response.status(401).entity("not authorized").type("text/plain").build();
173        } else if (e instanceof WebResourceNotFoundException) {
174            return Response.status(404).entity(e.getMessage()).type("text/plain").build();
175        } else {
176            return super.handleError(e);
177        }
178    }
179}