Базовая аутентификация Apache CFX HP Quality Center

Я пишу коннектор REST для HP Quality Center, используя Apache CFX. Я хотел бы использовать инфраструктуру CFX для выполнения упреждающей аутентификации при отправке запроса на сервер.

HP Quality Center использует механизм проверки подлинности на основе Basic. Для аутентификации запрос на получение отправляется по адресу http:///qcbin/authentication-point/authenticate со стандартным заголовком базовой аутентификации. Затем сервер возвращает файл cookie («LWSSO»), который необходимо включать во все последующие запросы. Запрос ресурса с сервера перед аутентификацией приведет к ошибке 401 с заголовком WWW-Authenticate, который содержит URI точки аутентификации (например, LWSSO realm="http://:80/qcbin/authentication-point").

В идеале я хотел бы создать CFX HttpAuthProvider или Interceptor, который обрабатывает аутентификацию, перехватывая ответ 401, анализируя заголовок WWW-Authenticate и выполняя запрос на URI точки аутентификации перед кэшированием файла cookie для всех последующих запросов.

Это позволило бы мне создать чистый API на основе прокси, используя фабричный шаблон. Например:

public QualityCenter create(String url, String username, String password) {
    JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
    bean.setAddress(url);
    bean.setUsername(username);
    bean.setPassword(password);
    bean.setServiceClass(QualityCenter.class);      

       // TODO: Setup authentication modules here that use AuthPolicy for credentials.

    return bean.create(QualityCenter.class);
}

Я просто не могу понять, возможно ли это и где лучше всего реализовать функциональность.


person S73417H    schedule 28.11.2014    source источник


Ответы (1)


В итоге я решил эту проблему, не используя Apache CXF, вместо этого выбрав Джерси.

Я сделал это, создав два фильтра JAXRS. Этот первый фильтр перехватывает 401 ответ от сервера, следует адресу точки аутентификации, возвращаемому в заголовке «WWW-Authenticate», и выполняет аутентификацию BASIC. Затем исходный запрос воспроизводится на сервере.

Вторая часть этого уравнения — еще один фильтр, который обрабатывает файлы cookie сеанса. Таким образом, при воспроизведении исходного запроса присутствует файл cookie аутентификации.

Два фильтра выглядят так:

class AuthenticationFilter implements ClientResponseFilter {

private final String username;
private final String password;

public AuthenticationFilter(String username, String password) {
    this.username = username;
    this.password = password;
}

@Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
    if (responseContext.getStatus() == Response.Status.UNAUTHORIZED.getStatusCode()) {
        String header = responseContext.getHeaders().getFirst(WWW_AUTHENTICATE);

        // Check if we have been given the authentication redirect go-ahead.
        if (!header.startsWith("LWSSO")) {
            return;
        }

        String authUri = header.substring(13, header.length() - 1);
        Client client = ClientBuilder.newClient(requestContext.getConfiguration());
        String credentials = "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
        Response response = client.target(authUri).path("authenticate").request(MediaType.TEXT_PLAIN_TYPE).header(AUTHORIZATION, credentials).get();
        if (response.getStatus() == Response.Status.OK.getStatusCode()) {
            URI uri = requestContext.getUri();
            MediaType mediaType = requestContext.getMediaType();
            String method = requestContext.getMethod();
            NewCookie cookie = response.getCookies().get("LWSSO_COOKIE_KEY");
            MultivaluedMap<String, Object> headers = requestContext.getHeaders();
            headers.remove(WWW_AUTHENTICATE);
            Invocation.Builder builder = requestContext.getClient().target(uri).request(mediaType).headers(headers).cookie(cookie);

            Invocation invocation;
            if (requestContext.getEntity() != null) {
                invocation = builder.build(method, Entity.entity(
                        requestContext.getEntity(), mediaType));
            } else {
                invocation = builder.build(method);
            }

            Response replayed = invocation.invoke();
            responseContext.setStatus(replayed.getStatus());
            responseContext.setStatusInfo(replayed.getStatusInfo());
            if (replayed.hasEntity()) {
                responseContext.setEntityStream(replayed
                        .readEntity(InputStream.class));
            }
            responseContext.getHeaders().clear();
            responseContext.getHeaders()
                    .putAll(replayed.getStringHeaders());
        }
    }
}}


class SessionFilter implements ClientRequestFilter, ClientResponseFilter {

    private final Map<String, NewCookie> cookies = new HashMap<String, NewCookie>();

    @Override
    public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
        cookies.putAll(responseContext.getCookies());
    }

    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        for(NewCookie cookie: cookies.values()) {
            requestContext.getHeaders().add("Cookie", cookie);          
        }
    }

}
person S73417H    schedule 03.12.2014