001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
005 *
006 * The contents of this file are subject to the terms
007 * of the Common Development and Distribution License
008 * (the License). You may not use this file except in
009 * compliance with the License.
010 *
011 * You can obtain a copy of the License at
012 * https://opensso.dev.java.net/public/CDDLv1.0.html or
013 * opensso/legal/CDDLv1.0.txt
014 * See the License for the specific language governing
015 * permission and limitations under the License.
016 *
017 * When distributing Covered Code, include this CDDL
018 * Header Notice in each file and include the License file
019 * at opensso/legal/CDDLv1.0.txt.
020 * If applicable, add the following below the CDDL Header,
021 * with the fields enclosed by brackets [] replaced by
022 * your own identifying information:
023 * "Portions Copyrighted [year] [name of copyright owner]"
024 *
025 * $Id: Utils.java,v 1.9 2008/11/10 22:56:59 veiming Exp $
026 *
027 * Portions Copyright 2013-2016 ForgeRock AS.
028 */
029
030package com.sun.identity.liberty.ws.soapbinding; 
031
032import static org.forgerock.openam.utils.Time.*;
033
034import java.io.ByteArrayInputStream;
035
036import java.text.MessageFormat;
037
038import java.util.ArrayList;
039import java.util.Date;
040import java.util.HashMap;
041import java.util.HashSet;
042import java.util.Iterator;
043import java.util.List;
044import java.util.Map;
045import java.util.ResourceBundle;
046import java.util.Set;
047import java.util.StringTokenizer;
048
049import javax.xml.bind.Marshaller;
050import javax.xml.bind.Unmarshaller;
051import javax.xml.bind.JAXBContext;
052import javax.xml.bind.JAXBException;
053import javax.xml.bind.NotIdentifiableEvent;
054import javax.xml.bind.PropertyException;
055import javax.xml.bind.ValidationEvent;
056import javax.xml.bind.helpers.DefaultValidationEventHandler;
057import javax.xml.namespace.QName;
058import javax.xml.soap.MessageFactory;
059import javax.xml.soap.SOAPMessage;
060import javax.xml.soap.MimeHeaders;
061
062import org.w3c.dom.Document;
063import org.w3c.dom.Element;
064
065import com.sun.identity.common.PeriodicCleanUpMap;
066import com.sun.identity.common.SystemTimerPool;
067import com.sun.identity.common.TaskRunnable;
068import com.sun.identity.liberty.ws.util.ProviderManager;
069import com.sun.identity.liberty.ws.util.ProviderUtil;
070import com.sun.identity.shared.debug.Debug;
071import com.sun.identity.shared.locale.Locale;
072import com.sun.identity.shared.configuration.SystemPropertiesManager;
073import com.sun.identity.shared.xml.XMLUtils;
074
075/**
076 * This class contains utility methods.
077 *
078 * @supported.api
079 */
080
081public class Utils {
082    static final String NAMESPACE_PREFIX_MAPPING_LIST_PROP =
083                "com.sun.identity.liberty.ws.jaxb.namespacePrefixMappingList";
084    static final String JAXB_PACKAGE_LIST_PROP =
085                "com.sun.identity.liberty.ws.jaxb.packageList";
086
087
088    static final String DEFAULT_JAXB_PACKAGES =
089        "com.sun.identity.liberty.ws.common.jaxb.soap:" +
090        "com.sun.identity.liberty.ws.common.jaxb.assertion:" +
091        "com.sun.identity.liberty.ws.common.jaxb.protocol:" +
092        "com.sun.identity.liberty.ws.common.jaxb.ac:" +
093        "com.sun.identity.liberty.ws.disco.jaxb:" +
094        "com.sun.identity.liberty.ws.disco.jaxb11:" +
095        "com.sun.identity.liberty.ws.disco.plugins.jaxb:" +
096        "com.sun.identity.liberty.ws.interaction.jaxb:" +
097        "com.sun.identity.liberty.ws.meta.jaxb:" +
098        "com.sun.identity.liberty.ws.paos.jaxb:" +
099        "com.sun.identity.liberty.ws.common.jaxb.ps:" +
100        "com.sun.identity.liberty.ws.common.jaxb.security:" +
101        "com.sun.identity.liberty.ws.soapbinding.jaxb:" +
102        "com.sun.identity.liberty.ws.soapbinding.jaxb11:" +
103        "com.sun.identity.liberty.ws.idpp.jaxb:" +
104        "com.sun.identity.liberty.ws.idpp.plugin.jaxb:" +
105        "com.sun.identity.liberty.ws.common.jaxb.secext:" +
106        "com.sun.identity.liberty.ws.common.jaxb.utility:" +
107        "com.sun.identity.liberty.ws.common.jaxb.xmlenc:" +
108        "com.sun.identity.liberty.ws.common.jaxb.xmlsig";
109
110    static com.sun.identity.liberty.ws.common.jaxb.soap.ObjectFactory soapOF =
111        new com.sun.identity.liberty.ws.common.jaxb.soap.ObjectFactory();
112
113    static com.sun.identity.liberty.ws.soapbinding.jaxb.ObjectFactory soapBOF =
114        new com.sun.identity.liberty.ws.soapbinding.jaxb.ObjectFactory();
115
116    static com.sun.identity.liberty.ws.common.jaxb.secext.ObjectFactory secOF =
117        new com.sun.identity.liberty.ws.common.jaxb.secext.ObjectFactory();
118
119    static final QName FAULT_CODE_SERVER =
120                             new QName(SOAPBindingConstants.NS_SOAP, "Server");
121    static String faultStringServerError = null;
122    static Debug debug = null;
123    public static ResourceBundle bundle = null;
124
125    static MessageFactory messageFactory = null;
126
127    static HashMap nsPrefix = new HashMap();
128    static String jaxbPackages = null;
129    static JAXBContext jc = null;
130
131    static final String STALE_TIME_LIMIT_PROP =
132                "com.sun.identity.liberty.ws.soap.staleTimeLimit";
133    static int stale_time_limit = 300000; // millisec
134
135    static final String SUPPORTED_ACTORS_PROP =
136               "com.sun.identity.liberty.ws.soap.supportedActors";
137    static final String LIBERTY_WSF_VERSION =
138        "com.sun.identity.liberty.wsf.version";
139    static Set supportedActors = new HashSet();
140
141    static final String MESSAGE_ID_CACHE_CLEANUP_INTERVAL_PROP =
142        "com.sun.identity.liberty.ws.soap.messageIDCacheCleanupInterval";
143    static int message_ID_cleanup_interval = 60000; // millisec    
144    private static Map messageIDMap = null;
145
146    static {
147        bundle = Locale.getInstallResourceBundle("libSOAPBinding");
148        faultStringServerError = bundle.getString("ServerError");
149        debug = Debug.getInstance("libIDWSF");
150
151        try {
152            messageFactory = MessageFactory.newInstance();
153        } catch (Exception ex) {
154            debug.error("Utils.static: Unable to create SOAP Message Factory",
155                        ex);
156        }
157
158        String tmpNSPre =
159                  SystemPropertiesManager.get(NAMESPACE_PREFIX_MAPPING_LIST_PROP);
160        if (tmpNSPre != null && tmpNSPre.length() > 0) {
161            StringTokenizer stz = new StringTokenizer(tmpNSPre, "|");
162            while(stz.hasMoreTokens()) {
163                String token = stz.nextToken().trim();
164                int index = token.indexOf('=');
165                if (index != -1 && index != 0 && index != token.length() - 1) {
166                    String prefix = token.substring(0, index);
167                    String ns = token.substring(index + 1);
168                    if (debug.messageEnabled()) {
169                        debug.message("Utils.static: add ns = " + ns +
170                                      ", prefix = " + prefix);
171                    }
172                    nsPrefix.put(ns, prefix);
173                } else {
174                    if (debug.warningEnabled()) {
175                        debug.warning("Utils.static: Invalid syntax " +
176                                      "for Namespace Prefix Mapping List: " +
177                                      token);
178                    }
179                }
180            }          
181        }
182
183        String tmpJaxbPkgs = SystemPropertiesManager.get(JAXB_PACKAGE_LIST_PROP);
184        if (tmpJaxbPkgs != null && tmpJaxbPkgs.length() > 0) {
185            jaxbPackages = DEFAULT_JAXB_PACKAGES + ":" + tmpJaxbPkgs;
186        } else {
187            jaxbPackages = DEFAULT_JAXB_PACKAGES;
188        }
189        if (debug.messageEnabled()) {
190            debug.message("Utils.static: jaxbPackages = " + jaxbPackages);
191        }
192
193        try {
194            jc = JAXBContext.newInstance(jaxbPackages);
195        } catch (JAXBException jaxbe) {
196            Utils.debug.error("Utils.static:", jaxbe);
197        }
198
199        String tmpstr = SystemPropertiesManager.get(STALE_TIME_LIMIT_PROP);
200        if (tmpstr != null) {
201            try {
202                stale_time_limit = Integer.parseInt(tmpstr);
203            } catch (Exception ex) {
204                if (debug.warningEnabled()) {
205                    debug.warning("Utils.static: Unable to get stale time " +
206                                  "limit. Default value will be used");
207                }
208            }
209        }
210
211        tmpstr = SystemPropertiesManager.get(SUPPORTED_ACTORS_PROP);
212        if (tmpstr != null) {
213            StringTokenizer stz = new StringTokenizer(tmpstr, "|");
214            while(stz.hasMoreTokens()) {
215                String token = stz.nextToken();
216                if (token.length() > 0) {
217                    supportedActors.add(token);
218                }
219            }
220        }
221        tmpstr =
222            SystemPropertiesManager.get(MESSAGE_ID_CACHE_CLEANUP_INTERVAL_PROP);
223        if (tmpstr != null) {
224            try {
225                message_ID_cleanup_interval = Integer.parseInt(tmpstr);
226            } catch (Exception ex) {
227                if (debug.warningEnabled()) {
228                    debug.warning("Utils.CleanUpThread.static: Unable to" +
229                            " get stale time limit. Default value " +
230                            "will be used");
231                }
232            }
233        }
234        messageIDMap = new PeriodicCleanUpMap(
235            message_ID_cleanup_interval, stale_time_limit);
236        SystemTimerPool.getTimerPool().schedule((TaskRunnable) messageIDMap,
237            new Date(((currentTimeMillis() + message_ID_cleanup_interval)
238            / 1000) * 1000));
239    }
240
241    /**
242     * Returns JAXB namespace prefix mapping. Key is the namespace and value
243     * is the prefix.
244     *
245     * @return a Map of JAXB namespace prefix mapping
246     * @supported.api
247     */
248    static public Map getNamespacePrefixMapping() {
249        return nsPrefix;
250    }
251
252    /**
253     * Returns a String of JAXB packages seperated by ":".
254     *
255     * @return a String of JAXB packages seperated by ":".
256     * @supported.api
257     */
258    public static String getJAXBPackages() {
259        return jaxbPackages;
260    }
261
262    /**
263     * Converts Document to SOAPMessage
264     *
265     * @param doc the source Document
266     * @return SOAPMessage
267     * @throws SOAPBindingException if an error occurs while converting
268     *         the document
269     * @supported.api
270     */
271    public static SOAPMessage DocumentToSOAPMessage(Document doc)
272    throws SOAPBindingException {
273        SOAPMessage msg = null;
274        try {
275            MimeHeaders mimeHeaders = new MimeHeaders();
276            mimeHeaders.addHeader("Content-Type", "text/xml");
277            
278            String xmlstr = XMLUtils.print(doc);
279            if (debug.messageEnabled()) {
280                debug.message("Utils.DocumentToSOAPMessage: xmlstr = " +
281                        xmlstr);
282            }
283            msg = messageFactory.createMessage(
284                    mimeHeaders,
285                    new ByteArrayInputStream(
286                    xmlstr.getBytes(SOAPBindingConstants.DEFAULT_ENCODING)));
287        } catch (Exception e) {
288            debug.error("Utils.DocumentToSOAPMessage", e);
289            throw new SOAPBindingException(e.getMessage());
290        }
291        return msg;
292    }
293
294    /**
295     * Converts a list of JAXB objects to a list of 
296     * <code>org.w3c.dom.Element</code>
297     *
298     * @param jaxbObjs a list of JAXB objects
299     * @return a list of <code>org.w3c.dom.Element</code>
300     * @throws JAXBException if an error occurs while converting JAXB objects.
301     *
302     * @supported.api
303     */
304    public static List convertJAXBToElement(List jaxbObjs) 
305                                            throws JAXBException{
306        List result = new ArrayList();
307        if (jaxbObjs != null && !jaxbObjs.isEmpty()) {
308            Iterator iter = jaxbObjs.iterator();
309            while(iter.hasNext()) {
310                result.add(convertJAXBToElement(iter.next()));
311            }
312        }
313        return result;
314    }
315
316    /**
317     * Converts a JAXB object to a <code>org.w3c.dom.Element</code>.
318     *
319     * @param jaxbObj a JAXB object
320     * @return a <code>org.w3c.dom.Element</code>
321     * @throws JAXBException if an error occurs while converting JAXB object.
322     * @supported.api
323     */
324    public static Element convertJAXBToElement(Object jaxbObj)
325                          throws JAXBException {
326        Marshaller m = jc.createMarshaller();
327        try {
328            m.setProperty("com.sun.xml.bind.namespacePrefixMapper",
329                    new NamespacePrefixMapperImpl());
330        } catch(PropertyException ex) {
331            debug.error("Utils.convertJAXBToElement", ex);
332        }
333        Document doc = null;
334        try {
335            doc = XMLUtils.newDocument();
336        } catch (Exception ex) {
337            debug.error("Utils.convertJAXBToElement:", ex);
338        }
339        m.marshal(jaxbObj, doc);
340        return doc.getDocumentElement();
341    }
342
343    /**
344     * Converts a JAXB object to a <code>org.w3c.dom.Element</code>.
345     *
346     * @param jaxbObj a JAXB object
347     * @return a <code>org.w3c.dom.Element</code>
348     * @throws JAXBException if an error occurs while converting JAXB object.
349     * @supported.api
350     */
351    public static Element convertJAXBToElement(Object jaxbObj,
352            boolean checkIdref) throws JAXBException {
353        Marshaller m = jc.createMarshaller();
354        try {
355            m.setProperty("com.sun.xml.bind.namespacePrefixMapper",
356                    new NamespacePrefixMapperImpl());
357            
358        } catch(PropertyException ex) {
359            debug.error("Utils.convertJAXBToElement", ex);
360        }
361        
362        if (!checkIdref) {
363            m.setEventHandler(
364                    new DefaultValidationEventHandler() {
365                public boolean handleEvent(ValidationEvent event) {
366                    if (event instanceof NotIdentifiableEvent) {
367                        return true;
368                    }
369                    return super.handleEvent(event);
370                }
371            });
372        }
373        
374        Document doc = null;
375        try {
376            doc = XMLUtils.newDocument();
377        } catch (Exception ex) {
378            debug.error("Utils.convertJAXBToElement:", ex);
379        }
380        m.marshal(jaxbObj, doc);
381        return doc.getDocumentElement();
382    }
383
384    /**
385     * Converts a list of <code>org.w3c.dom.Element</code> to a list of 
386     * JAXB objects.
387     *
388     * @param elements a list of <code>org.w3c.dom.Element</code>
389     * @return a list of JAXB objects
390     * @throws JAXBException if an error occurs while converting
391     *                          <code>org.w3c.dom.Element</code>.
392     * @supported.api
393     */
394    public static List convertElementToJAXB(List elements) 
395                                            throws JAXBException{
396        List result = new ArrayList();
397        if (elements != null && !elements.isEmpty()) {
398            Iterator iter = elements.iterator();
399            while(iter.hasNext()) {
400                result.add(convertElementToJAXB((Element)iter.next()));
401            }
402        }
403        return result;
404    }
405
406    /**
407     * Converts a <code>org.w3c.dom.Element</code> to a JAXB object.
408     *
409     * @param element a <code>org.w3c.dom.Element</code>.
410     * @return a JAXB object
411     * @throws JAXBException if an error occurs while converting
412     *                          <code>org.w3c.dom.Element</code>
413     * @supported.api
414     */
415    public static Object convertElementToJAXB(Element element)
416                         throws JAXBException {
417        Unmarshaller u = jc.createUnmarshaller();
418        return u.unmarshal(element);
419    }
420
421    /**
422     * Converts a value of XML boolean type to Boolean object.
423     *
424     * @param str a value of XML boolean type
425     * @return a Boolean object
426     * @throws Exception if there is a syntax error
427     * @supported.api
428     */
429    public static Boolean StringToBoolean(String str) throws Exception {
430        if (str == null) {
431            return null;
432        }
433        
434        if (str.equals("true") || str.equals("1")) {
435            return Boolean.TRUE;
436        }
437        
438        if (str.equals("false") || str.equals("0")) {
439            return Boolean.FALSE;
440        }
441        
442        throw new Exception();
443    }
444
445    /**
446     * Converts a Boolean object to a String representing XML boolean.
447     *
448     * @param bool a Boolean object.
449     * @return a String representing the boolean value.
450     * @supported.api
451     */
452    public static String BooleanToString(Boolean bool) {
453        if (bool == null) {
454            return "";
455        }
456        
457        return bool.booleanValue() ? "1" : "0";
458    }
459
460    /**
461     * Converts a string value to a QName. The prefix of the string value
462     * is resolved to a namespace relative to the element.
463     *
464     * @param str the String to be converted.
465     * @param element the Element object.
466     * @return the QName Object.
467     * @supported.api
468     */
469    public static QName convertStringToQName(String str,Element element) {
470        if (str == null) {
471            return null;
472        }
473        
474        String prefix = "";
475        String localPart;
476        int index = str.indexOf(":");
477        if (index == -1) {
478            localPart = str;
479        } else {
480            prefix = str.substring(0, index);
481            localPart = str.substring(index + 1);
482        }
483        String ns = getNamespaceForPrefix(prefix, element);
484        return new QName(ns, localPart);
485    }
486
487
488    /**
489     *  Gets the XML namespace URI that is mapped to the specified prefix, in
490     *  the context of the DOM element e
491     *
492     * @param  prefix  The namespace prefix to map
493     * @param  e       The DOM element in which to calculate the prefix binding
494     * @return         The XML namespace URI mapped to prefix in the context of e
495     */
496    public static String getNamespaceForPrefix(String prefix, Element e) {
497        return e.lookupNamespaceURI(prefix);
498    }
499
500    /**
501     * Enforces message processiong rules defined in the spec.
502     *
503     * @param message a message
504     * @param requestMessageID the request messageID if we are checking a
505     *                         response message or null if we are checking a
506     *                         request message
507     * @param isServer true if this is a server
508     * @throws SOAPBindingException if the message violates rules on client.
509     * @throws SOAPFaultException if the message violates rules on server.
510     */
511    public static void enforceProcessingRules(Message message, String requestMessageID,
512            boolean isServer)
513            throws SOAPBindingException, SOAPFaultException {
514        CorrelationHeader corrH = message.getCorrelationHeader();
515        String messageID = corrH.getMessageID();
516        checkCorrelationHeader(corrH, requestMessageID, isServer);
517        checkProviderHeader(message.getProviderHeader(), messageID, isServer);
518        checkProcessingContextHeader(message.getProcessingContextHeader(),
519                messageID, isServer);
520        checkConsentHeader(message.getConsentHeader(), messageID, isServer);
521        List usagHs = message.getUsageDirectiveHeaders();
522        if (usagHs != null && !usagHs.isEmpty()) {
523            Iterator iter = usagHs.iterator();
524            while(iter.hasNext()) {
525                UsageDirectiveHeader usagH = (UsageDirectiveHeader)iter.next();
526                checkUsageDirectiveHeader(usagH, messageID, isServer);
527            }
528        }
529    }
530    
531    /**
532     * Enforces message Correlation header processiong rules defined
533     * in the spec.
534     *
535     * @param  corrH a Correlation header
536     * @param  requestMessageID the request messageID if we are checking a
537     *                         response message or null if we are checking a
538     *                         request message
539     * @param  isServer true if this is a server
540     * @throws SOAPBindingException if the Correlation header violates rules
541     *         on client side
542     * @throws SOAPFaultException if the Correlation header violates rules
543     *                               on server side
544     */
545    static void checkCorrelationHeader(CorrelationHeader corrH,
546            String  requestMessageID, boolean isServer)
547            throws SOAPBindingException, SOAPFaultException {
548        if (corrH == null) {
549            if (isServer) {
550                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
551                        faultStringServerError, null,
552                        new SOAPFaultDetail(
553                        SOAPFaultDetail.ID_STAR_MSG_NOT_UNSTD,null,null));
554                throw new SOAPFaultException(new Message(sf));
555            } else {
556                throw new SOAPBindingException(
557                        bundle.getString("CorrelationHeaderNull"));
558            }
559        }
560        
561        String messageID = corrH.getMessageID();
562        
563        try {
564            checkActorAndMustUnderstand(corrH.getActor(),
565                    corrH.getMustUnderstand(),
566                    messageID, isServer);
567        } catch (SOAPFaultException sfe) {
568            sfe.getSOAPFaultMessage().getSOAPFault().getDetail()
569            .setCorrelationHeader(corrH);
570            throw sfe;
571        }
572        
573        Date timestamp = corrH.getTimestamp();
574        Date now = newDate();
575        if ((now.getTime() - timestamp.getTime()) > stale_time_limit) {
576            if (isServer) {
577                SOAPFaultDetail sfd =
578                        new SOAPFaultDetail(SOAPFaultDetail.STALE_MSG,
579                        messageID, null);
580                sfd.setCorrelationHeader(corrH);
581                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
582                        faultStringServerError, null, sfd);
583                throw new SOAPFaultException(new Message(sf));
584                
585            } else {
586                throw new SOAPBindingException(bundle.getString("staleMsg"));
587            }
588        }
589        
590        Long prevMsgIDTime = (Long)messageIDMap.get(messageID);
591        long currentTime = currentTimeMillis();
592        if (prevMsgIDTime != null &&
593                currentTime - prevMsgIDTime.longValue() < stale_time_limit) {
594            
595            if (isServer) {
596                SOAPFaultDetail sfd =
597                        new SOAPFaultDetail(SOAPFaultDetail.DUPLICATE_MSG,
598                        messageID, null);
599                sfd.setCorrelationHeader(corrH);
600                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
601                        faultStringServerError, null, sfd);
602                throw new SOAPFaultException(new Message(sf));
603                
604            } else {
605                throw new SOAPBindingException(bundle.getString("dupMsg"));
606            }
607        } else {
608            synchronized (messageIDMap) {
609                if (debug.messageEnabled()) {
610                    debug.message("Utils.checkCorrelationHeader: adding " +
611                            "messageID: " + messageID);
612                }
613                messageIDMap.put(messageID, new Long(currentTime));
614            }
615        }
616        
617        String refToMessageID = corrH.getRefToMessageID();
618        if (refToMessageID != null && requestMessageID != null &&
619                !refToMessageID.equals(requestMessageID)) {
620            
621            if (isServer) {
622                SOAPFaultDetail sfd =
623                        new SOAPFaultDetail(
624                        SOAPFaultDetail.INVALID_REF_TO_MSG_ID,messageID, null);
625                sfd.setCorrelationHeader(corrH);
626                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
627                        faultStringServerError, null, sfd);
628                throw new SOAPFaultException(new Message(sf));
629                
630            } else {
631                throw new SOAPBindingException(bundle.getString("invalidRef"));
632            }
633        }
634    }
635
636    /**
637     * Enforces message Provider header processing rules defined
638     * in the spec.
639     *
640     * @param provH a Correlation header
641     * @param messageID the messageID in Correlation header
642     * @param isServer true if this is a server
643     * @throws SOAPBindingException if the Provider header violates rules
644     *                                 on client side
645     * @throws SOAPFaultException if the Provider header violates rules
646     *                               on server side
647     */
648    static void checkProviderHeader(ProviderHeader provH,
649            String messageID,boolean isServer)
650            throws SOAPBindingException, SOAPFaultException {
651
652        if (provH == null) {
653            return;
654        }
655        
656        try {
657            checkActorAndMustUnderstand(provH.getActor(),
658                    provH.getMustUnderstand(),
659                    messageID, isServer);
660        } catch (SOAPFaultException sfe) {
661            sfe.getSOAPFaultMessage().getSOAPFault().getDetail()
662            .setProviderHeader(provH);
663            throw sfe;
664        }
665        
666        if (isServer && SOAPBindingService.enforceOnlyKnownProviders()) {
667            String providerID = provH.getProviderID();
668            ProviderManager providerManager = ProviderUtil.getProviderManager();
669
670            if (!providerManager.containsProvider(providerID)) {
671                SOAPFaultDetail sfd = new SOAPFaultDetail(
672                    SOAPFaultDetail.PROVIDER_ID_NOT_VALID, messageID, null);
673                sfd.setProviderHeader(provH);
674                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
675                    faultStringServerError, null, sfd);
676                throw new SOAPFaultException(new Message(sf));
677            }
678            
679            String affID = provH.getAffiliationID();
680            if ((affID != null) &&
681                (!providerManager.isAffiliationMember(providerID, affID))) {
682
683                SOAPFaultDetail sfd = new SOAPFaultDetail(
684                    SOAPFaultDetail.AFFILIATION_ID_NOT_VALID, messageID, null);
685                sfd.setProviderHeader(provH);
686                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
687                    faultStringServerError, null, sfd);
688                throw new SOAPFaultException(new Message(sf));
689            }
690        }
691    }
692
693    /**
694     * Enforces message Processing Context header processiong rules defined
695     * in the spec.
696     * @param procH a Processing Context header
697     * @param messageID the messageID in Correlation header
698     * @param isServer true if this is a server
699     * @throws SOAPBindingException if the Processing Context header
700     *                                 violates rules on client side
701     * @throws SOAPFaultException if the Processing Context header violates
702     *                               rules on server side
703     */
704    static void checkProcessingContextHeader(ProcessingContextHeader procH,
705            String messageID, boolean isServer)
706            throws SOAPBindingException, SOAPFaultException {
707        if (procH == null) {
708            return;
709        }
710
711        try {
712            checkActorAndMustUnderstand(procH.getActor(),
713                                        procH.getMustUnderstand(),
714                                        messageID, isServer);
715        } catch (SOAPFaultException sfe) {
716            sfe.getSOAPFaultMessage().getSOAPFault().getDetail()
717               .setProcessingContextHeader(procH);
718            throw sfe;
719        }
720
721        if (isServer) {
722            SOAPFaultDetail sfd =
723                    new SOAPFaultDetail(SOAPFaultDetail.PROC_CTX_URI_NOT_UNSTD,
724                                        messageID, null);
725            sfd.setProcessingContextHeader(procH);
726            SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
727                                         faultStringServerError, null, sfd);
728            throw new SOAPFaultException(new Message(sf));
729        } else {
730            throw new SOAPBindingException(
731                            bundle.getString("ProcessingContextUnsupported"));
732        }
733    }
734
735    /**
736     * Enforces message Consent header processiong rules defined in the spec.
737     *
738     * @param consH a Consent header
739     * @param messageID the messageID in Correlation header
740     * @param isServer true if this is a server
741     * @throws SOAPBindingException if the Consent header violates rules on
742     *                                 client side
743     * @throws SOAPFaultException if the Consent header violates rules
744     *                               on server side
745     */
746    static void checkConsentHeader(ConsentHeader consH,String messageID,
747            boolean isServer) throws SOAPBindingException, SOAPFaultException {
748        if (consH == null) {
749            return;
750        }
751        
752        try {
753            checkActorAndMustUnderstand(consH.getActor(),
754                    consH.getMustUnderstand(),
755                    messageID, isServer);
756        } catch (SOAPFaultException sfe) {
757            sfe.getSOAPFaultMessage().getSOAPFault().getDetail()
758            .setConsentHeader(consH);
759            throw sfe;
760        }
761    }
762
763    /**
764     * Enforces message Usage Directive header processiong rules defined in
765     * the spec.
766     *
767     * @param usagH a Usage Directive header
768     * @param messageID the messageID in Correlation header
769     * @param isServer true if this is a server
770     * @throws SOAPBindingException if the Usage Directive header violates
771     *                                 rules on client side
772     * @throws SOAPFaultException if the Usage Directive header violates
773     *                               rules on server side
774     */
775    static void checkUsageDirectiveHeader(UsageDirectiveHeader usagH,
776            String messageID,boolean isServer)
777            throws SOAPBindingException, SOAPFaultException {
778        if (usagH == null) {
779            return;
780        }
781        
782        try {
783            checkActorAndMustUnderstand(usagH.getActor(),
784                    usagH.getMustUnderstand(),
785                    messageID, isServer);
786        } catch (SOAPFaultException sfe) {
787            List usagHs = new ArrayList();
788            usagHs.add(usagH);
789            sfe.getSOAPFaultMessage().getSOAPFault().getDetail()
790            .setUsageDirectiveHeaders(usagHs);
791            throw sfe;
792        }
793    }
794
795    /**
796     * Checks 'actor' and 'mustUnderstand' attribute of a header.
797     *
798     * @param actor the value of 'actor' attribute of a header.
799     * @param mustUnderstand the value of 'mustUnderstand' attribute of a
800     *                       header.
801     * @param messageID the messageID in Correlation header.
802     * @param isServer true if this is a server.
803     * @throws SOAPBindingException if the actor and mustUnderstand violates
804     *                                 rules on client side
805     * @throws SOAPFaultException if the actor and mustUnderstand violates
806     *                               rules on server side
807     */
808    static void checkActorAndMustUnderstand(String actor,Boolean mustUnderstand,
809            String messageID,boolean isServer)
810            throws SOAPBindingException, SOAPFaultException {
811        if (actor != null && !supportedActors.contains(actor)) {
812            if (isServer) {
813                SOAPFaultDetail sfd =
814                        new SOAPFaultDetail(SOAPFaultDetail.BOGUS_ACTOR,
815                        messageID, null);
816                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
817                        faultStringServerError, null, sfd);
818                throw new SOAPFaultException(new Message(sf));
819            } else {
820                throw new SOAPBindingException(
821                        bundle.getString("bogusActor"));
822            }
823        }
824        
825        if (mustUnderstand != null && !mustUnderstand.booleanValue()) {
826            if (isServer) {
827                SOAPFaultDetail sfd =
828                        new SOAPFaultDetail(SOAPFaultDetail.BOGUS_MUST_UNSTND,
829                        messageID, null);
830                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
831                        faultStringServerError, null, sfd);
832                throw new SOAPFaultException(new Message(sf));
833            } else {
834                throw new SOAPBindingException(
835                        bundle.getString("bogusMustUnderstand"));
836            }
837        }
838    }
839    
840    /**
841     * Gets localized string from resource bundle.
842     *
843     * @param key a key to a resource bundle
844     * @param params parameters to MessageFormat
845     * @return a localized string.
846     * @supported.api
847     */
848    public static String getString(String key, Object[] params) {
849        return MessageFormat.format(bundle.getString(key), params);
850    }
851    
852    /**
853     * Returns the default web services version.
854     *
855     * @return the default web services version.
856     */
857    public static String getDefaultWSFVersion() {
858        return SystemPropertiesManager.get(LIBERTY_WSF_VERSION,
859            SOAPBindingConstants.WSF_11_VERSION);
860    }
861
862}