/** * Check the response and answer true if authentication succeeds. We are making simplifying * assumptions here and assuming that the password is available to us for computation of the MD5 * hash. We also dont cache authentications so that the user has to authenticate on each * registration. * * @param user is the username * @param authHeader is the Authroization header from the SIP request. * @param requestLine is the SIP Request line from the SIP request. * @exception SIPAuthenticationException is thrown when authentication fails or message is bad */ public boolean doAuthenticate(String user, AuthorizationHeader authHeader, Request request) { String realm = authHeader.getRealm(); String username = authHeader.getUsername(); URI requestURI = request.getRequestURI(); if (username == null) { ProxyDebug.println( "DEBUG, DigestAuthenticateMethod, doAuthenticate(): " + "WARNING: userName parameter not set in the header received!!!"); username = user; } if (realm == null) { ProxyDebug.println( "DEBUG, DigestAuthenticateMethod, doAuthenticate(): " + "WARNING: realm parameter not set in the header received!!! WE use the default one"); realm = DEFAULT_REALM; } ProxyDebug.println( "DEBUG, DigestAuthenticateMethod, doAuthenticate(): " + "Trying to authenticate user: "******" for " + " the realm: " + realm); String password = (String) passwordTable.get(username + "@" + realm); if (password == null) { ProxyDebug.println( "DEBUG, DigestAuthenticateMethod, doAuthenticate(): " + "ERROR: password not found for the user: "******"@" + realm); return false; } String nonce = authHeader.getNonce(); // If there is a URI parameter in the Authorization header, // then use it. URI uri = authHeader.getURI(); // There must be a URI parameter in the authorization header. if (uri == null) { ProxyDebug.println( "DEBUG, DigestAuthenticateMethod, doAuthenticate(): " + "ERROR: uri paramater not set in the header received!"); return false; } ProxyDebug.println( "DEBUG, DigestAuthenticationMethod, doAuthenticate(), username:"******"!"); ProxyDebug.println("DEBUG, DigestAuthenticationMethod, doAuthenticate(), realm:" + realm + "!"); ProxyDebug.println( "DEBUG, DigestAuthenticationMethod, doAuthenticate(), password:"******"!"); ProxyDebug.println("DEBUG, DigestAuthenticationMethod, doAuthenticate(), uri:" + uri + "!"); ProxyDebug.println("DEBUG, DigestAuthenticationMethod, doAuthenticate(), nonce:" + nonce + "!"); ProxyDebug.println( "DEBUG, DigestAuthenticationMethod, doAuthenticate(), method:" + request.getMethod() + "!"); String A1 = username + ":" + realm + ":" + password; String A2 = request.getMethod().toUpperCase() + ":" + uri.toString(); byte mdbytes[] = messageDigest.digest(A1.getBytes()); String HA1 = ProxyUtilities.toHexString(mdbytes); ProxyDebug.println("DEBUG, DigestAuthenticationMethod, doAuthenticate(), HA1:" + HA1 + "!"); mdbytes = messageDigest.digest(A2.getBytes()); String HA2 = ProxyUtilities.toHexString(mdbytes); ProxyDebug.println("DEBUG, DigestAuthenticationMethod, doAuthenticate(), HA2:" + HA2 + "!"); String cnonce = authHeader.getCNonce(); String KD = HA1 + ":" + nonce; if (cnonce != null) { KD += ":" + cnonce; } KD += ":" + HA2; mdbytes = messageDigest.digest(KD.getBytes()); String mdString = ProxyUtilities.toHexString(mdbytes); String response = authHeader.getResponse(); ProxyDebug.println( "DEBUG, DigestAuthenticateMethod, doAuthenticate(): " + "we have to compare his response: " + response + " with our computed" + " response: " + mdString); int res = (mdString.compareTo(response)); if (res == 0) { ProxyDebug.println( "DEBUG, DigestAuthenticateMethod, doAuthenticate(): " + "User authenticated..."); } else { ProxyDebug.println( "DEBUG, DigestAuthenticateMethod, doAuthenticate(): " + "User not authenticated..."); } return res == 0; }
/** * Generates an authorisation header in response to wwwAuthHeader. * * @param method method of the request being authenticated * @param uri digest-uri * @param requestBody the body of the request. * @param authHeader the challenge that we should respond to * @param userCredentials username and pass * @return an authorisation header in response to authHeader. * @throws OperationFailedException if auth header was malformated. */ private AuthorizationHeader getAuthorization( String method, String uri, String requestBody, WWWAuthenticateHeader authHeader, UserCredentialHash userCredentials) { String response = null; // JvB: authHeader.getQop() is a quoted _list_ of qop values // (e.g. "auth,auth-int") Client is supposed to pick one String qopList = authHeader.getQop(); String qop = (qopList != null) ? "auth" : null; String nc_value = "00000001"; String cnonce = "xyz"; response = MessageDigestAlgorithm.calculateResponse( authHeader.getAlgorithm(), userCredentials.getHashUserDomainPassword(), authHeader.getNonce(), nc_value, // JvB added cnonce, // JvB added method, uri, requestBody, qop, sipStack.getStackLogger()); // jvb changed AuthorizationHeader authorization = null; try { if (authHeader instanceof ProxyAuthenticateHeader) { authorization = headerFactory.createProxyAuthorizationHeader(authHeader.getScheme()); } else { authorization = headerFactory.createAuthorizationHeader(authHeader.getScheme()); } authorization.setUsername(userCredentials.getUserName()); authorization.setRealm(authHeader.getRealm()); authorization.setNonce(authHeader.getNonce()); authorization.setParameter("uri", uri); authorization.setResponse(response); if (authHeader.getAlgorithm() != null) { authorization.setAlgorithm(authHeader.getAlgorithm()); } if (authHeader.getOpaque() != null) { authorization.setOpaque(authHeader.getOpaque()); } // jvb added if (qop != null) { authorization.setQop(qop); authorization.setCNonce(cnonce); authorization.setNonceCount(Integer.parseInt(nc_value)); } authorization.setResponse(response); } catch (ParseException ex) { throw new RuntimeException("Failed to create an authorization header!"); } return authorization; }
/** * Generates an authorisation header in response to wwwAuthHeader. * * @param method method of the request being authenticated * @param uri digest-uri * @param requestBody the body of the request. * @param authHeader the challenge that we should respond to * @param username * @param password * @return an authorisation header in response to authHeader. * @throws OperationFailedException if auth header was malformated. */ public static AuthorizationHeader getAuthorizationHeader( String method, String uri, String requestBody, WWWAuthenticateHeader authHeader, String username, String password) { String response = null; HeaderFactory headerFactory = SipFactories.headerFactory; // JvB: authHeader.getQop() is a quoted _list_ of qop values // (e.g. "auth,auth-int") Client is supposed to pick one String qopList = authHeader.getQop(); String qop = (qopList != null) ? "auth" : null; String nc_value = "00000001"; String cnonce = "xyz"; try { response = MessageDigestResponseAlgorithm.calculateResponse( authHeader.getAlgorithm(), username, authHeader.getRealm(), password, authHeader.getNonce(), nc_value, // JvB added cnonce, // JvB added method, uri, requestBody, qop); // jvb changed } catch (NullPointerException exc) { throw new IllegalStateException("The authenticate header was malformatted", exc); } AuthorizationHeader authorization = null; try { if (authHeader instanceof ProxyAuthenticateHeader) { authorization = headerFactory.createProxyAuthorizationHeader(authHeader.getScheme()); } else { authorization = headerFactory.createAuthorizationHeader(authHeader.getScheme()); } authorization.setUsername(username); authorization.setRealm(authHeader.getRealm()); authorization.setNonce(authHeader.getNonce()); authorization.setParameter("uri", uri); authorization.setResponse(response); if (authHeader.getAlgorithm() != null) { authorization.setAlgorithm(authHeader.getAlgorithm()); } if (authHeader.getOpaque() != null && authHeader.getOpaque().length() > 0) { authorization.setOpaque(authHeader.getOpaque()); } // jvb added if (qop != null) { authorization.setQop(qop); authorization.setCNonce(cnonce); authorization.setNonceCount(Integer.parseInt(nc_value)); } authorization.setResponse(response); } catch (ParseException ex) { throw new SecurityException("Failed to create an authorization header!"); } return authorization; }
/* * (non-Javadoc) * * @see gov.nist.javax.sip.clientauthutils.AuthenticationHelper#handleChallenge(javax.sip.message.Response, * javax.sip.ClientTransaction, javax.sip.SipProvider) */ public ClientTransaction handleChallenge( Response challenge, ClientTransaction challengedTransaction, SipProvider transactionCreator, int cacheTime) throws SipException, NullPointerException { try { if (sipStack.isLoggingEnabled()) { sipStack.getStackLogger().logDebug("handleChallenge: " + challenge); } SIPRequest challengedRequest = ((SIPRequest) challengedTransaction.getRequest()); Request reoriginatedRequest = null; /* * If the challenged request is part of a Dialog and the * Dialog is confirmed the re-originated request should be * generated as an in-Dialog request. */ if (challengedRequest.getToTag() != null || challengedTransaction.getDialog() == null || challengedTransaction.getDialog().getState() != DialogState.CONFIRMED) { reoriginatedRequest = (Request) challengedRequest.clone(); } else { /* * Re-originate the request by consulting the dialog. In particular * the route set could change between the original request and the * in-dialog challenge. */ reoriginatedRequest = challengedTransaction.getDialog().createRequest(challengedRequest.getMethod()); Iterator<String> headerNames = challengedRequest.getHeaderNames(); while (headerNames.hasNext()) { String headerName = headerNames.next(); if (reoriginatedRequest.getHeader(headerName) != null) { ListIterator<Header> iterator = reoriginatedRequest.getHeaders(headerName); while (iterator.hasNext()) { reoriginatedRequest.addHeader(iterator.next()); } } } } // remove the branch id so that we could use the request in a new // transaction removeBranchID(reoriginatedRequest); if (challenge == null || reoriginatedRequest == null) { throw new NullPointerException("A null argument was passed to handle challenge."); } ListIterator authHeaders = null; if (challenge.getStatusCode() == Response.UNAUTHORIZED) { authHeaders = challenge.getHeaders(WWWAuthenticateHeader.NAME); } else if (challenge.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED) { authHeaders = challenge.getHeaders(ProxyAuthenticateHeader.NAME); } else { throw new IllegalArgumentException("Unexpected status code "); } if (authHeaders == null) { throw new IllegalArgumentException( "Could not find WWWAuthenticate or ProxyAuthenticate headers"); } // Remove all authorization headers from the request (we'll re-add them // from cache) reoriginatedRequest.removeHeader(AuthorizationHeader.NAME); reoriginatedRequest.removeHeader(ProxyAuthorizationHeader.NAME); // rfc 3261 says that the cseq header should be augmented for the new // request. do it here so that the new dialog (created together with // the new client transaction) takes it into account. // Bug report - Fredrik Wickstrom CSeqHeader cSeq = (CSeqHeader) reoriginatedRequest.getHeader((CSeqHeader.NAME)); try { cSeq.setSeqNumber(cSeq.getSeqNumber() + 1l); } catch (InvalidArgumentException ex) { throw new SipException("Invalid CSeq -- could not increment : " + cSeq.getSeqNumber()); } /* Resolve this to the next hop based on the previous lookup. If we are not using * lose routing (RFC2543) then just attach hop as a maddr param. */ if (challengedRequest.getRouteHeaders() == null) { Hop hop = ((SIPClientTransaction) challengedTransaction).getNextHop(); SipURI sipUri = (SipURI) reoriginatedRequest.getRequestURI(); sipUri.setMAddrParam(hop.getHost()); if (hop.getPort() != -1) sipUri.setPort(hop.getPort()); } ClientTransaction retryTran = transactionCreator.getNewClientTransaction(reoriginatedRequest); WWWAuthenticateHeader authHeader = null; SipURI requestUri = (SipURI) challengedTransaction.getRequest().getRequestURI(); while (authHeaders.hasNext()) { authHeader = (WWWAuthenticateHeader) authHeaders.next(); String realm = authHeader.getRealm(); AuthorizationHeader authorization = null; String sipDomain; if (this.accountManager instanceof SecureAccountManager) { UserCredentialHash credHash = ((SecureAccountManager) this.accountManager) .getCredentialHash(challengedTransaction, realm); URI uri = reoriginatedRequest.getRequestURI(); sipDomain = credHash.getSipDomain(); authorization = this.getAuthorization( reoriginatedRequest.getMethod(), uri.toString(), (reoriginatedRequest.getContent() == null) ? "" : new String(reoriginatedRequest.getRawContent()), authHeader, credHash); } else { UserCredentials userCreds = ((AccountManager) this.accountManager).getCredentials(challengedTransaction, realm); sipDomain = userCreds.getSipDomain(); if (userCreds == null) throw new SipException("Cannot find user creds for the given user name and realm"); // we haven't yet authenticated this realm since we were // started. authorization = this.getAuthorization( reoriginatedRequest.getMethod(), reoriginatedRequest.getRequestURI().toString(), (reoriginatedRequest.getContent() == null) ? "" : new String(reoriginatedRequest.getRawContent()), authHeader, userCreds); } sipStack .getStackLogger() .logDebug("Created authorization header: " + authorization.toString()); if (cacheTime != 0) cachedCredentials.cacheAuthorizationHeader(sipDomain, authorization, cacheTime); reoriginatedRequest.addHeader(authorization); } if (sipStack.isLoggingEnabled()) { sipStack.getStackLogger().logDebug("Returning authorization transaction." + retryTran); } return retryTran; } catch (SipException ex) { throw ex; } catch (Exception ex) { sipStack.getStackLogger().logError("Unexpected exception ", ex); throw new SipException("Unexpected exception ", ex); } }