[Pendente - testar] Probleminha básico com webservices

Olá,

cenário atual:

tenho 2 webservices (NÃO SSL) que fazem assinatura digital e depois chamam outros webservices SSL.

estou com o seguinte problema:

desde que coloquei em produção o segundo webservice apenas um dos dois funciona corretamente, no caso o webservice q da erro volta com a seguinte mensagem:

;nested exception is: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

infelizemente para fazer a assinatura digital nos 2 webservices preciso utilizar o mesmo certificado, mas os serviços não são chamados ao mesmo tempo.

o certificado esta no caminho correto, tanto q se deixar apenas 1 webservice rodando(dps de parar e iniciar novamente o servidor) ele funciona normalmente.

alguém ai tem como dar um help? dica? sugestão? ajuda?

desde já obrigado!!!

att,

Imagino que você esteja com o mesmo problema que eu tive há algum tempo atrás: o certificado (na verdade, o conjunto de certificados) continha vários alias. Quando você habilita somente um serviço, ele já deixa o certificado certo selecionado no SSLSocketFactory. Quando você coloca dois serviços, ele seleciona um dos alias, mas como o certificado certo está contido no outro alias, dá pau.

Eu postei a resolução no meu blog: http://alesaudate.com (mando o endereço assim, sem ser direto no post, porque aqui do trabalho não consigo acessar). Dá uma olhada lá e vê se ajuda.

[]´s

asaudate obrigado pela ajuda hein,

estou lendo aqui o post no seu blog,
bom pelo o q eu acho q entendi a 1° coisa seria adicionar no meu projeto as classes: SSLSocketFactoryGenerator e AliasSelectorKeyManager correto?

e depois eu teria q adaptar a minha chamado ao webservice ssl através do “dispatch” ?

bom faço a minima idéia como eu vou fazer isso mais obrigado pelo help hein!!

valeu a super ajuda!

Exato, essas classes vão ajustar a seleção do alias da maneira que lhe convier. É fundamental que você entenda o funcionamento do AliasSelectorKeyManager, porque é ele quem vai fazer a seleção do certificado correto. E, sim, um drawback desse sistema é que ele te obriga a usar o Dispatch - o que te obriga, também, a montar o XML que vai ser passado para o web service. Em todo caso, é possível usar o JAXB para mapear suas classes para esses XML´s.

[]´s

asaudate mais uma vez obrigado pela ajuda hein, estava conseguindo caminhar mas acho q empaquei no seguinte problema:

java.lang.ClassCastException: javax.xml.namespace.QName cannot be cast to javax.xml.soap.Name

é a 1° vez que tento utilizar Dispatch na vida(e também montar manualmente os xml que serão passados heheh).
meu código esta da seguinte maneira:

		try {
			URL wsdlLocation = new URL("https://enderecoWsdl.com.br/enderecoWsdl.svc?wsdl");

			QName serviceName = new QName(nms, "nomeServico");
			QName portName = new QName(nms, "nomePorta");

			Service service = Service.create(wsdlLocation, serviceName);
			Dispatch<SOAPMessage> dispatch = service.createDispatch(portName,SOAPMessage.class, Service.Mode.MESSAGE);
			BindingProvider bp = (BindingProvider) dispatch;
			MessageFactory mf = ((SOAPBinding) bp.getBinding()).getMessageFactory();

			SOAPMessage request = mf.createMessage();
			SOAPBody body = request.getSOAPBody();

			//abaixo a exception que ocorre no casting QName to Name:

			SOAPBodyElement nfeStatusServico = (SOAPBodyElement) body.addBodyElement((Name) new QName("elementoBody"));
			SOAPElement nfeDadosMsg = nfeStatusServico.addChildElement("elementoChild");
			nfeDadosMsg.addTextNode(conteudoNode);

			System.out.println(env.getDispatcher("Alias").invoke(request));

		} catch (Exception e) {
			System.out.println("erro: " + e.getMessage() + " causa: " + e.getCause());
			e.printStackTrace();
		}

estou usando como exemplo,estudo,consulta os links abaixo:

http://www.ibm.com/developerworks/br/websphere/library/techarticles/0707_thaker/0707_thaker.html
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/twbs_jaxwsdynclient.html
http://download.oracle.com/javaee/5/tutorial/doc/bnbhr.html
http://www.guj.com.br/posts/list/199552.java

estou utilizando o jdk 1.6 up 21.

toda a ajuda será muito bem vinda! ^^

Obrigado!

Se você tirar o cast, o que acontece?

sem o cast fica aparece o seguinte erro:

The method addBodyElement(Name) in the type SOAPBody is not applicable for the arguments (QName)

o eclipse “sugere”:

Cast argument 1 to ‘Name’
Change to "addChildElement(…)’
Change to ‘addDocument(…)’

valeu de novo asaudate!

Alexandre Saudate,

resolvi o problema do cast da seguinte maneira:

javax.xml.soap.Name soapAction = envelope.createName("nfeRecepcaoLote","","http://www.portalfiscal.inf.br/nfe/wsdl/NfeRecepcao");
SOAPBodyElement nfeStatusServico = body.addBodyElement(soapAction);

