001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2012-2014 ForgeRock AS. 015 */ 016 017package org.forgerock.openig.filter; 018 019import static org.forgerock.openig.util.Json.*; 020 021import java.io.IOException; 022import java.net.URI; 023import java.net.URISyntaxException; 024 025import org.forgerock.openig.el.Expression; 026import org.forgerock.openig.handler.Handler; 027import org.forgerock.openig.handler.HandlerException; 028import org.forgerock.openig.header.LocationHeader; 029import org.forgerock.openig.heap.GenericHeaplet; 030import org.forgerock.openig.heap.HeapException; 031import org.forgerock.openig.http.Exchange; 032import org.forgerock.openig.http.Message; 033import org.forgerock.openig.util.URIUtil; 034 035/** 036 * Rewrites Location headers on responses that generate a redirect that would 037 * take the user directly to the application being proxied rather than taking 038 * the user through OpenIG. 039 */ 040public class LocationHeaderFilter extends GenericFilter { 041 042 /** The base URI of the OpenIG instance, used to rewrite Location headers. */ 043 private Expression baseURI; 044 045 /** 046 * Sets the base URI used to rewrite Location headers. 047 * @param baseURI expression that, when evaluated, will represents the base URI of this OpenIG instance 048 */ 049 public void setBaseURI(final Expression baseURI) { 050 this.baseURI = baseURI; 051 } 052 053 @Override 054 public void filter(Exchange exchange, Handler next) throws HandlerException, IOException { 055 // We only care about responses so just call the next handler in the chain. 056 next.handle(exchange); 057 058 processResponse(exchange); 059 } 060 061 /** 062 * Rewrite Location header if it would have the user go directly to the application. 063 * 064 * @param exchange the exchange containing the response message containing the Location header 065 */ 066 private void processResponse(Exchange exchange) throws HandlerException { 067 Message<?> message = exchange.response; 068 LocationHeader header = new LocationHeader(message); 069 if (header.toString() != null) { 070 try { 071 URI currentURI = new URI(header.toString()); 072 URI rebasedURI = URIUtil.rebase(currentURI, evaluateBaseUri(exchange)); 073 // Only rewrite header if it has changed 074 if (!currentURI.equals(rebasedURI)) { 075 message.getHeaders().remove(LocationHeader.NAME); 076 message.getHeaders().add(LocationHeader.NAME, rebasedURI.toString()); 077 } 078 } catch (URISyntaxException ex) { 079 throw logger.debug(new HandlerException(ex)); 080 } 081 } 082 } 083 084 private URI evaluateBaseUri(final Exchange exchange) throws URISyntaxException, HandlerException { 085 String uri = baseURI.eval(exchange, String.class); 086 if (uri == null) { 087 throw logger.debug(new HandlerException("Evaluated baseURI cannot be null")); 088 } 089 return new URI(uri); 090 } 091 092 /** Creates and initializes a LocationHeaderFilter in a heap environment. */ 093 public static class Heaplet extends GenericHeaplet { 094 @Override 095 public Object create() throws HeapException { 096 097 LocationHeaderFilter filter = new LocationHeaderFilter(); 098 filter.baseURI = asExpression(config.get("baseURI").required()); 099 100 return filter; 101 } 102 } 103}