I'm working with the Jain Sip library, trying to create a connection to an asterisk server. I've been working with the textclient example app from this page: http://www.oracle.com/technetwork/articles/entarch/introduction-jain-sip-090386.html
but this doesn't actually authenticate with the server. I can send messages to users on the server, but I normally require a user/password authentication on the server.
As far as I can tell I have to use the "javax.sip.OUTBOUND_PROXY" property, but I can't find any documentation on how to set a username or password. Has anyone else had any success with this?
There are two forms of authentication in SIP – authentication of a user agent (UA) by a proxy, redirect, or registration server and authentication of one UA by another. With Transport Layer Security (TLS), mutual authentication of proxies or a proxy and UA is accomplished using certificates.
JAIN SIP is the standardized Java interface to the Session Initiation Protocol for desktop and server applications. JAIN SIP enables transaction stateless, transaction stateful and dialog stateful control over the protocol.
The Java APIs for Integrated Networks (JAIN) is a JCP work group managing telecommunication standards. Session Initiation Protocol (SIP) is a standard communication protocol, discussed in a previous article. Put Java and SIP together and you get the JAIN SIP API, a standard and powerful API for telecommunications.
The best example I have found on registration is found here. Here is the gist of if just in case the link dries-up one day:
REGISTER request is used to update the current location of a user on the REGISTRAR server. The application sends a REGISTER message informing the server its current location which in turn is stored in location server. When a caller calls a user the proxy server uses this information to find the location of the callee.
Register request should be sent by the client periodically. The validity of the REGISTER request is determined by the Expires header.
Flow
Sample Request
REGISTER sip:sip.linphone.org SIP/2.0 Call-ID: [email protected] CSeq: 1 REGISTER From: <sip:[email protected]>;tag=-1427592833 To: <sip:[email protected]> Max-Forwards: 70 Via: SIP/2.0/TCP 223.1.1.128:5060;branch=z9hG4bK-323532-2a454f4ec2a4213f6d6928eba479521d Contact: <sip:[email protected];transport=tcp> Content-Length: 0
Now lets see how to construct the above request using the NIST SIP Stack.
First step is to create a class that implements the SIPListener. Make sure your SIP Stack is Initializing NIST JAIN SIP Stack.
Create Call-ID header
CallIdHeader callIdHeader = this.sipProvider.getNewCallId();
Create CSeq header
CSeqHeader cSeqHeader = this.headerFactory.createCSeqHeader(cseq, "REGISTER");
Create From header
Address fromAddress = addressFactory.createAddress("sip:" + username + '@' + server); FromHeader fromHeader = this.headerFactory.createFromHeader(fromAddress, String.valueOf(this.tag));
Create To Header
ToHeader toHeader = this.headerFactory.createToHeader(fromAddress, null);
Create Max-Forwards header
MaxForwardsHeader maxForwardsHeader = this.headerFactory.createMaxForwardsHeader(70);
Create a Via header
ArrayList viaHeaders = new ArrayList(); ViaHeader viaHeader = this.headerFactory.createViaHeader(this.ip, this.port, "tcp", null); viaHeaders.add(viaHeader);
Create contact header
this.contactAddress = this.addressFactory.createAddress("sip:" + this.username + '@' + this.ip + "transport=tcp");
// Create the contact header used for all SIP messages. this.contactHeader = this.headerFactory.createContactHeader(contactAddress);
Once all the headers are created it is time to create the request itself.
request = this.messageFactory.createRequest("REGISTER sip:" + server + "SIP/2.0\r\n\r\n"); request.addHeader(callIdHeader); request.addHeader(cSeqHeader); request.addHeader(fromHeader); request.addHeader(toHeader); request.addHeader(maxForwardsHeader); request.addHeader(viaHeader); request.addHeader(contactHeader);
Now that the request object is created with all the necessary headers it is time to send the request.
inviteTid = sipProvider.getNewClientTransaction(request); // send the request out. inviteTid.sendRequest();
Once the request is sent successfully the response will be passed to the application using the processResponse callback in SIPListener.
public void processResponse(ResponseEvent responseEvent) { int statusCode = responseEvent.getResponse().getStatusCode(); }
Code
public void register(Response response) { try { cseq++; ArrayList viaHeaders = new ArrayList(); ViaHeader viaHeader = this.headerFactory.createViaHeader(this.ip, this.port, "tcp", null); viaHeaders.add(viaHeader); // The "Max-Forwards" header. MaxForwardsHeader maxForwardsHeader = this.headerFactory .createMaxForwardsHeader(70); // The "Call-Id" header. CallIdHeader callIdHeader = this.sipProvider.getNewCallId(); // The "CSeq" header. CSeqHeader cSeqHeader = this.headerFactory.createCSeqHeader(cseq, "REGISTER"); Address fromAddress = addressFactory.createAddress("sip:" + username + '@' + server); FromHeader fromHeader = this.headerFactory.createFromHeader( fromAddress, String.valueOf(this.tag)); // The "To" header. ToHeader toHeader = this.headerFactory.createToHeader(fromAddress, null); // this.contactHeader = this.headerFactory // .createContactHeader(contactAddress); request = this.messageFactory.createRequest("REGISTER sip:" + server + " SIP/2.0\r\n\r\n"); request.addHeader(callIdHeader); request.addHeader(cSeqHeader); request.addHeader(fromHeader); request.addHeader(toHeader); request.addHeader(maxForwardsHeader); request.addHeader(viaHeader); request.addHeader(contactHeader); if (response != null) { retry = true; AuthorizationHeader authHeader = Utils.makeAuthHeader(headerFactory, response, request, username, password); request.addHeader(authHeader); } inviteTid = sipProvider.getNewClientTransaction(request); // send the request out. inviteTid.sendRequest(); this.dialog = inviteTid.getDialog(); // Send the request statelessly through the SIP provider. // this.sipProvider.sendRequest(request); // Display the message in the text area. logger.debug("Request sent:\n" + request.toString() + "\n\n"); } catch (Exception e) { // If an error occurred, display the error. e.printStackTrace(); logger.debug("Request sent failed: " + e.getMessage() + "\n"); } }
You can also view the reference post on authentication here. Here is the gist of if just in case the link dries-up one day:
During a SIP request if the server responds with 401 Proxy Authentication Required or 401 Unauthorized then it means the client has to replay the same request again with MD5 challenge.
The client should use nonce value from the response header WWW-Authenticate.
WWW-Authenticate: Digest realm="sip.linphone.org", nonce="JbAO1QAAAAA3aDI0AADMobiT7toAAAAA", opaque="+GNywA==", algorithm=MD5, qop="auth"
The client should use nonce to generate the MD5 challenge and make the original request again with the Authorization header.
Steps to create the MD5 Challenge
Create first MD5 hash using username + “:” + realm + “:” + password
String a1 = username + ":" + realm + ":" + password; String ha1 = toHexString(mdigest.digest(a1.getBytes()));
Create second MD5 hash using request_method + “:” + request_uri
String a2 = request_method.toUpperCase() + ":" + request_uri; String ha2 = toHexString(mdigest.digest(a2.getBytes()));
If qop in the response header is “auth” then the final MD5 hash is calculated using step 3a else if it is undefined or empty refer step 3b.
3a. Create the final MD5 string using ha1 + “:” + nonce + “:” + nonceCount + “:” + cNonce + “:” + qop + “:” + ha2
String finalStr = ha1 + ":" + nonce + ":" + nonceCount + ":" + cNonce + ":" + qop + ":" + ha2; String response = toHexString(mdigest.digest(finalStr.getBytes()));
3b. Create the final MD5 string using ha1 + “:” + nonce + “:” + ha2
String finalStr = ha1 + ":" + nonce + ":" + ha2; String response = toHexString(mdigest.digest(finalStr.getBytes()));
Check the example from here http://code.google.com/p/jain-sip/source/browse/#git%2Fsrc%2Fexamples%2Fauthorization
Why do you need to go this low level, you might be better off with using a SIP Servlets Container such as Mobicents http://code.google.com/p/sipservlets/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With