Получить незашифрованный пароль WS-Security на конечной точке службы с помощью Metro + WSIT?

Я пишу сервис SOAP (назовем его X), который действует как своего рода "перенаправляющий прокси", заменяя несколько элементов в теле, затем вызывая другой сервис SOAP (Y). Я хотел бы использовать те же учетные данные WS-Security (имя пользователя и пароль ввиде открытого текста), которые я получаю в X при вызове Y, но у меня возникают проблемы с получением значения элемента Password.

Политика, которую я заявляю в моем wsit-package.service.xml файл ссылается на реализацию 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>

Я могу получить доступ к паролю в валидаторе:

@Override
public boolean validate(Request request) throws PasswordValidationException {
    String password = ((PlainTextPasswordRequest) request).getPassword();
    return true;
}

Однако, поскольку валидатор не имеет доступа к WebServiceContext, нет удобного места для его хранения, доступного для моей конечной точки службы.

С другими заголовками, например WS-Addressing, я могу использовать обработчик (реализация SOAPHandler<SOAPMessageContext>), чтобы вытащить значения, а затем поместить их обратно в контекст под областью приложения для моей конечной точки для извлечения. Заголовки WS-Security уже удаляются к тому времени, когда сообщение SOAP попадает в мою цепочку обработчиков, поэтому нет способа получить их значения в обработчике.

Если не считать чего-то радикального, например, использовать валидатор для хранения пароля в базе данных / глобальной карте / хранилище потоков, есть ли у меня какой-либо способ восстановить пароль WS-Security, который был предоставлен на моей конечной точке?

Должен отметить, что я могу получить доступ к информации о имени пользователя WS-Security на моей конечной точке через Subject subj = SubjectAccessor.getRequesterSubject(context), но это, кажется, не содержит пароль.

1 ответ

Решение

Из-за отсутствия лучшего решения я использовал хранилище ThreadLocal для доступа к имени пользователя и паролю WS-Security в моей конечной точке службы:

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;
    }

}
Другие вопросы по тегам