0

我目前正在使用 JAIN SIP API 在纯 Java 中开发一个 SIP 客户端,以重新注册、验证并将消息发送到运行在单独机器上的 Asterisk 服务器。

我已经分两步处理了注册和身份验证过程: 1. 发出注册 SIP 请求 2. 如果响应是 401(它是)从 Asterisk 检索 WWW-AuthenticatonHeader 并使用废话为响应字段生成 md5 哈希在我正在填充的 AuthenticationHeader 上设置。

md5 将散列用户名、密码、请求类型等并将其添加到 AuthenticationHeader。

在此之后,我然后发送我之前提出的相同请求,但附加了 AuthenticationHeader。

这是我的代码基于的示例:

http://vkslabs.com/sip-register-request-using-jain-sip/

我遇到的问题是 Asterisk 服务器一直响应 401 状态代码,尽管添加了包含用户名和密码的 md5 哈希的 AuthHeaders,所以我想知道 Asterisk 服务器是否使用不同类型的身份验证质询/方法?

我如何从 Asterisks 访问日志以查看它拒绝我的身份验证请求的确切原因?可能是用户名和密码错误?无效的废话?

目前,服务器只返回 401,而没有更多关于问题的详细信息。

下面是我创建的发出注册请求的代码,如果失败,则再次执行此操作,但这次添加 AuthenticationHeader

public void registerClient(String username, String password,
            ResponseEvent evnt) throws Exception {

        cSeqHeader = headerFactory.createCSeqHeader(1, Request.REGISTER);
//      request = messageFactory.createRequest(requestURI, Request.REGISTER,
//              callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaders,
//              maxForwards);

        request = this.messageFactory.createRequest("REGISTER sip:"
                + toHost + " SIP/2.0\r\n\r\n");
        request.addHeader(callIdHeader);
        request.addHeader(cSeqHeader);
        request.addHeader(fromHeader);
        request.addHeader(toHeader);
        request.addHeader(maxForwards);
        request.addHeader(viaHeader);
        request.addHeader(contactHeader);

        request.addHeader(contactHeader);
        if (evnt != null) {
            request.addHeader(createAuthHeader(username, password, evnt, Request.REGISTER));
        }

        if (transaction == null) {
            transaction = sipProvider.getNewClientTransaction(request);
        }

        transaction.sendRequest();
    }

    private AuthenticationHeader createAuthHeader(String username,
            String password, ResponseEvent response, String requestMethod)
            throws ParseException, NoSuchAlgorithmException {

        AuthenticationHeader header = (AuthenticationHeader) headerFactory
                .createAuthorizationHeader("Digest");

        // get authentication type and nounce from wwwAuthheader we receive from
        // response object
        WWWAuthenticateHeader wwwAuthHeader = (WWWAuthenticateHeader) response
                .getResponse().getHeader(WWWAuthenticateHeader.NAME);

        String nonce = wwwAuthHeader.getNonce();
        String qop = wwwAuthHeader.getQop();
        String realm = wwwAuthHeader.getRealm();
        String opaque = wwwAuthHeader.getOpaque();


        // prepare and md5 username password and realm.
        MessageDigest messageDigest = MessageDigest.getInstance(wwwAuthHeader
                .getAlgorithm());
        ;
        String message = String.format("%1$s:%2$s:%3$s", username, realm,
                password);
        String ha1 = toHexString(messageDigest.digest(message.getBytes()));

        // prepare second md5 value for request method and request URI used
        String message2 = String.format("%1$s:%2$s", requestMethod, requestURI);
        String ha2 = toHexString(messageDigest.digest(message2.getBytes()));

        String responseValue;

        // check what type of digest we need and apply it auth header by
        // checking qop
        if (qop != null && qop.equals(AUTH)) {
            // Create the final MD5 string using ha1 + “:” + nonce + “:” +
            // nonceCount + “:” + cNonce + “:” + qop + “:” + ha2
            // responseValue = String.format("%1$s:%2$s:%3$s:%4$s:%5$s:",
            // ha1,nonce,)

        } else {
            // Create the final MD5 string using ha1 + “:” + nonce + “:” + ha2
            responseValue = String.format("%1$s:%2$s:%3$s", ha1, nonce, ha2);
            String responseConverted = toHexString(messageDigest.digest(responseValue
                    .getBytes()));
            System.out.println(responseConverted);
            System.out.println(wwwAuthHeader.getAlgorithm());
            System.out.println(username);
            System.out.println(nonce);
            System.out.println(realm);
            System.out.println(responseConverted);

            header.setAlgorithm(wwwAuthHeader.getAlgorithm());
            header.setUsername(username);
            header.setNonce(nonce);
            header.setRealm(realm);
            // header.setQop(qop);
            header.setURI(request.getRequestURI());
            header.setResponse(responseConverted);
            if(opaque != null) {
                header.setOpaque(opaque);
            }
        }

        return header;

    }

    private static final char[] toHex = { '0', '1', '2', '3', '4', '5', '6',
            '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

    /**
     * From Nist/JAIN examples: convert an array of bytes to an hexadecimal
     * string
     * 
     * @return a string (length = 2 * b.length)
     * @param b
     *            bytes array to convert to a hexadecimal string
     */
    static String toHexString(byte b[]) {
        int pos = 0;
        char[] c = new char[b.length * 2];
        for (int i = 0; i < b.length; i++) {
            c[pos++] = toHex[(b[i] >> 4) & 0x0F];
            c[pos++] = toHex[b[i] & 0x0f];
        }
        return new String(c);
    }

谢谢

4

1 回答 1

0

您已使用在 401 请求中发送的 nonce 进行身份验证。请重新阅读 sip RFC。

于 2013-05-25T10:33:07.390 回答