Example #1
0
        //---------------------------------------------------------------------
        // private methods
        //---------------------------------------------------------------------
        /// <summary>
        /// This function calls the OS dialog to prompt user for credential.
        /// </summary>
        /// <param name="target">
        /// The credential target. It is displayed in the prompt dialog and is
        /// used for credential storage.
        /// </param>
        /// <param name="hwdOwner">The parent for the dialog.</param>
        /// <param name="userName">The username supplied by the user.</param>
        /// <param name="password">The password supplied by the user.</param>
        /// <returns>
        /// DialogResult.OK = if Successfully prompted user for credentials.
        /// DialogResult.Cancel = if user cancelled the prompt dialog.
        /// </returns>
        private static DialogResult ShowOSCredentialDialog(string target, IntPtr hwdOwner, out string userName, out string password)
        {
            DialogResult retValue = DialogResult.Cancel;
            userName = string.Empty;
            password = string.Empty;

            string titleFormat = SR.CredentialDialog_TitleFormat;
            string descriptionFormat = SR.CredentialDialog_DescriptionTextFormat;

            // Create the CREDUI_INFO structure.
            NativeMethods.CREDUI_INFO info = new NativeMethods.CREDUI_INFO();
            info.pszCaptionText = string.Format(CultureInfo.CurrentUICulture, titleFormat, target);
            info.pszMessageText = string.Format(CultureInfo.CurrentUICulture, descriptionFormat, target);
            info.hwndParentCERParent = hwdOwner;
            info.hbmBannerCERHandle = IntPtr.Zero;
            info.cbSize = Marshal.SizeOf(info);

            // We do not use CREDUI_FLAGS_VALIDATE_USERNAME flag as it doesn't allow plain user
            // (one with no domain component). Instead we use CREDUI_FLAGS_COMPLETE_USERNAME.
            // It does some basic username validation (like doesnt allow two "\" in the user name.
            // It does adds the target to the username. For example, if user entered "foo" for
            // taget "bar.com", it will return username as "bar.com\foo". We trim out bar.com
            // while parsing the username. User can input "*****@*****.**" as workaround to provide
            // "bar.com\foo" as the username.
            // We specify CRED_TYPE_SERVER_CREDENTIAL flag as the stored credentials appear in the
            // "Control Panel->Stored Usernames and Password". It is how IE stores and retrieve
            // credentials. By using the CRED_TYPE_SERVER_CREDENTIAL flag allows IE and VS to
            // share credentials.
            // We dont specify the CREDUI_FLAGS_EXPECT_CONFIRMATION as the VS proxy service consumers
            // dont call back into the service to confirm that the call succeeded.
            NativeMethods.CREDUI_FLAGS flags = NativeMethods.CREDUI_FLAGS.SERVER_CREDENTIAL |
                                                NativeMethods.CREDUI_FLAGS.SHOW_SAVE_CHECK_BOX |
                                                NativeMethods.CREDUI_FLAGS.COMPLETE_USERNAME |
                                                NativeMethods.CREDUI_FLAGS.EXCLUDE_CERTIFICATES;

            StringBuilder user = new StringBuilder(Convert.ToInt32(NativeMethods.CREDUI_MAX_USERNAME_LENGTH));
            StringBuilder pwd = new StringBuilder(Convert.ToInt32(NativeMethods.CREDUI_MAX_PASSWORD_LENGTH));
            int saveCredentials = 0;
            // Ensures that CredUPPromptForCredentials results in a prompt.
            int netError = NativeMethods.ERROR_LOGON_FAILURE;

            // Call the OS API to prompt for credentials.
            NativeMethods.CredUIReturnCodes result = NativeMethods.CredUIPromptForCredentials(
                info,
                target,
                IntPtr.Zero,
                netError,
                user,
                NativeMethods.CREDUI_MAX_USERNAME_LENGTH,
                pwd,
                NativeMethods.CREDUI_MAX_PASSWORD_LENGTH,
                ref saveCredentials,
                flags);

            if (result == NativeMethods.CredUIReturnCodes.NO_ERROR) {
                userName = user.ToString();
                password = pwd.ToString();

                try {
                    if (Convert.ToBoolean(saveCredentials)) {
                        // Try reading the credentials back to ensure that we can read the stored credentials. If
                        // the CredUIPromptForCredentials() function is not able successfully call CredGetTargetInfo(),
                        // it will store credentials with credential type as DOMAIN_PASSWORD. For DOMAIN_PASSWORD
                        // credential type we can only retrive the user name. As a workaround, we store the credentials
                        // as credential type as GENERIC.
                        string storedUserName;
                        string storedPassword;
                        bool successfullyReadCredentials = ReadOSCredentials(target, out storedUserName, out storedPassword);
                        if (!successfullyReadCredentials ||
                            !string.Equals(userName, storedUserName, StringComparison.Ordinal) ||
                            !string.Equals(password, storedPassword, StringComparison.Ordinal)) {
                            // We are not able to retrieve the credentials. Try storing them as GENERIC credetails.

                            // Create the NativeCredential object.
                            NativeMethods.NativeCredential customCredential = new NativeMethods.NativeCredential();
                            customCredential.userName = userName;
                            customCredential.type = NativeMethods.CRED_TYPE_GENERIC;
                            customCredential.targetName = CreateCustomTarget(target);
                            // Store credentials across sessions.
                            customCredential.persist = (uint)NativeMethods.CRED_PERSIST.LOCAL_MACHINE;
                            if (!string.IsNullOrEmpty(password)) {
                                customCredential.credentialBlobSize = (uint)Marshal.SystemDefaultCharSize * ((uint)password.Length);
                                customCredential.credentialBlob = Marshal.StringToCoTaskMemAuto(password);
                            }

                            try {
                                NativeMethods.CredWrite(ref customCredential, 0);
                            } finally {
                                if (customCredential.credentialBlob != IntPtr.Zero) {
                                    Marshal.FreeCoTaskMem(customCredential.credentialBlob);
                                }

                            }
                        }
                    }
                } catch {
                    // Ignore that failure to read back the credentials. We still have
                    // username and password to use in the current session.
                }

                retValue = DialogResult.OK;
            } else if (result == NativeMethods.CredUIReturnCodes.ERROR_CANCELLED) {
                retValue = DialogResult.Cancel;
            } else {
                Debug.Fail("CredUIPromptForCredentials failed with result = " + result.ToString());
                retValue = DialogResult.Cancel;
            }

            info.Dispose();
            return retValue;
        }
