/** * Generates the WWW-Authenticate header. * * <p>The header MUST follow this template : * * <pre> * WWW-Authenticate = "WWW-Authenticate" ":" "Digest" * digest-challenge * * digest-challenge = 1#( realm | [ domain ] | nOnce | * [ digest-opaque ] |[ stale ] | [ algorithm ] ) * * realm = "realm" "=" realm-value * realm-value = quoted-string * domain = "domain" "=" <"> 1#URI <"> * nonce = "nonce" "=" nonce-value * nonce-value = quoted-string * opaque = "opaque" "=" quoted-string * stale = "stale" "=" ( "true" | "false" ) * algorithm = "algorithm" "=" ( "MD5" | token ) * </pre> * * @param request HTTP Servlet request * @param response HTTP Servlet response * @param config Login configuration describing how authentication should be performed * @param nOnce nonce token */ protected void setAuthenticateHeader( SipServletRequestImpl request, SipServletResponseImpl response, SipLoginConfig config, String nOnce) { // Get the realm name String realmName = config.getRealmName(); if (realmName == null) realmName = request.getServerName() + ":" + request.getServerPort(); byte[] buffer = null; synchronized (md5Helper) { buffer = md5Helper.digest(nOnce.getBytes()); } String authenticateHeader = "Digest realm=\"" + realmName + "\", " + "qop=\"auth\", nonce=\"" + nOnce + "\", " + "opaque=\"" + md5Encoder.encode(buffer) + "\""; // There are different headers for different types of auth if (response.getStatus() == SipServletResponseImpl.SC_PROXY_AUTHENTICATION_REQUIRED) { response.setHeader("Proxy-Authenticate", authenticateHeader); } else { response.setHeader("WWW-Authenticate", authenticateHeader); } }
/** * @param inviteTransaction * @param inviteRequest */ private static final void send487Response( Transaction inviteTransaction, SipServletRequestImpl inviteRequest) throws IllegalStateException, DispatcherException { SipServletResponseImpl inviteResponse = (SipServletResponseImpl) inviteRequest.createResponse(Response.REQUEST_TERMINATED); inviteRequest.setRoutingState(RoutingState.CANCELLED); // JSR 289 Section 6.2.1.1 Cancel Message Processing : since receiving a CANCEL request causes // the UAS // to respond to an ongoing INVITE transaction with a non-2XX (specifically, 487) response, the // SipSession state // normally becomes TERMINATED as a result of the non-2XX final response sent back to the UAC. // Issue 1484 : http://code.google.com/p/mobicents/issues/detail?id=1484 // we terminate the session only for initial requests if (inviteRequest.isInitial()) { inviteRequest.getSipSession().setState(State.TERMINATED); } try { Response requestTerminatedResponse = (Response) inviteResponse.getMessage(); ((ServerTransaction) inviteTransaction).sendResponse(requestTerminatedResponse); } catch (SipException e) { throw new DispatcherException( Response.SERVER_INTERNAL_ERROR, "Impossible to send the 487 to the INVITE transaction corresponding to CANCEL", e); } catch (InvalidArgumentException e) { throw new DispatcherException( Response.SERVER_INTERNAL_ERROR, "Impossible to send the 487 to the INVITE transaction corresponding to CANCEL", e); } }
/** * Authenticate the user making this request, based on the specified login configuration. Return * <code>true</code> if any specified constraint has been satisfied, or <code>false</code> if we * have created a response challenge already. * * @param request Request we are processing * @param response Response we are creating * @param config Login configuration describing how authentication should be performed * @exception IOException if an input/output error occurs */ public boolean authenticate( SipServletRequestImpl request, SipServletResponseImpl response, SipLoginConfig config) throws IOException { principal = null; // Have we already authenticated someone? principal = request.getUserPrincipal(); // String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (principal != null) { if (log.isDebugEnabled()) log.debug("Already authenticated '" + principal.getName() + "'"); return (true); } // Validate any credentials already included with this request String authorization = request.getHeader("authorization"); if (authorization != null) { principal = findPrincipal(request, authorization, context.getRealm()); if (principal != null) { String username = parseUsername(authorization); register(request, response, principal, Constants.DIGEST_METHOD, username, null); return (true); } } // Send an "unauthorized" response and an appropriate challenge // Next, generate a nOnce token (that is a token which is supposed // to be unique). String nOnce = generateNOnce(request); setAuthenticateHeader(request, response, config, nOnce); response.send(); // hres.flushBuffer(); return (false); }
/** {@inheritDoc} */ public void dispatchMessage( final SipProvider sipProvider, SipServletMessageImpl sipServletMessage) throws DispatcherException { // final SipNetworkInterfaceManager sipNetworkInterfaceManager = // sipApplicationDispatcher.getSipNetworkInterfaceManager(); final SipServletRequestImpl sipServletRequest = (SipServletRequestImpl) sipServletMessage; if (logger.isInfoEnabled()) { logger.info("Routing of Cancel Request " + sipServletRequest); } /* * WARNING: routing of CANCEL is special because CANCEL does not contain Route headers as other requests related * to the dialog. But still it has to be routed through the app path * of the INVITE */ /* If there is a proxy with the request, let's try to send it directly there. * This is needed because of CANCEL which is a subsequent request that might * not have Routes. For example if the callee has'n responded the caller still * doesn't know the route-record and just sends cancel to the outbound proxy. */ // boolean proxyCancel = false; ServerTransaction cancelTransaction = (ServerTransaction) sipServletRequest.getTransaction(); if (cancelTransaction != null && !TransactionState.TERMINATED.equals(cancelTransaction.getState())) { if (logger.isDebugEnabled()) { logger.debug("Sending 200 to Cancel " + sipServletRequest); } try { // First we need to send OK ASAP because of retransmissions both for // proxy or app SipServletResponseImpl cancelResponse = (SipServletResponseImpl) sipServletRequest.createResponse(200, "Canceling"); Response cancelJsipResponse = (Response) cancelResponse.getMessage(); cancelTransaction.sendResponse(cancelJsipResponse); } catch (SipException e) { throw new DispatcherException( Response.SERVER_INTERNAL_ERROR, "Impossible to send the ok to the CANCEL", e); } catch (InvalidArgumentException e) { throw new DispatcherException( Response.SERVER_INTERNAL_ERROR, "Impossible to send the ok to the CANCEL", e); } if (logger.isDebugEnabled()) { logger.debug("checking what to do with the CANCEL " + sipServletRequest); } DispatchTask dispatchTask = new CancelDispatchTask(sipServletRequest, sipProvider); // Execute CANCEL without waiting for previous requests because if we wait for an INVITE to // complete // all responses will be already sent by the time the CANCEL is out of the queue. this.sipApplicationDispatcher.getAsynchronousExecutor().execute(dispatchTask); } else { if (logger.isDebugEnabled()) { logger.debug( "Retransmission received for CANCEL " + sipServletRequest + ", transaction " + cancelTransaction); if (cancelTransaction != null) { logger.debug("Cancel Transaction state " + cancelTransaction.getState()); } } } }