问题
I'm writing a SOAP service (let's call it X) that acts as a "forwarding proxy" of sorts, replacing several elements in the body, then calling another SOAP service (Y). I would like to use the same WS-Security credentials (plaintext username and password) that I receive in X when I call Y, but I am having trouble retrieving the value of the Password element.
The policy that I declare in my wsit-package.service.xml
file references an implementation of com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidator
:
<wsp1_2:Policy wsu:Id="UsernameToken"
xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
xmlns:wsss="http://schemas.sun.com/2006/03/wss/server"
xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy">
<wsp1_2:ExactlyOne>
<wsp1_2:All>
<sp:SupportingTokens>
<wsp1_2:Policy>
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/
ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient" />
<sp:IncludeTimestamp />
</wsp1_2:Policy>
</sp:SupportingTokens>
<wsss:ValidatorConfiguration wspp:visibility="private" >
<wsss:Validator name="usernameValidator"
classname="com.service.validator.SecurityValidator" />
</wsss:ValidatorConfiguration>
</wsp1_2:All>
</wsp1_2:ExactlyOne>
</wsp1_2:Policy>
I am able to access the password in the validator:
@Override
public boolean validate(Request request) throws PasswordValidationException {
String password = ((PlainTextPasswordRequest) request).getPassword();
return true;
}
However, since the validator does not have access to the WebServiceContext, there is not a convenient place to store it that is accessible to my service endpoint.
With other headers, e.g. WS-Addressing, I am able to use a Handler (implementation of SOAPHandler<SOAPMessageContext>
) to pull out the values, then put them back in the context under the application scope for my endpoint to retrieve. WS-Security headers are already stripped by the time the SOAP message gets to my handler chain, so there is no way to retrieve their values in a Handler.
Short of doing something drastic like using the validator to store the password in a database/global map/threadlocal storage, is there any way for me to retrieve the WS-Security Password that was supplied at my endpoint?
I should note that I am able to access the WS-Security Username information at my endpoint via Subject subj = SubjectAccessor.getRequesterSubject(context)
, but this does not appear to contain the password.
回答1:
For lack of a better solution, I ended up using ThreadLocal storage to access the WS-Security Username and Password in my service endpoint:
package com.my.ws.validator;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidationException;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidator;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback.PlainTextPasswordRequest;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback.Request;
public class SecurityValidator implements PasswordValidator {
private static final ThreadLocal<String> username = new ThreadLocal<String>();
private static final ThreadLocal<String> password = new ThreadLocal<String>();
@Override
public boolean validate(final Request request) throws PasswordValidationException {
if (request instanceof PlainTextPasswordRequest) {
PlainTextPasswordRequest plainText = (PlainTextPasswordRequest) request;
if (null == plainText.getUsername() || plainText.getUsername().trim().isEmpty())
throw new PasswordValidationException("A username must be provided");
else
username.set(plainText.getUsername());
if (null == plainText.getPassword() || plainText.getPassword().trim().isEmpty())
throw new PasswordValidationException("A password must be provided");
else
password.set(plainText.getPassword());
return true;
}
return false;
}
public static String getUsername() {
String user = username.get();
username.remove();
return user;
}
public static String getPassword() {
String pass = password.get();
password.remove();
return pass;
}
}
来源:https://stackoverflow.com/questions/13297345/retrieve-plaintext-ws-security-password-at-service-endpoint-with-metro-wsit