Question
Michoel Reach · Mar 31, 2021

End Session programmatically

We have a background job that keeps an eye on our ongoing CSP sessions, counts licenses used and some other tasks. Question: If I know the session ID (something like "wuuZ2Gwgxw"), how do I (find and) end that particular session programmatically in ObjectScript - i.e., the equivalent of %session.EndSession=1 in the csp page code?

Thanks!

Michael Reach

Product version: Caché 2018.1
$ZV: Cache for Windows (x86-64) 2018.1.4 (Build 505_1_20258U) Thu Sep 10 2020 10:22:22 EDT
00
0 0 12 160
Log in or sign up to continue

Replies

What are the triggers for a session closure?

Sorry, could you explain what you mean by this? If you mean, when would we want to end a session, the answer is that we have been getting a lot of CSP sessions created by pings on the web page from the outside. Someone from who-knows-where calls the web page, a session is created and it uses a license until the grace period expires 20 minutes later. If half-a-dozen of them happen at once (which has been happening), we're out of licenses.

So we were trying to look over the license usage each minute, check each of the licenses associated with a CSP type, and end the session if that user never actually logged in.

This is for educational use only, so if you break your system, lose your cat, or your ice cream goes all melty by using my example below, please don't hold me accountable.

Also, I would like to mention that I borrowed the base structure from the ^%SS utility in the %SYS namespace.

I would also like to mention that in my *very* limited testing, you'll only have a CSP Session ID while there's actually "stuff" going on in the CSP Page. If you're executing a two-minute query in a CSP Page, whilst that query is running you can see (and clobber) that session. If the query is complete and you're just scrollin' round the results not generating new HTTP requests into the CSP Page, you may not be able to see the CSP Session ID.

That said, this did work for me to kill a CSP Session mid-query:

ZZPROCKILL ; 
 OLDNS=$NAMESPACE
 $NAMESPACE="%SYS"
 query="",parm=1
 Set Rset=##class(%Library.ResultSet).%New("SYS.Process:SS")
 Do Rset.Execute(parm)
 POP=0
 While Rset.Next() {
Username=Rset.Get("User")
CONTINUE:Username'="UnknownUser"
NameSpace=Rset.Get("Namespace")
NameSpace="" NameSpace="%SYS" 
; i (Dir'=""),(NameSpace'=Dir) continue
Set Pid=Rset.Get("Process")
Process=##CLASS(%SYS.ProcessQuery).Open(Pid)
SID=Process.CSPSessionID
Process.%Close()
!,$J($s(($zversion(1)=1):$ZH(+Pid),1:Pid),8)_$Case(JobType,1:"*",:""),?20,Username,?40,NameSpace,?50,SID,!
    SID'="" $SYSTEM.Process.Terminate(Pid)
 }
 Rset.%Close()
 
 $NAMESPACE=OLDNS
 Q
 ;

I have 'embiggened' the line of code that actually terminates the process, and I did make one further assumption in my code: That the CSP Sessions would be run under the user: UnknownUser - If your system uses a different user to execute CSP, you'll need to change the username in the CONTINUE: line (ZZPROCKILL+10).

If you want to just see if you can find CSP sessions and not actually terminate them, comment out that final 'embiggened' line in the While loop (that starts with i SID'="").

Hope this helps!

Thank you! Does this reclaim the license as well? Is any other cleanup required?

Michael

I notice that you aren't actually doing the lookup by session id, just looking at all the system processes there are. Does that mean that there isn't really any way to do this on the session level?

Michael

Try the following:

status=$$DeleteSession^%SYS.cspServer("wuuZ2Gwgxw")

This is not documented or supported. Use at your own risk.

But since you specified Caché 2018.1, which is no longer being developed so not may change in the future (not counting security patches).

Wow, cool! Thanks!

Michael

If I could ask, does this reclaim the license used for the CSP session, or is there another step that does that quickly?

Thanks!

I was curious.
What problem do you hope to solve by deleting the section?
Is there a section that may have frozen? Or is the normal expiration time not long enough?

We are getting hits from random IP addresses around the world, a few times a week. They ping the page and then never proceed further, never log in (they wouldn't be able to without an account). We get half-a-dozen hits within a few seconds, using up half-a-dozen licenses - we only have 14, and several more are used anyhow by the system. Those session persist for twenty minutes because of the Grace period for our CSP pages. When that happens, it is very likely that some of our own users will be unable to log in because all the licenses are gone.

We try to stop them at the firewall, but it's new IP addresses every time, and anyone can go to our website.

So what I wanted to do was check the license logging every minute, see which sessions are from IPs that never tried to log in, say after a minute, and get rid of them. That way we get the license(s) back. I have working code that identifies those sessions.

If I were coming from a CSP page itself, I would do something like

%session.EndSession=1
%session.Data
%session.Logout()
But that won't work from an outside job: I need to be able to access the right session. That's all I'm trying to do: get access to the correct %CSP.Session object.

I understood that 14 licenses + Grace Period are your biggest pains.
In past, I  decreased the risk by moving ALL (suspicious) connections to a dedicated  User
observing his maxConnection limit using %CSP.Session.Login() especially this explanation:

Login with this username and password, returns a status code to show if it worked or not. This method also trades license units at the same time so this CSP session will be logged in as a named user. If you pass type=1 then this will trade licenses only and not login as this user.

This can't avoid a DDoS attack but it limits the initial impact and allows you to
protect some emergency licenses.

[As I know the inventor of Grace Period since it was rolled out with a lot of pain for customers
I'm not willing to discuss this "feature" in public again]