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: AssertionManager.java,v 1.13 2010/01/09 19:41:06 qcheng Exp $
026 *
027 * Portions Copyrighted 2013-2015 ForgeRock AS.
028 */
029
030package com.sun.identity.saml;
031
032import java.util.Map;
033import java.util.HashMap;
034import java.util.Date;
035import java.util.List;
036import java.util.ArrayList;
037import java.util.Set;
038import java.util.HashSet;
039import java.util.Iterator;
040import java.net.InetAddress;
041import org.w3c.dom.Element;
042import com.sun.identity.common.GeneralTaskRunnable;
043import com.sun.identity.common.PeriodicGroupRunnable;
044import com.sun.identity.common.ScheduleableGroupAction;
045import com.sun.identity.common.SystemTimerPool;
046import com.sun.identity.common.TaskRunnable;
047import com.sun.identity.common.TimerPool;
048import com.sun.identity.saml.assertion.*;
049import com.sun.identity.saml.protocol.*;
050import com.sun.identity.saml.common.*;
051import com.sun.identity.saml.plugins.*;
052import com.sun.identity.saml.xmlsig.*;
053import com.sun.identity.shared.Constants;
054import com.sun.identity.shared.DateUtils;
055import com.sun.identity.common.SystemConfigurationUtil;
056import com.sun.identity.shared.encode.Base64;
057import com.sun.identity.shared.stats.Stats;
058import com.sun.identity.shared.xml.XMLUtils;
059import java.util.StringTokenizer;
060import com.sun.identity.plugin.monitoring.FedMonAgent;
061import com.sun.identity.plugin.monitoring.FedMonSAML1Svc;
062import com.sun.identity.plugin.monitoring.MonitorManager;
063import com.sun.identity.plugin.session.SessionException;
064import com.sun.identity.plugin.session.SessionManager;
065import com.sun.identity.plugin.session.SessionProvider;
066import javax.servlet.http.HttpServletRequest;
067import javax.servlet.http.HttpServletResponse;
068
069/**
070 * The class <code>AssertionManager</code> is a <code>final</code> class
071 * that provides interfaces to create, get and destroy <code>Assertion</code>s.
072 * <p>
073 * It is a singleton class; an instance of this class can be obtained by
074 * calling <code>AssertionManager.getInstance()</code>.
075 * <p>
076 * Having obtained an instance of <code>AssertionManager</code>, its methods
077 * can be called to create/get <code>Assertion</code>, and 
078 * <code>AssertionArtifact</code>, and to obtain decision from an 
079 * <code>Query</code>.
080 * <p>
081 * This class could only be used in the same JVM as OpenAM.
082 * @supported.api
083 */
084public final class AssertionManager {
085
086    // General stats class
087    public static Stats assStats;
088    public static Stats artStats;
089    
090    // Assertion Statistics Class
091    private static AssertionStats assertionStats;
092    
093    // Artifact Statistics Class
094    private static ArtifactStats artifactStats;
095    
096    private static final String SUPER_USER =
097        "com.sun.identity.authentication.super.user";
098    private static String superUser = null;
099    private static SessionProvider sessionProvider = null;
100    
101    private static long cleanUpInterval;
102    private static long assertionTimeout;
103    private static long artifactTimeout;
104    private static long notBeforeSkew;
105
106    private static FedMonAgent agent;
107    private static FedMonSAML1Svc saml1Svc;
108    
109    static {
110        assStats = Stats.getInstance("amAssertionMap");
111        artStats = Stats.getInstance("amArtifactMap");
112        superUser = SystemConfigurationUtil.getProperty(SUPER_USER);
113        try {
114            sessionProvider = SessionManager.getProvider();
115        } catch (SessionException se) {
116            SAMLUtils.debug.error("Static: Couldn't get SessionProvider.", 
117                se);
118            sessionProvider = null; 
119        }
120        cleanUpInterval = ((Integer) SAMLServiceManager.getAttribute(
121            SAMLConstants.CLEANUP_INTERVAL_NAME)).intValue() * 1000;
122        artifactTimeout = ((Integer) SAMLServiceManager.getAttribute(
123            SAMLConstants.ARTIFACT_TIMEOUT_NAME)).intValue() * 1000;
124        assertionTimeout = ((Integer) SAMLServiceManager.getAttribute(
125            SAMLConstants.ASSERTION_TIMEOUT_NAME)).intValue() * 1000;
126        notBeforeSkew = ((Integer) SAMLServiceManager.getAttribute(
127            SAMLConstants.NOTBEFORE_TIMESKEW_NAME)).intValue() * 1000;
128
129        agent = MonitorManager.getAgent();
130        saml1Svc = MonitorManager.getSAML1Svc();
131    }
132    
133    // Singleton instance of AssertionManager
134    private static AssertionManager instance = null;
135
136    // used to store artifact to assertionID mapping
137    private static Map artEntryMap = null;
138    // used to store assertionIDString to entry mapping
139    private static Map idEntryMap = null;
140    
141    private static TaskRunnable assertionTimeoutRunnable;
142    private static TaskRunnable artifactTimeoutRunnable;
143    private static TaskRunnable goThroughRunnable;
144
145    private static String assertionVersion = null; 
146    private static String protocolVersion = null; 
147    
148
149    private class Entry {
150        private String destID = null;
151        private String artString = null;
152        private Object token = null;
153        private Assertion assertion = null;
154
155        public Entry(Assertion assertion, String destID, String artString,
156            Object token)
157        {
158            this.assertion = assertion;
159            this.destID = destID;
160            this.artString = artString;
161            this.token = token;
162        }
163
164        public Assertion getAssertion() {
165            return assertion;
166        }
167
168        public String getDestID() {
169            return destID;
170        }
171
172        public void setDestID(String newDestID) {
173            destID = newDestID;
174        }
175
176        public String getArtifactString() {
177            return artString;
178        }
179
180        public void setArtifactString(String newArtifactString) {
181            artString = newArtifactString;
182        }
183
184        public Object getSSOToken() {
185            return token;
186        }
187    }
188
189    private class ArtEntry {
190        private String aID = null;
191        private long expiretime = 0;
192
193        public ArtEntry(String aID, long expiretime) {
194            this.aID = aID;
195            this.expiretime = expiretime;
196        }
197
198        public String getAssertionID() {
199            return aID;
200        }
201
202        public long getExpireTime() {
203            return expiretime;
204        }
205    }
206
207    /**
208     * Default Constructor
209     */
210    private AssertionManager() {
211        idEntryMap = new HashMap();
212        artEntryMap = new HashMap();
213        try { 
214            assertionVersion = SystemConfigurationUtil.getProperty(
215                SAMLConstants.SAML_ASSERTION_VERSION); 
216            protocolVersion = SystemConfigurationUtil.getProperty(
217                SAMLConstants.SAML_PROTOCOL_VERSION); 
218        } catch (Exception e) { 
219            assertionVersion = SAMLConstants.ASSERTION_VERSION_1_0; 
220            protocolVersion = SAMLConstants.PROTOCOL_VERSION_1_0; 
221        }
222        TimerPool timerPool = SystemTimerPool.getTimerPool();
223        ScheduleableGroupAction assertionTimeoutAction = new
224            ScheduleableGroupAction() {
225            public void doGroupAction(Object obj) {
226                deleteAssertion((String) obj, null);
227            }
228        };
229        
230        assertionTimeoutRunnable = new PeriodicGroupRunnable(
231            assertionTimeoutAction, cleanUpInterval, assertionTimeout, true);
232        timerPool.schedule(assertionTimeoutRunnable, new Date(((
233            System.currentTimeMillis() + cleanUpInterval) / 1000) * 1000));
234        
235        ScheduleableGroupAction artifactTimeoutAction = new
236            ScheduleableGroupAction() {
237            public void doGroupAction(Object obj) {
238                deleteAssertion(null, (String) obj);
239            }
240        };
241        
242        artifactTimeoutRunnable = new PeriodicGroupRunnable(
243            artifactTimeoutAction, cleanUpInterval, artifactTimeout, true);
244        
245        timerPool.schedule(artifactTimeoutRunnable, new Date(((
246            System.currentTimeMillis() + cleanUpInterval) / 1000) * 1000));
247        
248        goThroughRunnable = new GoThroughRunnable(cleanUpInterval);
249        
250        timerPool.schedule(goThroughRunnable, new Date(((
251            System.currentTimeMillis() + cleanUpInterval) / 1000) * 1000));
252        
253        if (assStats.isEnabled()) {
254            artifactStats = new ArtifactStats(artEntryMap);
255            artStats.addStatsListener(artifactStats);
256            assertionStats = new AssertionStats(idEntryMap);
257            assStats.addStatsListener(assertionStats);
258        }
259
260    }
261
262    /**
263     * Gets the singleton instance of <code>AssertionManager</code>.
264     * @return The singleton <code>AssertionManager</code> instance
265     * @throws SAMLException if unable to get the singleton
266     *         <code>AssertionManager</code> instance.
267     * @supported.api
268     */
269    public static AssertionManager getInstance() throws SAMLException {
270        // not throwing any exception
271        if (instance == null) {
272            synchronized (AssertionManager.class) {
273                if (instance == null) {
274                    if (SAMLUtils.debug.messageEnabled() ) {
275                        SAMLUtils.debug.message("Constructing a new instance"
276                                + " of AssertionManager");
277                    }
278                    instance = new AssertionManager();
279                }
280            }
281        }
282        return instance;
283    }
284
285    /** 
286     * This method creates an Assertion that contains an
287     * <code>AuthenticationStatement</code>.
288     * @param token user's session object that contains authentication
289     *     information which is needed to create the 
290     *     <code>AuthenticationStatement</code>. 
291     * @return Assertion The created Assertion.
292     * @throws SAMLException If the Assertion cannot be created.
293     * @supported.api
294     */
295    public Assertion createAssertion(Object token)
296        throws SAMLException
297    {
298        if (assertionVersion.equals(SAMLConstants.ASSERTION_VERSION_1_0)) {
299            return createAssertion(token, null,
300                SAMLConstants.DEPRECATED_CONFIRMATION_METHOD_ARTIFACT, 0);
301        } else if(assertionVersion.equals(
302            SAMLConstants.ASSERTION_VERSION_1_1)) {
303            return createAssertion(token, null,
304                SAMLConstants.CONFIRMATION_METHOD_ARTIFACT, 1);
305        } else { 
306            throw new SAMLException(SAMLUtils.bundle.getString(
307                "assertionVersionNotSupport"));
308        }
309    } 
310
311    /**
312     * This method creates an Assertion that contains an 
313     * <code>AuthenticationStatement</code> and 
314     * an <code>AttributeStatement</code>.
315     * @param token User' session object that contains authentication
316     *     information which is needed to create the 
317     *     <code>AuthenticationStatement</code> for the Assertion.
318     * @param attributes A list of Attribute objects which are used to
319     *     create the <code>AttributeStatement</code> for the Assertion.
320     * @return Assertion The created Assertion.
321     * @throws SAMLException If the Assertion cannot be created.
322     * @supported.api
323     */
324    public Assertion createAssertion(Object token, List attributes)
325        throws SAMLException
326    {   if (assertionVersion.equals(SAMLConstants.ASSERTION_VERSION_1_0)) {
327            return createAssertion(token, attributes,
328                SAMLConstants.DEPRECATED_CONFIRMATION_METHOD_ARTIFACT, 0);
329        } else if (assertionVersion.equals(
330            SAMLConstants.ASSERTION_VERSION_1_1)) {
331            return createAssertion(token, attributes,
332                SAMLConstants.CONFIRMATION_METHOD_ARTIFACT, 1);
333        } else { 
334            throw new SAMLException(SAMLUtils.bundle.getString(
335                        "assertionVersionNotSupport"));
336        }
337    } 
338
339    private Assertion createAssertion(Object token, List attributes,
340        String confirmationMethod, int minorVersion)
341        throws SAMLException
342    {
343        if (token == null) {
344            SAMLUtils.debug.error("AssertionManager.createAssertion(id):"
345                + "input Session is null.");
346            throw new SAMLException(SAMLUtils.bundle.getString("nullInput"));
347        }
348        if (sessionProvider == null) {
349            throw new SAMLException(SAMLUtils.bundle.getString(
350                "nullSessionProvider"));
351        }
352        String id = sessionProvider.getSessionID(token);
353        return createAssertion(id, null, null, attributes, 
354             confirmationMethod, minorVersion, null);
355    }
356
357    /**
358     * This method creates an <code>AssertionArtifact</code> for the given
359     * Assertion.
360     *
361     * @param assertion The Assertion for which an Artifact needs to be created.
362     * @param destID The <code>sourceID</code> of the site for which the 
363     *        <code>AssertionArtifact</code> is created. It is in raw String
364     *        format (not Base64 encoded, for example.) This String can be
365     *        obtained from converting the 20 bytes sequence to char Array, then
366     *        from the char Array to String.
367     * @return <code>AssertionArtifact</code>
368     * @throws SAMLException If the <code>AssertionArtifact</code> cannot be
369     *         created.
370     * @supported.api
371     */
372    public AssertionArtifact createAssertionArtifact(Assertion assertion,
373                                                        String destID)
374        throws SAMLException
375    {
376        if ((assertion == null) || (destID == null) || (destID.length() == 0)) {
377            SAMLUtils.debug.error("AssertionManager.createAssertionArti"
378                    + "fact(Assertion, String): null input.");
379            throw new SAMLException(SAMLUtils.bundle.getString("nullInput"));
380        }
381
382        Map partner = (Map) SAMLServiceManager.getAttribute(
383                                                SAMLConstants.PARTNER_URLS);
384        if ((partner == null) || (!partner.containsKey(destID))) {
385            SAMLUtils.debug.error("AssertionManager.createAssertionArtifact:" +
386                "(Assertion, String): destID not in partner list.");
387            throw new SAMLException(
388                        SAMLUtils.bundle.getString("destIDNotFound"));
389        }
390
391        String handle = SAMLUtils.generateAssertionHandle();
392        if (handle == null) {
393            SAMLUtils.debug.error("AssertionManager.createAssertion"
394                        + "Artifact(Assertion,String): couldn't generate "
395                        + "assertion handle.");
396            throw new SAMLResponderException(
397                SAMLUtils.bundle.getString("errorCreateArtifact"));
398        }
399        String sourceID = (String) SAMLServiceManager.getAttribute(
400                                        SAMLConstants.SITE_ID);
401        AssertionArtifact art = new AssertionArtifact(sourceID, handle);
402        String artString = art.getAssertionArtifact();
403        String aID = assertion.getAssertionID();
404        Entry entry = (Entry) idEntryMap.get(aID);
405        if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
406            saml1Svc.incSAML1Cache(FedMonSAML1Svc.ASSERTIONS,
407                FedMonSAML1Svc.CREAD);
408        }
409        if ((entry == null) && !validateNumberOfAssertions(idEntryMap)) {
410            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
411                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ASSERTIONS,
412                    FedMonSAML1Svc.CMISS);
413            }
414            entry = new Entry(assertion, destID, artString, null);
415            try {
416                synchronized (idEntryMap) {
417                    idEntryMap.put(aID, entry);
418                }
419                if ((agent != null) &&
420                    agent.isRunning() &&
421                    (saml1Svc != null))
422                {
423                        saml1Svc.incSAML1Cache(
424                        FedMonSAML1Svc.ASSERTIONS,
425                        FedMonSAML1Svc.CWRITE);
426                }
427                goThroughRunnable.addElement(aID);
428            } catch (Exception e) {
429                SAMLUtils.debug.error("AssertionManager.createAssertion"
430                        + "Artifact(Assertion,String): couldn't add to "
431                        + "idEntryMap." + e);
432                throw new SAMLResponderException(
433                        SAMLUtils.bundle.getString("errorCreateArtifact"));
434            }
435            if (LogUtils.isAccessLoggable(java.util.logging.Level.FINER)) {
436                String[] data = {SAMLUtils.bundle.getString("assertionCreated"),
437                    assertion.toString(true, true)};
438                LogUtils.access(java.util.logging.Level.FINER, 
439                    LogUtils.ASSERTION_CREATED, data);
440            } else {
441                String[] data = {SAMLUtils.bundle.getString("assertionCreated"),
442                    assertion.getAssertionID()};
443                LogUtils.access(java.util.logging.Level.INFO, 
444                    LogUtils.ASSERTION_CREATED, data);
445            }
446        } else {
447            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
448                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ASSERTIONS,
449                    FedMonSAML1Svc.CHIT);
450            }
451            String preArtString = entry.getArtifactString();
452            if (preArtString != null) {
453                if ((agent != null) &&
454                    agent.isRunning() &&
455                    (saml1Svc != null))
456                {
457                        saml1Svc.incSAML1Cache(
458                        FedMonSAML1Svc.ARTIFACTS,
459                        FedMonSAML1Svc.CREAD);
460                }
461            
462                if (artEntryMap.containsKey(preArtString)) {
463                    if ((agent != null) &&
464                        agent.isRunning() &&
465                        (saml1Svc != null))
466                    {
467                            saml1Svc.incSAML1Cache(
468                            FedMonSAML1Svc.ARTIFACTS,
469                            FedMonSAML1Svc.CHIT);
470                    }
471                    SAMLUtils.debug.error("AssertionManager.createAssertion"
472                        + "Artifact(Asssertion, String): Artifact exists for "
473                        + "the assertion.");
474                    throw new SAMLResponderException(
475                        SAMLUtils.bundle.getString("errorCreateArtifact"));
476                } else {
477                    if ((agent != null) &&
478                        agent.isRunning() &&
479                        (saml1Svc != null))
480                    {
481                            saml1Svc.incSAML1Cache(
482                            FedMonSAML1Svc.ARTIFACTS,
483                            FedMonSAML1Svc.CMISS);
484                    }
485                }
486            }
487            entry.setDestID(destID);
488            entry.setArtifactString(artString);
489        }
490        // add to artEntry map
491        try {
492            Object oldEntry = null;
493            synchronized (artEntryMap) {
494                oldEntry = artEntryMap.put(artString, new
495                    ArtEntry(aID, System.currentTimeMillis() +
496                    artifactTimeout));
497            }
498            if (oldEntry != null) {
499                artifactTimeoutRunnable.removeElement(artString);
500            }
501            artifactTimeoutRunnable.addElement(artString);
502            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
503                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ARTIFACTS,
504                    FedMonSAML1Svc.CWRITE);
505            }
506        } catch (Exception e) {
507            SAMLUtils.debug.error("AssertionManager.createAssertionArt"
508                    + "fact(Assertion,String): couldn't add artifact to the "
509                    + "artEntryMap", e);
510            throw new SAMLResponderException(
511                SAMLUtils.bundle.getString("errorCreateArtifact"));
512        }
513        String[] data = {SAMLUtils.bundle.getString("assertionArtifactCreated"),
514                         artString, aID};
515        LogUtils.access(java.util.logging.Level.INFO,
516                        LogUtils.ASSERTION_ARTIFACT_CREATED, data);
517        return art;
518    }
519
520    /**
521     * This method gets all valid Assertions managed by this 
522     * <code>AssertionManager</code>.
523     * @param token User's session object which is allowed to get all
524     *     Assertion.
525     * @return A Set of valid Assertion IDs. Each element in the Set is a
526     * String representing an Assertion ID. 
527     * @throws SAMLException If this method can not gets all valid Assertions.
528     * @supported.api
529     */
530    public Set getAssertions(Object token)
531        throws SAMLException
532    {
533        if (token == null) {
534            SAMLUtils.debug.error("AssertionManager.getAssertions(Object"
535                + "): input session is null.");
536            throw new SAMLException(SAMLUtils.bundle.getString("nullInput"));
537        }
538        
539        if (!isSuperUser(token)) {
540            SAMLUtils.debug.error("AssertionManager.getAssertions(Object"
541                + "): Session doesn't have the privilege.");
542            throw new SAMLException(SAMLUtils.bundle.getString("noPrivilege"));
543        }
544        
545        return idEntryMap.keySet();
546    }
547
548    private boolean isSuperUser(Object token) {
549        try {
550            if (sessionProvider == null) {
551                SAMLUtils.debug.error("SessionProvider is null.");
552                return false;
553            }
554            String userID = (String) sessionProvider.getProperty(token, 
555                Constants.UNIVERSAL_IDENTIFIER)[0];
556            if (superUser != null && superUser.length() > 0) {
557                return superUser.equalsIgnoreCase(userID);
558            }
559        } catch (Exception e) {
560            if (SAMLUtils.debug.messageEnabled()) {
561                SAMLUtils.debug.message(
562                    "AssertionManager.isSuperUser:Exception: ", e);
563            }
564        }
565        return false;
566    }
567
568    /**
569     * This method gets the Assertion based on the Assertion ID.
570     * @param id The Assertion ID.
571     * @return An Assertion identified by the Assertion ID.
572     * @throws SAMLException If this method can not get the Assertion.
573     */
574    public Assertion getAssertion(String id)
575        throws SAMLException
576    {
577        if ((id == null) || (id.length() == 0)) {
578            SAMLUtils.debug.error("AssertionManager.getAssetion(String): "
579                        + "id is null.");
580            throw new SAMLException(SAMLUtils.bundle.getString("nullInput"));
581        }
582        AssertionIDReference idRef = new AssertionIDReference(id);
583        return getAssertion(idRef, null, false);
584    }
585
586    /**
587     * This method gets all valid <code>AssertionArtifacts</code>
588     * managed by this <code>AssertionManager</code>.
589     *
590     * @param token User's session object which is allowed to get all
591     *     <code>AssertionArtifacts</code>.
592     * @return A Set of valid <code>AssertionArtifacts</code>. Each element in
593     *     the Set is an <code>AssertionArtifacts</code> object representing
594     *     an artifact.
595     * @throws SAMLException If this method can not gets all valid 
596     *     <code>AssertionArtifacts</code>.
597     * @supported.api
598     */
599    public Set getAssertionArtifacts(Object token)
600        throws SAMLException
601    {
602        if (token == null) {
603            SAMLUtils.debug.error("AssertionManager.getAssertionArtifacts(" + 
604                "Object token): input token is null.");
605            throw new SAMLException(SAMLUtils.bundle.getString("nullInput"));
606        }
607        
608        if (!isSuperUser(token)) {
609            SAMLUtils.debug.error("AssertionManager.getAssertionArtifacts(" + 
610                "Object token): Session doesn't have the privilege.");
611            throw new SAMLException(SAMLUtils.bundle.getString("noPrivilege"));
612        }
613        
614        return artEntryMap.keySet();
615    }
616 
617    /**
618     * Returns Assertion that contains <code>AuthenticationStatement</code>.
619     * @param id The String that contains authentication information which
620     *          is needed to create the assertion. It could be a string
621     *          representation of an id, a cookie, etc.
622     * @param artifact the value to be set in the SubjectConfirmation of the
623     *        <code>AuthenticationStatement</code>. If it's null, 
624     *        <code>SubjectConfirmation</code> is set to bearer.
625     * @param destID A String that is the site the assertion is created for.
626     * @param targetUrl A URL String representing the target site 
627     * @param version The relying party preferred Assertion version number. 
628     * @return Assertion The created Assertion.
629     * @throws SAMLException If the Assertion cannot be created.
630     */
631    public Assertion createSSOAssertion(String id, AssertionArtifact artifact,
632        String destID, String targetUrl, String version)
633        throws SAMLException {
634        return createSSOAssertion(id, artifact, null, null, destID,
635            targetUrl, version);
636    }
637     
638    /**
639     * Returns Assertion that contains <code>AuthenticationStatement</code>.
640     * @param id The String that contains authentication information which
641     *          is needed to create the assertion. It could be a string
642     *          representation of an id, a cookie, etc.
643     * @param artifact the value to be set in the SubjectConfirmation of the
644     *        <code>AuthenticationStatement</code>. If it's null, 
645     *        <code>SubjectConfirmation</code> is set to bearer.
646     * @param request The HttpServletRerquest object of the request.
647     * @param response The HttpServletResponse object.
648     * @param destID A String that is the site the assertion is created for.
649     * @param targetUrl A URL String representing the target site 
650     * @param version The relying party preferred Assertion version number. 
651     * @return Assertion The created Assertion.
652     * @throws SAMLException If the Assertion cannot be created.
653     */
654    public Assertion createSSOAssertion(String id, AssertionArtifact artifact,
655        HttpServletRequest request, HttpServletResponse response,
656        String destID, String targetUrl, String version)
657        throws SAMLException
658    {
659        List attributes = null;
660        Map partnerURLs = (Map) SAMLServiceManager.getAttribute(
661                                        SAMLConstants.PARTNER_URLS);
662        SAMLServiceManager.SOAPEntry partnerEntry = 
663                (SAMLServiceManager.SOAPEntry)partnerURLs.get(destID);
664
665        if (partnerEntry != null) {
666            try {
667                if (sessionProvider == null) {
668                    throw new SAMLException(SAMLUtils.bundle.getString(
669                        "nullSessionProvider"));
670                }    
671                Object userSession = sessionProvider.getSession(id);   
672                ConsumerSiteAttributeMapper cMapper =
673                    partnerEntry.getConsumerSiteAttributeMapper();
674                if (cMapper != null) {
675                    attributes = cMapper.getAttributes(userSession,
676                        request, response, targetUrl);
677                } else {
678                    PartnerSiteAttributeMapper pMapper =
679                        partnerEntry.getPartnerSiteAttributeMapper();
680                    if (pMapper != null) {
681                        attributes = pMapper.getAttributes(
682                            userSession, targetUrl);
683                    } else {
684                        SiteAttributeMapper mapper =
685                            partnerEntry.getSiteAttributeMapper();
686                        if (mapper != null) {
687                            attributes = mapper.getAttributes(userSession);
688                        }
689                    }
690                }
691            } catch ( SessionException ssoe) {
692                SAMLUtils.debug.error("AssertionManager.createAssertion(id):"
693                    + " exception retrieving info from the Session", ssoe);
694                return null;
695            }
696        }
697   
698        String nameIDFormat = request.getParameter(
699            SAMLConstants.NAME_ID_FORMAT);
700        if (artifact == null) {
701            // SAML post profile 
702            if (version.equals(SAMLConstants.ASSERTION_VERSION_1_1)) {
703                // set minor version to 1
704                return createAssertion(id, artifact, destID, attributes,
705                     SAMLConstants.CONFIRMATION_METHOD_BEARER, 1, nameIDFormat);
706            } else {
707                // set minor version to 0 
708                return createAssertion(id, artifact, destID, attributes,
709                     SAMLConstants.CONFIRMATION_METHOD_BEARER, 0, nameIDFormat);
710            }
711        } else {
712            if(version == null || version.equals(
713                SAMLConstants.ASSERTION_VERSION_1_0)) {
714                return createAssertion(id, artifact, destID, attributes, 
715                    SAMLConstants.DEPRECATED_CONFIRMATION_METHOD_ARTIFACT, 0,
716                    nameIDFormat); 
717            } else if (version.equals(SAMLConstants.ASSERTION_VERSION_1_1)) { 
718                return createAssertion(id, artifact, destID, attributes, 
719                    SAMLConstants.CONFIRMATION_METHOD_ARTIFACT, 1,
720                    nameIDFormat);
721            } else {
722                SAMLUtils.debug.error("Input version " + version + 
723                                       " is not supported.");
724                return null; 
725            }
726        }
727    }
728
729    private Assertion createAssertion(String id, AssertionArtifact artifact,
730        String destID, List attributes, String confirmationMethod,
731        int minorVersion, String nameIDFormat) throws SAMLException 
732    {
733        // check input
734        if ((id == null) || (id.length() == 0)) {
735            if (SAMLUtils.debug.messageEnabled()) {
736                SAMLUtils.debug.message("AssertionManager.createAssertion(id):"
737                        + "null input.");
738            }
739            throw new SAMLException(SAMLUtils.bundle.getString("nullInput"));
740        }
741        validateNumberOfAssertions(idEntryMap);
742        String authMethod = null;
743        Date authInstant = null;
744        Object token = null;
745        String clientIP = null;
746        try {
747            if (sessionProvider == null) {
748                throw new SAMLException(SAMLUtils.bundle.getString(
749                    "nullSessionProvider"));
750            }
751            token = sessionProvider.getSession(id);
752            authMethod = (String) sessionProvider.getProperty(
753                token, SessionProvider.AUTH_METHOD)[0];
754            String authSSOInstant = (String)
755                sessionProvider.getProperty(token,"authInstant")[0]; 
756            if (authSSOInstant == null || authSSOInstant.equals("")) {
757                authInstant = new Date();
758            } else {
759                authInstant = DateUtils.stringToDate(authSSOInstant);
760            }                
761
762            try {
763                InetAddress clientIPAddress =
764                    InetAddress.getByName(sessionProvider.getProperty(
765                    token,"Host")[0]);
766                clientIP = clientIPAddress.getHostAddress();
767            } catch (Exception e) {
768                // catching exception here since client ip is optional
769                if (SAMLUtils.debug.messageEnabled()) {
770                    SAMLUtils.debug.message("AssertionManager." + 
771                        "createAssertion(id):" +
772                        "exception when obtaining client ip: ", e);
773                }
774            }
775        } catch (Exception e) {
776            SAMLUtils.debug.error("AssertionManager." +
777                "createAssertion(id):" +
778                " exception retrieving info from the Session: ", e);
779            return null;
780        }
781
782        Map partnerURLs =
783            (Map) SAMLServiceManager.getAttribute(SAMLConstants.PARTNER_URLS);
784        SAMLServiceManager.SOAPEntry partnerEntry =
785            (SAMLServiceManager.SOAPEntry)partnerURLs.get(destID);
786
787        NameIdentifierMapper niMapper = null;
788        if (partnerEntry != null) {
789            niMapper = partnerEntry.getNameIdentifierMapper();
790        }
791        if (niMapper == null) {
792            niMapper = new DefaultNameIdentifierMapper();
793        }
794
795        String srcID =
796            (String)SAMLServiceManager.getAttribute(SAMLConstants.SITE_ID);
797
798        NameIdentifier ni = niMapper.getNameIdentifier(token, srcID, destID, nameIDFormat);
799        if (ni == null) {
800            SAMLUtils.debug.error("AssertionManager.createAssertion(id): " +
801                                  "name identifier is null.");
802            return null;
803        }
804
805        SubjectConfirmation subConfirmation = null;
806        String artString = null;
807        if ((confirmationMethod != null) && (confirmationMethod.length() > 0)) {
808            subConfirmation = new SubjectConfirmation(confirmationMethod);
809        } else {
810            if (artifact != null) {
811                if (minorVersion == 0) {
812                    // set default for SAML Artifact profile 
813                    // here, we use SAML 1.0 confirmation method as default.
814                    confirmationMethod = 
815                        SAMLConstants.DEPRECATED_CONFIRMATION_METHOD_ARTIFACT;
816                } else {
817                    confirmationMethod = 
818                        SAMLConstants.CONFIRMATION_METHOD_ARTIFACT;
819                }
820                subConfirmation = new SubjectConfirmation(confirmationMethod);
821            } else {
822                // set to bearer for POST profile
823                subConfirmation = new SubjectConfirmation(
824                                SAMLConstants.CONFIRMATION_METHOD_BEARER);
825            }
826        }
827
828        if (artifact != null) { 
829            artString = artifact.getAssertionArtifact(); 
830        }
831        Subject sub = new Subject(ni, subConfirmation);
832        SubjectLocality subjLocality = null;
833        if ((clientIP != null) && (clientIP.length() != 0)) {
834            subjLocality = new SubjectLocality(clientIP, null);
835        }
836        Set statements = new HashSet();
837        statements.add(new AuthenticationStatement(authMethod, authInstant,
838                        sub, subjLocality, null));
839
840        if ((attributes != null) && (!attributes.isEmpty())) {
841            statements.add(new AttributeStatement(sub, attributes));
842        }
843        Date issueInstant = new Date();
844        Date notBefore = new Date(issueInstant.getTime() - notBeforeSkew);
845        // TODO: this period will be different for bearer
846        Date notAfter = new Date(issueInstant.getTime() + assertionTimeout);
847        Conditions cond = new Conditions(notBefore, notAfter);
848        String issuer = (String) SAMLServiceManager.getAttribute(
849                                        SAMLConstants.ISSUER_NAME);
850        Assertion assertion = new Assertion(null, issuer, issueInstant, cond,
851                                        statements);
852        assertion.setMinorVersion(minorVersion);
853        String aIDString = assertion.getAssertionID();
854
855        // TODO:set AuthorityBinding if any
856
857        if (((Boolean) SAMLServiceManager.getAttribute(
858                SAMLConstants.SIGN_ASSERTION)).booleanValue())
859        {
860            assertion.signXML();
861        }
862
863        Entry entry = new Entry(assertion, destID, artString, token);
864        try {
865            Object oldEntry = null;
866            synchronized (idEntryMap) {
867                oldEntry = idEntryMap.put(aIDString, entry);
868            }
869            if (oldEntry != null) {
870                assertionTimeoutRunnable.removeElement(aIDString);
871            }
872            assertionTimeoutRunnable.addElement(aIDString);
873            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
874                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ASSERTIONS,
875                    FedMonSAML1Svc.CWRITE);
876            }
877        } catch (Exception e) {
878            if (SAMLUtils.debug.messageEnabled()) {
879                SAMLUtils.debug.message("AssertionManager: couldn't add "
880                        + "to idEntryMap.", e);
881            }
882            throw new SAMLResponderException(
883                    SAMLUtils.bundle.getString("errorCreateAssertion"));
884        }
885
886        if (LogUtils.isAccessLoggable(java.util.logging.Level.FINER)) {
887            String[] data = { SAMLUtils.bundle.getString("assertionCreated"),
888                assertion.toString(true, true)};
889            LogUtils.access(java.util.logging.Level.FINER,
890                LogUtils.ASSERTION_CREATED, data);
891        } else {
892            String[] data = { SAMLUtils.bundle.getString("assertionCreated"),
893                aIDString};
894            LogUtils.access(java.util.logging.Level.INFO,
895                LogUtils.ASSERTION_CREATED, data);
896        }
897
898        if (artString != null) {
899            // put artifact in artEntryMap
900            try {
901                Object oldEntry = null;
902                synchronized (artEntryMap) {
903                    oldEntry = artEntryMap.put(artString, new
904                        ArtEntry(aIDString,
905                        (System.currentTimeMillis() + artifactTimeout)));
906                }
907                if (oldEntry != null) {
908                    artifactTimeoutRunnable.removeElement(artString);
909                }
910                artifactTimeoutRunnable.addElement(artString);
911                if ((agent != null) && agent.isRunning() && (saml1Svc != null)){
912                        saml1Svc.incSAML1Cache(
913                        FedMonSAML1Svc.ARTIFACTS,
914                        FedMonSAML1Svc.CWRITE);
915                }
916            } catch (Exception e) {
917                if (SAMLUtils.debug.messageEnabled()) {
918                    SAMLUtils.debug.message("AssertionManager: couldn't add "
919                        + "artifact to the artEntryMap.", e);
920                }
921                throw new SAMLResponderException(
922                    SAMLUtils.bundle.getString("errorCreateArtifact"));
923            }
924            String[] data = {SAMLUtils.bundle.getString(
925                  "assertionArtifactCreated"), artString, aIDString};
926            LogUtils.access(java.util.logging.Level.INFO,
927                        LogUtils.ASSERTION_ARTIFACT_CREATED, data);
928        }
929
930        if (token != null) {
931            // create a listener and add the listener to the token
932            AssertionSSOTokenListener listener = new AssertionSSOTokenListener(
933                aIDString, artString);
934            try {
935                sessionProvider.addListener(token, listener);
936            } catch (SessionException e) {
937                SAMLUtils.debug.error("AssertionManager.createAssertion(id):"
938                    + " Couldn't add listener to session:", e);
939            } catch (UnsupportedOperationException uoe) {
940                SAMLUtils.debug.warning("AssertionManager.createAssertion(id):"
941                    + " Operation add listener to session not supported:",
942                    uoe);
943            }
944        }
945
946        return assertion;
947    }
948
949    /**
950     * Deletes an assertion from the server. This method is used by the
951     * AssertionSSOTokenListener and cleanup method in the package.
952     * @param assertionID the id of the Assertion to be deleted.
953     * @param artifact the artifact associated with this assertionID.
954     *          When it's null, no artifact is associated with this assertionID.
955     */ 
956    void deleteAssertion(String assertionID, String artifact) {
957        ArtEntry artEntry = null;
958        if (artifact != null) {
959            // this is the case when Session expired, and the assertion
960            // was created for artifact
961            artEntry = (ArtEntry) artEntryMap.remove(artifact);
962            String[] data = {SAMLUtils.bundle.getString(
963                "assertionArtifactRemoved"), artifact};
964            LogUtils.access(java.util.logging.Level.FINE, 
965                LogUtils.ASSERTION_ARTIFACT_REMOVED, data);
966        }
967
968        if (assertionID != null) {
969            Entry entry = null;
970            entry = (Entry) idEntryMap.remove(assertionID);
971            if (entry != null) {
972                String[] data = {SAMLUtils.bundle.getString("assertionRemoved"),
973                    assertionID};
974                LogUtils.access(java.util.logging.Level.FINE,
975                    LogUtils.ASSERTION_REMOVED, data);
976                if (artifact == null) {
977                    // this is the case when assertion expired, check to see
978                    // if the assertion is associated with an artifact
979                    String artString = entry.getArtifactString();
980                    if (artString != null) {
981                        synchronized (artEntryMap) {
982                            artEntryMap.remove(artString);
983                        }
984                        String[] data2 = {SAMLUtils.bundle.getString(
985                            "assertionArtifactRemoved"), artifact};
986                        LogUtils.access(java.util.logging.Level.FINE,
987                            LogUtils.ASSERTION_ARTIFACT_REMOVED, data2);
988                    }
989                }
990            }
991        } else {
992           if ((artEntry != null) && SAMLServiceManager.getRemoveAssertion()) {
993                synchronized (idEntryMap) {
994                    idEntryMap.remove(artEntry.getAssertionID());
995                }
996            }
997        }
998    }
999
1000    /**
1001     * Gets assertion associated with the AssertionArtifact.
1002     * @param artifact An AssertionArtifact.
1003     * @param destID A Set of String that represents the destination site id.
1004     *          The destination site requesting the assertion using
1005     *          the artifact. This String is compared with the destID that
1006     *          the artifact is created for originally.
1007     * @param destCheckFlag true if desire to match the destionation id, 
1008     *                      otherwise it is false. If it is false, destID can 
1009     *                      be any string, including null. 
1010     * @return The Assertion referenced to by artifact.
1011     * @throws SAMLException If an error occurred during the process, or no
1012     *          assertion maps to the input artifact.
1013     */
1014    private Assertion getAssertion(AssertionArtifact artifact, Set destID, 
1015                                  boolean destCheckFlag)
1016                                  throws SAMLException {
1017        if (SAMLUtils.debug.messageEnabled()) {
1018            SAMLUtils.debug.message("getAssertion(arti): destID set= " +
1019                Base64.encode(SAMLUtils.stringToByteArray(
1020                    (String)destID.iterator().next())));
1021        }
1022        // check the destination id; also if this artifact exists
1023        String artString = artifact.getAssertionArtifact();
1024
1025        // get server id.
1026        String remoteUrl = SAMLUtils.getServerURL(
1027                                        artifact.getAssertionHandle());
1028        if (remoteUrl != null) { // not this server
1029            // call AssertionManagerClient.getAssertion
1030            if (SAMLUtils.debug.messageEnabled()) {
1031                SAMLUtils.debug.message("AssertionManager.getAssertion(art, " +
1032                    "destid: calling another server in lb site:" + remoteUrl);
1033            }
1034            AssertionManagerClient amc = new AssertionManagerClient(
1035                                        SAMLUtils.getFullServiceURL(remoteUrl));
1036            return amc.getAssertion(artifact, destID);
1037        } // else 
1038        // get the assertion ID
1039        String aIDString = null;
1040        long timeout = 0;
1041
1042        ArtEntry artEntry = (ArtEntry) artEntryMap.get(artString);
1043        if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
1044            saml1Svc.incSAML1Cache(FedMonSAML1Svc.ARTIFACTS,
1045                FedMonSAML1Svc.CREAD);
1046        }
1047        if (artEntry == null) {
1048            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
1049                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ARTIFACTS,
1050                    FedMonSAML1Svc.CMISS);
1051            }
1052            if (SAMLUtils.debug.messageEnabled()) {
1053                SAMLUtils.debug.message("AssertionManager.getAssertion(art, de"
1054                    + "stid): no Assertion found corresponding to artifact.");
1055            }
1056            throw new SAMLException(
1057                    SAMLUtils.bundle.getString("noMatchingAssertion"));
1058        } else {
1059            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
1060                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ARTIFACTS,
1061                    FedMonSAML1Svc.CHIT);
1062            }
1063        }
1064        aIDString = (String) artEntry.getAssertionID();
1065        if (aIDString == null) {
1066            if (SAMLUtils.debug.messageEnabled()) {
1067                SAMLUtils.debug.message("AssertionManager.getAssertion(art, de"
1068                + "stid): no AssertionID found corresponding to artifact.");
1069            }
1070            throw new SAMLException(
1071                SAMLUtils.bundle.getString("noMatchingAssertion"));
1072        }
1073
1074        timeout = artEntry.getExpireTime();
1075        if (System.currentTimeMillis() > timeout) {
1076            if (SAMLUtils.debug.messageEnabled()) {
1077                SAMLUtils.debug.message("AssertionManager.getAssertion(art, "
1078                    + "destid): artifact timed out.");
1079            }
1080            throw new SAMLException(
1081                SAMLUtils.bundle.getString("artifactTimedOut"));
1082        }
1083
1084        Entry entry = null;
1085        entry = (Entry) idEntryMap.get(aIDString);
1086        if (entry == null) {
1087            if (SAMLUtils.debug.messageEnabled()) {
1088                SAMLUtils.debug.message("AssertionManager.getAssertion(art, de"
1089                   + "stid): no Entry found corresponding to artifact.");
1090            }
1091            throw new SAMLException(
1092                SAMLUtils.bundle.getString("noMatchingAssertion"));
1093        }
1094
1095        if (destCheckFlag) {
1096            // check the destination id
1097            String dest = entry.getDestID();
1098            if (dest == null) {
1099                if (SAMLUtils.debug.messageEnabled()) {
1100                    SAMLUtils.debug.message("AssertionManager.getAssertion(" + 
1101                    "art, destid): no destID found corresponding to artifact.");
1102                }
1103                throw new SAMLException(
1104                    SAMLUtils.bundle.getString("noDestIDMatchingArtifact"));
1105            }
1106            if (destID == null || !destID.contains(dest)) {
1107                if (SAMLUtils.debug.messageEnabled()) {
1108                    SAMLUtils.debug.message("AssertionManager.getAssertion(art"+
1109                                    ", destid): destinationID doesn't match.");
1110                }
1111                throw new SAMLException(
1112                    SAMLUtils.bundle.getString("destIDNotMatch"));
1113            }
1114        }
1115        Assertion assertion = entry.getAssertion();
1116        if (assertion == null) {
1117            if (SAMLUtils.debug.messageEnabled()) {
1118                SAMLUtils.debug.message("AssertionManager.getAssertion(art, de"
1119                    + "stid): no Assertion found corresponding to aID.");
1120            }
1121            throw new SAMLException(
1122                SAMLUtils.bundle.getString("noMatchingAssertion"));
1123        }
1124        
1125        // remove the asssertion from artEntryMap
1126        synchronized (artEntryMap) {
1127            artEntryMap.remove(artString);
1128        }
1129        artifactTimeoutRunnable.removeElement(artString);
1130        String[] data = {SAMLUtils.bundle.getString(
1131            "assertionArtifactVerified"), artString};
1132        LogUtils.access(java.util.logging.Level.INFO,
1133            LogUtils.ASSERTION_ARTIFACT_VERIFIED, data);
1134
1135        if (SAMLServiceManager.getRemoveAssertion()) {
1136            synchronized(idEntryMap) {
1137                idEntryMap.remove(aIDString);
1138            }
1139            assertionTimeoutRunnable.removeElement(aIDString);
1140        }
1141        
1142        // check the time of the assertion
1143        if (!assertion.isTimeValid()) {
1144            if (SAMLUtils.debug.messageEnabled()) {
1145                SAMLUtils.debug.message("AssertionManager: assertion "
1146                        + aIDString + " is expired.");
1147            }
1148            throw new SAMLException(
1149                        SAMLUtils.bundle.getString("assertionTimeNotValid"));
1150        }
1151        return assertion;
1152    }
1153    
1154    /**
1155     * Gets assertion associated with the AssertionArtifact.
1156     * @param artifact An AssertionArtifact.
1157     * @param destID The destination site requesting the assertion using
1158     *          the artifact. This String is compared with the destID that
1159     *          the artifact is created for originally.
1160     * @return The Assertion referenced to by artifact.
1161     * @throws SAMLException If an error occurred during the process, or no
1162     *          assertion maps to the input artifact.
1163     */
1164    public Assertion getAssertion(AssertionArtifact artifact, String destID)
1165                                 throws SAMLException {
1166        if ((artifact == null) || destID == null || destID.length() == 0) {
1167            if (SAMLUtils.debug.messageEnabled()) {
1168                SAMLUtils.debug.message("AssertionManager: input is null.");
1169            }
1170            throw new SAMLRequesterException(
1171                SAMLUtils.bundle.getString("nullInput"));
1172        }
1173        Set destSet = new HashSet();
1174        destSet.add(destID);
1175        return getAssertion(artifact, destSet, true); 
1176    }
1177    
1178     /**
1179     * Gets assertion associated with the AssertionArtifact.
1180     * @param artifact An AssertionArtifact.
1181     * @param destID A Set of String that represents the destination site id. 
1182     *          The destination site requesting the assertion using
1183     *          the artifact. Each string in this set compares with the destID 
1184     *          that the artifact is created for originally. If found match, 
1185     *          continue the operation. Otherwise, throws error.     
1186     * @return The Assertion referenced to by artifact.
1187     * @throws SAMLException If an error occurred during the process, or no
1188     *          assertion maps to the input artifact.
1189     */
1190    public Assertion getAssertion(AssertionArtifact artifact, Set destID)
1191                                 throws SAMLException {
1192        if ((artifact == null) || destID == null || destID.isEmpty()) {
1193            if (SAMLUtils.debug.messageEnabled()) {
1194                SAMLUtils.debug.message("AssertionManager: input is null.");
1195            }
1196            throw new SAMLRequesterException(
1197                SAMLUtils.bundle.getString("nullInput"));
1198        }
1199        return getAssertion(artifact, destID, true); 
1200    }
1201    
1202    /**
1203     * Gets assertion associated with the AssertionArtifact.
1204     * @param artifact An AssertionArtifact.
1205     * @return The Assertion referenced to by artifact.
1206     * @throws SAMLException If an error occurred during the process, or no
1207     *          assertion maps to the input artifact.
1208     */
1209    protected  Assertion getAssertion(AssertionArtifact artifact)
1210                                throws SAMLException {
1211        if ((artifact == null)) {
1212            if (SAMLUtils.debug.messageEnabled()) {
1213                SAMLUtils.debug.message("AssertionManager: input is null.");
1214            }
1215            throw new SAMLRequesterException(
1216                SAMLUtils.bundle.getString("nullInput"));
1217        }
1218        return getAssertion(artifact, null, false);
1219    }
1220    
1221    /**
1222     * Gets assertion created from the query.
1223     * @param query An Assertion Query.
1224     * @param destID to whom the assertion will be created for.
1225     * @return The Assertion that is created from the query.
1226     * @throws SAMLException If the Assertion cannot be created due to an 
1227     *          error in the query or in the receiver.
1228     */
1229    public Assertion getAssertion(Query query, String destID)
1230                                throws SAMLException {
1231        if (query == null) {
1232            if (SAMLUtils.debug.messageEnabled()) {
1233                SAMLUtils.debug.message("AssertionManager.getAssertion: input"
1234                                        + " query is null.");
1235            }
1236            throw new SAMLRequesterException(
1237                        SAMLUtils.bundle.getString("nullInput"));
1238        }
1239
1240        Assertion result = null;
1241        int queryType = query.getQueryType();
1242        if (queryType == Query.AUTHENTICATION_QUERY) {
1243            result = getAuthenticationAssertion((AuthenticationQuery)query,
1244                                                destID);
1245        } else if (queryType == Query.AUTHORIZATION_DECISION_QUERY) {
1246            result = getAuthorizationDecisionAssertion(
1247                        (AuthorizationDecisionQuery)query, destID);
1248        } else if (queryType == Query.ATTRIBUTE_QUERY) {
1249            result = getAttributeAssertion((AttributeQuery)query, destID);
1250        } else {
1251            if (SAMLUtils.debug.messageEnabled()) {
1252                SAMLUtils.debug.message("AssertionManager.getAssertion: this "
1253                    + "type of query is not supported:" + queryType);
1254            }
1255            throw new SAMLRequesterException(
1256                        SAMLUtils.bundle.getString("queryNotSupported"));
1257        }
1258        return result;
1259    }
1260
1261    /**
1262     * Gets assertion created from an AttributeQuery.
1263     * @param query An AttributeQuery.
1264     * @param destID to whom the assertion will be created for. Currently,
1265     *        it is the <code>sourceID</code> of the site that sends the query.
1266     * @return The Assertion that is created from the query.
1267     * @throws SAMLException If the Assertion cannot be created.
1268     */
1269    private Assertion getAttributeAssertion(AttributeQuery query, String destID)
1270                                        throws SAMLException
1271    {
1272        if (query == null) {
1273            // no need to log the error again
1274            return null;
1275        }
1276
1277        if ((destID == null) || (destID.length() == 0)) {
1278            if (SAMLUtils.debug.messageEnabled()) {
1279                SAMLUtils.debug.message("AssertionManager.getAttributeAssertion"
1280                        + ": missing destID.");
1281            }
1282            throw new SAMLException(
1283                        SAMLUtils.bundle.getString("missingDestID"));
1284        }
1285        validateNumberOfAssertions(idEntryMap);
1286        Map entries = (Map) SAMLServiceManager.getAttribute(
1287                                        SAMLConstants.PARTNER_URLS);
1288        if (entries == null) {
1289            if (SAMLUtils.debug.messageEnabled()) {
1290                SAMLUtils.debug.message("AssertionManager.getAttributeAssertion"
1291                    + ": empty partner URL list.");
1292            }
1293            throw new SAMLException(
1294                        SAMLUtils.bundle.getString("emptyPartnerURLList"));
1295        }
1296
1297        SAMLServiceManager.SOAPEntry destSite = (SAMLServiceManager.SOAPEntry)
1298                                        entries.get(destID);
1299        AttributeMapper attrMapper = null;
1300        if ((destSite == null) ||
1301            ((attrMapper = destSite.getAttributeMapper()) == null))
1302        {
1303            if (SAMLUtils.debug.messageEnabled()) {
1304                SAMLUtils.debug.message("AssertionManager.getAttributeAssertion"
1305                    + ": couldn't obtain AttributeMapper.");
1306            }
1307            throw new SAMLException(
1308                SAMLUtils.bundle.getString("errorObtainAttributeMapper"));
1309        }
1310
1311        Subject subject = query.getSubject();
1312        String tokenID = attrMapper.getSSOTokenID(query);
1313        Object token = null;
1314        String issuerName = (String) SAMLServiceManager.getAttribute(
1315                                SAMLConstants.ISSUER_NAME);
1316        if (tokenID != null) {
1317            try {
1318                if (sessionProvider == null) {
1319                    throw new SAMLException(SAMLUtils.bundle.getString(
1320                        "nullSessionProvider"));
1321                }
1322                token = sessionProvider.getSession(tokenID);
1323            } catch (Exception e) {
1324                if (SAMLUtils.debug.messageEnabled()) {
1325                    SAMLUtils.debug.message("AssertionManager.getAttribute"
1326                        + "Assertion: invalid SSO token:", e);
1327                }
1328                throw new SAMLException(
1329                    SAMLUtils.bundle.getString("invalidSSOToken"));
1330            }
1331        } else { // token is null
1332            Assertion assertion = attrMapper.getSSOAssertion(query);
1333            if (assertion == null) {
1334                if (SAMLUtils.debug.messageEnabled()) {
1335                    SAMLUtils.debug.message("AssertionManager.getAttribute"
1336                        + "Assertion: couldn't find SSOAssertion in query.");
1337                }
1338                throw new SAMLException(
1339                        SAMLUtils.bundle.getString("noSSOAssertion"));
1340            }
1341            if (!assertion.isSignatureValid()) {
1342                if (SAMLUtils.debug.messageEnabled()) {
1343                    SAMLUtils.debug.message("AssertionManager.getAttribute"
1344                        + "Assertion: SSOAssertion is signature invalid.");
1345                }
1346                throw new SAMLException(
1347                    SAMLUtils.bundle.getString("assertionSignatureNotValid"));
1348            }
1349            if (!assertion.isTimeValid()) {
1350                if (SAMLUtils.debug.messageEnabled()) {
1351                    SAMLUtils.debug.message("AssertionManager.getAttribute"
1352                        + "Assertion: SSOAssertion is time invalid.");
1353                }
1354                throw new SAMLException(
1355                        SAMLUtils.bundle.getString("assertionTimeNotValid"));
1356            }
1357            Iterator iter = assertion.getStatement().iterator();
1358            Statement statement = null;
1359            Subject ssoSubject = null;
1360            while (iter.hasNext()) {
1361                statement = (Statement) iter.next();
1362                if (statement.getStatementType() ==
1363                                Statement.AUTHENTICATION_STATEMENT)
1364                {
1365                    ssoSubject = ((AuthenticationStatement) statement).
1366                                                                getSubject();
1367                    break;
1368                }
1369            }
1370            if (ssoSubject == null) {
1371                if (SAMLUtils.debug.messageEnabled()) {
1372                    SAMLUtils.debug.message("AssertionManager.getAttribute"
1373                            + "Assertion: missing AuthenticationStatement in "
1374                            + "SSOAssertion.");
1375                }
1376                throw new SAMLException(
1377                    SAMLUtils.bundle.getString("noAuthNStatement"));
1378            }
1379            String issuer = assertion.getIssuer();
1380            String aID = assertion.getAssertionID();
1381            if ((issuerName != null) && (issuerName.equals(issuer)) &&
1382                (SAMLUtils.getServerURL(aID) == null))
1383            {
1384                // this server is the issuer
1385                if (SAMLUtils.debug.messageEnabled()) {
1386                    SAMLUtils.debug.message("AssertionManager.getAttrAssertion:"
1387                        + "this server is the issuer.");
1388                }
1389                Entry entry = (Entry) idEntryMap.get(aID);
1390                if ((agent != null) && agent.isRunning() && (saml1Svc != null)){
1391                        saml1Svc.incSAML1Cache(
1392                        FedMonSAML1Svc.ASSERTIONS,
1393                        FedMonSAML1Svc.CREAD);
1394                }
1395                if (entry != null) {
1396                    token = entry.getSSOToken();
1397                    if (token != null) {
1398                        verifySSOTokenAndNI(token,
1399                                        ssoSubject.getNameIdentifier());
1400                    }
1401                    if ((agent != null) &&
1402                        agent.isRunning() &&
1403                        (saml1Svc != null))
1404                    {
1405                        saml1Svc.incSAML1Cache(
1406                            FedMonSAML1Svc.ASSERTIONS,
1407                            FedMonSAML1Svc.CHIT);
1408                    }
1409                } else {
1410                    if ((agent != null) &&
1411                        agent.isRunning() &&
1412                        (saml1Svc != null))
1413                    {
1414                        saml1Svc.incSAML1Cache(
1415                            FedMonSAML1Svc.ASSERTIONS,
1416                            FedMonSAML1Svc.CMISS);
1417                    }
1418                }
1419            } else { // this machine is not the issuer
1420                if (SAMLUtils.debug.messageEnabled()) {
1421                    SAMLUtils.debug.message("AssertionManager.getAttrAssertion:"
1422                        + "this server is not the issuer.");
1423                }
1424                token = checkAssertionAndCreateSSOToken(assertion, null,
1425                                                        ssoSubject);
1426            }
1427        }
1428
1429        // get here then got a valid token
1430        List attributes = attrMapper.getAttributes(query, destID, token);
1431        if ((attributes == null) || (attributes.size() == 0)) {
1432            return null;
1433        }
1434
1435        Set stmtSet = new HashSet();
1436        stmtSet.add(new AttributeStatement(subject, attributes));
1437        Date issueInstant = new Date();
1438        Date notBefore = new Date(issueInstant.getTime() - notBeforeSkew);
1439        Date notAfter = new Date(issueInstant.getTime() + assertionTimeout);
1440        Conditions cond = new Conditions(notBefore, notAfter);
1441        Assertion newAssertion = new Assertion(null, issuerName, issueInstant,
1442                                        cond, stmtSet);
1443        if (((Boolean) SAMLServiceManager.getAttribute(
1444                SAMLConstants.SIGN_ASSERTION)).booleanValue())
1445        {
1446            newAssertion.signXML();
1447        }
1448        String aIDString = newAssertion.getAssertionID();
1449        // don't save the token and don't add listener 
1450        Entry newEntry = new Entry(newAssertion, destID, null, null);
1451
1452        // add newEntry to idEntryMap
1453        try {
1454            Object oldEntry = null;
1455            synchronized (idEntryMap) {
1456                oldEntry = idEntryMap.put(aIDString, newEntry);
1457            }
1458            if (oldEntry != null) {
1459                assertionTimeoutRunnable.removeElement(aIDString);
1460            }
1461            assertionTimeoutRunnable.addElement(aIDString);
1462            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
1463                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ASSERTIONS,
1464                    FedMonSAML1Svc.CWRITE);
1465            }
1466        } catch (Exception e) {
1467            if (SAMLUtils.debug.messageEnabled()) {
1468                SAMLUtils.debug.message("AssertionManager.getAttributeAssertion"
1469                    + " couldn't add assertion to the idEntryMap.", e);
1470            }
1471        }
1472
1473        if (LogUtils.isAccessLoggable(java.util.logging.Level.FINER)) {
1474            String[] data = { SAMLUtils.bundle.getString("assertionCreated"),
1475                              newAssertion.toString(true, true)};
1476            LogUtils.access(java.util.logging.Level.FINER,
1477                    LogUtils.ASSERTION_CREATED, data);
1478        } else {
1479            String[] data = { SAMLUtils.bundle.getString("assertionCreated"),
1480                              aIDString};
1481            LogUtils.access(java.util.logging.Level.INFO,
1482                    LogUtils.ASSERTION_CREATED, data);
1483        }
1484
1485        return newAssertion;
1486    }
1487
1488    /**
1489     * Gets assertion created from an AuthenticationQuery.
1490     * @param query An AuthenticationQuery.
1491     * @param destID to whom the assertion will be created for.
1492     * @return The Assertion that is created from the query.
1493     * @throws SAMLException If the Assertion cannot be created.
1494     */
1495    private Assertion getAuthenticationAssertion(
1496                AuthenticationQuery query, String destID) throws SAMLException
1497    {
1498        if (query == null) {
1499            // no need to log the error again
1500            return null;
1501        }
1502        validateNumberOfAssertions(idEntryMap);
1503
1504        // get the subject of the query
1505        Subject subject = query.getSubject();
1506
1507        // get SubjectConfirmation
1508        SubjectConfirmation sc = subject.getSubjectConfirmation();
1509        if (sc == null) {
1510            if (SAMLUtils.debug.messageEnabled()) {
1511                SAMLUtils.debug.message("AssertionManager.getAuthNAssertion:"
1512                    + " missing SubjectConfirmation.");
1513            }
1514            // since we couldn't find the SSOToken in SubjectConfirmationData
1515            // we don't know if the subject is authenticated to OpenAM.
1516            throw new SAMLException(
1517                SAMLUtils.bundle.getString("missingSubjectConfirmation"));
1518        }
1519        // check ConfirmationMethod
1520        if (!SAMLUtils.isCorrectConfirmationMethod(sc)) {
1521            // don't need to log again
1522            throw new SAMLException(
1523                SAMLUtils.bundle.getString("wrongConfirmationMethodValue"));
1524        }
1525
1526        // get SubjectConfirmationData
1527        Element scData = sc.getSubjectConfirmationData();
1528        if (scData == null) {
1529            if (SAMLUtils.debug.messageEnabled()) {
1530                SAMLUtils.debug.message("AssertionManager.getAuthNAssertion:"
1531                    + " missing SubjectConfirmationData in the Subject.");
1532            }
1533            throw new SAMLException(
1534                SAMLUtils.bundle.getString("missingSubjectConfirmationData"));
1535        }
1536
1537        // SSOTokenID == scData
1538        String authMethod = null;
1539        Date authInstant = null;
1540        String nameQualifier = null;
1541        String name = null;
1542        Object token = null;
1543        String clientIP = null;
1544        try {
1545            if (sessionProvider == null) {
1546                throw new SAMLException(SAMLUtils.bundle.getString(
1547                    "nullSessionProvider"));
1548            } 
1549            token = sessionProvider.getSession(
1550                XMLUtils.getElementString(scData));
1551            authMethod = SAMLServiceManager.getAuthMethodURI(
1552               sessionProvider.getProperty(token, "AuthType")[0]);
1553            // get authenticationInstant
1554            authInstant = DateUtils.stringToDate(
1555               sessionProvider.getProperty(token, "authInstant")[0]);
1556            // get the nameQualifier of the NameIdentifier
1557            nameQualifier = XMLUtils.escapeSpecialCharacters(
1558               sessionProvider.getProperty(token, "Organization")[0]);          
1559            // get the name of the NameIdentifier
1560            name = XMLUtils.escapeSpecialCharacters(
1561               sessionProvider.getPrincipalName(token));      
1562            try {
1563                InetAddress clientIPAddress = 
1564                    InetAddress.getByName(sessionProvider.getProperty(
1565                    token,"ipaddress")[0]);
1566                clientIP = clientIPAddress.getHostAddress();
1567            } catch (Exception e) {
1568                // catching exception here since clientIP is optional
1569                if (SAMLUtils.debug.messageEnabled()) {
1570                    SAMLUtils.debug.message("AssertionManager." +
1571                        "getAuthNAssertion: exception when getting " +
1572                        "client ip.");
1573                }
1574            }
1575        } catch (Exception e) {
1576            if (SAMLUtils.debug.messageEnabled()) {
1577                SAMLUtils.debug.message("AssertionManager.getAuthNAssertion:"
1578                    + " exception retrieving info from the SSOToken:", e);
1579            }
1580            throw new SAMLException(
1581                SAMLUtils.bundle.getString("wrongSubjectConfirmationData"));
1582        }
1583
1584        // get and check NameIdentifier
1585        NameIdentifier ni = subject.getNameIdentifier();
1586        if (ni != null) {
1587            String niName = ni.getName();
1588            String niNameQualifier = ni.getNameQualifier();
1589            if (((niName != null) && (!niName.equalsIgnoreCase(name))) ||
1590                ((niNameQualifier != null) &&
1591                (!niNameQualifier.equalsIgnoreCase(nameQualifier))))
1592            {
1593                if (SAMLUtils.debug.messageEnabled()) {
1594                    SAMLUtils.debug.message("AssertionManager.getAuthNAssertion"
1595                        + ": NameIdentifier is different from info in "
1596                        + "SubjectConfirmation");
1597                }
1598                throw new SAMLException(
1599                    SAMLUtils.bundle.getString("wrongNameIdentifier"));
1600            }
1601        }
1602
1603        // get and check AuthenticationMethod in the query
1604        String am = query.getAuthenticationMethod();
1605        // check it against authMethod
1606        if ((am != null) && (am.length() != 0) &&
1607            (!am.equalsIgnoreCase(authMethod)))
1608        {
1609            if (SAMLUtils.debug.messageEnabled()) {
1610                SAMLUtils.debug.message("AssertionManager.getAuthNAssertion:"
1611                    + " couldn't form an assertion matching the "
1612                    + "AuthenticationMethod in the query.");
1613            }
1614            throw new SAMLException(SAMLUtils.bundle.getString(
1615                "authenticationMethodInQueryNotMatch"));
1616        }
1617        SubjectLocality subjLocality = null;
1618        if ((clientIP != null) && (clientIP.length() != 0)) {
1619            subjLocality = new SubjectLocality(clientIP, null);
1620        }
1621        AuthenticationStatement statement =
1622            new AuthenticationStatement(authMethod, authInstant, subject,
1623                subjLocality, null);
1624        Date issueInstant = new Date();
1625        // get this period from the config
1626        Date notAfter = new Date(issueInstant.getTime() + assertionTimeout);
1627        Date notBefore = new Date(issueInstant.getTime() - notBeforeSkew);
1628        Conditions cond = new Conditions(notBefore, notAfter);
1629        String issuer = (String) SAMLServiceManager.getAttribute(
1630                                SAMLConstants.ISSUER_NAME);
1631        Set statements = new HashSet();
1632        statements.add(statement);
1633        Assertion assertion = new Assertion(null, issuer, issueInstant, cond,
1634                                                statements);
1635        if (((Boolean) SAMLServiceManager.getAttribute(
1636                SAMLConstants.SIGN_ASSERTION)).booleanValue())
1637        {
1638            assertion.signXML();
1639        }
1640        String aIDString = assertion.getAssertionID();
1641
1642        Entry entry = new Entry(assertion, destID, null, token);
1643
1644        // add entry to idEntryMap
1645        try {
1646            Object oldEntry = null;
1647            synchronized (idEntryMap) {
1648                oldEntry = idEntryMap.put(aIDString, entry);
1649            }
1650            if (oldEntry != null) {
1651                assertionTimeoutRunnable.removeElement(aIDString);
1652            }
1653            assertionTimeoutRunnable.addElement(aIDString);
1654            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
1655                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ASSERTIONS,
1656                    FedMonSAML1Svc.CWRITE);
1657            }
1658        } catch (Exception e) {
1659            if (SAMLUtils.debug.messageEnabled()) {
1660                SAMLUtils.debug.message("AssertionManager.getAuthNAssertion:"
1661                    + " couldn't add assertion to the idEntryMap.", e);
1662            }
1663            throw new SAMLResponderException(
1664                SAMLUtils.bundle.getString("errorCreateAssertion"));
1665        }
1666
1667        if (LogUtils.isAccessLoggable(java.util.logging.Level.FINER)) {
1668            String[] data = { SAMLUtils.bundle.getString("assertionCreated"),
1669                              assertion.toString(true, true)};
1670            LogUtils.access(java.util.logging.Level.FINER,
1671                    LogUtils.ASSERTION_CREATED, data);
1672        } else {
1673            String[] data = { SAMLUtils.bundle.getString("assertionCreated"),
1674                              aIDString};
1675            LogUtils.access(java.util.logging.Level.INFO,
1676                    LogUtils.ASSERTION_CREATED, data);
1677        }
1678
1679        // create a listener and add the listener to the token
1680        AssertionSSOTokenListener listener =
1681            new AssertionSSOTokenListener(aIDString);
1682        try {
1683            sessionProvider.addListener(token, listener);
1684        } catch (SessionException e)  {
1685            SAMLUtils.debug.error("AssertionManager.getAuthNAssertion:"
1686                + " Couldn't add listener to token:", e);
1687            // don't need to throw an exception
1688        }
1689
1690        return assertion;
1691    }
1692
1693    /**
1694     * Gets assertion created from an AuthorizationDecisionQuery.
1695     * @param query An AuthorizationDecisionQuery.
1696     * @param destID to whom the assertion will be created for.
1697     * @return The Assertion that is created from the query.
1698     * @throws SAMLException If the Assertion cannot be created.
1699     */
1700    private Assertion getAuthorizationDecisionAssertion(
1701                AuthorizationDecisionQuery query, String destID)
1702                throws SAMLException
1703    {
1704        return getAuthorizationDecisionAssertion(query, destID, true);
1705    }
1706
1707    /**
1708     * Gets assertion created from an AuthorizationDecisionQuery.
1709     * @param query An AuthorizationDecisionQuery.
1710     * @param destID to whom the assertion will be created for.
1711     * @param store if true, the assertion is stored internally.
1712     * @return The Assertion that is created from the query.
1713     * @throws SAMLException If the Assertion cannot be created.
1714     */
1715    private Assertion getAuthorizationDecisionAssertion(
1716                AuthorizationDecisionQuery query, String destID, boolean store)
1717                throws SAMLException
1718    {
1719        if (query == null) {
1720            // no need to log the error again
1721            return null;
1722        }
1723
1724        if ((destID == null) || (destID.length() == 0)) {
1725            if (SAMLUtils.debug.messageEnabled()) {
1726                SAMLUtils.debug.message("AssertionManager.getAuthZAssertion: "
1727                    + "missing destID.");
1728            }
1729            throw new SAMLException(
1730                SAMLUtils.bundle.getString("missingDestID"));
1731        }
1732
1733        Map entries = (Map) SAMLServiceManager.getAttribute(
1734                        SAMLConstants.PARTNER_URLS);
1735        if (entries == null) {
1736            if (SAMLUtils.debug.messageEnabled()) {
1737                SAMLUtils.debug.message("AssertionManager.getAuthZAssertion: "
1738                    + "empty partnerURL list.");
1739            }
1740            throw new SAMLException(
1741                SAMLUtils.bundle.getString("emptyPartnerURLList"));
1742        }
1743
1744        SAMLServiceManager.SOAPEntry destSite = (SAMLServiceManager.SOAPEntry)
1745                                                entries.get(destID);
1746        ActionMapper actionMapper = null;
1747        if ((destSite == null) ||
1748            ((actionMapper = destSite.getActionMapper()) == null))
1749        {
1750            if (SAMLUtils.debug.messageEnabled()) {
1751                SAMLUtils.debug.message("AssertionManager.getAuthZAssertion: "
1752                    + "couldn't obtain ActionMapper.");
1753            }
1754            throw new SAMLException(
1755                SAMLUtils.bundle.getString("errorObtainActionMapper"));
1756        }
1757
1758        Subject querySubject = query.getSubject();
1759        NameIdentifier queryNI = querySubject.getNameIdentifier();
1760        Object token = null;
1761        boolean existingToken = true;
1762
1763        String tokenID = actionMapper.getSSOTokenID(query);
1764        if (tokenID != null) {
1765            // if there is a token, then the token must be valid
1766            try {
1767                if (sessionProvider == null) {
1768                    throw new SAMLException(SAMLUtils.bundle.getString(
1769                        "nullSessionProvider"));
1770                }
1771                token = sessionProvider.getSession(tokenID);
1772            } catch (Exception e) {
1773                if (SAMLUtils.debug.messageEnabled()) {
1774                    SAMLUtils.debug.message("AssertionManager.getAuthZAssertion"
1775                        + ": invalid SSO token:", e);
1776                }
1777                throw new SAMLException(
1778                    SAMLUtils.bundle.getString("invalidSSOToken"));
1779            }
1780            verifySSOTokenAndNI(token, queryNI);
1781        } else {
1782            Assertion assertion = actionMapper.getSSOAssertion(query, destID);
1783            if (assertion != null) {
1784                // if there is an assertion, then it must be valid
1785                Map tokenMap = verifyAssertionAndGetSSOToken(querySubject,
1786                    assertion);
1787                token = (Object) tokenMap.get("true");
1788                if (token == null){
1789                    existingToken = false;
1790                    token = (Object) tokenMap.get("false");
1791                }
1792            }
1793        }
1794
1795        if (token == null) {
1796            if (SAMLUtils.debug.messageEnabled()) {
1797                SAMLUtils.debug.message("AssertionManager.getAuthZAssertion: "
1798                    + "Couldn't obtain ssotoken.");
1799            }
1800            throw new SAMLException(
1801                SAMLUtils.bundle.getString("cannotVerifySubject"));
1802        }
1803
1804        Map map = actionMapper.getAuthorizationDecisions(query, token, destID);
1805
1806        // no need to invalidate the newly created ssotoken since the token
1807        // will be invalidated/destroyed when the short maxSessionTime and
1808        // maxIdleTime are reached.
1809        return getAuthorizationDecisionAssertion(query, destID, true,
1810                                token, existingToken, map);
1811    }
1812
1813    private Map verifyAssertionAndGetSSOToken(Subject querySubject,
1814                                                Assertion assertion)
1815                                                throws SAMLException
1816    {
1817        if ((querySubject == null) || (assertion == null)) {
1818            if (SAMLUtils.debug.messageEnabled()) {
1819                SAMLUtils.debug.message("AssertionManager.verifyAssertionAnd"
1820                        + "GetSSOToken: null input.");
1821            }
1822            throw new SAMLException(
1823                        SAMLUtils.bundle.getString("cannotVerifySubject"));
1824        }
1825
1826        if (!assertion.isSignatureValid()) {
1827            if (SAMLUtils.debug.messageEnabled()) {
1828                SAMLUtils.debug.message("AssertionManager.verifyAssertionAnd"
1829                    + "GetSSOToken: SSOAssertion is signature invalid.");
1830            }
1831            throw new SAMLException(
1832                SAMLUtils.bundle.getString("assertionSignatureNotValid"));
1833        }
1834        if (!assertion.isTimeValid()) {
1835            if (SAMLUtils.debug.messageEnabled()) {
1836                SAMLUtils.debug.message("AssertionManager.verifyAssertionAnd"
1837                    + "GetSSOToken: SSOAssertion is time invalid.");
1838            }
1839            throw new SAMLException(
1840                SAMLUtils.bundle.getString("assertionTimeNotValid"));
1841        }
1842        
1843        // TODO: check AudienceRestrictionConditions if any
1844
1845        Map tokenMap = new HashMap();
1846        Object token = null;
1847        String issuerName = (String) SAMLServiceManager.getAttribute(
1848                                                SAMLConstants.ISSUER_NAME);
1849        String issuer = assertion.getIssuer();
1850        String aID = assertion.getAssertionID();
1851        if ((issuerName != null) && (issuerName.equals(issuer)) &&
1852            (SAMLUtils.getServerURL(aID) == null))
1853        {
1854            // this server is the issuer
1855            if (SAMLUtils.debug.messageEnabled()) {
1856                SAMLUtils.debug.message("AssertionManager.getAuthZAssertion:"
1857                    + "this server is the issuer.");
1858            }
1859            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
1860                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ASSERTIONS,
1861                    FedMonSAML1Svc.CREAD);
1862            }
1863            Entry entry = (Entry) idEntryMap.get(aID);
1864            if (entry != null) {
1865                if ((agent != null) && agent.isRunning() && (saml1Svc != null)){
1866                        saml1Svc.incSAML1Cache(
1867                        FedMonSAML1Svc.ASSERTIONS,
1868                        FedMonSAML1Svc.CHIT);
1869                }
1870                token = entry.getSSOToken();
1871                if (token != null) {
1872                    verifySSOTokenAndNI(token,
1873                                        querySubject.getNameIdentifier());
1874                    tokenMap.put("true", token);
1875                    return tokenMap;
1876                }
1877            } else {
1878                if ((agent != null) && agent.isRunning() && (saml1Svc != null)){
1879                    saml1Svc.incSAML1Cache(
1880                        FedMonSAML1Svc.ASSERTIONS,
1881                        FedMonSAML1Svc.CMISS);
1882                }
1883            }
1884
1885            if (SAMLUtils.debug.messageEnabled()) {
1886                SAMLUtils.debug.message("AssertionManager.verifyAssertionAnd"
1887                    + "GetSSOToken: either not an AuthN assertion or token "
1888                    + "is not for this subject.");
1889            }
1890            throw new SAMLException(SAMLUtils.bundle.
1891                                        getString("cannotVerifySubject"));
1892        } else { 
1893            if (SAMLUtils.debug.messageEnabled()) {
1894                SAMLUtils.debug.message("AssertionManager.getAuthZAssertion:"
1895                        + "this server is not the issuer.");
1896            }
1897            Iterator iter = assertion.getStatement().iterator();
1898            Statement statement = null;
1899            AuthenticationStatement ssoStatement = null;
1900            while (iter.hasNext()) {
1901                statement = (Statement) iter.next();
1902                if (statement.getStatementType() ==
1903                                Statement.AUTHENTICATION_STATEMENT)
1904                {
1905                    ssoStatement = (AuthenticationStatement) statement;
1906                    break;
1907                }
1908            }
1909            if (ssoStatement == null) {
1910                if (SAMLUtils.debug.messageEnabled()) {
1911                    SAMLUtils.debug.message("AssertionManager.verifyAssertion"
1912                        + "AndGetSSOToken:  missing AuthenticationStatement in "
1913                        + "SSOAssertion.");
1914                }
1915                throw new SAMLException(
1916                    SAMLUtils.bundle.getString("noAuthNStatement"));
1917            }
1918
1919            token = checkAssertionAndCreateSSOToken(assertion,
1920                        (AuthenticationStatement)statement, querySubject);
1921            tokenMap.put("false", token);
1922        }
1923        return tokenMap;
1924    }
1925
1926    private void verifySSOTokenAndNI(Object token, NameIdentifier ni)
1927        throws SAMLException 
1928    {
1929        String name = null;
1930        String nameQualifier = null;
1931        try {
1932            if (sessionProvider == null) {
1933                throw new SAMLException(SAMLUtils.bundle.getString(
1934                    "nullSessionProvider"));
1935            }
1936            name = XMLUtils.escapeSpecialCharacters(
1937                sessionProvider.getPrincipalName(token));
1938            nameQualifier = XMLUtils.escapeSpecialCharacters(
1939                sessionProvider.getProperty(token, "Organization")[0]);
1940        } catch (Exception e) {
1941            if (SAMLUtils.debug.messageEnabled()) {
1942                SAMLUtils.debug.message("AssertionManager.verifySSOTokenAndNI: "
1943                    + "Session is not valid.", e);
1944            }
1945            throw new SAMLException(
1946                SAMLUtils.bundle.getString("cannotVerifySubject"));
1947        }
1948
1949        if (ni == null) {
1950            return;
1951        }
1952
1953        String niName = ni.getName();
1954        String niNameQualifier = ni.getNameQualifier();
1955        if (((niName != null) && (!niName.equalsIgnoreCase(name))) ||
1956            ((niNameQualifier != null) && (!niNameQualifier.
1957                                        equalsIgnoreCase(nameQualifier))))
1958        {
1959            if (SAMLUtils.debug.messageEnabled()) {
1960                SAMLUtils.debug.message("AssertionManager.verifySSOToken"
1961                        + "AndNI: NameIdentifier is different from info in "
1962                        + "token.");
1963            }
1964            throw new SAMLException(SAMLUtils.bundle.
1965                                getString("wrongNameIdentifier"));
1966        }
1967    }
1968
1969    private Object checkAssertionAndCreateSSOToken(Assertion assertion,
1970        AuthenticationStatement statement, Subject subject)
1971        throws SAMLException
1972    {
1973        // check if issuer is on our list.
1974        String issuer = assertion.getIssuer();
1975        SAMLServiceManager.SOAPEntry sourceSite =
1976                                SAMLUtils.getSourceSite(issuer);
1977        if (sourceSite == null) {
1978            if (SAMLUtils.debug.messageEnabled()) {
1979                SAMLUtils.debug.message("AssertionManager.checkAssertionAnd"
1980                    + "CreateSSOToken: issuer is not on the partnerURL list.");
1981            }
1982            throw new SAMLException(SAMLUtils.bundle.
1983                                        getString("cannotVerifySubject"));
1984        }
1985
1986        // TODO: check AudienceRestrictionCondition if any
1987
1988        if (statement != null) {
1989            // check the subject
1990            if ((subject == null) || (!subject.equals(statement.getSubject())))
1991            {
1992                if (SAMLUtils.debug.messageEnabled()) {
1993                    SAMLUtils.debug.message("AssertionManager.verifyAndGetSSO"
1994                        + "Token: wrong subject in evidence.");
1995                }
1996                throw new SAMLException(SAMLUtils.bundle.
1997                                        getString("cannotVerifySubject"));
1998            }
1999        }
2000        return createTempSSOToken(assertion, subject, sourceSite);
2001    }
2002
2003    private Object createTempSSOToken(Assertion assertion, Subject subject,
2004                        SAMLServiceManager.SOAPEntry sourceSite)
2005                        throws SAMLException
2006    {
2007        List assertions = new ArrayList();
2008        assertions.add(assertion);        
2009        String srcID = sourceSite.getSourceID();
2010        String name = null;
2011        String org = null;
2012
2013        PartnerAccountMapper paMapper = sourceSite.getPartnerAccountMapper();
2014        if (paMapper != null) {
2015            Map map = paMapper.getUser(assertions, srcID, null);
2016            name = (String) map.get(PartnerAccountMapper.NAME);
2017            org = (String) map.get(PartnerAccountMapper.ORG);
2018        }
2019
2020        if ((org == null) || (name == null)) {
2021            if (SAMLUtils.debug.messageEnabled()) {
2022                SAMLUtils.debug.message("AssertionManager." +
2023                    "createTempSSOToken: couldn't map the subject " +
2024                    "to a local user.");
2025            }
2026            throw new SAMLRequesterException(
2027                SAMLUtils.bundle.getString("cannotMapSubject"));
2028        } else {
2029            if (SAMLUtils.debug.messageEnabled()) {
2030                SAMLUtils.debug.message("AssertionManager." +
2031                    "createTempSSOToken: org = " + org + ", name = " + 
2032                    name);
2033            }
2034        }
2035        
2036        Object token = null; 
2037        try {
2038            Map infoMap = new HashMap();
2039            if ((org != null) && (org.length() != 0)) {
2040                infoMap.put(SessionProvider.REALM, org);
2041            } else {
2042                infoMap.put(SessionProvider.REALM, "/");
2043            }
2044            infoMap.put(SessionProvider.PRINCIPAL_NAME, name);
2045            infoMap.put(SessionProvider.AUTH_LEVEL, "0");        
2046            token = SAMLUtils.generateSession(null, null, infoMap); 
2047        } catch (Exception e) {
2048            if (SAMLUtils.debug.messageEnabled()) {
2049                SAMLUtils.debug.message("AssertionManger." + 
2050                    "createTempSSOToken: Couldn't retrieve " + 
2051                    "the ssotoken.", e);
2052            }
2053            throw new SAMLResponderException(
2054                SAMLUtils.bundle.getString("errorCreateAssertion"));
2055        }
2056        return token; 
2057    }
2058
2059    /**
2060     * @param addListener A listener to the single sign on token is added only
2061     *        when both store and addListener are true.
2062     */
2063    private Assertion getAuthorizationDecisionAssertion(
2064        AuthorizationDecisionQuery query, String destID,
2065        boolean store, Object token,
2066        boolean addListener, Map actionMap)
2067        throws SAMLException
2068    {
2069        if (actionMap == null) {
2070            if (SAMLUtils.debug.messageEnabled()) {
2071                SAMLUtils.debug.message("AssertionManager.getAuthZAssertion: "
2072                    + "actionMap from ActionMapper is null.");
2073            }
2074            throw new SAMLException(
2075                        SAMLUtils.bundle.getString("nullAuthZDecision"));
2076        }
2077
2078        validateNumberOfAssertions(idEntryMap);
2079        int decision;
2080        List newActions = null;
2081        if ((newActions = (List) actionMap.get(ActionMapper.PERMIT)) != null) {
2082            decision = AuthorizationDecisionStatement.DecisionType.PERMIT;
2083        } else if ((newActions = (List) actionMap.get(ActionMapper.DENY))
2084                                                                != null)
2085        {
2086            decision = AuthorizationDecisionStatement.DecisionType.DENY;
2087        } else {
2088            newActions = (List) actionMap.get(ActionMapper.INDETERMINATE);
2089            if (newActions == null) {
2090                // try not to be too restrictive
2091                newActions = query.getAction();
2092            }
2093            decision = 
2094                AuthorizationDecisionStatement.DecisionType.INDETERMINATE;
2095        }
2096
2097        //create statement
2098        AuthorizationDecisionStatement statement =
2099                new AuthorizationDecisionStatement(
2100                        query.getSubject(), query.getResource(), decision,
2101                        newActions, query.getEvidence());
2102
2103        Date issueInstant = new Date();
2104        Date notAfter = new Date(issueInstant.getTime() + assertionTimeout);
2105        Date notBefore = new Date(issueInstant.getTime() - notBeforeSkew);
2106        Conditions cond = new Conditions(notBefore, notAfter);
2107        String issuer = (String) SAMLServiceManager.getAttribute(
2108                                                SAMLConstants.ISSUER_NAME);
2109        Set statements = new HashSet();
2110        statements.add(statement);
2111        Assertion assertion = new Assertion(null, issuer, issueInstant, cond,
2112                                                statements);
2113        if (((Boolean) SAMLServiceManager.getAttribute(
2114                SAMLConstants.SIGN_ASSERTION)).booleanValue())
2115        {
2116            assertion.signXML();
2117        }
2118        String aIDString = assertion.getAssertionID();
2119
2120        if (store) {
2121            Entry entry = null;
2122            if (addListener) {
2123                // create a listener and add the listener to the token
2124                AssertionSSOTokenListener listener =
2125                        new AssertionSSOTokenListener(aIDString);
2126                try {
2127                    if (sessionProvider == null) {
2128                        throw new SAMLException(SAMLUtils.bundle.
2129                            getString("nullSessionProvider"));
2130                    }
2131                    sessionProvider.addListener(token, listener);
2132                } catch (SessionException e)  {
2133                    SAMLUtils.debug.error("AssertionManager.getAuthNAssertion:"
2134                        + " Couldn't get listener to token:", e);
2135                    // don't need to throw an exception
2136                }
2137            }
2138            entry = new Entry(assertion, destID, null, null);
2139
2140            // put assertion in idEntryMap
2141            try {
2142                Object oldEntry = null;
2143                synchronized (idEntryMap) {
2144                    oldEntry = idEntryMap.put(aIDString, entry);
2145                }
2146                if (oldEntry != null) {
2147                    assertionTimeoutRunnable.removeElement(aIDString);
2148                }
2149                assertionTimeoutRunnable.addElement(aIDString);
2150                if ((agent != null) && agent.isRunning() && (saml1Svc != null)){
2151                    saml1Svc.incSAML1Cache(
2152                        FedMonSAML1Svc.ASSERTIONS,
2153                        FedMonSAML1Svc.CWRITE);
2154                }
2155            } catch (Exception e) {
2156                if (SAMLUtils.debug.messageEnabled()) {
2157                    SAMLUtils.debug.message("AssertionManager.getAuthZAssertion"
2158                        + ": couldn't add assertion to the idAssertionMap.", e);
2159                }
2160                throw new SAMLResponderException(
2161                    SAMLUtils.bundle.getString("errorCreateAssertion"));
2162            }
2163
2164            if (LogUtils.isAccessLoggable(java.util.logging.Level.FINER)) {
2165                String[] data = {SAMLUtils.bundle.getString("assertionCreated"),
2166                    assertion.toString(true, true)};
2167                LogUtils.access(java.util.logging.Level.FINER,
2168                    LogUtils.ASSERTION_CREATED, data);
2169            } else {
2170                String[] data = {SAMLUtils.bundle.getString("assertionCreated"),
2171                    aIDString};
2172                LogUtils.access(java.util.logging.Level.INFO,
2173                    LogUtils.ASSERTION_CREATED, data);
2174            }
2175        }
2176        
2177        return assertion;
2178    }
2179
2180    /**
2181     * Gets the Assertion referenced by an <code>AssertionIDReference</code>.
2182     * @param idRef The <code>AssertionIDReference</code> which references to an
2183     *        Assertion.
2184     * @return the Assertion referenced by the <code>AsertionIDReference</code>.
2185     * @throws SAMLException If an error occurred during the process; or
2186     *          the assertion could not be found.
2187     */
2188    public Assertion getAssertion(AssertionIDReference idRef)
2189                                        throws SAMLException
2190    {
2191        return getAssertion(idRef, null, false);
2192    }
2193
2194    /**
2195     * Gets the Assertion referenced by an <code>AssertionIDReference</code>.
2196     * This method is usually used after the call
2197     * <code>AssertionManager.getAssertions(SSOToken)</code>.
2198     * The assertion is retrieved from this <code>AssertionManager</code> only.
2199     * @param idRef The <code>AssertionIDReference</code> which references to an
2200     *        Assertion.
2201     * @param token Use's session object that is allowed to obtain the
2202     *        assertion. This token must have top level administrator role.
2203     * @return the Assertion referenced by the <code>AsertionIDReference</code>.
2204     * @throws SAMLException If an error occurred during the process; the token
2205     *         does not have the privilege; or the assertion could not be
2206     *         found.
2207     * @supported.api
2208     */
2209    public Assertion getAssertion(AssertionIDReference idRef, Object token)
2210        throws SAMLException {
2211        if (token == null) {
2212            SAMLUtils.debug.error("AssertionManager.getAssertion(idRef, token"
2213                + "): input token is null.");
2214            throw new SAMLException(SAMLUtils.bundle.getString("nullInput"));
2215        }
2216        
2217        if (!isSuperUser(token)) {
2218            SAMLUtils.debug.error("AssertionManager.getAssertion(idRef, token"
2219                + "): Session doesn't have the privilege.");
2220            throw new SAMLException(SAMLUtils.bundle.getString("noPrivilege"));
2221        }
2222        return getAssertion(idRef, null, true);
2223    }
2224
2225    /**
2226     * Gets the Assertion referenced by an <code>AssertionIDReference</code>.
2227     * @param idRef The <code>AssertionIDReference</code> which references to an
2228     *        Assertion.
2229     * @param destID The destination site id requesting the assertion using
2230     *        the assertion id reference. This String is compared with the
2231     *        <code>destID</code> that the assertion is created for originally.
2232     *        This field is not used (could be null) if the assertion was
2233     *        created without a <code>destID</code> originally. This String can
2234     *        be obtained from converting the 20 byte site id sequence to char
2235     *        array, then a new String from the char array.
2236     * @return the Assertion referenced by the <code>AsertionIDReference</code>.
2237     * @throws SAMLException If an error occurred during the process; or
2238     *          the assertion could not be found.
2239     * @supported.api
2240     */
2241    public Assertion getAssertion(AssertionIDReference idRef, String destID)
2242                                throws SAMLException {
2243        if (destID == null) {
2244            return getAssertion(idRef, null, false);
2245        } else {
2246            Set destSet = new HashSet();
2247            destSet.add(destID); 
2248            return getAssertion(idRef, destSet, false);
2249        }
2250    }
2251    
2252    /**
2253     * Gets the Assertion referenced by an <code>AssertionIDReference</code>.
2254     * @param idRef The <code>AssertionIDReference</code> which references to an
2255     *        Assertion.
2256     * @param destID A Set of destination site id. The destination site id
2257     *        requesting the assertion using the assertion id reference.
2258     *        This String is compared with the <code>destID</code> that the
2259     *        assertion is created for originally. This field is not used
2260     *        (could be null) if the assertion was created without a
2261     *        <code>destID</code> originally. This String can be obtained from
2262     *        converting the 20 byte site id sequence to char array, then a new
2263     *        String from the char array.
2264     * @return the Assertion referenced by the <code>AsertionIDReference</code>.
2265     * @throws SAMLException If an error occurred during the process; or
2266     *          the assertion could not be found.
2267     * @supported.api
2268     */
2269    public Assertion getAssertion(AssertionIDReference idRef, Set destID)
2270                                throws SAMLException {
2271        return getAssertion(idRef, destID, false);
2272    }
2273    
2274    /**
2275     * Gets the Assertion referenced by an <code>AssertionIDReference</code>.
2276     * @param id The <code>AssertionIDReference</code> which references to an
2277     *        Assertion.
2278     * @param destID A Set of String that represents the destination id. 
2279     *        The destination site id requesting the assertion using
2280     *        the assertion id reference. This String is compared with the
2281     *        <code>destID</code> that the assertion is created for originally.
2282     *        This field is not used (could be null) if the assertion was
2283     *        created without a <code>destID</code> originally. This String can
2284     *        be obtained from converting the 20 byte site id sequence to char
2285     *        array, then a new String from the char array.
2286     * @param useToken A boolean value. If set to true, destID is not
2287     *          checked against with the string that the assertion is created
2288     *          for originallyr, the assertion is retrieved from this server
2289     *          only.
2290     * @return the Assertion referenced by the <code>AsertionIDReference</code>.
2291     * @throws SAMLException If an error occurred during the process; or
2292     *          the assertion could not be found.
2293     */
2294    private Assertion getAssertion(AssertionIDReference idRef, Set destID,
2295                                boolean useToken)
2296                                throws SAMLException {
2297        if (SAMLUtils.debug.messageEnabled()) {
2298            SAMLUtils.debug.message("getAssertion(idRef): destID set=" +
2299                                     destID);
2300        }
2301        if (idRef == null) {
2302            if (SAMLUtils.debug.messageEnabled()) {
2303                SAMLUtils.debug.message("AssertionManager.getAssertion(Asser"
2304                    + "tionIDRef): null AssertionID.");
2305            }
2306            throw new SAMLRequesterException(
2307                SAMLUtils.bundle.getString("nullInput"));
2308        }
2309        String aIDString = idRef.getAssertionIDReference();
2310        if (!useToken) {
2311            // get server id.
2312            String remoteUrl = SAMLUtils.getServerURL(aIDString);
2313            if (remoteUrl != null) { // not this server
2314                // call AssertionManagerClient.getAssertion
2315                if (SAMLUtils.debug.messageEnabled()) {
2316                    SAMLUtils.debug.message("AssertionManager." + 
2317                        "getAssertion(idRef): calling another server" +
2318                        " in lb site:" + remoteUrl);
2319                }
2320                AssertionManagerClient amc = new AssertionManagerClient(
2321                                        SAMLUtils.getFullServiceURL(remoteUrl));
2322                return amc.getAssertion(idRef, destID);
2323            } //else 
2324        }
2325
2326        Entry entry = (Entry) idEntryMap.get(aIDString);
2327        if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
2328            saml1Svc.incSAML1Cache(FedMonSAML1Svc.ASSERTIONS,
2329                FedMonSAML1Svc.CREAD);
2330        }
2331        if (entry == null) {
2332            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
2333                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ASSERTIONS,
2334                    FedMonSAML1Svc.CMISS);
2335            }
2336            if (SAMLUtils.debug.messageEnabled()) {
2337                SAMLUtils.debug.message("AssertionManager.getAssertion(Asser"
2338                    + "tionIDRef): no matching assertion found in idEntryMap.");
2339            }
2340            throw new SAMLException(
2341                SAMLUtils.bundle.getString("noMatchingAssertion"));
2342        } else {
2343            if ((agent != null) && agent.isRunning() && (saml1Svc != null)) {
2344                saml1Svc.incSAML1Cache(FedMonSAML1Svc.ASSERTIONS,
2345                    FedMonSAML1Svc.CHIT);
2346            }
2347        }
2348
2349        Assertion assertion = entry.getAssertion();
2350        if (assertion == null) {
2351            if (SAMLUtils.debug.messageEnabled()) {
2352                SAMLUtils.debug.message("AssertionManager.getAssertion("
2353                    + "AssertionIDRef): no matching assertion found.");
2354            }
2355            throw new SAMLException(
2356                SAMLUtils.bundle.getString("noMatchingAssertion"));
2357        }
2358
2359        if (!useToken) {
2360            // check if the destID is correct
2361            String dest = entry.getDestID();
2362            if (dest != null) {
2363                if ((destID == null) || (!destID.contains(dest))) {
2364                    if (SAMLUtils.debug.messageEnabled()) {
2365                        SAMLUtils.debug.message("AssertionManager.getAssertion("
2366                            + "AssertionID): destID doesn't match.");
2367                    }
2368                    throw new SAMLException(
2369                        SAMLUtils.bundle.getString("destIDNotMatch"));
2370                }
2371            }
2372        }
2373
2374        // check the time of the assertion
2375        if (!assertion.isTimeValid()) {
2376            if (SAMLUtils.debug.messageEnabled()) {
2377                SAMLUtils.debug.message("AssertionManager: assertion "
2378                        + aIDString + " is expired.");
2379            }
2380            throw new SAMLException("assertionTimeNotValid");
2381        }
2382
2383        return assertion;
2384    }
2385
2386    /**
2387     * Creates an AssertionArtifact.
2388     * @param id The String that contains authentication information which
2389     *          is needed to create the assertion. It could be a string
2390     *          representation of an id, a cookie, etc.
2391     * @param destID The destination site that the artifact is created for.
2392     * @return The AssertionArtifact.
2393     * @throws SAMLException If the AssertionArtifact cannot be created.
2394     */
2395    public AssertionArtifact createAssertionArtifact(String id,
2396        String destID) throws SAMLException {
2397        return createAssertionArtifact(id, destID, null, null);
2398    }
2399    /**
2400     * Creates an AssertionArtifact.
2401     * @param id The String that contains authentication information which
2402     *          is needed to create the assertion. It could be a string
2403     *          representation of an id, a cookie, etc.
2404     * @param destID The destination site that the artifact is created for.
2405     * @param targetUrl A URL String representing the target site 
2406     * @param version The relying party preferred Assertion version number. 
2407     * @return The AssertionArtifact.
2408     * @throws SAMLException If the AssertionArtifact cannot be created.
2409     */
2410    public AssertionArtifact createAssertionArtifact(String id,
2411                                String destID, String targetUrl,
2412                                String version)
2413                                throws SAMLException {
2414        return createAssertionArtifact(id, destID, null, null, 
2415            targetUrl, version);
2416    }
2417    /**
2418     * Creates an AssertionArtifact.
2419     * @param id The String that contains authentication information which
2420     *          is needed to create the assertion. It could be a string
2421     *          representation of an id, a cookie, etc.
2422     * @param destID The destination site that the artifact is created for.
2423     * @param request The HttpServletRerquest object of the request.
2424     * @param response The HttpServletResponse object.
2425     * @param targetUrl A URL String representing the target site 
2426     * @param version The relying party preferred Assertion version number. 
2427     * @return The AssertionArtifact.
2428     * @throws SAMLException If the AssertionArtifact cannot be created.
2429     */
2430    public AssertionArtifact createAssertionArtifact(String id,
2431        String destID, HttpServletRequest request,
2432        HttpServletResponse response, String targetUrl,
2433        String version) throws SAMLException {
2434        // check input
2435        if ((id == null) || (destID == null)) {
2436            if (SAMLUtils.debug.messageEnabled()) {
2437                SAMLUtils.debug.message("AssertionManager: null input for"
2438                        + " method createAssertionArtifact.");
2439            }
2440            throw new SAMLRequesterException(
2441                SAMLUtils.bundle.getString("nullInput"));
2442        }
2443
2444        Map partner = (Map) SAMLServiceManager.getAttribute(
2445                                                SAMLConstants.PARTNER_URLS);
2446        if ((partner == null) || (!partner.containsKey(destID))) {
2447            SAMLUtils.debug.error("AssertionManager.createAssertionArtifact:" +
2448                "(String, String): destID not in partner list.");
2449            throw new SAMLException(
2450                        SAMLUtils.bundle.getString("destIDNotFound"));
2451        }
2452
2453        // create assertion id and artifact
2454        String handle = SAMLUtils.generateAssertionHandle();
2455        if (handle == null) {
2456            if (SAMLUtils.debug.messageEnabled()) {
2457                SAMLUtils.debug.message("AssertionManager.createAssertionArt"
2458                    + "ifact: couldn't generate assertion handle.");
2459            }
2460            throw new SAMLResponderException(
2461                SAMLUtils.bundle.getString("errorCreateArtifact"));
2462        }
2463
2464        String sourceID = (String) SAMLServiceManager.getAttribute(
2465                                        SAMLConstants.SITE_ID);
2466        AssertionArtifact art = new AssertionArtifact(sourceID, handle);
2467        Assertion assertion = createSSOAssertion(id, art, 
2468            request, response, destID, targetUrl, version);
2469        try {
2470            if (version != null) { 
2471                StringTokenizer st = new StringTokenizer(version,".");
2472                if (st.countTokens() == 2) { 
2473                    assertion.setMajorVersion(
2474                        Integer.parseInt(st.nextToken().trim())); 
2475                    assertion.setMinorVersion(
2476                        Integer.parseInt(st.nextToken().trim()));
2477                }
2478            }
2479        } catch (NumberFormatException ne) { 
2480            throw new SAMLException(ne.getMessage()); 
2481        }
2482        return art;
2483    }
2484
2485    /**
2486     * This method returns the decision of an AuthorizationQuery.
2487     * @param authZQuery An AuthorizationQuery that contains the question:
2488     *                  Is this subject authorized to perfrom this action on
2489     *                  this resource?
2490     * @param destID the SourceID of the site where the query is from.
2491     * @return an int whose value is defined in
2492     *          AuthorizationDecisionStatement.DecisionType.
2493     */
2494    public int isAllowed(AuthorizationDecisionQuery authZQuery, String destID) {
2495        if (authZQuery == null) {
2496            SAMLUtils.debug.error("AssertionManager.isAllowed: null input.");
2497            return AuthorizationDecisionStatement.DecisionType.INDETERMINATE;
2498        }
2499
2500        Assertion assertion = null;
2501        try {
2502            assertion = getAuthorizationDecisionAssertion(authZQuery, destID,
2503                                                                false);
2504        } catch (SAMLException e) {
2505            SAMLUtils.debug.error("AssertionManager.isAllowed: exception thrown"
2506                + " when trying to get an assertion from authZQuery. ", e);
2507            return AuthorizationDecisionStatement.DecisionType.INDETERMINATE;
2508        }
2509
2510        // double check, shouldn't be here
2511        if (assertion == null) {
2512            return AuthorizationDecisionStatement.DecisionType.INDETERMINATE;
2513        } 
2514
2515        // Got an assertion
2516        Set statements = assertion.getStatement();
2517        if ((statements != null) && (!statements.isEmpty())) {
2518            Iterator iter = statements.iterator();
2519            while (iter.hasNext()) {
2520                Statement statement = (Statement) iter.next();
2521                if (statement.getStatementType() ==
2522                        Statement.AUTHORIZATION_DECISION_STATEMENT)
2523                {
2524                    // we know there should be only one authZstatement
2525                    return ((AuthorizationDecisionStatement) statement).
2526                                getDecision();
2527                }
2528            }
2529            // still here means no authZstatement
2530            SAMLUtils.debug.error("AssertionManager.isAllowed: no "
2531                        + "authZstatement in assertion.");
2532            return AuthorizationDecisionStatement.DecisionType.INDETERMINATE;
2533        } else {
2534            SAMLUtils.debug.error("AssertionManager.isAllowed: no statements in"
2535                + " assertion.");
2536            return AuthorizationDecisionStatement.DecisionType.INDETERMINATE;
2537        }
2538    }
2539
2540    boolean validateNumberOfAssertions(Map idEntryMap) 
2541        throws SAMLResponderException 
2542    {
2543        Integer maxNumber = (Integer) SAMLServiceManager.getAttribute(
2544                        SAMLConstants.ASSERTION_MAX_NUMBER_NAME);
2545        int maxValue = maxNumber.intValue();
2546        if ((maxValue != 0) && (idEntryMap.size() > maxValue)) {
2547            SAMLUtils.debug.error("AssertionManager.createAssertion"
2548                + "Artifact(assertion,String): reached maxNumber of "
2549                + "assertions.");
2550            throw new SAMLResponderException(
2551                SAMLUtils.bundle.getString("errorCreateArtifact"));
2552        } else {
2553            return false;
2554        }
2555    }
2556
2557    private class GoThroughRunnable extends GeneralTaskRunnable {
2558        private Set keys;
2559        private long runPeriod;
2560        
2561        public GoThroughRunnable(long runPeriod) {
2562            this.keys = new HashSet();
2563            this.runPeriod = runPeriod;
2564        }
2565        
2566        public boolean addElement(Object obj) {
2567           synchronized (keys) {
2568                return keys.add(obj);
2569            }
2570        }
2571    
2572        public boolean removeElement(Object obj) {
2573            synchronized (keys) {
2574                return keys.remove(obj);
2575            }
2576        }
2577    
2578        public boolean isEmpty() {
2579            return false;
2580        }
2581    
2582        public long getRunPeriod() {
2583            return runPeriod;
2584        }
2585        
2586        public void run() {
2587            long currentTime = System.currentTimeMillis();
2588            String keyString;
2589            Entry entry;
2590            Assertion assertion;
2591            SAMLUtils.debug.message("Clean up runnable wakes up..");
2592            synchronized (keys) {
2593                Iterator keyIter = keys.iterator();
2594                if (SAMLUtils.debug.messageEnabled()) {
2595                    SAMLUtils.debug.message("AssertionManager::"
2596                        +"CleanUpThread::number of assertions in "
2597                        + "IdEntryMap:"+idEntryMap.size());
2598                }
2599                while (keyIter.hasNext()) {
2600                    keyString = (String) keyIter.next();
2601                    entry = (Entry) idEntryMap.get(keyString);
2602                    if (entry != null) {
2603                        assertion = entry.getAssertion();
2604                        if (assertion != null) {
2605                            if (assertion.getConditions() != null) {
2606                                if (!assertion.isTimeValid()) {
2607                                    keyIter.remove();
2608                                    deleteAssertion(keyString, null);
2609                                }
2610                            } else {
2611                                // if conditions are absent, calculate time
2612                                // validity of assertion as if notBefore is
2613                                // issueInstant - notBeforeSkew and notOnOrAfter
2614                                // is assertion time out + issueInstant
2615   
2616                                Date issueInstant = assertion.getIssueInstant();
2617                                Date notBefore = new Date(issueInstant.getTime()
2618                                    - notBeforeSkew);
2619                                Date notOnOrAfter = new Date(
2620                                    issueInstant.getTime() + assertionTimeout);
2621                                if (!((currentTime >= notBefore.getTime()) &&
2622                                    (currentTime < notOnOrAfter.getTime()))) {
2623                                    keyIter.remove();
2624                                    deleteAssertion(keyString, null);
2625                                }
2626                            }
2627                        }
2628                    }
2629                }
2630            }
2631        }
2632    }
2633
2634}