Example #2
0
        //---------------------------------------------------------------------
        // private methods
        //---------------------------------------------------------------------


        /// <summary>
        /// This function calls the OS dialog to prompt user for credential.
        /// </summary>
        /// <param name="target">
        /// The credential target. It is displayed in the prompt dialog and is
        /// used for credential storage.
        /// </param>
        /// <param name="hwdOwner">The parent for the dialog.</param>
        /// <param name="userName">The username supplied by the user.</param>
        /// <param name="password">The password supplied by the user.</param>
        /// <returns>
        /// DialogResult.OK = if Successfully prompted user for credentials.
        /// DialogResult.Cancel = if user cancelled the prompt dialog.
        /// </returns>
        private static DialogResult ShowOSCredentialDialog(string target, IntPtr hwdOwner, out string userName, out string password)
        {
            DialogResult retValue = DialogResult.Cancel;

            userName = string.Empty;
            password = string.Empty;

            string titleFormat       = SR.CredentialDialog_TitleFormat;
            string descriptionFormat = SR.CredentialDialog_DescriptionTextFormat;

            // Create the CREDUI_INFO structure.
            NativeMethods.CREDUI_INFO info = new NativeMethods.CREDUI_INFO();
            info.pszCaptionText      = string.Format(CultureInfo.CurrentUICulture, titleFormat, target);
            info.pszMessageText      = string.Format(CultureInfo.CurrentUICulture, descriptionFormat, target);
            info.hwndParentCERParent = hwdOwner;
            info.hbmBannerCERHandle  = IntPtr.Zero;
            info.cbSize = Marshal.SizeOf(info);

            // We do not use CREDUI_FLAGS_VALIDATE_USERNAME flag as it doesn't allow plain user
            // (one with no domain component). Instead we use CREDUI_FLAGS_COMPLETE_USERNAME.
            // It does some basic username validation (like doesnt allow two "\" in the user name.
            // It does adds the target to the username. For example, if user entered "foo" for
            // taget "bar.com", it will return username as "bar.com\foo". We trim out bar.com
            // while parsing the username. User can input "*****@*****.**" as workaround to provide
            // "bar.com\foo" as the username.
            // We specify CRED_TYPE_SERVER_CREDENTIAL flag as the stored credentials appear in the
            // "Control Panel->Stored Usernames and Password". It is how IE stores and retrieve
            // credentials. By using the CRED_TYPE_SERVER_CREDENTIAL flag allows IE and VS to
            // share credentials.
            // We dont specify the CREDUI_FLAGS_EXPECT_CONFIRMATION as the VS proxy service consumers
            // dont call back into the service to confirm that the call succeeded.
            NativeMethods.CREDUI_FLAGS flags = NativeMethods.CREDUI_FLAGS.SERVER_CREDENTIAL |
                                               NativeMethods.CREDUI_FLAGS.SHOW_SAVE_CHECK_BOX |
                                               NativeMethods.CREDUI_FLAGS.COMPLETE_USERNAME |
                                               NativeMethods.CREDUI_FLAGS.EXCLUDE_CERTIFICATES;

            StringBuilder user            = new StringBuilder(Convert.ToInt32(NativeMethods.CREDUI_MAX_USERNAME_LENGTH));
            StringBuilder pwd             = new StringBuilder(Convert.ToInt32(NativeMethods.CREDUI_MAX_PASSWORD_LENGTH));
            int           saveCredentials = 0;
            // Ensures that CredUPPromptForCredentials results in a prompt.
            int netError = NativeMethods.ERROR_LOGON_FAILURE;

            // Call the OS API to prompt for credentials.
            NativeMethods.CredUIReturnCodes result = NativeMethods.CredUIPromptForCredentials(
                info,
                target,
                IntPtr.Zero,
                netError,
                user,
                NativeMethods.CREDUI_MAX_USERNAME_LENGTH,
                pwd,
                NativeMethods.CREDUI_MAX_PASSWORD_LENGTH,
                ref saveCredentials,
                flags);


            if (result == NativeMethods.CredUIReturnCodes.NO_ERROR)
            {
                userName = user.ToString();
                password = pwd.ToString();

                try {
                    if (Convert.ToBoolean(saveCredentials))
                    {
                        // Try reading the credentials back to ensure that we can read the stored credentials. If
                        // the CredUIPromptForCredentials() function is not able successfully call CredGetTargetInfo(),
                        // it will store credentials with credential type as DOMAIN_PASSWORD. For DOMAIN_PASSWORD
                        // credential type we can only retrive the user name. As a workaround, we store the credentials
                        // as credential type as GENERIC.
                        string storedUserName;
                        string storedPassword;
                        bool   successfullyReadCredentials = ReadOSCredentials(target, out storedUserName, out storedPassword);
                        if (!successfullyReadCredentials ||
                            !string.Equals(userName, storedUserName, StringComparison.Ordinal) ||
                            !string.Equals(password, storedPassword, StringComparison.Ordinal))
                        {
                            // We are not able to retrieve the credentials. Try storing them as GENERIC credetails.

                            // Create the NativeCredential object.
                            NativeMethods.NativeCredential customCredential = new NativeMethods.NativeCredential();
                            customCredential.userName   = userName;
                            customCredential.type       = NativeMethods.CRED_TYPE_GENERIC;
                            customCredential.targetName = CreateCustomTarget(target);
                            // Store credentials across sessions.
                            customCredential.persist = (uint)NativeMethods.CRED_PERSIST.LOCAL_MACHINE;
                            if (!string.IsNullOrEmpty(password))
                            {
                                customCredential.credentialBlobSize = (uint)Marshal.SystemDefaultCharSize * ((uint)password.Length);
                                customCredential.credentialBlob     = Marshal.StringToCoTaskMemAuto(password);
                            }

                            try {
                                NativeMethods.CredWrite(ref customCredential, 0);
                            } finally {
                                if (customCredential.credentialBlob != IntPtr.Zero)
                                {
                                    Marshal.FreeCoTaskMem(customCredential.credentialBlob);
                                }
                            }
                        }
                    }
                } catch {
                    // Ignore that failure to read back the credentials. We still have
                    // username and password to use in the current session.
                }

                retValue = DialogResult.OK;
            }
            else if (result == NativeMethods.CredUIReturnCodes.ERROR_CANCELLED)
            {
                retValue = DialogResult.Cancel;
            }
            else
            {
                Debug.Fail("CredUIPromptForCredentials failed with result = " + result.ToString());
                retValue = DialogResult.Cancel;
            }

            info.Dispose();
            return(retValue);
        }