{"record":{"id":"a20b434d4dd9a1a5","repo":"TechnitiumSoftware/DnsServer","slug":"cannot-change-password-for-sso-users","errorCode":null,"errorMessage":"Cannot change password for SSO users.","messagePattern":"Cannot change password for SSO users\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"warning","filePath":"DnsServerCore/Auth/User.cs","lineNumber":261,"sourceCode":"            {\n                case UserPasswordHashType.OldScheme:\n                    using (HMAC hmac = new HMACSHA256(Encoding.UTF8.GetBytes(password)))\n                    {\n                        return Convert.ToHexString(hmac.ComputeHash(Encoding.UTF8.GetBytes(_username))).ToLowerInvariant();\n                    }\n\n                case UserPasswordHashType.PBKDF2_SHA256:\n                    return Convert.ToHexString(Rfc2898DeriveBytes.Pbkdf2(Encoding.UTF8.GetBytes(password), _salt, _iterations, HashAlgorithmName.SHA256, 32)).ToLowerInvariant();\n\n                default:\n                    throw new NotSupportedException();\n            }\n        }\n\n        public void ChangePassword(string newPassword, int iterations = DEFAULT_ITERATIONS)\n        {\n            if (_isSsoUser)\n                throw new InvalidOperationException(\"Cannot change password for SSO users.\");\n\n            _passwordHashType = UserPasswordHashType.PBKDF2_SHA256;\n            _iterations = iterations;\n\n            _salt = new byte[32];\n            RandomNumberGenerator.Fill(_salt);\n\n            _passwordHash = GetPasswordHashFor(newPassword);\n        }\n\n        public void LoadOldSchemeCredentials(string passwordHash)\n        {\n            if (_isSsoUser)\n                throw new InvalidOperationException();\n\n            _passwordHashType = UserPasswordHashType.OldScheme;\n            _passwordHash = passwordHash;\n        }","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Auth/User.cs#L243-L279","documentation":"Thrown by User.ChangePassword() when the user was created via an external Single Sign-On (SSO) identity provider. Such users have no local password credential (the _isSsoUser flag is set), so changing a local password is meaningless and would leave the account in an inconsistent state. The guard fires before any hash/salt regeneration so no state is mutated.","triggerScenarios":"Calling user.ChangePassword(newPassword) on a User instance whose _isSsoUser is true. In Technitium DNS Server this happens when an administrator attempts to reset the password of an SSO-linked account through the web API or the AuthManager wrapper.","commonSituations":"Mixing local and SSO users in the same directory; an admin UI form that always offers a 'change password' action regardless of account type; migrating from local auth to SSO and forgetting that migrated accounts keep their SSO flag.","solutions":["Check user.IsSsoUser before calling ChangePassword and skip or redirect the request to the SSO provider's password flow.","If the account must become a local password account, create a new local user instead of trying to convert the SSO user.","Gate the password-change API endpoint so it returns a 4xx 'not applicable for SSO users' response instead of letting the exception propagate."],"exampleFix":"// before\nuser.ChangePassword(newPassword);\n\n// after\nif (!user.IsSsoUser)\n    user.ChangePassword(newPassword);\nelse\n    throw new InvalidOperationException(\"Password changes are managed by the SSO identity provider.\");","handlingStrategy":"validation","validationCode":"if (user.IsSsoUser)\n    return BadRequest(\"Cannot change password for an SSO user; use the identity provider.\");\nuser.ChangePassword(newPassword);","typeGuard":"static bool CanChangePassword(User user) => !user.IsSsoUser;","tryCatchPattern":null,"preventionTips":["Branch all password-management flows on user.IsSsoUser.","Expose password-change only for local accounts in the UI.","Document that SSO users must reset passwords at the IdP."],"tags":["auth","sso","password","technitium-dns-server","invalidoperation"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}