Running an API Gateway in an environment where Siteminder Agent produces SMSESSION cookies, one can see that the idle and max timeout of the session doesn't get honored as configured on the API Gateway.
To illustrate, when a SMSESSION cookie comes to an API Gateway Server protected resource, having an idle timeout of 5 min, after some time (around 60 minutes) the "Authenticate Against CA Single Sign-On assertion" returns code 4 which means that the session has expired.
The problem is that for the API Gateway the session timeout is set to 8 hours and the idle timeout to 5 minutes. So the API Gateway curiously ends the session before the session timeout it has in its configuration.
API Gateway 9.4CR04;
Policy Server 12.7 on Windows 2016;
Policy Server JDK 1.8.0_202;
The problem is that the environment presents a mixture of Persistent and Non-Persistent realms across the browser journey. The first MYSESSION is created in the Persistent realm. The further MYSESSION cookies get updated on Non Persistent realms. As such, when the Agents ask to get the session update to the Policy Server, the Policy Server checks the value in the Session Store, even if the reached Realm is Non-Persistent. This is so as the MYSESSION sessionspec has a value by saying that the session is persistent.
Let's take a look at the full journey.
fiddler.saz :
The user myuser logs in at IDP at Tue, 19 May 2020 08:02:37 GMT and
gets its first MYSESSION cookie :
Line 101 :
POST https://myidp.myidpdomain.com:20015/cred/login.fcc?TYPE=33554433&REALMOID=06-85544s544s-d44s-444s-5sss-2245d5s55d5&GUID&SMAUTHREASON=0&METHOD=GET&SMAGENTNAME=-SM-SeDSD454das564dd4e4sd44sd4455ed5d5s4d45e5e55s4cx11sas444s4s&SWATARGET=-SM-HTTP%3A%2F%2Fmyidp.myidpdomain.com%3A20016%2Faffwebservices%2Fredirectjsp%2Fredirect.jsp%3FSPID%3Dmyspid%26ProtocolBinding%3Durn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Abindings%3AHTTP--POST%26SMPORTALURL%3Dhttp-%3A-%2F-%2Fmyidp.myidpdomain.com%3A20016-%2Faffwebservices-%2Fpublic-%2Fsaml2sso%26SAMLTRANSACTIONID%3Dee7c9c18--60bda7cf--cefb212f--3a29b570--eb6d88a8--cc
USERPH=myuser&PASSWORD=xxasdasd%25&smquerydata=&smauthreason=0&smagentname=SeDSD454das564dd4e4sd44sd4455ed5d5s4d45e5e55s4cx11sas444s4s&USER=myuser%40SYSSEDE&postpreservationdata=&target=-SM-HTTP%253A%252F%252Fmyidp.myidpdomain.com%253A20016%252Faffwebservices%252Fredirectjsp%252Fredirect.jsp%253FSPID%253Dmyspid%2526ProtocolBinding%253Durn%253Aoasis%253Anames%253Atc%253ASAML%253A2.0%253Abindings%253AHTTP--POST%2526SMPORTALURL%253Dhttp-%253A-%252F-%252Fmyidp.myidpdomain.com-%253A20016-%252Faffwebservices-%252Fpublic-%252Fsaml2sso%2526SAMLTRANSACTIONID%253Dee7c9c18--60bda7cf--cefb212f--3a29b570--eb6d88a8--cc
HTTP/1.1 302 HTTP/1.1 302 Object Moved
Server: Microsoft-IIS/7.5
MYOTHERSESSION=cmWv0F6RdzBg52LJr
Date: Tue, 19 May 2020 08:02:34 GMT
Line 105 :
POST https://mysp.myspdomain.com/affwebservices/public/saml2assertionconsumer
MYOTHERSESSION=ntmZUuz0w/fOIpfEteQ4qKPcCHFxmAkku2fbqwRJv3EeZTG5IZqZl
SAMLResponse=PFJlc3BvbnNlIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIERl
HTTP/1.1 302 Moved Temporarily
Date: Tue, 19 May 2020 08:02:37 GMT
Server: Apache
MYSESSION=Mb48J3Urd2guiSFJEO6QF/ne1PQLweGnsKCMzAquK1hclDcVaZQ4qfmsqjbPtlB
Line 107 :
POST https://myapplication.myspdomain.com/rest/SAML
MYOTHERSESSION=ntmZUuz0w
MYSESSION=Mb48J3Urd2guiSFJEO6QF
SAMLResponse=PFJlc3BvbnNlIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIERl
HTTP/1.1 302 Found
Date: Tue, 19 May 2020 08:02:37 GMT
And later, the MYSESSION get renewed, even if we don't see the user
session being renewed in the Policy Servers since 08:02:37 (brower
time) 10:02:37 (policy server time) :
Line 211 :
GET https://myapplication.myspdomain.com/rest/login/RefreshJwt
MYOTHERSESSION=ntmZUuz0w
MYSESSION=Mb48J3Urd2guiSFJEO6QF
HTTP/1.1 200 OK
Date: Tue, 19 May 2020 08:06:07 GMT
MYSESSION=sVGLvgPnqH6ZBrsG4QCov0 [...]
{"status":"ok","code":0,"message":"LoginJWT successfully retrieved.","content":{"result":"{\"expirationDate\":\"2020-05-19T08:11:07\"}"}}
Line 405 :
GET https://myapplication.myspdomain.com/rest/login/RefreshJwt
MYOTHERSESSION=ntmZUuz0w/fOIpfEteQ4qKPcCHFxmAkku2fbqwRJv3EeZTG5IZqZl
MYSESSION=5L2skVVITbvosHwHdVtfllpmBXhCmanpWHZc2FnYfDSx8c
HTTP/1.1 200 OK
Date: Tue, 19 May 2020 08:59:07 GMT
MYSESSION=LciE4ZSa5wtRp6vDSD1WCRPDj04ea6lHffeeaEECbVXfEvOV0ko3vZs2WTVNDCJbb [...]
{"status":"ok","code":0,"message":"LoginJWT successfully retrieved.","content":{"result":"{\"expirationDate\":\"2020-05-19T09:04:07\"}"}}
Line 409 :
GET https://myapplication.myspdomain.com/rest/login/RefreshJwt
MYOTHERSESSION=ntmZUuz0w/fOIpfEteQ4qKPcCHFxmAkku2fbqwRJv3EeZTG5IZqZl
MYSESSION=LciE4ZSa5wtRp6vDSD1WCRPDj04ea6lHffeeaEECbVXfEvOV0ko3vZs2WTVNDCJbb [...]
HTTP/1.1 200 OK
Date: Tue, 19 May 2020 09:02:37 GMT
MYSESSION=zNJK9B52YwhLR6eA9URM8VJmYpsmI0b33RWasGSe4oZ7g2gZ [...]
{"status":"ok","code":0,"message":"LoginJWT successfully retrieved.","content":{"result":"{\"expirationDate\":\"2020-05-19T09:07:37\"}"}}
Until the Agent requests to validate the session to the Policy Server
an hour later :
Line 420 :
GET https://myapplication.myspdomain.com/rest/login/RefreshJwt
MYOTHERSESSION=ntmZUuz0w/fOIpfEteQ4qKPcCHFxmAkku2fbqwRJv3EeZTG5IZqZl [...]
MYSESSION=zNJK9B52YwhLR6eA9URM8VJmYpsmI0b3 [...]
HTTP/1.1 400 Bad Request
Date: Tue, 19 May 2020 09:06:07 GMT
{"status":"error","code":400,"message":"ERROR in service JWT
StatusCode = Unauthorized, Content =
{\n\"status\":\"Unauthorized\",\n\"code\":\"401\",\n\"desc\":\"Invalid
MYSESSION cookie.\"\nReason code: 4\nMessage:Session has
expired.\n}","content":{}}
apilog.log :
The MYSESSION cookie gets refreshed :
2020-05-19T11:02:37.597+0200 INFO 2830 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ce | GWIP:10.0.0.100 |
myspapplication.REST | /portalFI/v1/api/* | /rest/ | Start
Method
2020-05-19T11:02:37.597+0200 INFO 2830 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ce | GWIP:10.0.0.100 |
myspapplication.REST | /portalFI/v1/api/* |
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiIsImtpZCI6InNpZ25hdHVyZWp3d [...]
Authorization from request header.
2020-05-19T11:02:37.598+0200 INFO 2830 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ce | GWIP:10.0.0.100 |
myspapplication.REST | /portalFI/v1/api/* | Validating JWT...
2020-05-19T11:02:37.598+0200 INFO 2830 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ce | GWIP:10.0.0.100 |
myspapplication.REST | /portalFI/v1/api/* | JWT recived :
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiIsImtpZCI6InNpZ25hdHVyZWp3d [...]
2020-05-19T11:02:37.608+0200 INFO 2830 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ce | GWIP:10.0.0.100 |
myspapplication.REST | /portalFI/v1/api/* | Expiration time
extracted : 1589879047.
2020-05-19T11:02:37.608+0200 INFO 2830 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ce | GWIP:10.0.0.100 |
myspapplication.REST | /portalFI/v1/api/* | JWT succesfully
validated.
2020-05-19T11:02:37.610+0200 INFO 2830 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ce | GWIP:10.0.0.100 |
myspapplication.REST | /portalFI/v1/api/* | /rest/ | Routing
to http://10.0.0.1/rest/login/RefreshJwt...
2020-05-19T11:02:37.611+0200 WARNING 2830
com.l7tech.common.http.prov.apache.components.HttpComponentsClient:
Bad Authorization header
presenteyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiIsImtpZCI6InNpZ25hdHVyZWp3d [...]
2020-05-19T11:02:37.736+0200 INFO 2830 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ce | GWIP:10.0.0.100 |
myspapplication.REST | /portalFI/v1/api/* | Response:
Header: Access-Control-Expose-Headers:Set-Cookie,
Access-Control-Max-Age:1728000, Cache-Control:no-cache, no-store,
Content-Encoding:gzip, Content-Length:145,
Content-Type:application/json;charset=utf-8, Date:Tue, 19 May 2020
09:02:37 GMT, Expires:-1, Pragma:no-cache,
Set-Cookie:MYSESSION=zNJK9B52YwhLR6eA9URM8VJmYpsmI0b33RWasGSe4oZ7g2gZ+ [...]
domain=.myspdomain.com; path=/; SameSite=None,
mwall=user_account=vegBQDuO9EXtVU3+WIuI6uoAmWiFn/0rBugFd0jQMhChXXKhKmLNX6Z [...]
domain=.myspdomain.com; path=/,
securitysession=jwtSecurity=eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiIsImtpZCI6InNpZ25h [...]
domain=.myspdomain.com; path=/.
And then the Agent renews the Session by the Policy Server, which
replies that Session has expired :
2020-05-19T11:06:07.621+0200 INFO 3214 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ef | GWIP:10.0.0.100 | Refresh JWT |
/oauth/v2/refresh/jwt* | Start Method
2020-05-19T11:06:07.621+0200 INFO 3214 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ef | GWIP:10.0.0.100 | Refresh JWT |
/oauth/v2/refresh/jwt* | Authorization from request header:
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiIsImtpZCI [...]
2020-05-19T11:06:07.622+0200 INFO 3214 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ef | GWIP:10.0.0.100 | Refresh JWT |
/oauth/v2/refresh/jwt* | Validating JWT...
2020-05-19T11:06:07.622+0200 INFO 3214 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ef | GWIP:10.0.0.100 | Refresh JWT |
/oauth/v2/refresh/jwt* | JWT recived :
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiIsImtpZCI6InNpZ [...]
2020-05-19T11:06:07.631+0200 INFO 3214 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ef | GWIP:10.0.0.100 | Refresh JWT |
/oauth/v2/refresh/jwt* | Expiration time extracted : 1589879257.
2020-05-19T11:06:07.631+0200 INFO 3214 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ef | GWIP:10.0.0.100 | Refresh JWT |
/oauth/v2/refresh/jwt* | JWT succesfully validated.
2020-05-19T11:06:07.633+0200 INFO 3214 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ef | GWIP:10.0.0.100 | Refresh JWT |
/oauth/v2/refresh/jwt* | AuthN: MYSESSION cookie
zNJK9B52YwhLR6eA9URM8VJmYpsmI0b33RWasGSe4oZ7g2gZ+7ilvSx [...]
2020-05-19T11:06:07.640+0200 WARNING 3214
com.ca.siteminder.SiteMinderLowLevelAgent: Session Cookie expired!
2020-05-19T11:06:07.640+0200 WARNING 3214
com.l7tech.log.custom.apilog: -5: 0000017115e4c7f0-132ef |
GWIP:10.0.0.100 | Refresh JWT | /oauth/v2/refresh/jwt* | Invalid
cookie detected. Reason code: 4, message:Session has expired.
2020-05-19T11:06:07.640+0200 WARNING 3214
com.l7tech.log.custom.apilog: -5: 0000017115e4c7f0-132ef |
GWIP:10.0.0.100 | Refresh JWT | /oauth/v2/refresh/jwt* | End
Method. APIGW HTTP response: 401 - Unauthorized.
2020-05-19T11:06:07.640+0200 SEVERE 3214
com.l7tech.server.SoapMessageProcessingServlet: RaiseErrorAssertion
is stopping execution.
2020-05-19T11:06:07.641+0200 WARNING 3214
com.l7tech.external.assertions.siteminder.server.ServerSiteMinderAuthenticateAssertion:
10102: CA Single Sign-On Authenticate Against CA Single Sign-On
assertion: Unable to authenticate user using SSO
Token:zNJK9B52YwhLR6eA9URM8VJmYpsmI0b33RWasGSe4oZ7g2gZ+7ilvSx [...]
2020-05-19T11:06:07.643+0200 INFO 3302 com.l7tech.log.custom.apilog:
-4: 0000017115e4c7f0-132ee | GWIP:10.0.0.100 |
myspapplication.REST | /portalFI/v1/api/* | Response:
Header: Access-Control-Expose-Headers:Set-Cookie,
Access-Control-Max-Age:1728000, Cache-Control:no-cache, no-store,
Content-Encoding:gzip, Content-Length:201,
Content-Type:application/json;charset=utf-8, Date:Tue, 19 May 2020
09:06:07 GMT, Expires:-1, Pragma:no-cache. Body:
{"status":"error","code":400,"message":"ERROR in service JWT
StatusCode = Unauthorized, Content =
{\n\"status\":\"Unauthorized\",\n\"code\":\"401\",\n\"desc\":\"Invalid
FMSession cookie.\"\nReason code: 4\nMessage:Session has
expired.\n}","content":{}}.
But the Session hasn't expired, but rather the IdleTimeout has been
reached from a long time ago :
smps.log :
[15216/15456][Tue May 19 2020
11:06:07][SmSessionServer.cpp:571][ERROR][sm-Server-06007]
failed. Error code : 2
smtracedefault.log :
Policy Server creates the sessionspec for the MYSESSION on the
Persistent Realm at 10:02:37 :
"samlidp:myidp" (06-erss44d44s5-1s55-ws44-dd4s-d1225444s55v) :
[05/19/2020][10:02:37.362][10:02:37][15216][17940][Sm_Auth_Message.cpp:4835][C
Sm_Auth_Message::SendReply][s21050/r49][samlidp:myidp][][][][saml
idp:myidp][samlidp:myidp][myldap][
][][][][][][][][][][][][** Status: Authenticated. ][samlidp:myidp
_auth][][][cn=myuser,dc=mydomain,dc=com]
[][][][][][06-erss44d44s5-1s55-ws44-dd4s-d1225444s55v][][][][]
and the Agent never comes back to the Policy Server to validate the
MYSESSION sessionspec data until one hour after having first created
the MYSESSION at 11:02:37 :
[05/19/2020][11:02:37.584][11:02:37][15216][19340][SmMessage.cpp:557][CSmMessa
ge::ParseAgentMessage][s23524/r4][myagent][][][][][][][][][][][][][][]
[][][][/myapp/myapplication][Receive request attribute 201, data size is
26][][][][][][][][][][][][][][]
[05/19/2020][11:02:37.584][11:02:37][15216][19340][Sm_Az_Message.cpp:598][CSm_
Az_Message::SendReply][s23524/r4][myagent][][][][/myapp/myapplication]
[myapplication][][][][][][][][][][][][][][** Status: Protected. ][][][][][][
][][][][][][][][]
and the validation of the cookie sessionspec is done against the
Non-Persistent Realm :
"/myapp/myapplication" (06-82fbddc4-5f61-404e-b679-24f749f30dc8)
[05/19/2020][11:06:07.560][11:06:07][15216][15456][SmMessage.cpp:557][CSmMessa
ge::ParseAgentMessage][s23524/r10][myagent][][][][][][][][][][][][][][
][][][][/myapp/myapplication][Receive request attribute 201, data size i
s 26][][][][][][][][][][][][][][]
[05/19/2020][11:06:07.560][11:06:07][15216][15456][SmMessage.cpp:557][CSmMessa
ge::ParseAgentMessage][s23524/r10][myagent][][][][][][][][][][][][][][
][][][][8aHhuj0rN4ViEkqismdYV
[...]
Ze1Dt5Us1OKB][Receive request attribut
e 209, data size is 512][][][][][][][][][][][][][][]
But as the sessionspec as been created on a persistent realm, then the
sessionspec data has "SessionPersistent" value set and as such, Policy
Server looks in the Session Store to find it and read the
SessionMaxTimeout
SessionIdleTimeout (1)(2)
values, and as the sessionspec data hasn't been update from more than
an hour, then the idle timeout value triggers :
[05/19/2020][11:06:07.560][11:06:07][15216][15456][SmSSProvider.cpp:594][CSmSS
Provider::GetSession][][][][][][][][][][][][][][][][][][][][][Enter function C
SmSSProvider::GetSession][][][][][][][][][][][][][][]
[05/19/2020][11:06:07.560][11:06:07][15216][15456][SmSSProvider.cpp:620][CSmSS
Provider::GetSession][][][][][][][][][][][][][2][][][][][][][][Leave function
CSmSSProvider::GetSession][][16][][][][][][D44s44454d441152s55w41z15df=][][][]
[][][]
[05/19/2020][11:06:07.560][11:06:07][15216][15456][SmSessionServer.cpp:571][][
][][][][][][][][][][][][][][][][][][][][LogMessage:ERROR:[sm-Server-06007]
failed. Error code : 2][][][][][][][][][][][][][][]
[05/19/2020][11:06:07.560][11:06:07][15216][15456][SmAuthSession.cpp:379][SmAu
thSession][][][][][][][][][][][][][][][][][][][][][Idle timeout exceeded][][][
][][][][][][][][][][][]
[05/19/2020][11:06:07.560][11:06:07][15216][15456][Sm_Auth_Message.cpp:4835][C
Sm_Auth_Message::SendReply][s23524/r10][myagent][][][][/myapp/myapplication]
[myapplication][][][][][][][][][][][][][]
[** Status: Not Validated. Session has expired][myagent][][][][][][][][]
[06-55s5ddf4-5w5s-44s8-e556-224s55df4ffd4][][][Session has expired][]
pstore.xml :
realm "/myapp/myapplication"
<Object Class="CA.SM::Realm"
Xid="CA.SM::[email protected]"
CreatedDateTime="2019-09-05T16:30:09"
ModifiedDateTime="2020-04-23T15:32:20"
UpdatedBy="acnminder" UpdateMethod="GUI">
<Property Name="CA.SM::Realm.Name">
<StringValue>/myapp/myapplication</StringValue>
</Property>
<Property Name="CA.SM::Realm.ResourceFilter">
<StringValue>/myapp/myapplication</StringValue>
</Property>
<Property Name="CA.SM::Realm.MaxTimeout">
<NumberValue>28800</NumberValue>
</Property>
<Property Name="CA.SM::Realm.IdleTimeout">
<NumberValue>300</NumberValue>
<Property Name="CA.SM::Realm.SessionType">
<NumberValue>0</NumberValue>
where 300 is 5 minutes and session type is non-persistent as per value
of "0".
realm "samlidp:myidp"
<Object Class="CA.SM::Realm"
Xid="CA.SM::[email protected]"
CreatedDateTime="2019-12-19T13:15:28"
ModifiedDateTime="2020-04-23T15:31:37"
UpdatedBy="acnminder" UpdateMethod="GUI">
<Property Name="CA.SM::Realm.Name">
<StringValue>samlidp:myidp</StringValue>
<Property Name="CA.SM::Realm.Desc">
<StringValue>Backing Object for Partnership Federation - do not edit</StringValue>
<Property Name="CA.SM::Realm.MaxTimeout">
<NumberValue>28800</NumberValue>
</Property>
<Property Name="CA.SM::Realm.IdleTimeout">
<NumberValue>300</NumberValue>
<Property Name="CA.SM::Realm.SessionType">
<NumberValue>1</NumberValue>
where 300 is 5 minutes and session type is persistent as per value
"1".
Review the implementation and make all realms persistent or all non-persistent, but avoid having a mixture of persistent and non-persistent.
(1)
What information is stored in the SMSESSION Cookie
SESSIONSPEC can only be decrypted by Policy server. It contains
following information :
SessionMaxTimeout
SessionIdleTimeout
SessionPersistent
(2)
SSO between seperate Siteminder environments
the SessionSpec SessionPersistent data
is set, then, when validating the session, the Policy Server from
envrionment B tries to find the data in a Session Store, and as it
cannot find the data in a Session Store, it reports the error.
In order to get SSO, you should set your realms the same type, and not
a mixture of persistent and not persistent.
when realms are persistents, you do need a shared Session Store
between the environments, in order for each of them to find the
Session that bring the SMSESSION and to be able to validate it without
having to ask for credentials. Both environment should share the same
Session Store.