Consegui resolver o problema.
Segui o seguinte tutorial:
http://docs.oracle.com/cd/E17802_01/webservices/webservices/reference/tutorials/wsit/doc/WSIT_Security9.html#wp162458
As configurações do web service, no servidor:
Serviço seguro: habilitado
Localização de keystore: keystore.jks, no diretório do Glassfish.
Demais configurações: padrão ou como especificado no tutorial.
As configurações do cliente do web service na aplicação-cliente:
Credenciais de autenticação: dinâmico
Handler de callback de nome de usuário: security.PWCallback (pacote security, classe PWCallback)
Handler de callback de senha: security.PWCallback
Localização de truststore: cacerts.jks (o arquivo deve ser colocado em PastadoProjeto>build>classes>META-INF, manualmente)
Demais configurações: padrão
Código da classe PWCallback:
[code]package security;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
public class PWCallback implements CallbackHandler {
//thread specific username, initialized to null;
private static ThreadLocal username = new ThreadLocal() {
@Override
protected synchronized Object initialValue() {
return null;
}
};
//thread specific password, initialized to null;
private static ThreadLocal password = new ThreadLocal() {
@Override
protected synchronized Object initialValue() {
return null;
}
};
public static void setThreadIdentity(String user, String passw) {
password.set(user);
username.set(passw);
}
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof NameCallback) {
NameCallback nc = (NameCallback) callbacks[i];
String user = (String) username.get();
nc.setName(user);
username.set(null);
} else if (callbacks[i] instanceof PasswordCallback) {
PasswordCallback pc = (PasswordCallback) callbacks[i];
String passCode = (String) password.get();
pc.setPassword(passCode.toCharArray());
//also, after each use revert to using default
password.set(null);
}
}
}
}[/code]
Código da classe Main:
[code]package client;
import java.util.Scanner;
import security.PWCallback;
import security.Pref;
public class Main {
public static void main(String[] args) {
try {
Scanner scan = new Scanner(System.in);
String id = scan.nextLine();
PWCallback.setThreadIdentity("123", "usuario");
server.CalculatorWS_Service service = new server.CalculatorWS_Service();
server.CalculatorWS port = service.getCalculatorWSPort();
java.lang.String resultado = port.hello(id);
System.out.println("Result = " + resultado);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}[/code]
O único problema que ocorreu, foi que como se pode ver na linha
da classe Main, eu tive que inverter os argumentos, para que o código funcionasse. O esperado era setThreadIdentity(String user, String passw), mas quando passei os argumentos na ordem certa, estava dando exception, pois a senha era tida como o nome de usuário. Alguém sabe por que isso ocorre?
Além disso, o único “empecilho” é que implementando o web service dessa maneira, ao criar um usuário novo para o sistema, terei que criar um usuário com mesmo login e senha no glassfish. Mas isso não é um problema tão grande, já que a empresa tem apenas 15 representantes de venda, e eles raramente mudam.
PS: para implementar a classe PWCallBack e entender como utilizá-la utilizei o seguinte link:
http://netbeans-org.1045718.n5.nabble.com/How-to-do-dynamic-authentication-with-default-callback-handler-td3274173.html