{"record":{"id":"636306f74b44793e","repo":"apereo/cas","slug":"no-wctx-parameter-is-found","errorCode":null,"errorMessage":"No wctx parameter is found","messagePattern":"No wctx parameter is found","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-wsfederation/src/main/java/org/apereo/cas/support/wsfederation/web/WsFederationCookieManager.java","lineNumber":52,"sourceCode":"    private final Collection<WsFederationConfiguration> configurations;\n    private final CasConfigurationProperties casProperties;\n\n    private final WsFederationServerStateSerializer serializer;\n\n    /**\n     * Retrieve service.\n     *\n     * @param context the request context\n     * @return the service\n     */\n    public Service retrieve(final RequestContext context) {\n        val request = WebUtils.getHttpServletRequestFromExternalWebflowContext(context);\n\n        val contextId = request.getParameter(WCTX);\n        LOGGER.debug(\"Parameter [{}] received: [{}]\", WCTX, contextId);\n        if (StringUtils.isBlank(contextId)) {\n            LOGGER.error(\"No [{}] parameter is found\", WCTX);\n            throw new IllegalArgumentException(\"No \" + WCTX + \" parameter is found\");\n        }\n\n        val configuration = configurations.stream()\n            .filter(cookie -> cookie.getId().equalsIgnoreCase(contextId))\n            .findFirst()\n            .orElseThrow(() -> new IllegalArgumentException(\"Could not locate WsFederation configuration for \" + contextId));\n\n        val cookieGen = configuration.getCookieGenerator();\n        var serverState = cookieGen.retrieveCookieValue(request);\n        if (StringUtils.isBlank(serverState)) {\n            serverState = Optional.ofNullable(request.getSession(false))\n                .map(session -> session.getAttribute(configuration.getId()))\n                .map(String.class::cast)\n                .orElse(null);\n        }\n        if (StringUtils.isBlank(serverState)) {\n            LOGGER.error(\"No server state value could be retrieved to determine the state of the delegated authentication session\");\n            throw new IllegalArgumentException(\"No state could be found to determine session state\");","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-wsfederation/src/main/java/org/apereo/cas/support/wsfederation/web/WsFederationCookieManager.java#L34-L70","documentation":"Thrown by WsFederationCookieManager.retrieve when the incoming WS-Federation request has no wctx parameter (or it is blank). The wctx value is used to select the matching WsFederationConfiguration (by id) from the registered configurations, so without it the request cannot be routed to an identity provider configuration.","triggerScenarios":"A request reaches the WS-Federation callback/validation flow without a wctx request parameter: the IdP did not echo back wctx, the client dropped the query parameter, or the request bypassed the initial CAS WS-Federation redirect that establishes it.","commonSituations":"Users bookmarking or hand-crafting the callback URL without wctx, a misconfigured IdP relying-party trust that strips custom query parameters, proxies/rewrites dropping query strings, or testing the callback endpoint directly.","solutions":["Verify the IdP echoes the wctx parameter back on the sign-in response; check the relying-party trust configuration preserves it.","Ensure clients initiate the flow via CAS's WS-Federation entry point (which sets wctx) rather than hitting the callback URL directly.","Check reverse proxies/load balancers are not stripping query parameters on the redirect back to CAS.","If you construct callback URLs yourself in tests or integrations, include the original wctx value from the outgoing request."],"exampleFix":"// before: callback invoked without wctx\nString callback = \"https://cas.example.org/cas/login?client_name=WSFederation\";\n// after: preserve wctx from the original redirect\nString callback = \"https://cas.example.org/cas/login?client_name=WSFederation&wctx=\" + originalWctx;","handlingStrategy":"validation","validationCode":"// guard before entering the validation flow\nString wctx = request.getParameter(\"wctx\");\nif (wctx == null || wctx.isBlank()) {\n    throw new IllegalArgumentException(\"wctx parameter missing; requests must originate from the CAS WS-Federation entry point\");\n}","typeGuard":"function hasWctx(request) {\n  const wctx = request.query && request.query.wctx;\n  return typeof wctx === 'string' && wctx.length > 0;\n}","tryCatchPattern":"try {\n    wsFederationCookieManager.retrieve(context);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"wctx\")) {\n        LOGGER.warn(\"Request reached WS-Fed validation without wctx; redirecting to entry point\");\n        return redirectToWsFederationEntryPoint();\n    }\n    throw e;\n}","preventionTips":["Always start the WS-Fed flow from CAS's entry point so wctx is generated and echoed by the IdP.","Verify proxy/rewrite rules preserve query parameters on the IdP-to-CAS redirect.","Warn users/integrators not to bookmark or manually edit callback URLs."],"tags":["ws-federation","missing-parameter","wctx","request-validation"],"backgroundTag":"missing-required-argument","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}