我正在使用Apache CFX向HP Quality Center编写REST连接器。我想在向服务器发出请求时使用CFX基础设施进行抢先认证
HP Quality Center使用基于Basic的身份验证机制。要进行身份验证,请使用标准的基本身份验证标头将get请求发送到http:/// qcbin / authentication-point / authenticate。然后,服务器返回一个cookie(“LWSSO”),该cookie必须包含在所有后续请求中。在进行身份验证之前从服务器请求资源将导致401具有包含身份验证点URI的WWW-Authenticate标头(例如,LWSSO realm =“http://:80 / qcbin / authentication-point)。
理想情况下,我想创建一个CFX HttpAuthProvider或Interceptor,它通过拦截401响应来处理身份验证,解析出WWW-Authenticate头并在为所有后续请求缓存cookie之前对身份验证点URI执行请求。
这将允许我使用工厂模式创建一个干净的基于代理的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);
}
我似乎无法弄清楚这是否可行以及最佳实施功能。
答案 0 :(得分: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);
}
}
}