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