Question

I am using JAIN-SIP to register to an Asterisk server and to initiate a call with another SIP softphone. For Asterisk I am running the default configuration for http://www.raspberry-asterisk.org/, with some extensions (SIP users) added.

When I send a REGISTER message to Asterisk, the (Asterisk) server sends back an authentication challenge as expected. My problem is, once I respond to this challenge, Asterisk asks for the same authentication again. After the second authentication response it is finally accepted. I do not understand why it works this way, so I assume I must have something very basic wrong.

Example code:

package sip.test.example;

import gov.nist.javax.sip.SipStackExt;
import gov.nist.javax.sip.clientauthutils.*;

import javax.sip.*;
import javax.sip.address.*;
import javax.sip.header.*;
import javax.sip.message.*;
import java.util.*;

public class WhyDoesThisAuthenticateTwice {
  private SipStackExt sipStack;
  private HeaderFactory header;
  private SipProvider udp;
  private final String sipId = "2";
  private final String myIp = "192.168.1.152";
  private final int myPort = 5060;
  private final String myPw = "password22";
  private final String realm = "asterisk";
  private final String asteriskIp = "192.168.1.171";
  private final int asteriskPort = 5060;
  private final String tag = "fgdfdf";

  public static void main(String[] args) throws Exception {
    new WhyDoesThisAuthenticateTwice().register();
  }

  public void register() throws Exception {
    SipFactory sipFactory = SipFactory.getInstance();
    sipFactory.setPathName("gov.nist");
    Properties properties = new Properties();

    properties.setProperty("javax.sip.STACK_NAME", "test-phone");
    properties.setProperty("javax.sip.OUTBOUND_PROXY", asteriskIp+":"+asteriskPort+"/udp");

    this.sipStack = (SipStackExt) sipFactory.createSipStack(properties);
    header = sipFactory.createHeaderFactory();
    AddressFactory address = sipFactory.createAddressFactory();
    MessageFactory message = sipFactory.createMessageFactory();

    ListeningPoint udpPoint = sipStack.createListeningPoint(myIp, myPort, "udp");

    MySIPListener listener = new MySIPListener();

    udp = sipStack.createSipProvider(udpPoint);
    udp.addSipListener(listener);

    SipURI myRealmURI = address.createSipURI(sipId, realm);
    Address fromAddress = address.createAddress(myRealmURI);
    fromAddress.setDisplayName(sipId);
    FromHeader fromHeader = header.createFromHeader(fromAddress, tag);

    SipURI myURI = address.createSipURI(sipId, myIp);
    myURI.setPort(myPort);
    Address contactAddress = address.createAddress(myURI);
    contactAddress.setDisplayName(sipId);
    ContactHeader contactHeader = header.createContactHeader(contactAddress);

    MaxForwardsHeader maxForwards = header.createMaxForwardsHeader(5);

    List<ViaHeader> viaHeaders = new ArrayList<>();
    CallIdHeader callIdHeader = udp.getNewCallId();
    long seq = 1;
    CSeqHeader cSeqHeader = header.createCSeqHeader(seq++, Request.REGISTER);
    ToHeader toHeader = header.createToHeader(fromAddress, null);
    URI requestURI = address.createURI("sip:"+asteriskIp+":"+asteriskPort);

    Request request = message.createRequest(requestURI, Request.REGISTER, callIdHeader,
            cSeqHeader, fromHeader, toHeader, viaHeaders, maxForwards);
    request.addHeader(contactHeader);
    ExpiresHeader eh = header.createExpiresHeader(300);
    request.addHeader(eh);
    ClientTransaction transaction = udp.getNewClientTransaction(request);
    transaction.sendRequest();
    System.out.println("Sent request:");
    System.out.println(request);
  }

  private class MySIPListener implements SipListener {
    @Override
    public void processRequest(RequestEvent requestEvent) {}
    @Override
    public void processResponse(ResponseEvent event) {
      try {
        Response response = event.getResponse();
        System.out.println("Response received:");
        System.out.println(response);
        if (response.getStatusCode() != 401) return;
        ClientTransaction tid = event.getClientTransaction();
        AccountManagerImpl manager = new AccountManagerImpl();
        AuthenticationHelper helper = sipStack.getAuthenticationHelper(manager, header);
        ClientTransaction transaction = helper.handleChallenge(response, tid, udp, 5);
        transaction.sendRequest();
        Request request = transaction.getRequest();
        System.out.println("Sent request with authentication info:");
        System.out.println(request);
      } catch (SipException e) { e.printStackTrace(); }
    }

    @Override
    public void processTimeout(TimeoutEvent timeoutEvent) {}
    @Override
    public void processIOException(IOExceptionEvent exceptionEvent) {}
    @Override
    public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {}
    @Override
    public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {}
  }

  private class AccountManagerImpl implements AccountManager {
    @Override
    public UserCredentials getCredentials(ClientTransaction clientTransaction, String s) {
      return new UserCredentials() {
        @Override
        public String getUserName() { return sipId; }
        @Override
        public String getPassword() { return myPw; }
        @Override
        public String getSipDomain() { return realm; }
      };
    }
  }
}

When I run it, this is what I get:

