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