Inquiridor
Problemas com Certificados + Java WS

Pergunta
-
Olá Pessoal,
Estou com o seguinte problema:
Um cliente possui um WebService exposto em Java, com SOAP 1.1, onde tive que codificar um bind personalizado para funcionar, pois além da versão do SOAP, havia a necessidade de se utilizar WS Security - https, e também UsernameToken, somente com assinatura das partes da mensagem, sem criptografia, com certificados para o cliente e para o servidor.
Tudo foi configurado corretamente e funciona, exceto pela seguinte questão: A idéia é permitir acesso deste WS por vários clientes, cada um com seu certificado.
Porém, na sessão behaviors do app.config está especificado o certificado do servidor, e este não é o comportamento desejado - gostaríamos não precisar especificar este certificado (o que gera erro no momento da conexão - certificado não informado) ou então especificar não o certificado da empresa, mas sim o da CertSign - autoridade pai do certificado em questão, com ChainTrust ativado. Porém gera outro erro, indicando que o certificado usado na assinatura da msg de envio é diferente do usado na assinatura da msg de retorno.
A idéia é não precisar repassar o certificado a todos os clientes sempre que o certificado for renovado.
Como ter este cliente WCF se conectando ao servidor mas sem precisar instalar o certificado do servidor nos clientes?
Obrigado!
Leandro C. Almeida - MCP- Editado Leandro C. Almeida quarta-feira, 15 de setembro de 2010 21:14 Melhora da pergunta
Todas as Respostas
-
Boas Leandro,
Mas a sua dificuldade é em alterar o certificado em tempo de execução?
O serviço está utilizando o certificado apenas para proteger a mensagem ou está utilizando o certificado para autenticar o usuario?
http://www.israelaece.com -
Olá Israel,
Em primeiro lugar, obrigado pelo interesse em ajudar.
O certificado é usado tanto para assinar a mensagem quanto para autenticar o usuário.
Abaixo, segue o binding criado para tal:
MyBinding.cs
public class MyBinding : System.ServiceModel.Channels.Binding
{
public override BindingElementCollection CreateBindingElements()
{
BindingElementCollection be = new BindingElementCollection();
X509SecurityTokenParameters initiator = new X509SecurityTokenParameters( X509KeyIdentifierClauseType.Thumbprint, SecurityTokenInclusionMode.AlwaysToRecipient);
X509SecurityTokenParameters recipient = new X509SecurityTokenParameters(X509KeyIdentifierClauseType.Thumbprint, SecurityTokenInclusionMode.AlwaysToInitiator);
AsymmetricSecurityBindingElement element = new AsymmetricSecurityBindingElement(recipient, initiator);
element.SetKeyDerivation(false);
element.IncludeTimestamp = true;
element.AllowSerializedSigningTokenOnReply = true;
element.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
element.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
UserNameSecurityTokenParameters tokenParameters = new UserNameSecurityTokenParameters();
tokenParameters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
tokenParameters.RequireDerivedKeys = false;
element.EndpointSupportingTokenParameters.Signed.Add(tokenParameters);
be.Add(element);
be.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
be.Add(new HttpsTransportBindingElement());
return be;
}
public override string Scheme
{
get { return "https"; }
}
}
Behavior do App.config:
<behaviors>
<endpointBehaviors>
<behavior name="AnbimaBehavior">
<clientCredentials>
<clientCertificate findValue="5d b4 a8 h0 33 21 d3 66 61 c2 23 f3 24 76 4d 9e 65 92 0f a2"
x509FindType="FindByThumbprint" />
<serviceCertificate>
<defaultCertificate findValue="5d b4 a8 h0 33 21 d3 66 61 c2 23 f3 24 76 4d 9e 65 92 0f a2"
x509FindType="FindByThumbprint" />
<authentication certificateValidationMode="None" />
</serviceCertificate>
<httpDigest impersonationLevel="Identification" />
</clientCredentials>
</behavior>
Gostaríamos de não precisar especificar o serviceCertificate ou, caso especificar, que fosse o da CertSign, para não precisar enviar o certificado do servidor para o cliente final.
Obrigado!
Leandro C. Almeida - MCP -
Boas Leandro,
Deixa ver se consigo te ajudar em algo. Você está se referindo ao certificado informado no elemento serviceCertificate?
Se sim, esse certificado é utilizado para que o cliente valide o serviço, ou seja, evita que o cliente responda para um serviço falso. Esse elemento é utilizado para especificar as configurações utilizandas pelo cliente para validar o certificado apresentado pelo serviço durante a autenticação do HTTPS/SSL ou pode conter o certificado utilizado pelo serviço para criptografas as mensagens, quando se utiliza a segurança baseada na mensagem.
http://www.israelaece.com -
Ok Israel,
Agora, para o cliente validar o serviço, eu precisarei entregar meu certificado do serviço (.cer) para meus clientes finais? (isso é o que não gostaríamos) O ideal seria que o app cliente validasse o serviço pela autoridade "pai" - a CertSign, onde não precisaria enviar meu certificado do serviço.
Quando eu tento fazer isso, especificando o certificado, é gerado o seguinte erro, na resposta do serviço: "A mensagem de entrada foi assinada com um token diferente do usado para criptografar o corpo. Isto não era esperado".
Analisando o trace, as mensagens trafegam, mas na validação da assinatura do corpo que o serviço manda, o WCF no cliente rejeita a assinatura, pois está diferente do especificado no certificado da CertSign. Dá para indicar qual o certificado/chave pública será usada para validar a assinatura do retorno?
PS: Seu blog já me ajudou muito - parabéns pelo trabalho!
Leandro C. Almeida - MCP -
Boas Leandro,
Já tentou remover o serviceCertificate do cliente e definir a propriedade NegotiateServiceCredential dos dois lados como True?
http://www.israelaece.com -
Olá Israel,
Tentei seguir sua sugestão, porém não consegui testá-la até o fim, pois meu Binding é feito via código e não possui a propriedade Security.
Eu cheguei a criar a propriedade na classe do binding (MyBinding) e também instanciei o objeto e setei a propriedade Security.Message.NegotiateServiceCredential p/ True no método CreateBindingElements().
Depois removi do behavior (app.config) o serviceCertificate do cliente e o erro que recebi foi: "O certificado de serviço não é fornecido para o destino http... Especifique um certificado de serviço em ClientCredentials".
Acho que a propriedade não surtiu efeito - talvez por causa do binding...
Abs,
Leandro C. Almeida - MCP -
Boas Leandro,
Em algum lugar, há algum tempo, eu vi que a negociação não é suportada em algumas plataformas, mas não sei te precisar se o Java fornece isso ou não. A negociação talvez resolva o seu problema, ou seja, evita a necessidade dos clientes terem acesso out-of-band a chave pública do certificado do serviço. (http://msdn.microsoft.com/en-us/library/ms733102(VS.90).aspx).
Mas lendo mais calmamente o seu post inicial, você disse que o serviço foi desenvolvido em Java e você está tentando consumir via WCF? Se for isso, ai precisaremos ver se o serviço está expondo a chave pública para negociação ou somente out-of-band.
http://www.israelaece.com