{"record":{"id":"6403c9dc26902605","repo":"rancher/rancher","slug":"saml-providers-do-not-implement-authenticate-user","errorCode":null,"errorMessage":"SAML providers do not implement Authenticate User API","messagePattern":"SAML providers do not implement Authenticate User API","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/auth/providers/saml/saml_provider.go","lineNumber":111,"sourceCode":"func (s *Provider) TransformToAuthProvider(authConfig map[string]any) (map[string]any, error) {\n\tp := common.TransformToAuthProvider(authConfig)\n\tswitch s.name {\n\tcase PingName:\n\t\tp[publicclient.PingProviderFieldRedirectURL] = formSamlRedirectURLFromMap(authConfig, s.name)\n\tcase ADFSName:\n\t\tp[publicclient.ADFSProviderFieldRedirectURL] = formSamlRedirectURLFromMap(authConfig, s.name)\n\tcase KeyCloakName:\n\t\tp[publicclient.KeyCloakProviderFieldRedirectURL] = formSamlRedirectURLFromMap(authConfig, s.name)\n\tcase OKTAName:\n\t\tp[publicclient.OKTAProviderFieldRedirectURL] = formSamlRedirectURLFromMap(authConfig, s.name)\n\tcase ShibbolethName:\n\t\tp[publicclient.ShibbolethProviderFieldRedirectURL] = formSamlRedirectURLFromMap(authConfig, s.name)\n\t}\n\treturn p, nil\n}\n\nfunc (s *Provider) AuthenticateUser(http.ResponseWriter, *http.Request, any) (apiv3.Principal, []apiv3.Principal, string, error) {\n\treturn apiv3.Principal{}, nil, \"\", fmt.Errorf(\"SAML providers do not implement Authenticate User API\")\n}\n\n// Logout guards against a regular logout when the system has SLO, i.e. LogoutAll forced.\nfunc (s *Provider) Logout(w http.ResponseWriter, r *http.Request, token accessor.TokenAccessor) error {\n\tproviderName := token.GetAuthProvider()\n\n\tlogrus.Debugf(\"SAML [logout]: triggered by provider %s\", providerName)\n\n\tprovider, ok := SamlProviders[providerName]\n\tif !ok {\n\t\treturn fmt.Errorf(\"SAML [logout]: Rancher provider resource `%v` not configured at all\", providerName)\n\t}\n\n\tif provider.sloForced {\n\t\treturn fmt.Errorf(\"SAML [logout]: Rancher provider resource `%v` configured for forced SLO, rejecting regular logout\", providerName)\n\t}\n\n\treturn nil","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/rancher/rancher/blob/932558d4e68565aff2d2f36e89ec4a391b06e7c5/pkg/auth/providers/saml/saml_provider.go#L93-L129","documentation":"SAML providers in Rancher deliberately do not implement the AuthenticateUser API (the direct, non-browser credential exchange used by e.g. local auth). SAML requires the browser-redirect protocol with the IdP, so Provider.AuthenticateUser always returns this error. It signals an unsupported operation, not a malfunction.","triggerScenarios":"POST to /v3-public/authProviders/<ping|adfs|keycloak|okta|shibboleth>/action/authenticateUser with credentials in the body; any client code that treats all auth providers as exposing the same authenticateUser interface and calls it against a SAML provider.","commonSituations":"Automation or CLI scripts written against local/ldap auth reused for SAML; UI code paths that fall back to direct authentication; API clients expecting a token from username/password regardless of provider type.","solutions":["Use the SAML login flow instead: POST the samlLogin action and follow the returned idpRedirectUrl through the IdP","For API access, log in via a provider that supports direct authentication (e.g. local) or use a pre-issued API token","Gate client-side: skip authenticateUser calls for the five SAML provider names"],"exampleFix":"// before\nresp, err := client.Post(\"/v3-public/authProviders/ping/action/authenticateUser\", body)\n\n// after: use the redirect-based flow for SAML providers\nresp, err := client.Post(\"/v3-public/authProviders/ping/action/samlLogin\", samlLoginBody)\n// then open resp.idpRedirectUrl in a browser/session-capable client","handlingStrategy":"validation","validationCode":"var samlProviders = map[string]bool{\"ping\": true, \"adfs\": true, \"keycloak\": true, \"okta\": true, \"shibboleth\": true}\n\nfunc authenticateUser(providerName string, body io.Reader) (*http.Response, error) {\n    if samlProviders[providerName] {\n        return nil, fmt.Errorf(\"provider %s requires the browser-based samlLogin flow\", providerName)\n    }\n    return client.Post(fmt.Sprintf(\"/v3-public/authProviders/%s/action/authenticateUser\", providerName), body)\n}","typeGuard":"func supportsAuthenticateUser(providerName string) bool {\n    switch providerName {\n    case \"ping\", \"adfs\", \"keycloak\", \"okta\", \"shibboleth\":\n        return false // SAML: browser redirect flow only\n    }\n    return true\n}","tryCatchPattern":null,"preventionTips":["Branch client auth code on provider protocol (SAML vs direct) before choosing the action","For API/automation against SAML-enabled Rancher, use API tokens or a local admin instead of password exchange","Read the provider capability matrix rather than assuming a uniform auth API"],"tags":["saml","unsupported-operation","api","authentication"],"backgroundTag":null,"analyzedSha":"932558d4e68565aff2d2f36e89ec4a391b06e7c5","analyzedAt":"2026-08-16T04:37:02.125Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}