Esempio n. 1
0
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                if (Request.HttpMethod == "POST")
                {
                    byte[] buffer = new byte[Request.InputStream.Length];
                    Request.InputStream.Read(buffer, 0, buffer.Length);

                    // Notification data is supplied in Base64 format, to avoid digital signature encoding issues
                    string data = Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.ASCII.GetString(buffer)));

                    // Load the notification data into an XmlDocument
                    XmlDocument notification = new XmlDocument();
                    notification.LoadXml(data);

                    // Items in the notification XML are in the Sage SSO namespace, so we need to add an
                    // XmlNamespaceManager here. See the schema documentation for Notification for more details on
                    // the notification XML format.
                    XmlNamespaceManager nsmgr = new XmlNamespaceManager(notification.NameTable);
                    nsmgr.AddNamespace("sso", "http://sso.sage.com");

                    CheckNotificationValidSignature(notification);

                    CheckNotificationNotExpired(notification, nsmgr);

                    CheckNotificationNotReplayed(notification, nsmgr);

                    // This XPath expression will only return an XmlNode if the notification type node contains "Session.Ended" and there
                    // is a parameter with the name "SessionId".
                    XmlNode sessionIdNode = notification.SelectSingleNode("/sso:Notification[sso:Type=\"Session.Ended\"]/sso:Parameters/sso:Parameter[sso:Name=\"SessionId\"]/sso:Value", nsmgr);

                    if (sessionIdNode != null)
                    {
                        // Remove the SSO session from the session map. The next time a page is loaded for that SSO session ID,
                        // the map is checked and, if the session is not found the application session is ended.
                        SSOSessionMap.EndSSOSession(new Guid(sessionIdNode.InnerText));
                    }

                    // This XPath expression will only return an XmlNode if the notification type node contains "Session.ExpiryDue" and there
                    // is a parameter with the name "SessionId".
                    sessionIdNode = notification.SelectSingleNode("/sso:Notification[sso:Type=\"Session.ExpiryDue\"]/sso:Parameters/sso:Parameter[sso:Name=\"SessionId\"]/sso:Value", nsmgr);

                    if (sessionIdNode != null)
                    {
                        // The session will expire shortly. We need to determine whether we need to
                        // extend the session in Sage SSO and act accordingly.
                        Guid ssoSessionId = new Guid(sessionIdNode.InnerText);

                        if (SSOSessionMap.HasSSOSession(ssoSessionId))
                        {
                            // This XPath expression returns the Timestamp parameter value in the notification.
                            XmlNode ssoSessionExpiryDueNode = notification.SelectSingleNode("/sso:Notification/sso:Parameters/sso:Parameter[sso:Name=\"Timestamp\"]/sso:Value", nsmgr);

                            // The timestamp, like all Sage SSO timestamps, is in XSD schema format and is UTC.
                            DateTime ssoSessionExpiryDue = XmlConvert.ToDateTime(ssoSessionExpiryDueNode.InnerText, XmlDateTimeSerializationMode.RoundtripKind);

                            DateTime newSSOSessionExpiry = DateTime.MinValue;

                            // If there has been some user activity on this session we'll call Sage SSO to extend the
                            // SSO session to match the application session expiry time based on the last activity
                            // and the application session timeout setting.
                            if (SSOSessionMap.ShouldExtendSSOSession(ssoSessionId, ssoSessionExpiryDue, out newSSOSessionExpiry))
                            {
                                using (WebSSOServiceSoapClient client = new WebSSOServiceSoapClient("WebSSOServiceSoapClient"))
                                {
                                    client.Open();

                                    SessionExtendRequest request = new SessionExtendRequest()
                                    {
                                        SessionId = ssoSessionId,
                                        SessionExpiry = newSSOSessionExpiry,
                                        SessionExpirySpecified = true
                                    };

                                    try
                                    {
                                        // Call Sage SSO to extend the SSO session to match our application session
                                        SessionExtendResponse response = client.SessionExtend(request);

                                        // Extend the SSO session in the session map to synchronise with what Sage SSO
                                        // tells us. It's important to observe the session expiry that's returned
                                        // because the Sage SSO session may be nearing its hard timeout and we
                                        // don't want to extend the application session beyond that.
                                        SSOSessionMap.ExtendSSOSession(ssoSessionId, response.SessionExpiry);

                                        // The ExpiryDue flag tells us whether this session is in its expiry period. If
                                        // ExpiryDue returns true at this point either we haven't extended the session far enough
                                        // past the expiry due threshold to cause Sage SSO to unmark the session (perhaps
                                        // because there was some activity right at the start of the application session but
                                        // nothing since) or the SSO session is approaching its hard timeout.
                                        //
                                        // If the flag is false then we'll receive another notification before the session expires,
                                        // if it's true then we WON'T receive another notification before the session expires and
                                        // we must call Sage SSO to extend the session if there's any activity.
                                        SSOSessionMap.SetShouldExtendSSOSessionOnUserActivity(ssoSessionId, response.ExpiryDue);
                                    }
                                    catch (Exception)
                                    {
                                        // There was a problem extending the session on Sage SSO, or some other local problem
                                        // with the SSO session map or application session state. The safest thing to do
                                        // at this point is to end the application session.
                                        SSOSessionMap.EndSSOSession(ssoSessionId);
                                    }
                                }
                            }
                            else
                            {
                                // We're not extending the SSO session right now but we mark the mapped SSO session
                                // as requiring extension on user activity. If the user makes a call into the
                                // application while the session is marked, we call Sage SSO to extend the session and un-mark
                                // the application session. You can see this code in PageBase.cs in the OnLoad() method.
                                // The application will receive another notification when the Sage SSO session is next due to expire.
                                SSOSessionMap.SetShouldExtendSSOSessionOnUserActivity(ssoSessionId, true);
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                // We catch all exceptions here so we don't return a 500 Internal Server Error to Sage SSO.
                // In a production system, it would be a good idea to log these.
            }
        }
Esempio n. 2
0
        // Check for the existence of an SSO session, record the activity and extend it by calling SSO, if needed. Refresh
        // should be called each time a page is loaded (or if any Ajax service is called). Returns true if the SSO
        // session was successfully refreshed.
        public static bool Refresh()
        {
            bool refreshed = false;

            if (HasSession)
            {
                Guid ssoSessionId = Current.SSOSessionId;

                if (SSOSessionMap.ShouldExtendSSOSessionOnUserActivity(ssoSessionId))
                {
                    // The Sage SSO session associated with this application session has been marked expiry due since
                    // the last time there was activity. Call Sage SSO to extend the session and then clear the
                    // mark so that we don't call SessionExtend again until we receive another Session.ExpiryDue
                    // notification.

                    using (WebSSOServiceSoapClient client = new WebSSOServiceSoapClient("WebSSOServiceSoapClient"))
                    {
                        client.Open();

                        SessionExtendRequest request = new SessionExtendRequest()
                        {
                            SessionId = ssoSessionId,
                            SessionExpiry = DateTime.UtcNow + TimeSpan.FromMinutes(HttpContext.Current.Session.Timeout),
                            SessionExpirySpecified = true
                        };

                        try
                        {
                            // Call Sage SSO to extend the session to match our application session.
                            SessionExtendResponse response = client.SessionExtend(request);
                            Current.AuthenticationToken = response.UserAuthenticationToken;

                            // Extend the SSO session in the session map to synchronise with what Sage SSO
                            // tells us. It's important to observe the session expiry that's returned
                            // because the Sage SSO session may be nearing its hard timeout and we
                            // don't want to extend the application session beyond that.
                            SSOSessionMap.ExtendSSOSession(ssoSessionId, response.SessionExpiry);

                            // Unlike when we handle the Session.ExpiryDue notification, we always clear
                            // the expiry due flag here to avoid making continual calls to Sage SSO
                            // if the SSO session is nearing the hard timeout.
                            SSOSessionMap.SetShouldExtendSSOSessionOnUserActivity(ssoSessionId, false);

                            refreshed = true;
                        }
                        catch (Exception)
                        {
                            // There was a problem extending the session on Sage SSO, or some other local problem
                            // with the SSO session map or application session state. The safest thing to do
                            // at this point is to end the application session.
                            Current.End();
                        }
                    }
                }
                else
                {
                    try
                    {
                        // Record the activity in the SSO session map.
                        SSOSessionMap.RefreshSSOSession(ssoSessionId);

                        refreshed = true;
                    }
                    catch (Exception)
                    {
                        // There was a problem refreshing the SSO session in the SSO session map. The safest thing
                        // to do at this point is to end the application session.
                        Current.End();
                    }
                }
            }

            return refreshed;
        }