I'm working in a project, made with Java 8 and Spring Boot, in which I want to add the Wss4jSecurityInterceptor for login purposes.
So far, this is what I've done in the WebServiceConfig class
@Bean
public AuthorizationCallBackHandler authorizationCallBackHandler(){
AuthorizationCallBackHandler callbackHandler = new AuthorizationCallBackHandler();
return callbackHandler;
}
@Bean
public Wss4jSecurityInterceptor securityInterceptor(){
Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();
securityInterceptor.setValidationActions("UsernameToken");
securityInterceptor.setValidationCallbackHandler(authorizationCallBackHandler());
return securityInterceptor;
}
@Override
public void addInterceptors(List interceptors) {
interceptors.add(securityInterceptor());
//interceptors.add(endPointInterceptor());
}
So, with this, every request that arrives at my Web Service, will be intercepted by the Wss4jSecurityInterceptor and will be handled by my custom callback, defined like this
public class AuthorizationCallBackHandler implements CallbackHandler{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
VnWsCredentialRepository credentialsRepo;
@Autowired
AuthUtility authUtil;
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
if (callbacks[0] instanceof WSPasswordCallback) {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
String username = pc.getIdentifier();
VnWsCredential credentials = credentialsRepo.findByUsername(username);
logger.info("Request of authentication for username" + username);
String p = pc.getPassword();
// set the password on the callback. This will be compared to the
// password which was sent from the client.
if (credentials == null) {
pc.setPassword(null);
}else {
// String encodedPsw = authUtil.obtaindMD5Value(credentials.getPassword());
// pc.setPassword(encodedPsw);
pc.setPassword(credentials.getPassword());
}
}
if (callbacks[0] instanceof UsernameTokenPrincipalCallback) {
UsernameTokenPrincipalCallback pc = (UsernameTokenPrincipalCallback) callbacks[0];
pc.getPrincipal();
}
}
}
Here's my problem: when the Callback gets called, it receives an array that holds just 1 callback with a "CleanupCallback" type and I'm not, of course, able to do anything with it.
What am I missing in the following settings?
This is the SOAP call that I'm making with SOAP UI
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:it="some.fancy.ws">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-3967AEB46D733EF6E2154990461080350">
<wsse:Username>Just a user</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">just a password</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">pUn8VjdpVaIamSAIwXEeXg==</wsse:Nonce>
<wsu:Created>2019-02-16T17:03:30.803Z</wsu:Created>
</wsse:UsernameToken></wsse:Security>
</soapenv:Header>
<soapenv:Body>
<it:getPOrderRequest>
<it:poNumber>2197111225-F03292</it:poNumber>
</it:getPOrderRequest>
</soapenv:Body>
</soapenv:Envelope>
For anyone interested, I solved this thing by first of all removing from the request the content inside the header.
After that, I setted up an Outgoing WSS with the credentials and, just like that, the Wss4j Security Handler converted the Callback to the instance I wanted (that is, WSPasswordCallback).
Lesson learned: if Wss4j detects a some kind of error in handling the SOAP Request, it will generate a CleanupCallback and not an instance of WSPasswordCallback