/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * https://opensso.dev.java.net/public/CDDLv1.0.html or * opensso/legal/CDDLv1.0.txt * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at opensso/legal/CDDLv1.0.txt. * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * $Id: InteractionManager.java,v 1.5 2008/08/06 17:28:10 exu Exp $ * * Portions Copyrighted 2016 ForgeRock AS. */ package com.sun.identity.liberty.ws.interaction; import static org.forgerock.openam.utils.Time.*; import com.sun.identity.common.PeriodicCleanUpMap; import com.sun.identity.common.SystemTimerPool; import com.sun.identity.common.TaskRunnable; import com.sun.identity.common.TimerPool; import com.sun.identity.shared.debug.Debug; import com.sun.identity.shared.encode.URLEncDec; import com.sun.identity.liberty.ws.common.LogUtil; import com.sun.identity.liberty.ws.interaction.jaxb.InquiryElement; import com.sun.identity.liberty.ws.interaction.jaxb.InteractionResponseElement; import com.sun.identity.liberty.ws.interaction.jaxb.RedirectRequestElement; import com.sun.identity.liberty.ws.interaction.jaxb.StatusElement; import com.sun.identity.liberty.ws.interaction.jaxb.UserInteractionElement; import com.sun.identity.liberty.ws.soapbinding.Client; import com.sun.identity.liberty.ws.soapbinding.CorrelationHeader; import com.sun.identity.liberty.ws.soapbinding.Message; import com.sun.identity.liberty.ws.soapbinding.SOAPBindingConstants; import com.sun.identity.liberty.ws.soapbinding.SOAPBindingException; import com.sun.identity.liberty.ws.soapbinding.SOAPFault; import com.sun.identity.liberty.ws.soapbinding.SOAPFaultDetail; import com.sun.identity.liberty.ws.soapbinding.SOAPFaultException; import com.sun.identity.liberty.ws.soapbinding.Utils; import com.sun.identity.saml.common.SAMLUtils; import java.io.IOException; import java.math.BigInteger; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.UnknownHostException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.ConcurrentModificationException; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.logging.Level; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.bind.JAXBException; import javax.xml.namespace.QName; import org.w3c.dom.Element; /** * This class provides the interface and implementation for supporting * resource owner interaction. WSC and WSP would * collaborate with the singleton object instance of this class to provide * and use resource owner interaction. * @supported.api */ public class InteractionManager { /** * * Name of URL query parameter to be used by WSC to include * returnToURL, while redirecting user agent to * WSP. * * @supported.all.api */ public static final String RETURN_TO_URL = "ReturnToURL"; /** * Name of suggested URL query parameter to be used by WSC * to include an ID to refer to request message that led to user agent * redirect. * * @supported.api */ public static final String REQUEST_ID = "RequestID"; /** * Name of URL query parameter to be used by WSC to include * providerID of IDP, that was used to * authenticate user. * * @supported.api */ public static final String IDP = "IDP"; /** * Name of URL query parameter to be used by WSP to include * an ID to indicate that user agent is redirected back to * WSC from WSP * * @supported.api */ public static final String RESEND_MESSAGE = "ResendMessage"; /** * Name space URI of interaction service * @supported.api */ public static final String INTERACTION_NAMESPACE = "urn:liberty:is:2003-08"; /** * QName for s:Server * s - soap name space prefix */ public static final QName QNAME_SERVER = new QName(SOAPBindingConstants.NS_SOAP, "Server"); /** * QName for is:interactIfNeeded * is - name space prefix for interaction service */ public static final QName QNAME_INTERACT_IF_NEEDED = new QName(INTERACTION_NAMESPACE, "interactIfNeeded", "is"); /** * QName for is:doNotInteract * is - name space prefix for interaction service */ public static final QName QNAME_DO_NOT_INTERACT = new QName(INTERACTION_NAMESPACE, "doNotInteract", "is"); /** * QName for is:doNotInteractForData * is - name space prefix for interaction service */ public static final QName QNAME_DO_NOT_INTERACT_FOR_DATA = new QName(INTERACTION_NAMESPACE, "doNotInteractForData", "is"); /** * QName for is:interactionRequired * is - name space prefix for interaction service */ public static final QName QNAME_INTERACTION_REQUIRED = new QName(INTERACTION_NAMESPACE, "interactionRequired"); /** * QName for is:forData * is - name space prefix for interaction service */ public static final QName QNAME_INTERACTION_REQUIRED_FOR_DATA = new QName(INTERACTION_NAMESPACE, "forData"); /** * QName for is:timeNotSufficient * is - name space prefix for interaction service */ public static final QName QNAME_INTERACTION_TIME_NOT_SUFFICEINT = new QName(INTERACTION_NAMESPACE, "timeNotSufficient"); /** * QName for is:timeOut * is - name space prefix for interaction service */ public static final QName QNAME_INTERACTION_TIMED_OUT = new QName(INTERACTION_NAMESPACE, "timeOut"); /** * QName for is:interactIfNeeded * is - name space prefix for interaction service */ public static final QName QNAME_INTERACTION_CAN_NOT_DETERMINE_REQUEST_HOST = new QName(INTERACTION_NAMESPACE, "canNotDetermineRequestHostName"); /** * Constant string to indicate generic server error */ public static final String SERVER_ERROR = "Server Error"; static final String TRANS_ID = "TransID"; private static InteractionManager interactionManager = null; private static Debug debug = Debug.getInstance("libIDWSF"); private static final String REDIRECT_URL = "redirectURL"; private static final String FAULT_ACTOR = "http://schemas.xmlsoap.org/soap/actor/next"; private static final String INTERACTION_RB_NAME = "libInteraction"; private InteractionCache cache = new InteractionCache(); private com.sun.identity.liberty.ws.interaction.jaxb.ObjectFactory objectFactory; private InteractionConfig interactionConfig; /** * Gets singleton object instance of InteractionManager * @return singleton object instance of InteractionManager * * @supported.api */ synchronized public static InteractionManager getInstance() { if (interactionManager == null) { interactionManager = new InteractionManager(); } return interactionManager; } private InteractionManager() { objectFactory = JAXBObjectFactory.getObjectFactory(); interactionConfig = InteractionConfig.getInstance(); if (debug.messageEnabled()) { debug.message( "InteractionManager():constructed singleton instance"); } } /** * Sends SOAP request to WSP. * This would be invoked at WSC side. * * @param requestMessage request message. * @param connectTo SOAP URL to which to send the SOAP request * @param certAlias SOAP Client Certificate Alias * @param soapAction SOAP Action Attribute * @param returnToURL URL to which to redirect user agent after * WSP - resource owner interactions * @param httpRequest HTTP request object of current user agent request * @param httpResponse HTTP response object of current user agent request * @return response SOAP response message sent by WSP. * * @throws InteractionException for generic interaction error * @throws InteractionRedirectException if user agent is redirected to * WSP for resource owner interactions * @throws SOAPBindingException for generic SOAP binding errors * @throws SOAPFaultException if the response message has SOAP fault * * @supported.api */ public Message sendRequest(Message requestMessage, String connectTo, String certAlias, String soapAction, String returnToURL, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws InteractionException, InteractionRedirectException, SOAPBindingException, SOAPFaultException { if (debug.messageEnabled()) { debug.message("InteractionManager.sendRequest():" + " entering with messageID=" + requestMessage.getCorrelationHeader().getMessageID() + ":refToMessageID=" + requestMessage.getCorrelationHeader().getRefToMessageID() + ":requestMessage=" + requestMessage); } // construct and set UserInteraction element in requestMessage if (interactionConfig.wscIncludesUserInteractionHeader()) { Enumeration locales = httpRequest.getLocales(); List acceptLanguages = new ArrayList(); while (locales.hasMoreElements()) { acceptLanguages.add(locales.nextElement().toString()); } if (debug.messageEnabled()) { debug.message("InteractionManager.sendRequest():" + "Accept-Language specified by httpRequest=" + acceptLanguages); } UserInteractionElement ue = createUserInteractionElement( acceptLanguages); String id = SAMLUtils.generateID(); ue.setId(id); if (ue != null) { try { Element element = Utils.convertJAXBToElement(ue); requestMessage.setOtherSOAPHeader( element, id); } catch (JAXBException je) { debug.error("InteractionManager.sendRequest():" + "not setting userInteractionHeader:" + "can not convert JAXBObject to Element", je); } } } Message responseMessage = null; try { if (debug.messageEnabled()) { debug.message("InteractionManager.sendRequest():" + "invoking soap Client.sendRequest():" + ":requestMessage=" + requestMessage + ":connecTo=" + connectTo); } if (LogUtil.isLogEnabled()) { String[] objs =new String[1]; objs[0] = requestMessage.getCorrelationHeader() .getMessageID(); LogUtil.access(Level.INFO, LogUtil.IS_SENDING_MESSAGE,objs); } responseMessage = Client.sendRequest(requestMessage, connectTo, certAlias, soapAction); } catch (SOAPFaultException sfe) { if (debug.messageEnabled()) { debug.message("InteractionManager.sendRequest():" + " catching SOAPFaultException=" + sfe); } String redirectURL = getRedirectURL(sfe); if(redirectURL == null) { throw sfe; } String responseID = getResponseID(sfe); responseMessage = handleRedirectRequest(requestMessage, redirectURL, responseID, connectTo, certAlias, soapAction, returnToURL, httpRequest, httpResponse); } if (debug.messageEnabled()) { debug.message("InteractionManager.sendRequest():" + " returning response message=" + responseMessage); } if (LogUtil.isLogEnabled()) { String[] objs = new String[2]; objs[0] = responseMessage.getCorrelationHeader().getMessageID(); objs[1] = requestMessage.getCorrelationHeader().getMessageID(); LogUtil.access(Level.INFO,LogUtil.IS_RETURNING_RESPONSE_MESSAGE, objs); } return responseMessage; } /** * Resends a previously cached SOAP request message to WSP. * This would be invoked at WSC side. Message ID for the cached * message should be provided as value of REQUEST_ID query * parameter in httpRequest. * * @param returnToURL URL to which to redirect user agent after * WSP - resource owner interactions * @param httpRequest HTTP request object of current user agent request * @param httpResponse HTTP response object of current user agent request * @return response SOAP message sent by WSP. * * @throws InteractionException for generic interaction error * @throws InteractionRedirectException if user agent is redirected to * WSP for resource owner interactions * @throws SOAPBindingException if there are generic SOAP errors * @throws SOAPFaultException if the response message has SOAP fault * * @see #REQUEST_ID * * @supported.api */ public Message resendRequest(String returnToURL, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws InteractionRedirectException, InteractionException, SOAPBindingException, SOAPFaultException { return resendRequest(returnToURL, httpRequest, httpResponse, null); } /** * Resends a SOAP request message to WSP. * This would be invoked at WSC side. * * @param returnToURL URL to which to redirect user agent after * WSP - resource owner interactions * @param httpRequest HTTP request object of current user agent request * @param httpResponse HTTP response object of current user agent request * @param requestMessage SOAP message to be resent. * @return response SOAP message sent by WSP. * * @throws InteractionException for generic interaction error * @throws InteractionRedirectException if user agent is redirected to * WSP for resource owner interactions * @throws SOAPBindingException for generic SOAP errors * @throws SOAPFaultException if the response message has SOAP fault * * @supported.api */ public Message resendRequest(String returnToURL, HttpServletRequest httpRequest, HttpServletResponse httpResponse, Message requestMessage) throws InteractionRedirectException, InteractionException, SOAPBindingException, SOAPFaultException { if (debug.messageEnabled()) { debug.message("InteractionManager.resendRequest():entering "); } //check for RESEND_MESSAGE parameter String messageID = httpRequest.getParameter(RESEND_MESSAGE); if (messageID == null) { debug.error("InteractionManager.resend():" + " request without " + RESEND_MESSAGE + " in requestURL=" + httpRequest.getRequestURL().toString()); String objs[] = {RESEND_MESSAGE}; throw new InteractionException(INTERACTION_RB_NAME, "missing_query_parameter", objs); } //check whether WSP advised not to resend if ( (messageID == "0") || (messageID.equals("false")) ) { debug.error("InteractionManager.resend():" + " resend not allowed in requestURL=" + httpRequest.getRequestURL().toString()); throw new InteractionException(INTERACTION_RB_NAME, "wsp_advised_not_to_resend", null); } //check for original REQUEST_ID messageID = httpRequest.getParameter(REQUEST_ID); if (messageID == null) { debug.error("InteractionManager.resend():" + " request without " + REQUEST_ID + " in requestURL=" + httpRequest.getRequestURL().toString()); String[] objs = {REQUEST_ID}; throw new InteractionException(INTERACTION_RB_NAME, "request_missing_query_parameter", objs); } String connectTo = getConnectTo(messageID); if (connectTo == null) { debug.error("InteractionManager.resend():" + " old connectTo not found for messageID=" + messageID); throw new InteractionException(INTERACTION_RB_NAME, "old_connectTo_not_found", null); } if (requestMessage == null) { if (debug.messageEnabled()) { debug.message("InteractionManager.resendRequest():" + "invoking with null requestMessage:" + "old cached message would be used"); } Message oldMessage = getRequestMessage(messageID); if (oldMessage == null) { debug.error("InteractionManager.resend():" + " old message not found for messageID=" + messageID); throw new InteractionException(INTERACTION_RB_NAME, "old_message_not_found", null); } requestMessage = oldMessage; } else { if (debug.messageEnabled()) { debug.message("InteractionManager.resendRequest():" + "invoking with non null requestMessage"); } } CorrelationHeader ch = new CorrelationHeader(); ch.setRefToMessageID(InteractionManager.getInstance() .getRequestMessageID(messageID)); requestMessage.setCorrelationHeader(ch); if (debug.messageEnabled()) { debug.message("InteractionManager.resendRequest():" + "invoking InteractionManager.sendRequest():" + "with requestMessage=" + requestMessage + ":returnToURL=" + returnToURL); } if (LogUtil.isLogEnabled()) { String[] objs =new String[2]; objs[0] = messageID; objs[1] = ch.getMessageID(); LogUtil.access(Level.INFO,LogUtil.IS_RESENDING_MESSAGE,objs); } Message responseMessage = sendRequest(requestMessage, connectTo, getClientCert(messageID), getSoapAction(messageID), returnToURL, httpRequest, httpResponse); if (debug.messageEnabled()) { debug.message("InteractionManager.resendRequest():" + " returning responseMessage=" + responseMessage); } return responseMessage; } private Message handleRedirectRequest(Message requestMessage, String redirectURL, String messageID, String connectTo, String certAlias, String soapAction, String returnToURL, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws InteractionRedirectException, InteractionException { if (debug.messageEnabled()) { debug.message("InteractionManager.handleRedirectRequest():" + "entering with redirectURL=" + redirectURL); } //redirectURL should not have ReturnToURL parameter if (!(redirectURL.indexOf(RETURN_TO_URL + "=") == -1)) { debug.error( "InteractionManager.handleRedirectRequest():" + "Invalid redirectURL - illegal parameter " + RETURN_TO_URL + " in redirectURL=" + redirectURL); String objs[] = {RETURN_TO_URL, REDIRECT_URL}; throw new InteractionException(INTERACTION_RB_NAME, "illegal_parameter_in_redirectURL", objs); } //redirectURL should not have IDP parameter if (!(redirectURL.indexOf(IDP + "=") == -1)) { debug.error( "InteractionManager.handleRedirectRequest():" + "Invalid redirectURL - illegal parameter:" + IDP + " in redirectURL=" + redirectURL); String objs[] = {IDP, REDIRECT_URL}; throw new InteractionException(INTERACTION_RB_NAME, "illegal_parameter_in_redirectURL", objs); } //redirectURL should be https if (InteractionConfig.getInstance().wscEnforcesHttpsCheck() && (redirectURL.indexOf("https") != 0) ) { debug.error( "InteractionManager.handleRedirectRequest():" + "Invalid Request " + InteractionManager.REDIRECT_URL + " not https" + " in redirectURL=" + redirectURL); throw new InteractionException(INTERACTION_RB_NAME, "redirectURL_not_https", null); } //redirectURL should point to connectTo host if (InteractionConfig.getInstance() .wspEnforcesReturnToHostEqualsRequestHost() && !checkRedirectHost(redirectURL, connectTo)) { debug.error( "InteractionManager.handleRedirectRequest():" + "Invalid Request redirectToHost differs from " + " connectToHost:" + " in redirectURL=" + redirectURL + ":connectTo=" + connectTo); throw new InteractionException(INTERACTION_RB_NAME, "redirectURL_differs_from_connectTo", null); } String requestID = requestMessage.getCorrelationHeader().getMessageID(); setRequestMessage(requestID, requestMessage); setConnectTo(requestID, connectTo); setSoapAction(requestID, soapAction); setClientCert(requestID, certAlias); setRequestMessageID(requestID, messageID); if (debug.messageEnabled()) { debug.message("InteractionManager.handleRedirectRequest():cached " + " request message for messageID=" + messageID + ":requestID=" + requestID + ":requestMessage:" + (requestMessage == null) ); } returnToURL = returnToURL + "?" + REQUEST_ID + "=" + requestID; redirectURL = redirectURL +"&"+ RETURN_TO_URL + "=" + URLEncDec.encode(returnToURL); if (debug.messageEnabled()) { debug.message("InteractionManager.handleRedirectRequest():" + "redirecting user agent to redirectURL= " + redirectURL); } try { httpResponse.sendRedirect(redirectURL); } catch (IOException ioe) { //IOException debug.error("InteractionManager.handleRedirectRequest():" + " catching IOException", ioe); throw new InteractionException(INTERACTION_RB_NAME, "IOException_in_Interaction_Manager", null); } if (debug.messageEnabled()) { debug.message("InteractionManager.handleRedirectRequest():" + "redirected user agent to redirectURL= " + redirectURL); } if (LogUtil.isLogEnabled()) { String[] objs =new String[1]; objs[0] = requestID; LogUtil.access(Level.INFO,LogUtil.IS_REDIRECTED_USER_AGENT,objs); } throw new InteractionRedirectException(requestID); //return returnMessage; } /** * Handles resource owner interactions on behalf of WSP. * This is invoked at WSP side. * * @param requestMessage SOAP request that requires resource * owner interactions * @param inquiryElement query that WSP wants to pose to * resource owner. * @return SOAP message that contains InteractionResponse, * gathered by InteractionManager * * @throws InteractionException for generic interaction error * @throws InteractionSOAPFaultException if a SOAP fault * has to be returned to WSC * @throws SOAPFaultException if the response message has SOAP fault * * @deprecated * */ public Message handleInteraction(Message requestMessage, InquiryElement inquiryElement) throws InteractionException, InteractionSOAPFaultException, SOAPFaultException { return handleInteraction(requestMessage, inquiryElement, null); } /** * Handles resource owner interactions on behalf of WSP. * This is invoked at WSP side. * * @param requestMessage SOAP request that requires resource * owner interactions * @param inquiryElement query that WSP wants to pose to * resource owner * @param language language in which the query page needs to be rendered * @return SOAP message that contains InteractionResponse, * gathered by InteractionManager * * @throws InteractionException for generic interaction error * @throws InteractionSOAPFaultException if a SOAP fault * has to be returned to WSC * @throws SOAPFaultException if the response message has SOAP fault * * @supported.api */ public Message handleInteraction(Message requestMessage, InquiryElement inquiryElement, String language) throws InteractionException, InteractionSOAPFaultException, SOAPFaultException { if (debug.messageEnabled()) { debug.message("InteractionManager.handleInteraction():entering"); } //Check redirect is enabled for WSP if (!interactionConfig.wspSupportsRedirect()) { if (debug.warningEnabled()) { debug.warning("InteractionManager.handleInteraction():" + " WSP requests for interaction:wspWillRedirect=" + interactionConfig.wspSupportsRedirect()); debug.warning("InteractionManager.handleInteraction():" + "throwing InteractionException"); } throw new InteractionException(INTERACTION_RB_NAME, "wsp_does_not_support_interaction", null); } //Check wsc provided UserInteraction header UserInteractionElement ue = getUserInteractionElement(requestMessage); if (ue == null) { SOAPFaultException sfe = newRedirectFaultError( QNAME_INTERACTION_REQUIRED); if (debug.warningEnabled()) { debug.warning("InteractionManager.handleInteraction():" + " WSP requests for interaction - WSC did not " + " provide UserInteractionHeader"); debug.warning("InteractionManager.handleInteraction():" + "throwing InteractionSOAPFaultException=" + sfe); } throw new InteractionSOAPFaultException(sfe); } //Check WSC is willing to redirect if (ue.isRedirect() == false) { SOAPFaultException sfe = newRedirectFaultError( QNAME_INTERACTION_REQUIRED); if (debug.warningEnabled()) { debug.warning("InteractionManager.handleInteraction():" + "WSP rquests for interaction - WSC " + " says redirect=false"); debug.warning("InteractionManager.handleInteraction():" + "throwing InteractionSOAPFaultException=" + sfe); } throw new InteractionSOAPFaultException(sfe); } //Check WSC allowed interaction if (ue.getInteract().equals(QNAME_DO_NOT_INTERACT)) { SOAPFaultException sfe = newRedirectFaultError( QNAME_INTERACTION_REQUIRED); if (debug.warningEnabled()) { debug.warning("InteractionManager.handleInteraction():" + "WSP rquests for interaction - WSC " + " UserInteractionHeader says doNotInteract"); debug.warning("InteractionManager.handleInteraction():" + "throwing InteractionSOAPFaultException=" + sfe); } throw new InteractionSOAPFaultException(sfe); } //Check WSC allowed interaction for data if (interactionConfig.wspRedirectsForData() && ue.getInteract().equals( QNAME_DO_NOT_INTERACT_FOR_DATA)) { SOAPFaultException sfe = newRedirectFaultError( QNAME_INTERACTION_REQUIRED_FOR_DATA); if (debug.warningEnabled()) { debug.warning("InteractionManager.handleInteraction():" + "WSP rquests interaction for data - WSC " + " UserInteractionHeader says doNotInteractForData"); debug.warning("InteractionManager.handleInteraction():" + "throwing InteractionSOAPFaultException=" + sfe); } throw new InteractionSOAPFaultException(sfe); } //Check WSP will not exceed maxInteractionTime specified by WSC BigInteger uemi = ue.getMaxInteractTime(); if ( (uemi != null) && (interactionConfig.getWSPRedirectTime() > uemi.intValue()) ) { SOAPFaultException sfe = newRedirectFaultError( QNAME_INTERACTION_TIME_NOT_SUFFICEINT); if (debug.warningEnabled()) { debug.warning("InteractionManager.handleInteraction():" + "WSP inteaction time =" + interactionConfig.getWSPRedirectTime() + " exceeds WSC maxInteractTime= " + ue.getMaxInteractTime()); debug.warning("InteractionManager.handleInteraction():" + "throwing InteractionSOAPFaultException=" + sfe); } throw new InteractionSOAPFaultException(sfe); } String requestMessageID = requestMessage.getCorrelationHeader().getMessageID(); SOAPFaultException sfe = newRedirectFault(requestMessageID); String redirectResponseID = getResponseID(sfe); String requestIP = requestMessage.getIPAddress(); String requestHost = null; if (interactionConfig.wspEnforcesReturnToHostEqualsRequestHost()) { try { InetAddress inetAddress = InetAddress.getByName(requestIP); //requestHost = inetAddress.getCanonicalHostName(); requestHost = inetAddress.getHostName(); if (debug.messageEnabled()) { debug.message("InteractionManager.handleInteraction():" + " caching requestHost=" + requestHost + ", for redirectResponseID= " + redirectResponseID); } setRequestHost(redirectResponseID, requestHost); } catch (UnknownHostException uhe) { debug.error("InteractionManager.handleInteraction():" + " can not resolve host name", uhe); debug.error("InteractionManager.handleInteraction():" + " throwing InteractionSOAPFaultException", sfe); SOAPFaultException sfe1 = newRedirectFaultError( QNAME_INTERACTION_CAN_NOT_DETERMINE_REQUEST_HOST); throw new InteractionSOAPFaultException(sfe1); } } setInquiryElement(redirectResponseID, inquiryElement); setRequestMessageID(redirectResponseID, requestMessageID); setLanguage(redirectResponseID, language); if (debug.messageEnabled()) { debug.message("InteractionManager.handleInteraction():" + " throwing InteractionSOAPFaultException " + " to redirect user agent=" + sfe); } throw new InteractionSOAPFaultException(sfe); //return responseMessage; } private void setInquiryElement(String messageID, InquiryElement inquiryElement) { CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry == null) { cacheEntry = new CacheEntry(messageID); cache.putCacheEntry(messageID, cacheEntry); } cacheEntry.setInquiryElement(inquiryElement); } InquiryElement getInquiryElement(String messageID) { InquiryElement inquiryElement = null; CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry != null) { inquiryElement = cacheEntry.getInquiryElement(); } return inquiryElement; } void setInteractionResponseElement(String messageID, InteractionResponseElement interactionResponse) { CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry == null) { cacheEntry = new CacheEntry(messageID); cache.putCacheEntry(messageID, cacheEntry); } cacheEntry.setInteractionResponseElement(interactionResponse); } /** * Gets interaction response that was gathered from resource owner * by InteractionManager * * @param requestMessage request message. * * @return interaction response that was gathered by * InteractionManager. * * @throws InteractionException for interaction error * * @supported.api */ public InteractionResponseElement getInteractionResponseElement( Message requestMessage) throws InteractionException { InteractionResponseElement interactionResponseElement = null; CorrelationHeader ch = requestMessage.getCorrelationHeader(); String messageID = ch.getRefToMessageID(); CacheEntry cacheEntry = null; if (messageID != null) { cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry != null) { interactionResponseElement = cacheEntry.getInteractionResponseElement(); } if (debug.messageEnabled()) { debug.message("InteractionManager.getInteractionResponseElement():" + "for messageID=" + messageID + ":" + "responseElement=" + (interactionResponseElement != null)); } } if (LogUtil.isLogEnabled()) { String[] objs =new String[3]; objs[0] = ch.getMessageID(); objs[1] = ch.getRefToMessageID(); objs[2] = (cacheEntry == null) ? "NULL" : "NOT NULL"; LogUtil.access(Level.INFO,LogUtil.IS_RETURNING_RESPONSE_ELEMENT, objs); } return interactionResponseElement; } private void setRequestMessage(String messageID, Message requestMessage) { CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry == null) { cacheEntry = new CacheEntry(messageID); cache.putCacheEntry(messageID, cacheEntry); } cacheEntry.setRequestMessage(requestMessage); if (debug.messageEnabled()) { debug.message("InteractionManager.setRequestMessage():" + " cached request message for messageID=" + messageID + ":requestMessage:" + (requestMessage == null) ); } } private Message getRequestMessage(String messageID) { Message requestMessage = null; CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry != null) { requestMessage = cacheEntry.getRequestMessage(); } if (debug.messageEnabled()) { debug.message("InteractionManager.getRequestMessage():" + " looking up request message for messageID=" + messageID + ":requestMessage=" + (requestMessage == null) ); } return requestMessage; } private void setRequestMessageID(String messageID, String requestMessageID) { CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry == null) { cacheEntry = new CacheEntry(messageID); cache.putCacheEntry(messageID, cacheEntry); } cacheEntry.setRequestMessageID(requestMessageID); } String getRequestMessageID(String messageID) { String requestMessageID = null; CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry != null) { requestMessageID = cacheEntry.getRequestMessageID(); } return requestMessageID; } void setReturnToURL(String messageID, String returnToURL) { CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry == null) { cacheEntry = new CacheEntry(messageID); cache.putCacheEntry(messageID, cacheEntry); } cacheEntry.setReturnToURL(returnToURL); } String getReturnToURL(String messageID) { String returnToURL = null; CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry != null) { returnToURL = cacheEntry.getReturnToURL(); } return returnToURL; } void setRequestHost(String messageID, String requestHost) { CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry == null) { cacheEntry = new CacheEntry(messageID); cache.putCacheEntry(messageID, cacheEntry); } cacheEntry.setRequestHost(requestHost); } String getRequestHost(String messageID) { String requestHost = null; CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry != null) { requestHost = cacheEntry.getRequestHost(); } return requestHost; } private void setConnectTo(String messageID, String ConnectTo) { CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry == null) { cacheEntry = new CacheEntry(messageID); cache.putCacheEntry(messageID, cacheEntry); } cacheEntry.setConnectTo(ConnectTo); } private void setSoapAction(String messageID, String soapAction) { CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry == null) { cacheEntry = new CacheEntry(messageID); cache.putCacheEntry(messageID, cacheEntry); } cacheEntry.setSoapAction(soapAction); } private void setClientCert(String messageID, String certAlias) { CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry == null) { cacheEntry = new CacheEntry(messageID); cache.putCacheEntry(messageID, cacheEntry); } cacheEntry.setClientCert(certAlias); } private String getConnectTo(String messageID) { String connectTo = null; CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry != null) { connectTo = cacheEntry.getConnectTo(); } return connectTo; } private String getClientCert(String messageID) { String clientCert = null; CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry != null) { clientCert = cacheEntry.getClientCert(); } return clientCert; } private String getSoapAction(String messageID) { String soapAction = null; CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry != null) { soapAction = cacheEntry.getSoapAction(); } return soapAction; } private void setLanguage(String messageID, String language) { CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry == null) { cacheEntry = new CacheEntry(messageID); cache.putCacheEntry(messageID, cacheEntry); } cacheEntry.setLanguage(language); } String getLanguage(String messageID) { String language = null; CacheEntry cacheEntry = cache.getCacheEntry(messageID); if ( cacheEntry != null) { language = cacheEntry.getLanguage(); } return language; } private UserInteractionElement createUserInteractionElement( List acceptLanguages) { UserInteractionElement ue = null; try { ue =objectFactory.createUserInteractionElement(); ue.setInteract(interactionConfig .getWSCSpecifiedInteractionChoice()); ue.setRedirect(interactionConfig.wscSupportsRedirect()); ue.setMaxInteractTime( java.math.BigInteger.valueOf(interactionConfig .getWSCSpecifiedMaxInteractionTime())); ue.getLanguage().addAll(acceptLanguages); } catch (JAXBException je) { debug.error("InteractionManager.createUserInteractionElement():" + " can not create UserInteractionElement", je); } return ue; } static UserInteractionElement getUserInteractionElement( Message message) { UserInteractionElement ue = null; List list = message.getOtherSOAPHeaders(); try { list = Utils.convertElementToJAXB(list); } catch (JAXBException je) { debug.error("InteractionManager.getUserInteractionElement():" + "not able to get userInteractionElement:" + "can not convert Element to JAXBObject", je); return null; } Iterator iter = list.iterator(); while (iter.hasNext()) { Object obj = (Object)iter.next(); if (obj instanceof UserInteractionElement) { ue = (UserInteractionElement)obj; break; } } return ue; } private SOAPFaultException newRedirectFault(String messageID) { RedirectRequestElement re = null; try{ re = objectFactory.createRedirectRequestElement(); } catch (JAXBException je) { debug.error("InteractionManager.newRedirectFault():" + " can not create RedirectRequestElement", je); } CorrelationHeader ch = new CorrelationHeader(); String responseID = ch.getMessageID(); ch.setRefToMessageID(messageID); String redirectUrl = null; String lbRedirectUrl = interactionConfig.getLbWSPRedirectHandler(); String wspRedirectUrl = interactionConfig.getWSPRedirectHandler(); if(debug.messageEnabled()) { debug.message("InteractionManager.newRedirectURLFault():" + "wspRedirectURL:" + wspRedirectUrl + ", lbRedirectUrl:" + lbRedirectUrl); } if (lbRedirectUrl == null) { redirectUrl = wspRedirectUrl + "?" + TRANS_ID + "=" + responseID; if(debug.messageEnabled()) { debug.message("InteractionManager.newRedirectURLFault():" + "lbRedirectURL is null, rediectUrl:" + redirectUrl); } } else { //lbRedirectUrl defined redirectUrl = lbRedirectUrl + "?" + TRANS_ID + "=" + responseID + "&" + InteractionConfig.HANDLER_HOST_ID + "=" + InteractionConfig.getInstance().getLocalServerId(); if(debug.messageEnabled()) { debug.message("InteractionManager.newRedirectURLFault():" + "lbRedirectURL is not null, rediectUrl:" + redirectUrl); } } re.setRedirectURL(redirectUrl); List details = new ArrayList(); try { details.add(Utils.convertJAXBToElement(re)); } catch (JAXBException je) { debug.error("InteractionManager.newRedirectFault():" + " can not create newRedirectFault:" + " can not convert JAXBObject to Element", je); } SOAPFault sf = new SOAPFault( QNAME_SERVER, SERVER_ERROR, FAULT_ACTOR, new SOAPFaultDetail(details)); Message sfmsg = new Message(sf); sfmsg.setCorrelationHeader(ch); SOAPFaultException sfe = new SOAPFaultException(sfmsg); return sfe; } private SOAPFaultException newRedirectFaultError(QName errorCode) { StatusElement se = null; try{ se = objectFactory.createStatusElement(); } catch (JAXBException je) { debug.error("InteractionManager.newRedirectFaultError():" + " can not create StatusElement", je); } se.setCode(errorCode); List details = new ArrayList(); try { details.add(Utils.convertJAXBToElement(se)); } catch (JAXBException je) { debug.error("InteractionManager.newRedirectFaultError():" + "can not create new RedirectFaultError:" + "can not convert JAXBObject to Element", je); } SOAPFault sf = new SOAPFault( QNAME_SERVER, SERVER_ERROR, FAULT_ACTOR, new SOAPFaultDetail(details)); SOAPFaultException sfe = new SOAPFaultException(new Message(sf)); return sfe; } String getRedirectURL(SOAPFaultException sfe) throws SOAPFaultException { String redirectURL = null; List details = null; SOAPFaultDetail sfd = sfe.getSOAPFaultMessage().getSOAPFault().getDetail(); if (sfd != null) { details = sfd.getOtherChildren(); } try { details = Utils.convertElementToJAXB(details); } catch (JAXBException je) { debug.error("InteractionManager.getRedirectURL():" + " can not get Redirect URL", je); } if ( (details != null) && (details.size() > 0) && (details.get(0) instanceof RedirectRequestElement)) { RedirectRequestElement rre = (RedirectRequestElement)details.get(0); if (rre != null) { redirectURL = rre.getRedirectURL(); } } if (redirectURL == null) { throw sfe; } return redirectURL; } private boolean checkRedirectHost(String redirectURL, String connectTo) { boolean answer = false; try { URL redirectToURL = new URL(redirectURL); URL connectToURL = new URL(connectTo); String redirectHost = redirectToURL.getHost(); String connectToHost = connectToURL.getHost(); if (redirectHost.equals(connectToHost)) { answer = true; } } catch (MalformedURLException mfe) { debug.error("InteractionManager.checkRedirectHost():" + "redirectURL not a valid URL" + " :redirectURL=" + redirectURL + " :connectTo=" + connectTo, mfe); } return answer; } String getResponseID(SOAPFaultException sfe) throws SOAPFaultException{ String responseID = null; CorrelationHeader ch = sfe.getSOAPFaultMessage().getCorrelationHeader(); if (ch == null) { debug.error("InteractionManager.getResponseID():" + "null CorrelationHeader in SOAPFaultException"); throw sfe; } responseID = ch.getMessageID(); if (responseID == null) { debug.error("InteractionManager.getResponseID():" + "null messageID in SOAPFaultException"); throw sfe; } return responseID; } static class InteractionCache { private static final boolean VERBOSE_MESSAGE = false; private static final int SWEEP_INTERVAL = 60 * 1000; private static final int CACHE_ENTRY_MAX_IDLE_TIME = 120 * 1000; PeriodicCleanUpMap cache = new PeriodicCleanUpMap(SWEEP_INTERVAL, CACHE_ENTRY_MAX_IDLE_TIME); InteractionCache() { if (debug.messageEnabled()) { debug.message("InteactionCache.InteractionCache() " + " - entering constructor"); } if (debug.messageEnabled()) { debug.message("InteactionCache.InteractionCache() " + " - starting sweeper thread"); debug.message("InteractionCache.InteractionCache() " + " SWEEP_INTERVAL = " + SWEEP_INTERVAL); debug.message("InteractionCache.InteractionCache() " + " CACHE_ENTRY_MAX_IDLE_TIME = " + CACHE_ENTRY_MAX_IDLE_TIME); } SystemTimerPool.getTimerPool().schedule((TaskRunnable) cache, new Date(((currentTimeMillis() + SWEEP_INTERVAL) / 1000) * 1000)); if (debug.messageEnabled()) { debug.message("InteactionCache.InteractionCache() " + " - returning from constructor"); } } CacheEntry getCacheEntry(String messageID) { if (VERBOSE_MESSAGE && debug.messageEnabled()) { debug.message("InteractionCache.getCacheEntry():" + "looking up cacheEntry for messageID=" + messageID); debug.message("InteractionCache.getCacheEntry():" + " cached messageIDs=" + cache.keySet()); } CacheEntry entry = (CacheEntry)cache.get(messageID); if (entry != null) { cache.removeElement(messageID); cache.addElement(messageID); } return entry; } void putCacheEntry(String messageID, CacheEntry cacheEntry) { cache.put(messageID, cacheEntry); if (VERBOSE_MESSAGE && debug.messageEnabled()) { debug.message("InteractionCache.putCacheEntry():" + " cached cacheEntry for messageID=" + messageID); } } } static class CacheEntry { String messageID; //key String requestMessageID; Message requestMessage; InquiryElement inquiryElement; InteractionResponseElement interactionResponseElement; String connectTo; String certAlias; String soapAction; String returnToURL; String requestHost; String language; CacheEntry(String messageID) { this.messageID= messageID; } CacheEntry(String messageID, Message message) { this.messageID= messageID; this.requestMessage= message; } void setRequestMessage(Message requestMessage) { this.requestMessage = requestMessage; } Message getRequestMessage() { return requestMessage; } void setRequestMessageID(String requestMessageID) { this.requestMessageID = requestMessageID; } String getRequestMessageID() { return requestMessageID; } void setInquiryElement(InquiryElement inquiryElement) { this.inquiryElement = inquiryElement; } InquiryElement getInquiryElement() { return inquiryElement; } void setInteractionResponseElement( InteractionResponseElement interactionResponseElement) { this.interactionResponseElement = interactionResponseElement; } InteractionResponseElement getInteractionResponseElement() { return interactionResponseElement; } void setConnectTo(String connectTo) { this.connectTo = connectTo; } String getConnectTo() { return connectTo; } void setClientCert(String certAlias) { this.certAlias = certAlias; } String getClientCert() { return certAlias; } void setSoapAction(String soapAction) { this.soapAction = soapAction; } String getSoapAction() { return soapAction; } void setReturnToURL(String returnToURL) { this.returnToURL = returnToURL; } String getReturnToURL() { return returnToURL; } void setRequestHost(String requestHost) { this.requestHost = requestHost; } String getRequestHost() { return requestHost; } void setLanguage(String language) { this.language = language; } String getLanguage() { return language; } } }