Exemplo n.º 1
0
  /**
   * Performs strict router fix according to RFC3261 section 16.6 step 6
   *
   * <p>pre: top route header in request has no 'lr' parameter in URI post: request-URI added as
   * last route header, new req-URI = top-route-URI
   */
  public void fixStrictRouting(SIPRequest req) {

    RouteList routes = req.getRouteHeaders();
    Route first = (Route) routes.getFirst();
    SipUri firstUri = (SipUri) first.getAddress().getURI();
    routes.removeFirst();

    // Add request-URI as last Route entry
    AddressImpl addr = new AddressImpl();
    addr.setAddess(req.getRequestURI()); // don't clone it
    Route route = new Route(addr);

    routes.add(route); // as last one
    req.setRequestURI(firstUri);
    if (sipStack.isLoggingEnabled()) {
      sipStack.getStackLogger().logDebug("post: fixStrictRouting" + req);
    }
  }
  /*
   * (non-Javadoc)
   *
   * @see gov.nist.javax.sip.clientauthutils.AuthenticationHelper#attachAuthenticationHeaders(javax.sip.message.Request)
   */
  public void setAuthenticationHeaders(Request request) {
    SIPRequest sipRequest = (SIPRequest) request;

    String callId = sipRequest.getCallId().getCallId();

    request.removeHeader(AuthorizationHeader.NAME);
    Collection<AuthorizationHeader> authHeaders =
        this.cachedCredentials.getCachedAuthorizationHeaders(callId);
    if (authHeaders == null) {
      sipStack.getStackLogger().logDebug("Could not find authentication headers for " + callId);
      return;
    }

    for (AuthorizationHeader authHeader : authHeaders) {
      request.addHeader(authHeader);
    }
  }