mas infelizmente ainda to perdido no problema inicial,

Criei uma classe e adicionei os métodos:

public Dispatch<SOAPMessage> getDispatcher(String alias) throws IOException, GeneralSecurityException {
public Dispatch<SOAPMessage> getDispatcher (String wsdl, String namespace, String servicename, String portName){

agora na minha classe que realiza a chamada do webservice SSL acho q tem algo mt errado(heheh) :

		System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");
		System.setProperty("java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol");
		Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

		System.setProperty("javax.net.ssl.keyStoreType", "keyStoreType");
		System.setProperty("javax.net.ssl.keyStore","Certificado");
		System.setProperty("javax.net.ssl.keyStoreAlias", "AliasdoCertificado");
		System.setProperty("javax.net.ssl.keyStorePassword", "SenhaCertificado");

		System.setProperty("javax.net.ssl.trustStoreType", "JKS");
		System.setProperty("javax.net.ssl.trustStore","keystore");

		Envia env = new Envia(); //classe com os metodos getDispatcher

		try {
			URL wsdlLocation = new URL("wsdl");

			QName serviceName = new QName(nms, "serviceName");
			QName portName = new QName(nms, "portName");
						
			Service service = Service.create(wsdlLocation, serviceName);			
			
			Dispatch<SOAPMessage> dispatch = env.getDispatcher("alias");//passo alias q sera utilizado para estabelecer conexao
			
			BindingProvider bp = (BindingProvider) dispatch;
			MessageFactory mf = ((SOAPBinding) bp.getBinding()).getMessageFactory();
			
			SOAPMessage request = mf.createMessage();

			SOAPPart part = request.getSOAPPart();
			SOAPEnvelope envelope = part.getEnvelope();
			
			SOAPBody body = envelope.getBody();			
			Name soapAction = envelope.createName("string1","","string2");
									
			SOAPBodyElement elemento = body.addBodyElement(soapAction);

			SOAPElement dados = elemento.addChildElement("Dados");
			dados.addTextNode(dados);
			
			SOAPElement extras = elemento.addChildElement("Extras");
			extras.addTextNode(extras);
			
			SOAPElement param = elemento.addChildElement("Param");
			param.addTextNode(param);
			
			SOAPMessage response = dispatch.invoke(request);
			retorno = response.getSOAPBody().getTextContent();

		} catch (Exception e) {
			retorno = ("erro: " + e.getMessage() + " causa: "+ e.getCause());
		}
		return retorno;
	}

mais uma vez se tiver como dar um help nesse problema eu agradeço MUITO!!!
MUITO MESMO!!! :smiley:

att,

Cara, o problema está aqui:

		System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");
		System.setProperty("java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol");
		Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

		System.setProperty("javax.net.ssl.keyStoreType", "keyStoreType");
		System.setProperty("javax.net.ssl.keyStore","Certificado");
		System.setProperty("javax.net.ssl.keyStoreAlias", "AliasdoCertificado");// DZYON SA:04017374000170
		System.setProperty("javax.net.ssl.keyStorePassword", "SenhaCertificado");

		System.setProperty("javax.net.ssl.trustStoreType", "JKS");
		System.setProperty("javax.net.ssl.trustStore","keystore");

Você deve passar a SSLSocketFactory como parâmetro, do jeitinho que está explicado lá no post… se você setar a propriedade de sistema, ele vai usar sempre a mesma, com o mesmo certificado já travado.

[]´s

uhahuahauuh

q burro eu! ^^

desconfiei desde o principio q tinha algo a ver com as properties!!

:oops: :oops: :oops:

valeu Alexandre (mais uma vez!!!)

obrigado!

em breve posto os resultados

eu ja faria diferente, faria um jar para cada webservice com os stubs gerados, quando eu fosse escolher entre um ou outro, pegaria a URL de conexão como parametro e daria um load no respectivo jar, mas se resolveu é isso que conta, abraços.

Pois é, só que lembre-se de que, de acordo com a arquitetura da JVM, classes carregadas não são descarregadas nunca. Loogo… se você fizer a carga do jar em algum momento, o alias não vai descarregar nunca. Portanto, não é solução para o problema.

[]´s

Pois é, só que lembre-se de que, de acordo com a arquitetura da JVM, classes carregadas não são descarregadas nunca. Loogo… se você fizer a carga do jar em algum momento, o alias não vai descarregar nunca. Portanto, não é solução para o problema.

[]´s[/quote]

desculpe mas não vejo dessa forma Loogo… Portanto, não é solução para o problema. quando vc faz load do jar vc substitui tudo, o que havia antes do load ja não existe mais, automaticamente foi descarregado, vou citar um exemplo de quando comecei a implementar a NFe la na primeira versão, na empresa que eu trabalhava tinha uma app para cada estado então peguei cada jar de cada webservice coloquei tudo numa só e pela UF eu lia o respectivo jar, funciona até hoje, mas se não é boa pratica até gostaria que vc explicasse para que eu possa entender o porque, abraços.

Não é bem assim que a coisa funciona… veja, uma classe só pode ser descarregada se o class loader desta for desativado. Assim é tal que, como o class loader de classes de sistema nunca é desabilitado, elas também não são (fonte: http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#32202). A classe que mantém o alias de uma classe selecionado é sempre a mesma; uma vez “travado”, ele não destrava nunca (a não ser que você especifique um sistema de carga de alias dinâmico, como o que eu expus no meu blog).

Acho perfeitamente possível você ter colocado vários serviços na sua aplicação (obviamente, eu faço o mesmo nas minhas aplicações - trabalho com arquitetura SOA). No entanto, o que eu estou dizendo é que você só pode, assim, ter um tipo de alias selecionado para um tipo de certificado (se você tiver vários certificados diferentes, não deve influir muito). Para certificados parecidos (desculpe por usar o termo “parecido”, eu não sei dizer qual é o parâmetro de diferenciação que a JVM usa. Eu descobrí o problema quando precisei mudar de certificado dinamicamente e a os certificados possuíam uma ÚNICA LETRA diferente; esta letra estava no nome do usuário, dentro do certificado) não é possível fazer o switch dinâmico, já que a VM trava um único alias e não se pode mais fazer o switch - neste caso, a solução que eu passei deve ser aplicada.

Perceba que é uma situação com baixíssima chance de acontecer, na maioria dos projetos. No entanto, eles acontecem (é o segundo assunto com mais visitas do meu blog), e aí, deve se usar uma solução como essa.

Espero ter sido mais claro dessa vez. Caso algum ponto não tenha sido esclarecido, é só avisar, OK ?

[]´s

Post duplicado.

[quote=asaudate]Não é bem assim que a coisa funciona… veja, uma classe só pode ser descarregada se o class loader desta for desativado. Assim é tal que, como o class loader de classes de sistema nunca é desabilitado, elas também não são (fonte: http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#32202). A classe que mantém o alias de uma classe selecionado é sempre a mesma; uma vez “travado”, ele não destrava nunca (a não ser que você especifique um sistema de carga de alias dinâmico, como o que eu expus no meu blog).

Acho perfeitamente possível você ter colocado vários serviços na sua aplicação (obviamente, eu faço o mesmo nas minhas aplicações - trabalho com arquitetura SOA). No entanto, o que eu estou dizendo é que você só pode, assim, ter um tipo de alias selecionado para um tipo de certificado (se você tiver vários certificados diferentes, não deve influir muito). Para certificados parecidos (desculpe por usar o termo “parecido”, eu não sei dizer qual é o parâmetro de diferenciação que a JVM usa. Eu descobrí o problema quando precisei mudar de certificado dinamicamente e a os certificados possuíam uma ÚNICA LETRA diferente; esta letra estava no nome do usuário, dentro do certificado) não é possível fazer o switch dinâmico, já que a VM trava um único alias e não se pode mais fazer o switch - neste caso, a solução que eu passei deve ser aplicada.

Perceba que é uma situação com baixíssima chance de acontecer, na maioria dos projetos. No entanto, eles acontecem (é o segundo assunto com mais visitas do meu blog), e aí, deve se usar uma solução como essa.

Espero ter sido mais claro dessa vez. Caso algum ponto não tenha sido esclarecido, é só avisar, OK ?

[]´s[/quote]

hummmm, blz man, super claro ^^, com certeza tudo que vc falou esta certo, ainda não sou arquiteto SOA mas chego la:), mas no meu caso brother fazer o load do jar foi solução, pois resolveu meu problema, hoje eu não trabalho mais para a empresa que fiz isso, mas vou dar uma procurada nos meus fontes e verificar como implementei isso na éposa, mas você esta certo no que diz, depois vou dar uma lida no seu blog la, abraços e valeu pela informação.

opa, muito obrigado pela ajuda Alexandre e aix,

agora acho q consegui fazer todo o processo igual ao do blog do Alexandre, porém na hora de comunicar com o webservice ocorre o seguinte erro:

Message: Failed to access the WSDL at: https://enderecowsdl?wsdl. It failed with:sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: algorithm check failed: MD2withRSA is disabled. 
cause: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: algorithm check failed: MD2withRSA is disabled

pelo q eu entendi era um erro q teve no update 18 do java, mas esse bug já estava corrigido.

será q esse erro tem algo a ver com essa propriedade:

System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");

valeuuu,

att,

Esse erro acontece porque o servidor não conseguiu negociar um conjunto de certificados adequado. Em 90% dos casos, acontece porque você não tem o certificado certo…

[]´s

hummmm…

o certificado que eu importo no keystore, do webservice que eu quero consumir, tem o algoritmo de assinatura é MD2withRSA e o meu certificado q estabelece a comunicação tem o sha1RSA isso esta relacionado ou estou falando uma grande bobagem? eheheh

engraçado q quando eu faço pelo axis vai numa boa, tb posso estar errando na hora de passar o certificado né? bom d qualquer maneira vou tentar refazer tudo novamente…rsrs

Obrigado Alexandre!

att,