001/*
002 * Copyright 2015-2021 Ping Identity Corporation
003 *
004 * This program is free software; you can redistribute it and/or modify
005 * it under the terms of the GNU General Public License (GPLv2 only)
006 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
007 * as published by the Free Software Foundation.
008 *
009 * This program 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
012 * GNU General Public License for more details.
013 *
014 * You should have received a copy of the GNU General Public License
015 * along with this program; if not, see <http://www.gnu.org/licenses>.
016 */
017
018package com.unboundid.scim2.server.providers;
019
020import com.fasterxml.jackson.core.JsonParser;
021import com.fasterxml.jackson.databind.ObjectReader;
022import com.unboundid.scim2.common.messages.SearchRequest;
023import com.unboundid.scim2.common.utils.JsonUtils;
024import com.unboundid.scim2.common.utils.StaticUtils;
025import com.unboundid.scim2.server.utils.ServerUtils;
026
027import javax.annotation.Priority;
028import javax.ws.rs.BadRequestException;
029import javax.ws.rs.HttpMethod;
030import javax.ws.rs.NotSupportedException;
031import javax.ws.rs.Priorities;
032import javax.ws.rs.container.ContainerRequestContext;
033import javax.ws.rs.container.ContainerRequestFilter;
034import javax.ws.rs.container.PreMatching;
035import javax.ws.rs.core.MediaType;
036import javax.ws.rs.core.NoContentException;
037import javax.ws.rs.core.PathSegment;
038import javax.ws.rs.core.UriBuilder;
039import javax.ws.rs.ext.Provider;
040import java.io.IOException;
041import java.util.List;
042
043import static com.unboundid.scim2.common.utils.ApiConstants.*;
044
045/**
046 * A ContainerRequestFilter implementation to convert a search request using
047 * HTTP POST combine with the "{@code .search}" path extension to a regular search
048 * using HTTP GET.
049 */
050@Provider
051@PreMatching
052@Priority(Priorities.ENTITY_CODER)
053public class DotSearchFilter implements ContainerRequestFilter
054{
055  /**
056   * {@inheritDoc}
057   */
058  public void filter(final ContainerRequestContext requestContext)
059      throws IOException
060  {
061    if(requestContext.getMethod().equals(HttpMethod.POST) &&
062        requestContext.getUriInfo().getPath().endsWith(
063            SEARCH_WITH_POST_PATH_EXTENSION))
064
065    {
066      if(requestContext.getMediaType() == null ||
067          !(requestContext.getMediaType().isCompatible(
068              ServerUtils.MEDIA_TYPE_SCIM_TYPE) ||
069              requestContext.getMediaType().isCompatible(
070                  MediaType.APPLICATION_JSON_TYPE)))
071      {
072        throw new NotSupportedException();
073      }
074
075      ObjectReader reader =
076          JsonUtils.getObjectReader().forType(SearchRequest.class);
077      JsonParser p = reader.getFactory().createParser(
078          requestContext.getEntityStream());
079      if(p.nextToken() == null)
080      {
081        throw new BadRequestException(
082            new NoContentException("Empty Entity"));
083      }
084      SearchRequest searchRequest = reader.readValue(p);
085      UriBuilder builder = requestContext.getUriInfo().getBaseUriBuilder();
086      List<PathSegment> pathSegments =
087          requestContext.getUriInfo().getPathSegments();
088      for(int i = 0; i < pathSegments.size() - 1; i ++)
089      {
090        builder.path(pathSegments.get(i).getPath());
091      }
092      if(searchRequest.getAttributes() != null)
093      {
094        builder.queryParam(QUERY_PARAMETER_ATTRIBUTES,
095            ServerUtils.encodeTemplateNames(
096                StaticUtils.collectionToString(
097                    searchRequest.getAttributes(), ",")));
098      }
099      if(searchRequest.getExcludedAttributes() != null)
100      {
101        builder.queryParam(QUERY_PARAMETER_EXCLUDED_ATTRIBUTES,
102            ServerUtils.encodeTemplateNames(
103                StaticUtils.collectionToString(
104                    searchRequest.getExcludedAttributes(), ",")));
105      }
106      if(searchRequest.getFilter() != null)
107      {
108        builder.queryParam(QUERY_PARAMETER_FILTER,
109            ServerUtils.encodeTemplateNames(searchRequest.getFilter()));
110      }
111      if(searchRequest.getSortBy() != null)
112      {
113        builder.queryParam(QUERY_PARAMETER_SORT_BY,
114            ServerUtils.encodeTemplateNames(searchRequest.getSortBy()));
115      }
116      if(searchRequest.getSortOrder() != null)
117      {
118        builder.queryParam(QUERY_PARAMETER_SORT_ORDER,
119            ServerUtils.encodeTemplateNames(
120                searchRequest.getSortOrder().getName()));
121      }
122      if(searchRequest.getStartIndex() != null)
123      {
124        builder.queryParam(QUERY_PARAMETER_PAGE_START_INDEX,
125            searchRequest.getStartIndex());
126      }
127      if(searchRequest.getCount() != null)
128      {
129        builder.queryParam(QUERY_PARAMETER_PAGE_SIZE,
130            searchRequest.getCount());
131      }
132      requestContext.setRequestUri(builder.build());
133      requestContext.setMethod(HttpMethod.GET);
134    }
135  }
136}