Exemplo n.º 3
0
  /**
   * Return addresses for default proxy to forward the request to. The list is organized in the
   * following priority. If the requestURI refers directly to a host, the host and port information
   * are extracted from it and made the next hop on the list. If the default route has been
   * specified, then it is used to construct the next element of the list. <code>
   * RouteHeader firstRoute = (RouteHeader) req.getHeader( RouteHeader.NAME );
   * if (firstRoute!=null) {
   *   URI uri = firstRoute.getAddress().getURI();
   *    if (uri.isSIPUri()) {
   *       SipURI nextHop = (SipURI) uri;
   *       if ( nextHop.hasLrParam() ) {
   *           // OK, use it
   *       } else {
   *           nextHop = fixStrictRouting( req );        <--- Here, make the modifications as per RFC3261
   *       }
   *   } else {
   *       // error: non-SIP URI not allowed in Route headers
   *       throw new SipException( "Request has Route header with non-SIP URI" );
   *   }
   * } else if (outboundProxy!=null) {
   *   // use outbound proxy for nextHop
   * } else if ( req.getRequestURI().isSipURI() ) {
   *   // use request URI for nextHop
   * }
   *
   * </code>
   *
   * @param request is the sip request to route.
   */
  public Hop getNextHop(Request request) throws SipException {

    SIPRequest sipRequest = (SIPRequest) request;

    RequestLine requestLine = sipRequest.getRequestLine();
    if (requestLine == null) {
      return defaultRoute;
    }
    javax.sip.address.URI requestURI = requestLine.getUri();
    if (requestURI == null) throw new IllegalArgumentException("Bad message: Null requestURI");

    RouteList routes = sipRequest.getRouteHeaders();

    /*
     * In case the topmost Route header contains no 'lr' parameter (which
     * means the next hop is a strict router), the implementation will
     * perform 'Route Information Postprocessing' as described in RFC3261
     * section 16.6 step 6 (also known as "Route header popping"). That is,
     * the following modifications will be made to the request:
     *
     * The implementation places the Request-URI into the Route header field
     * as the last value.
     *
     * The implementation then places the first Route header field value
     * into the Request-URI and removes that value from the Route header
     * field.
     *
     * Subsequently, the request URI will be used as next hop target
     */

    if (routes != null) {

      // to send the request through a specified hop the application is
      // supposed to prepend the appropriate Route header which.
      Route route = (Route) routes.getFirst();
      URI uri = route.getAddress().getURI();
      if (uri.isSipURI()) {
        SipURI sipUri = (SipURI) uri;
        if (!sipUri.hasLrParam()) {

          fixStrictRouting(sipRequest);
          if (sipStack.isLoggingEnabled())
            sipStack.getStackLogger().logDebug("Route post processing fixed strict routing");
        }

        Hop hop = createHop(sipUri, request);
        if (sipStack.isLoggingEnabled())
          sipStack.getStackLogger().logDebug("NextHop based on Route:" + hop);
        return hop;
      } else {
        throw new SipException("First Route not a SIP URI");
      }

    } else if (requestURI.isSipURI() && ((SipURI) requestURI).getMAddrParam() != null) {
      Hop hop = createHop((SipURI) requestURI, request);
      if (sipStack.isLoggingEnabled())
        sipStack
            .getStackLogger()
            .logDebug("Using request URI maddr to route the request = " + hop.toString());

      // JvB: don't remove it!
      // ((SipURI) requestURI).removeParameter("maddr");

      return hop;

    } else if (defaultRoute != null) {
      if (sipStack.isLoggingEnabled())
        sipStack
            .getStackLogger()
            .logDebug("Using outbound proxy to route the request = " + defaultRoute.toString());
      return defaultRoute;
    } else if (requestURI.isSipURI()) {
      Hop hop = createHop((SipURI) requestURI, request);
      if (hop != null && sipStack.isLoggingEnabled())
        sipStack.getStackLogger().logDebug("Used request-URI for nextHop = " + hop.toString());
      else if (sipStack.isLoggingEnabled()) {
        sipStack.getStackLogger().logDebug("returning null hop -- loop detected");
      }
      return hop;

    } else {
      // The internal router should never be consulted for non-sip URIs.
      InternalErrorHandler.handleException(
          "Unexpected non-sip URI", this.sipStack.getStackLogger());
      return null;
    }
  }
