HP ALM Rest API QCSession 411 身份验证

HP ALM Rest API QCSession 411 Authentication

我正在使用 HP-ALM 12.01,它似乎充满了问题。我现在无法更新到另一个版本。

我正在尝试访问其余部分 api 以从 JUnit 自动上传测试结果。我正在使用 here 所示的基础设施(示例应用程序 -> 基础设施)。从中,我的连接脚本将 base64 编码的登录信息传递给 authentication-point/authenticate,并且我正在检索有效的 LWSSO cookie。但是,当我使用此 cookie 连接到 rest/site-session 以接收我的 QCSession cookie 时,我收到了 411 Length Required 错误。我试图将 Content-Length 硬编码到 header 中,如下所示

public void GetQCSession(){
    String qcsessionurl = con.buildUrl("rest/site-session");
    Map<String, String> requestHeaders = new HashMap<String, String>();
    requestHeaders.put("Content-Type", "application/xml");
    requestHeaders.put("Accept", "application/xml");
    requestHeaders.put("Content-Length", "0");
    try {
        Response resp = con.httpPost(qcsessionurl, null, requestHeaders);
        con.updateCookies(resp);
        System.out.println(resp.getStatusCode());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

这没有用。我还尝试修改基础架构以自动注入 Content-Length header,如此处所示

    private void prepareHttpRequest(
        HttpURLConnection con,
        Map<String, String> headers,
        byte[] bytes,
        String cookieString) throws IOException {

    String contentType = null;

    //attach cookie information if such exists
    if ((cookieString != null) && !cookieString.isEmpty()) {

        con.setRequestProperty("Cookie", cookieString);
    }

    //send data from headers
    if (headers != null) {

        //Skip the content-type header - should only be sent
        //if you actually have any content to send. see below.
        contentType = headers.remove("Content-Type");

        Iterator<Entry<String, String>>
                headersIterator = headers.entrySet().iterator();
        while (headersIterator.hasNext()) {
            Entry<String, String> header = headersIterator.next();
            con.setRequestProperty(header.getKey(), header.getValue());
        }
    }

    // If there's data to attach to the request, it's handled here.
    // Note that if data exists, we take into account previously removed
    // content-type.
    if ((bytes != null) && (bytes.length > 0)) {

        con.setDoOutput(true);

        //warning: if you add content-type header then you MUST send
        // information or receive error.
        //so only do so if you're writing information...
        if (contentType != null) {
            con.setRequestProperty("Content-Type", contentType);
        }

        OutputStream out = con.getOutputStream();
        out.write(bytes);
        out.flush();
        out.close();
        con.setRequestProperty("Content-Length", Integer.toString(bytes.length));
    } else {
        con.setRequestProperty("Content-Length", "0");
    }
}

这也行不通。 请注意,setRequestProperty 只是对 MessageHeader

执行 .set(key, value)

有没有人处理过这个问题或知道如何解决?

请注意,其中 none 个问题发生在 postman 身上。所有 4 个 cookie 都是在 site-session post.

之后生成的

问题是 Java 的 HttpURLConnection 在手动设置时会忽略某些属性。其中之一是 Content-Length。这是因为它会自动设置它自己。但是,如果您不发送任何数据,它根本不会发送它,由于其过时的 http 协议,ALM 不接受它,因为它希望收到 Content-Length 0。

要解决此问题,您必须告诉 java 允许受限的 headers。这是由 运行

完成的
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");

有关详细信息,请查看此处 Why does Content-Length HTTP header field use a value other than the one given in Java code?

POM.xml 依赖关系

<dependency>
    <groupId>org.glassfish.jersey.bundles</groupId>
    <artifactId>jaxrs-ri</artifactId>
    <version>2.0</version>
</dependency>

Java代码:登录,获取第一个缺陷,注销

import java.util.Base64;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

public class App {

    private static final String almURL = "https://abc.hp.com/qcbin";
    private static final String isAuthenticatedPath = "authentication-point/authenticate";
    private static final String qcSiteSession = "rest/site-session";
    private static final String logoutPath = "authentication-point/logout";
    private static String lswoocookie;
    private static String qcsessioncookie;

    public static String strDomain = "domain";
    public static String strProject = "project";
    public static String strUserName = "username";
    public static String strPassword = "password";

    public static Client client;
    public static WebTarget target;
    public static Invocation.Builder invocationBuilder;
    public static Response res;


    private static String getEncodedAuthString() {
        String auth = strUserName + ":" + strPassword;
        byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
        String authHeader = "Basic " + new String(encodedAuth);

        return authHeader;
    }

    public static void main(String args[]){
        client = ClientBuilder.newBuilder().build();

        /* Get LWSSO Cookie */
        target = client.target(almURL).path(
                isAuthenticatedPath);
        invocationBuilder = target.request(new String[] { "application/xml" });
        invocationBuilder.header("Authorization", getEncodedAuthString());
        res = invocationBuilder.get();
        lswoocookie = res.getCookies().get("LWSSO_COOKIE_KEY").getValue();

        /* Get QCSession Cookie */
        target = client.target(almURL).path(qcSiteSession);
        invocationBuilder = target
                .request();
        invocationBuilder.cookie("LWSSO_COOKIE_KEY", lswoocookie);
        res = invocationBuilder.post(null);
        qcsessioncookie = res.getCookies().get("QCSession").getValue();

        /* Get the first defect */
        String midPoint = "rest/domains/" + strDomain + "/projects/" + strProject;
        target = client.target(almURL).path(midPoint).path("defects/1");
        invocationBuilder = target
                .request(new String[] { "application/json" });
        invocationBuilder.cookie("LWSSO_COOKIE_KEY", lswoocookie);
        invocationBuilder.cookie("QCSession", qcsessioncookie);
        res = invocationBuilder.get();

        /* Logout */
        target = client.target(almURL).path(logoutPath);
        invocationBuilder = target
                .request();
        invocationBuilder.cookie("LWSSO_COOKIE_KEY", lswoocookie);
        invocationBuilder.cookie("QCSession", qcsessioncookie);
        res = invocationBuilder.post(null);
    }   
}

Barney 的代码示例略有扩展,因为它不适用于 ALM 12.5 设置。 主要区别在于,有更多的 cookies 并且 cookies 附加到 header

  Config config = new Config(dataService);
  String almURL = "https://" + config.host() + "/qcbin";

  client = ClientBuilder.newBuilder().build();
  target = client.target(almURL).path("api/authentication/sign-in");
  invocationBuilder = target
        .request(new String[] {"application/xml"})
        .accept(new String[] {"application/xml"});
  invocationBuilder.header("Authorization", getEncodedAuthString(config.username(), config.password()));

  res = invocationBuilder.post(null);

  String qcsessioncookie = res.getCookies().get("QCSession").getValue();
  String almusercookie = res.getCookies().get("ALM_USER").getValue();
  String xsrftokencookie = res.getCookies().get("XSRF-TOKEN").getValue();
  String lswoocookie = res.getCookies().get("LWSSO_COOKIE_KEY").getValue();

  /* Get the test-Set Data defect */
  String midPoint = "rest/domains/" + config.domain() + "/projects/" + config.project();
  target = client.target(almURL).path(midPoint).path("test-sets/1");
  invocationBuilder = target
        .request(new String[] {"application/xml"})
        .accept(new String[] {"application/xml"});

  concatenatedHeaderCookieString = "QCSession=" + qcsessioncookie + ";" + "ALM_USER=" + ";" + almusercookie + ";" + "XSRF-TOKEN=" + xsrftokencookie + ";"
        + "LWSSO_COOKIE_KEY=" + lswoocookie;
  invocationBuilder.header("Cookie", concatenatedHeaderCookieString);

  res = invocationBuilder.get();