Sent request:
REGISTER sip:192.168.1.171:5060 SIP/2.0
Call-ID: 6a1cb516446a3d66806d8750334b8d50@192.168.1.152
CSeq: 1 REGISTER
From: "2" <sip:2@asterisk>;tag=fgdfdf
To: "2" <sip:2@asterisk>
Max-Forwards: 5
Contact: "2" <sip:2@192.168.1.152:5060>
Expires: 300
Via: SIP/2.0/UDP 192.168.1.152:5060;branch=z9hG4bK-373634-2421c1e13c920e5a75f69f9a3f80f8d8
Content-Length: 0


Response received:
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.1.152:5060;branch=z9hG4bK-373634-2421c1e13c920e5a75f69f9a3f80f8d8;received=192.168.1.152
From: "2" <sip:2@asterisk>;tag=fgdfdf
To: "2" <sip:2@asterisk>;tag=as42a729fa
Call-ID: 6a1cb516446a3d66806d8750334b8d50@192.168.1.152
CSeq: 1 REGISTER
Server: FPBX-2.11.0(11.6.0)
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY,INFO,PUBLISH
Supported: replaces,timer
WWW-Authenticate: Digest algorithm=MD5,realm="asterisk",nonce="5bdc425c"
Content-Length: 0


Sent request with authentication info:
REGISTER sip:192.168.1.171:5060;maddr=192.168.1.171 SIP/2.0
Call-ID: 6a1cb516446a3d66806d8750334b8d50@192.168.1.152
CSeq: 2 REGISTER
From: "2" <sip:2@asterisk>;tag=fgdfdf
To: "2" <sip:2@asterisk>
Max-Forwards: 5
Contact: "2" <sip:2@192.168.1.152:5060>
Expires: 300
Via: SIP/2.0/UDP 192.168.1.152:5060;branch=z9hG4bK-373634-18fc265c4d5854f9a970d7545facd464
Authorization: Digest username="2",realm="asterisk",nonce="5bdc425c",uri="sip:192.168.1.171:5060;maddr=192.168.1.171",response="6dc54ff9338920a9b6d7d8755ce719cc",algorithm=MD5
Content-Length: 0


Response received:
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.1.152:5060;branch=z9hG4bK-373634-18fc265c4d5854f9a970d7545facd464;received=192.168.1.152
From: "2" <sip:2@asterisk>;tag=fgdfdf
To: "2" <sip:2@asterisk>;tag=as46d30f80
Call-ID: 6a1cb516446a3d66806d8750334b8d50@192.168.1.152
CSeq: 2 REGISTER
Server: FPBX-2.11.0(11.6.0)
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY,INFO,PUBLISH
Supported: replaces,timer
WWW-Authenticate: Digest algorithm=MD5,realm="asterisk",nonce="75ac799b"
Content-Length: 0


Sent request with authentication info:
REGISTER sip:192.168.1.171:5060;maddr=192.168.1.171 SIP/2.0
Call-ID: 6a1cb516446a3d66806d8750334b8d50@192.168.1.152
CSeq: 3 REGISTER
From: "2" <sip:2@asterisk>;tag=fgdfdf
To: "2" <sip:2@asterisk>
Max-Forwards: 5
Contact: "2" <sip:2@192.168.1.152:5060>
Expires: 300
Via: SIP/2.0/UDP 192.168.1.152:5060;branch=z9hG4bK-373634-64f022399c1ad437b6fffa21782c9376
Authorization: Digest username="2",realm="asterisk",nonce="75ac799b",uri="sip:192.168.1.171:5060;maddr=192.168.1.171",response="cd18746b954cfca05a65c04a23be4e77",algorithm=MD5
Content-Length: 0


Response received:
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.1.152:5060;branch=z9hG4bK-373634-64f022399c1ad437b6fffa21782c9376;received=192.168.1.152
From: "2" <sip:2@asterisk>;tag=fgdfdf
To: "2" <sip:2@asterisk>;tag=as46d30f80
Call-ID: 6a1cb516446a3d66806d8750334b8d50@192.168.1.152
CSeq: 3 REGISTER
Server: FPBX-2.11.0(11.6.0)
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY,INFO,PUBLISH
Supported: replaces,timer
Expires: 300
Contact: <sip:2@192.168.1.152:5060>;expires=300
Date: Mon, 17 Feb 2014 20:27:02 GMT
Content-Length: 0

As you can see, I get 401 Unauthorized back twice. Both time the REGISTER is sent again with authentication response included.

So my question is, why is the authentication not accepted the first time but on the second it is? It is performed by exactly the same code.

I have a slightly similar issue with sending INVITE messages. After successful REGISTER, when I send an INVITE, Asterisk requires me to authenticate again. The MySIPListener code above handles this one as well and produces the required INVITE with authentication response. However, all the examples I find on this always show just direct invite working since, I assume, you should be authenticated already. Perhaps related to the same issue?

So what am I doing wrong?

Was it helpful?

Solution

The request URI in the first attempt is sip:192.168.1.171:5060 while you are submitting challenge response based on sip:192.168.1.171:5060;maddr=192.168.1.171 and that is only updated on the next attempt.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top