So, I discovered an error present since CAS 6.5.0, which happens when calling REST service "/cas/v1/tickets/{TGT}" and passing it "service" which is not matched against any service registered in a given CAS instance.
Expected behavior: error "
403 Forbidden" is returned - analogical to when an authenticated user tries to access "/cas/login?service=<not-registered-service>" (in that case, this problem is caught early on - in the
org.apereo.cas.services.web.support.RegisteredServiceResponseHeadersEnforcementFilter.prepareFilterBeforeExecution() - apparently a filter which is not used for REST services).
Actual behavior: error "500 Internal Server Error" is returned, caused by
NullPointerException from ensureServiceSsoAccessIsAllowed(), called from
grantServiceTicket().
This problem seems to be
caused by
this commit, where inside
grantServiceTicket()
a call to
enforceRegisteredServiceAccess() (basically includes checking "registeredService" is found) was replaced by a
"too late" call to an overloaded variant of this method.
Can CAS authors please confirm and suggest a solution for this? By quickly analyzing the code, I guess it could be solved either by adding a null check into
ensureServiceSsoAccessIsAllowed(), or by returning the original call to
enforceRegisteredServiceAccess(), but I'm not sure without a deeper investigation of the CAS code. (For example, I would expect that
grantServiceTicket() will be structurally similar to grantProxyTicket(), but it isn't and I have no clue why.)
(I also wonder, possibly a topic for another thread, provided that I read it correctly, whether it is really correct that
enforceRegisteredServiceAccess() can currently NOT throw an exception even if passing it registeredService equal to null (see checks including calling a Groovy script
here). In previous versions, there was a simple null check and only then all other checks, which makes more sense to me, because follow-up code, like inside
grantServiceTicket(), seems to expect
registeredService is not null anyway.)