Re: authorization in register

Ryan Mitchell <[email protected]> Fri, 13 Jul 2007 10:03:36 -0700
Newsgroups gmane.comp.voip.nist-sip
Message-ID <[email protected]>
Hello Roberto,

The following is an excerpt from a larger system, so don't expect it to
compile, but I picked out the lines to show the essential details.  I
originally figured out the authentication bits from the examples
included with the NIST/JAIN source code.  The same code works for INVITE
407 challenges as well, using
ProxyAuthorizationHeader/ProxyAuthenticateHeader  where appropriate.

Hopefully my comments are readable.  There are not many comments in
makeAuthHeader() because I mostly copied this from other examples. 
Below I have hardcoded username & password.  In the real application I
have something like a User class where I call user.calcA1(mdigest,
realm) to get the A1 string.  This way the user object can avoid
exposing the password to the rest of the system; better yet just
pre-compute A1 for the user and store that in the database so you don't
have plaintext passwords anywhere.


/** Create & resend new request with authorization response to the
challenge given in resp. */
void handleResponse(Response resp, ClientTransaction ct, SipProvider
sipProvider) {

    int rc = resp.getStatusCode();  // verify rc==Response.UNAUTHORIZED

    // add this header to the new request to resend to the server
    AuthorizationHeader authHeader = makeAuthHeader(resp, ct.getRequest());

    // create new request - don't try to reuse the original
    Request req = (Request)ct.getRequest().clone();

    // before adding new authHeader, check if one already exists ...
sometimes SIP servers/proxies
    // will erroneously reject a request that contains an
AuthorizationHeader with 401/407 instead
    // of 403 -- so make sure we don't get into an infinite loop.
    Header ah_ = req.getHeader(AuthorizationHeader.NAME);
    if (ah_ != null && authHeader.equals(ah_)) {
        // give up, notify user of problem ...
        return;
    }

    req.addHeader(authHeader);

    // inc cseq
    CSeqHeader cseq = (CSeqHeader)resp.getHeader(CSeqHeader.NAME);
    cseq.setSeqNumber(cseq.getSeqNumber() + 1);
    req.setHeader(cseq);

    cit = sipProvider.getNewClientTransaction(req);
    cit.sendRequest();
}

AuthorizationHeader makeAuthHeader(Response resp, Request req) {

    // Authenticate header with challenge we need to reply to
    WWWAuthenticateHeader ah_c =   
(WWWAuthenticateHeader)resp.getHeader(WWWAuthenticateHeader.NAME);

    // Authorization header we will build with response to challenge
    AuthorizationHeader ah_r =
headerFactory.createAuthorizationHeader(ah_c.getScheme());

    // assemble data we need to create response string
    URI request_uri = req.getRequestURI();
    String request_method = req.getMethod();
    String nonce  = ah_c.getNonce();
    String algrm  = ah_c.getAlgorithm();
    String realm  = ah_c.getRealm();
    String username = "krusty";
    String password = "pw1234";

    MessageDigest mdigest = MessageDigest.getInstance(algrm);

    // A1
    String A1 = username + ":" + realm + ":" + password;
    String HA1 = Str.toHexString(mdigest.digest(A1.getBytes()));

    // A2
    String A2 = request_method.toUpperCase() + ":" + request_uri ;
    String HA2 = Str.toHexString(mdigest.digest(A2.getBytes()));

    // KD
    String KD = HA1 + ":" + nonce + ":" + HA2;
    String response = Str.toHexString(mdigest.digest(KD.getBytes()));

    ah_r.setRealm(realm);
    ah_r.setNonce(nonce);
    ah_r.setUsername(uap.getUsername());
    ah_r.setURI(request_uri);
    ah_r.setAlgorithm(algrm);
    ah_r.setResponse(response);

    return ah_r;
}

/**
 * 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);
}
private static final char[] toHex = { '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };




Roberto Mier Escandón wrote:
> Hi all
>  
> I have a simple question. Has anybody an example code for creating a
> second REGISTER message with Authorization header when a 401
> unauthorized response is received to a first REGISTER message?. This
> is, Is there a simply way with nist-sip of creating the Authorization
> header in the second register?
>  
> Thank you
>
> _______________________________________________
> nist-sip mailing list
> [email protected]
> http://www-x.antd.nist.gov/mailman/listinfo/nist-sip
>   


-- 
Ryan Mitchell <[email protected]>
Telecom Logic, LLC
503-943-2980