001/* 002 * Copyright 2015-2024 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.annotations.NotNull; 023import com.unboundid.scim2.common.messages.SearchRequest; 024import com.unboundid.scim2.common.utils.JsonUtils; 025import com.unboundid.scim2.common.utils.StaticUtils; 026import com.unboundid.scim2.server.utils.ServerUtils; 027 028import jakarta.annotation.Priority; 029import jakarta.ws.rs.BadRequestException; 030import jakarta.ws.rs.HttpMethod; 031import jakarta.ws.rs.NotSupportedException; 032import jakarta.ws.rs.Priorities; 033import jakarta.ws.rs.container.ContainerRequestContext; 034import jakarta.ws.rs.container.ContainerRequestFilter; 035import jakarta.ws.rs.container.PreMatching; 036import jakarta.ws.rs.core.MediaType; 037import jakarta.ws.rs.core.NoContentException; 038import jakarta.ws.rs.core.PathSegment; 039import jakarta.ws.rs.core.UriBuilder; 040import jakarta.ws.rs.ext.Provider; 041import java.io.IOException; 042import java.util.List; 043 044import static com.unboundid.scim2.common.utils.ApiConstants.*; 045 046/** 047 * A ContainerRequestFilter implementation to convert a search request using 048 * HTTP POST combine with the "{@code .search}" path extension to a regular search 049 * using HTTP GET. 050 */ 051@Provider 052@PreMatching 053@Priority(Priorities.ENTITY_CODER) 054public class DotSearchFilter implements ContainerRequestFilter 055{ 056 /** 057 * {@inheritDoc} 058 */ 059 public void filter(@NotNull final ContainerRequestContext requestContext) 060 throws IOException 061 { 062 if(requestContext.getMethod().equals(HttpMethod.POST) && 063 requestContext.getUriInfo().getPath().endsWith( 064 SEARCH_WITH_POST_PATH_EXTENSION)) 065 066 { 067 if(requestContext.getMediaType() == null || 068 !(requestContext.getMediaType().isCompatible( 069 ServerUtils.MEDIA_TYPE_SCIM_TYPE) || 070 requestContext.getMediaType().isCompatible( 071 MediaType.APPLICATION_JSON_TYPE))) 072 { 073 throw new NotSupportedException(); 074 } 075 076 ObjectReader reader = 077 JsonUtils.getObjectReader().forType(SearchRequest.class); 078 JsonParser p = reader.getFactory().createParser( 079 requestContext.getEntityStream()); 080 if(p.nextToken() == null) 081 { 082 throw new BadRequestException( 083 new NoContentException("Empty Entity")); 084 } 085 SearchRequest searchRequest = reader.readValue(p); 086 UriBuilder builder = requestContext.getUriInfo().getBaseUriBuilder(); 087 List<PathSegment> pathSegments = 088 requestContext.getUriInfo().getPathSegments(); 089 for(int i = 0; i < pathSegments.size() - 1; i ++) 090 { 091 builder.path(pathSegments.get(i).getPath()); 092 } 093 if(searchRequest.getAttributes() != null) 094 { 095 builder.queryParam(QUERY_PARAMETER_ATTRIBUTES, 096 ServerUtils.encodeTemplateNames( 097 StaticUtils.collectionToString( 098 searchRequest.getAttributes(), ","))); 099 } 100 if(searchRequest.getExcludedAttributes() != null) 101 { 102 builder.queryParam(QUERY_PARAMETER_EXCLUDED_ATTRIBUTES, 103 ServerUtils.encodeTemplateNames( 104 StaticUtils.collectionToString( 105 searchRequest.getExcludedAttributes(), ","))); 106 } 107 if(searchRequest.getFilter() != null) 108 { 109 builder.queryParam(QUERY_PARAMETER_FILTER, 110 ServerUtils.encodeTemplateNames(searchRequest.getFilter())); 111 } 112 if(searchRequest.getSortBy() != null) 113 { 114 builder.queryParam(QUERY_PARAMETER_SORT_BY, 115 ServerUtils.encodeTemplateNames(searchRequest.getSortBy())); 116 } 117 if(searchRequest.getSortOrder() != null) 118 { 119 builder.queryParam(QUERY_PARAMETER_SORT_ORDER, 120 ServerUtils.encodeTemplateNames( 121 searchRequest.getSortOrder().getName())); 122 } 123 if(searchRequest.getStartIndex() != null) 124 { 125 builder.queryParam(QUERY_PARAMETER_PAGE_START_INDEX, 126 searchRequest.getStartIndex()); 127 } 128 if(searchRequest.getCount() != null) 129 { 130 builder.queryParam(QUERY_PARAMETER_PAGE_SIZE, 131 searchRequest.getCount()); 132 } 133 requestContext.setRequestUri(builder.build()); 134 requestContext.setMethod(HttpMethod.GET); 135 } 136 } 137}