In the login-webflow.xml, after initialization ticketGrantingTicketExistsCheck tests for a TGT ID cookie value, and if one exists passes to hasServiceCheck which tests for a service= string, and if no service is provided passes to viewGenericLoginSuccess which displays the "Logged In" page. The problem is that the validity of the TGT ID has not been established. If it has timed out, or (as we found out) if CAS is restarted with an empty ticket registry, the validity of the TGT is not tested until a ST is requested.
This is confusing to the user, but of very low priority because you get prompted to login whenever you go to a real CAS protected service. So it mostly effects people who are testing CAS and notice something is "working" when it should have failed.
However, there is no good way to fix it within the WebFlow because the CentralAuthenticationService interface doesn't expose an obvious way to test the validity of a TGTID without issuing a ST. Without a code change you could try to grantServiceTicket for "http://some.bogus.service.name", and if the ST issues then the TGT is OK while if it throws invalidTicketException then the TGT is bad. If !registeredService.isEnabled() then a bogus service name thows UnauthorizedServiceException and no ST is issued. Otherwise, the ST sits around wasting memory and has to be expired (not a terrible idea).
If it is OK to change code, then there might be some public static String NOSERVICENAME that can be presented to grantServiceTicket and causes CentralAuthenticationServiceImpl to stop before generating a ST (or just move the service==null test to after the TGT validation logic.
Or we could add a validateTGT to the CAService interface, but that seems unnecessary.
Once some preferred way to do the TGT validate is found, then any presentation layer implementation has to use it. A small WebFlow bean could be inserted between hasServiceCheck and viewGenericLoginSuccess to make the test and direct to regular authentication on failure.