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: SessionContext.java,v 1.2 2008/06/25 05:47:21 qcheng Exp $
026 *
027 */
028
029
030package com.sun.identity.liberty.ws.security;
031
032import com.sun.identity.shared.DateUtils;
033
034import com.sun.identity.federation.common.IFSConstants;
035import com.sun.identity.federation.message.common.AuthnContext;
036import com.sun.identity.federation.message.common.FSMsgException;
037
038import com.sun.identity.liberty.ws.common.wsse.WSSEConstants;
039
040import com.sun.identity.saml.common.SAMLConstants;
041import com.sun.identity.saml.common.SAMLException;
042import com.sun.identity.saml.common.SAMLRequesterException;
043import com.sun.identity.saml.common.SAMLUtils;
044
045import java.text.ParseException;
046
047import java.util.Date;
048
049import org.w3c.dom.Element; 
050import org.w3c.dom.Node;
051import org.w3c.dom.NodeList;
052
053/** 
054 * The <code>SessionContext</code> class represents session status of an entity
055 * to another system entity. It is supplied to a relying party to support policy
056 * enforcement.
057 *
058 * @supported.all.api
059 */
060public class SessionContext {
061
062    protected SessionSubject _sessionSubject = null;
063    protected AuthnContext _authnContext = null;
064    protected String _providerID = null;
065    protected Date _issueInstant = null;
066    protected Date  _authenticationInstant = null;
067
068    
069    /**
070     * Default constructor 
071     */
072    protected SessionContext() {
073    }
074    
075    /**
076     * Constructs a <code>SessionContext</code> object from a
077     * <code>SessionSubject</code> object, a <code>AuthnContext</code>
078     * object and a <code>String</code>.
079     *
080     * @param sessionSubject <code>SessionSubject</code> object.
081     * @param authnContext authentication context object.
082     * @param providerID provider ID.
083     * @throws SAMLException if <code>sessionSubject</code> is null or
084     *            <code>providerID</code> is null.
085     */
086    public SessionContext(SessionSubject sessionSubject,
087                          AuthnContext authnContext,
088                          String providerID) throws SAMLException {
089        if ((sessionSubject == null) || (providerID == null)) {
090            SAMLUtils.debug.message("SessionContext: null input.");
091            throw new SAMLRequesterException(
092                      SAMLUtils.bundle.getString("nullInput"));
093        }
094        _sessionSubject = sessionSubject;
095        _authnContext = authnContext;
096        _providerID = providerID;
097        _issueInstant = new Date();
098        _authenticationInstant = new Date();
099    }
100
101    /**
102     * Returns the <code>SessionSubject</code> within the
103     * <code>SessionContext</code> object.
104     *
105     * @return <code>SessionSubject</code> object.
106     */
107    public SessionSubject getSessionSubject() {
108        return _sessionSubject;
109    }
110
111    /**
112     * Sets the <code>SessionSubject</code> object.
113     *
114     * @param sub <code>SessionSubject</code> object.
115     */
116    public void setSessionSubject(SessionSubject sub) {
117        _sessionSubject = sub;
118    }
119    
120    /**
121     * Returns the <code>AuthnContext</code> within the
122     * <code>SessionContext</code> object.
123     *
124     * @return <code>AuthnContext</code> object.
125     */
126    public AuthnContext getAuthnContext() {
127        return _authnContext;
128    }
129
130    /**
131     * Returns the <code>ProviderID</code> in the <code>SessionContext</code>
132     * object.
133     *
134     * @return <code>ProviderID</code> object
135     */
136    public String getProviderID() {
137        return _providerID;
138    }
139
140    /**
141     * Sets the <code>AuthnContext</code> in the <code>SessionContext</code>.
142     *
143     * @param authnContext <code>AuthnContext</code> to be set.
144     * @return true if <code>AuthnContext</code> was set.
145     */
146    public boolean setAuthnContext(AuthnContext authnContext) {
147        if (authnContext == null) {
148            if (SAMLUtils.debug.messageEnabled()) {
149                SAMLUtils.debug.message("SessionContext: " +
150                    "setAuthnContext: Input is null.");
151            }
152            return false;
153        }
154        _authnContext = authnContext;
155        return true;
156    }
157
158    /**
159     * Constructs an <code>SessionContext</code> object from a DOM Element. 
160     * 
161     * @param element representing a DOM tree element.
162     * @throws SAMLException if there is an error in the sender or in the
163     *            element definition.
164     */
165    public SessionContext(Element element)throws SAMLException {
166        // make sure input is not null
167        if (element == null) {
168            SAMLUtils.debug.message("AttributeStatement: null input.");
169            throw new SAMLRequesterException(
170                      SAMLUtils.bundle.getString("nullInput"));
171        }
172
173        // check if it's an ResourceAccessStatement
174        boolean valid = SAMLUtils.checkStatement(element, "SessionContext");
175        if (!valid) {
176            SAMLUtils.debug.message("SessionContext: Wrong input.");
177            throw new SAMLRequesterException(
178                SAMLUtils.bundle.getString("wrongInput"));
179        }
180
181        String authInstant = element.getAttribute("AuthenticationInstant");
182        String issueInstant = element.getAttribute("AssertionIssueInstant");
183        if ((authInstant == null) || (issueInstant == null)) {
184            SAMLUtils.debug.message("SessionContext: AuthenticationInstant " +
185                        "or AssertionIssueInstant is missing!");
186            throw new SAMLRequesterException(
187                SAMLUtils.bundle.getString("nullInput"));
188        }
189        try {
190            _issueInstant = DateUtils.stringToDate(issueInstant);
191            _authenticationInstant = DateUtils.stringToDate(authInstant);
192        } catch (ParseException e) {
193            //TODO: handle exception
194        }
195
196        //Handle the children elements of SessionContext
197        NodeList nodes = element.getChildNodes();
198        int nodeCount = nodes.getLength();
199        if (nodeCount > 0) {
200            for (int i = 0; i < nodeCount; i++) {
201                Node currentNode = nodes.item(i);
202                if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
203                    String tagName = currentNode.getLocalName();
204                    String tagNS = currentNode.getNamespaceURI();
205                    if ((tagName == null) || tagName.length() == 0 ||
206                        tagNS == null || tagNS.length() == 0) {
207                        if (SAMLUtils.debug.messageEnabled()) {
208                        SAMLUtils.debug.message("SessionContext: The tag name"+
209                                      " or tag namespace of child element is" +
210                                      " either null or empty.");
211                        }
212                        throw new SAMLRequesterException(
213                                  SAMLUtils.bundle.getString("nullInput"));
214                    }
215                    if (tagName.equals("SessionSubject") &&
216                        tagNS.equals("urn:liberty:sec:2003-08")) { //sec:
217                        if (_sessionSubject != null) {
218                            if (SAMLUtils.debug.messageEnabled()) {
219                                SAMLUtils.debug.message("SessionContext:" +
220                                   " should only contain one SessionSubject");
221                            }
222                            throw new SAMLRequesterException(
223                                      SAMLUtils.bundle.getString("oneElement"));
224                        } else {
225                            try {
226                                _sessionSubject =
227                                    new SessionSubject((Element) currentNode);
228                            } catch (Exception e) {
229                                if (SAMLUtils.debug.messageEnabled()) {
230                                    SAMLUtils.debug.message("SessionContext:" +
231                                                "could not new SessionSubject" +
232                                                " object.");
233                                }
234                                throw new SAMLRequesterException(
235                                        SAMLUtils.bundle.getString(
236                                                "SessionSubject"));
237                            }
238                        }
239                    } else if (tagName.equals("ProviderID") &&
240                        tagNS.equals("urn:liberty:sec:2003-08")) { //sec
241                        if (_providerID != null) {
242                            if (SAMLUtils.debug.messageEnabled()) {
243                                SAMLUtils.debug.message("SessionContext:"+
244                                            " should at most contain one" +
245                                            " ProviderID.");
246                             }
247                             throw new SAMLRequesterException(
248                                      SAMLUtils.bundle.getString("oneElement"));
249                        } else {
250                             _providerID = currentNode.getChildNodes().item(0)
251                                           .getNodeValue();
252                        }
253                    } else if (tagName.equals("AuthnContext") &&
254                        tagNS.equals("urn:liberty:iff:2003-08")) { //lib
255                        if (_authnContext != null) {
256                            if (SAMLUtils.debug.messageEnabled()) {
257                                SAMLUtils.debug.message("SessionContext: " +
258                                            "should at most contain one " +
259                                            "AuthnContext");
260                            }
261                            throw new SAMLRequesterException(
262                                      SAMLUtils.bundle.getString("oneElement"));
263                        } else {
264                            try {
265                                _authnContext = new AuthnContext((Element)
266                                                    currentNode);
267                            } catch (Exception e) {
268                                if (SAMLUtils.debug.messageEnabled()) {
269                                    SAMLUtils.debug.message("SessionContext:" +
270                                                "could not new AuthnContext" +
271                                                " object.", e);
272                                }
273                                throw new SAMLRequesterException(
274                                        SAMLUtils.bundle.getString(
275                                                "AuthnContext"));
276                            }
277                        }
278                    } else {
279                         if (SAMLUtils.debug.messageEnabled()) {
280                             SAMLUtils.debug.message("SessionContext: "+
281                                     "Wrong element " + tagName + " included.");
282                         }
283                         throw new SAMLRequesterException(
284                                     SAMLUtils.bundle.getString("wrongInput"));
285                    }
286                } // end of if (currentNode.getNodeType() == Node.ELEMENT_NODE)
287            } // end of for loop
288        }  // end of if (nodeCount > 0)
289        // check if the subject is null
290        if ((_sessionSubject == null)||(_authnContext == null)) {
291            if (SAMLUtils.debug.messageEnabled()) {
292                SAMLUtils.debug.message("SessionContext should contain " +
293                                        "one SessionSubject and one " +
294                                        " one AuthnContext.");
295            }
296            throw new SAMLRequesterException(
297                        SAMLUtils.bundle.getString("missingElement"));
298        }
299        
300    }
301
302    /**
303     * Returns a String representation of the <code>SessionContext</code>
304     * element.
305     *
306     * @return A string containing the valid XML for this element.
307     *         By default name space name is prepended to the element name
308     *         example <code>&lt;saml:Subject&gt;</code>.
309     * @throws ParseException if could not convert String Date
310     *            expression to Date object.
311     * @throws FSMsgException if could not get <code>AuthnContext</code> XML
312     *            String representation.
313     */
314    public String toXMLString() throws ParseException, FSMsgException {
315        return toXMLString(true, false);
316    }
317
318    /**
319     * Returns a String representation of the <code>&lt;SessionContext&gt;</code>
320     * element.
321     *
322     * @param includeNS if true prepends all elements by their Namespace
323     *        name <code>&lt;saml:Subject&gt;</code>.
324     * @param declareNS if true includes the namespace within the
325     *        generated XML.
326     * @return A string containing the valid XML for this element. Return null
327     *         if error happened.
328     * @throws ParseException if could not convert String Date
329     *            expression to Date object.
330     * @throws FSMsgException if could not get <code>AuthnContext</code> XML
331     *            String representation.
332     **/
333    public String toXMLString(boolean includeNS, boolean declareNS)
334        throws ParseException, FSMsgException {
335
336        SAMLConstants sc;
337        StringBuffer xml = new StringBuffer(3000);
338        String secprefix = "";
339        String libprefix = "";
340        String liburi = "";
341        String secNS = "";
342
343        if (includeNS) {
344             libprefix = IFSConstants.LIB_PREFIX;
345             secprefix = WSSEConstants.TAG_SEC + ":";
346        }
347        if (declareNS) {
348            liburi = IFSConstants.LIB_NAMESPACE_STRING;
349            secNS = " " + WSSEConstants.TAG_XMLNS + ":" +
350                    WSSEConstants.TAG_SEC + "=\"" + WSSEConstants.NS_SEC +
351                    "\"";
352        }
353
354        xml.append("<").append(secprefix).
355            append(WSSEConstants.TAG_SESSIONCONTEXT).append(secNS).append(" ").
356            append("AuthenticationInstant=").append("\"").
357            append(DateUtils.toUTCDateFormat(_issueInstant)).append("\" ").
358            append("AssertionIssueInstant=").append("\"").
359            append(DateUtils.toUTCDateFormat(_authenticationInstant)).
360            append("\"").
361            append(">");
362
363        xml.append(_sessionSubject.toXMLString(includeNS, declareNS));
364
365        xml.append("<").append(secprefix).append(WSSEConstants.TAG_PROVIDERID).
366            append(">").append(_providerID).append("</").append(secprefix).
367            append(WSSEConstants.TAG_PROVIDERID).append(">");
368
369        if (_authnContext != null) {
370            xml.append(_authnContext.toXMLString(includeNS, declareNS));
371        }
372
373        xml.append("</").append(secprefix).
374            append(WSSEConstants.TAG_SESSIONCONTEXT).append(">");
375
376        return xml.toString();
377    }
378}
379