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