Um servlet que busque uma página/redirecione requisições para outro servidor

Boa tarde, galera!

Estou com um “pequeno” problema e gostaria de saber se o que eu quero é possível.

Eu quero criar um servlet que busque uma página de outro servidor e a envie para o usuário como se a página estivesse no meu servidor. Além disso, quando o usuário fizer uma requisição dentro dessa página (enviar um formulário, por exemplo), esse servlet deverá redirecionar essa requisição (POST e GET) para o servidor que forneceu a página e devolver o resultado (uma outra página qualquer) devolta ao usuário.

Eu preciso fazer isso por dois motivos:

  1. Como não posso incluir um código (server-side) na página do outro servidor, preciso autenticar o usuário e determinar se ele pode ou não acessar aquela página através do meu servidor.
  2. O usuário NÃO PODE SABER A URL DA PÁGINA! Pois essa página não possui autenticação e, caso o usuário descubra a url dela, ele poderia repassar essa url para pessoas que, de outra forma, não deveriam ter acesso à ela.

Vocês sabem se isso é possível? Se for, como ficaria a implementação disso? Se não for possível, existe alguma outra alternativa para o problema?

Boa tarde mmatto;

Passei por um problema semelhante;

Eu tinha uma pagina de login em um determinado servidor feito em uma tecnologia, se o usuario fosse aceito seria redirecionado para um outro servidor que estaria utilizando uma outra tecnologia, porém essa pagina deveria estar chumbada, ou seja barra de endereços ocultas e com aparencia de popup;

O unico meio que eu conheço de abrir uma pagina assim é através de javascript:

window.open('','','scrollbars=no,menubar=no,top=0,left=0,resizable=yes,toolbar=no,status=no');

No meu caso eu trabalhei com os oncomplete dos botoes do prime faces que chamava uma função em js; Esse js fazia uma verificação em um campo hidden com um valor boleano que iria vir direto de um manegedBean. Se fosse true, redirecionava, se fosse false exibia o erro;

Foi mais ou menos essa idéia que eu utilizei

No Java não teria uma maneira de executar um POST ou GET pra outro servidor e “escrever” o resultado como html?
Eu tenho quase certeza que seja possível, só não descobri uma maneira de fazer isso, ainda.

Nessa sua solução, o usuário não tinha como descobrir a URL? Botão direito e “Propriedades da Página”? Ou através de algum atalho do navegador que permita reabrir a página numa nova janela? Outro problema são os atalhos do navegador, como, por exemplo, CTRL+P. Quando você imprime uma página, a URL dela fica no rodapé da página. Outro problema é que a URL da página fica armazenada no histórico do navegador.

Com certeza deve ter alguma maneira de “camuflar” a página como sendo do seu servidor, e não de outro. Um exemplo são as páginas chamadas de “Proxy anônimo” que muita gente usa no trabalho para burlar o firewall da empresa e acessar o Orkut, por exemplo. As páginas abertas por esses proxys são carregadas como sendo deles mesmo.

Boa tarde mmatto;

Agora entendi realmente qual a sua dúvida, infelizmente não vou poder te ajudar muito pq isso ja está além do meu conhecimento hahaha

…mas creio que a solução seja algo do tipo;(abstraindo um pouco)Tu cria um servlet que ira analisar as requisições(verificar se usuario esta logado, se tem permissão ou qualquer coisa que seja necessária) e ira se comunicar com um outro servlet, e a resposta deste segundo servlet sera mostrada para o usuario pelo primeiro servlet.

Não sei qual o suporte que java fornece para esse tipo de tarefa, mas creio que seja possível sim!

Consegui fazer alguns progressos!

Criei uma html inicial que possui um formulário com um campo de texto onde o usuário informar a url. Ao enviar esse formulário, o servlet abaixo busca a página usando as classes URL e URLConnection. Então eu uso a biblioteca Jsoup para alterar os atributos HREF e SRC de todos os elementos DOM que estejam como relativo para absoluto (usando como base a url informada pelo usuário). Isso faz com que imagens, scripts e css sejam baixados do servidor certo, e não do meu servidor.

Segue o código-fonte do servlet:

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

public class TunelServlet extends HttpServlet {

	private static final long serialVersionUID = -4675061985025674960L;

    @Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	// Busca a página informada pelo usuário, pegando o html e escrevendo-o
    	// como sendo do meu servidor.
    	carregarPagina(request.getParameter("url"), response);
	}

	private void carregarPagina(String url, HttpServletResponse response) {
		response.setContentType("text/html");
		try {
			URL pagina = new URL(url);
			
			PrintWriter out = response.getWriter();
			
			// Pega o html da página solicitada, fazendo um "parse" para que
			// os elementos DOM possam ser extraídos e acessados.
			Document doc = Jsoup.parse(pagina, 3*1000);
			// Navega por cada elemento DOM da página...
			for (Element e : doc.children()) {
				// Se o elemento possuir os atributos HREF e/ou SRC usando
				// caminhos relativos, esses atributos são alterados para
				// usarem o caminho absoluto.
				relativoParaAbsoluto(e);
			}
			
			// Escreve o html alterado da página solicitada como se
			// fosse uma página do meu servidor.
			out.println(doc.outerHtml());
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void relativoParaAbsoluto(Element e) {
		// Se o elemento possuir outros elementos filhos...
		for (Element c : e.children()) {
			// Chama a mesma função para cada um dos elementos filhos.
			relativoParaAbsoluto(c);
		}
		// Se o elementos possuir o atributo HREF, altera o caminho para
		// absoluto.
		if (e.attr("href") != "")
			e.attr("href", e.absUrl("href"));
		// Se o elementos possuir o atributo HREF, altera o caminho para
		// absoluto.
		if (e.attr("src") != "")
			e.attr("src", e.absUrl("src"));
	}
	
}

Ainda falta implementar um forma de redirecionar as requisições de formulários da página carregada para o seu servidor de origem e escrever os resultados como sendo do meu servidor (posso usar o mesmo método usado quando o usuário solicita a página pela primeira vez).

Mas estou com um problema que ainda não sei como resolver:
Eu consegui fazer com que as imagens, scripts externos e css’s externos fossem baixados corretamente pelo browser do usuário (usando a biblioteca Jsoap, como explicado acima). Mas quando os elementos html são criados dinamicamente pelo javascript, eu não consegui alterar os caminhos relativos para absolutos. Acho que o Jsoap não consegue fazer isso. Alguém tem alguma sugestão?