Exemplo n.º 4
0
  /**
   * Send an array of bytes.
   *
   * @param receiverAddress -- inet address
   * @param contactPort -- port to connect to.
   * @param transport -- tcp or udp.
   * @param retry -- retry to connect if the other end closed connection
   * @throws IOException -- if there is an IO exception sending message.
   */
  public Socket sendBytes(
      InetAddress senderAddress,
      InetAddress receiverAddress,
      int contactPort,
      String transport,
      byte[] bytes,
      boolean retry)
      throws IOException {
    int retry_count = 0;
    int max_retry = retry ? 2 : 1;
    // Server uses TCP transport. TCP client sockets are cached
    int length = bytes.length;
    if (sipStack.isLoggingEnabled()) {
      sipStack.logWriter.logDebug(
          "sendBytes "
              + transport
              + " inAddr "
              + receiverAddress.getHostAddress()
              + " port = "
              + contactPort
              + " length = "
              + length);
    }
    if (transport.compareToIgnoreCase(TCP) == 0) {
      String key = makeKey(receiverAddress, contactPort);
      // This should be in a synchronized block ( reported by
      // Jayashenkhar ( lucent ).

      try {
        boolean retval =
            this.ioSemaphore.tryAcquire(
                10000, TimeUnit.MILLISECONDS); // TODO - make this a stack config parameter?
        if (!retval) {
          throw new IOException("Could not acquire IO Semaphore after 10 second -- giving up ");
        }
      } catch (InterruptedException ex) {
        throw new IOException("exception in aquiring sem");
      }
      Socket clientSock = getSocket(key);

      try {

        while (retry_count < max_retry) {
          if (clientSock == null) {
            if (sipStack.isLoggingEnabled()) {
              sipStack.logWriter.logDebug("inaddr = " + receiverAddress);
              sipStack.logWriter.logDebug("port = " + contactPort);
            }
            // note that the IP Address for stack may not be
            // assigned.
            // sender address is the address of the listening point.
            // in version 1.1 all listening points have the same IP
            // address (i.e. that of the stack). In version 1.2
            // the IP address is on a per listening point basis.
            clientSock =
                sipStack
                    .getNetworkLayer()
                    .createSocket(receiverAddress, contactPort, senderAddress);
            OutputStream outputStream = clientSock.getOutputStream();
            writeChunks(outputStream, bytes, length);
            putSocket(key, clientSock);
            break;
          } else {
            try {
              OutputStream outputStream = clientSock.getOutputStream();
              writeChunks(outputStream, bytes, length);
              break;
            } catch (IOException ex) {
              if (sipStack.isLoggingEnabled()) sipStack.logWriter.logException(ex);
              // old connection is bad.
              // remove from our table.
              removeSocket(key);
              try {
                clientSock.close();
              } catch (Exception e) {
              }
              clientSock = null;
              retry_count++;
            }
          }
        }
      } finally {
        ioSemaphore.release();
      }

      if (clientSock == null) {
        throw new IOException("Could not connect to " + receiverAddress + ":" + contactPort);
      } else return clientSock;

      // Added by Daniel J. Martinez Manzano <*****@*****.**>
      // Copied and modified from the former section for TCP
    } else if (transport.compareToIgnoreCase(TLS) == 0) {
      String key = makeKey(receiverAddress, contactPort);
      try {
        boolean retval = this.ioSemaphore.tryAcquire(10000, TimeUnit.MILLISECONDS);
        if (!retval) throw new IOException("Timeout aquiring IO SEM");
      } catch (InterruptedException ex) {
        throw new IOException("exception in aquiring sem");
      }
      Socket clientSock = getSocket(key);
      try {
        while (retry_count < max_retry) {
          if (clientSock == null) {
            if (sipStack.isLoggingEnabled()) {
              sipStack.logWriter.logDebug("inaddr = " + receiverAddress);
              sipStack.logWriter.logDebug("port = " + contactPort);
            }
            if (!sipStack.useTlsAccelerator) {
              clientSock =
                  sipStack
                      .getNetworkLayer()
                      .createSSLSocket(receiverAddress, contactPort, senderAddress);
            } else {
              clientSock =
                  sipStack
                      .getNetworkLayer()
                      .createSocket(receiverAddress, contactPort, senderAddress);
            }
            OutputStream outputStream = clientSock.getOutputStream();
            writeChunks(outputStream, bytes, length);
            putSocket(key, clientSock);
            break;
          } else {
            try {
              OutputStream outputStream = clientSock.getOutputStream();
              writeChunks(outputStream, bytes, length);
              break;
            } catch (IOException ex) {
              if (sipStack.isLoggingEnabled()) sipStack.logWriter.logException(ex);
              // old connection is bad.
              // remove from our table.
              removeSocket(key);
              try {
                clientSock.close();
              } catch (Exception e) {
              }
              clientSock = null;
              retry_count++;
            }
          }
        }
      } finally {
        ioSemaphore.release();
      }
      if (clientSock == null) {
        throw new IOException("Could not connect to " + receiverAddress + ":" + contactPort);
      } else return clientSock;

    } else {
      // This is a UDP transport...
      DatagramSocket datagramSock = sipStack.getNetworkLayer().createDatagramSocket();
      datagramSock.connect(receiverAddress, contactPort);
      DatagramPacket dgPacket = new DatagramPacket(bytes, 0, length, receiverAddress, contactPort);
      datagramSock.send(dgPacket);
      datagramSock.close();
      return null;
    }
  }
  /**
   * 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;
  }
  /*
   * (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);
    }
  }