/// <summary> /// Request user credentials, coordinating between multiple threads looking for the same credentials. /// </summary> /// <remarks>Unlike Update, this will not re-prompt the user if they previously declined to provide credentials and it will assume any cached credentials work.</remarks> /// <returns>The new authentication provider</returns> /// <exception cref="WebChannelAuthorizationException">Thrown when no credentials were provided</exception> private static IWebAuthenticationProvider RequestUserCredentials(string entryUri, Guid repositoryId) { var cacheKey = new CredentialCacheKey(entryUri, repositoryId); IWebAuthenticationProvider authenticationProvider; //we only want one thread to pop up the UI to request authentication at a time. lock (g_RequestLock) { //WAIT: Since we requested the lock someone may have put credentials in the collection, so we have to check again. lock (g_Lock) { System.Threading.Monitor.PulseAll(g_Lock); if (g_CachedBlockedCredentials.ContainsKey(entryUri)) //someone may have just canceled. { throw new WebChannelAuthorizationException("User declined to provide credentials"); } if (g_CachedCredentials.TryGetValue(cacheKey, out authenticationProvider)) { return(authenticationProvider); //yep, someone else got them. } } var credentialEventArgs = new CredentialsRequiredEventArgs(entryUri, repositoryId, false, null); OnCredentialsRequired(null, credentialEventArgs); if (credentialEventArgs.Cancel) { //if the user canceled we need to cache that so we don't keep pounding the user. lock (g_Lock) { g_CachedBlockedCredentials[entryUri] = entryUri; System.Threading.Monitor.PulseAll(g_Lock); } throw new WebChannelAuthorizationException("User declined to provide credentials"); } if (ReferenceEquals(credentialEventArgs.AuthenticationProvider, null)) { throw new WebChannelAuthorizationException("No credentials are available for the specified server"); } authenticationProvider = credentialEventArgs.AuthenticationProvider; lock (g_Lock) { g_CachedCredentials.Add(cacheKey, authenticationProvider); System.Threading.Monitor.PulseAll(g_Lock); } System.Threading.Monitor.PulseAll(g_RequestLock); } return(authenticationProvider); }
private static void OnCredentialsRequired(object source, CredentialsRequiredEventArgs e) { CredentialsRequiredEventHandler handler = CredentialsRequired; if (handler != null) { handler(source, e); } }
/// <summary> /// Attempt to re-query the credentials for the specified URI /// </summary> /// <param name="entryUri">The entry URI to update credentials for</param> /// <param name="repositoryId">The owner Id to specify to the server (for example repository Id)</param> /// <param name="forceUpdate">True to force a requery to the user even if they previously canceled requesting credentials</param> /// <returns>True if the user provided updated credentials, false if they canceled</returns> public static bool UpdateCredentials(string entryUri, Guid repositoryId, bool forceUpdate) { var cacheKey = new CredentialCacheKey(entryUri, repositoryId); bool newCredentialsProvided = false; lock (g_Lock) //if we have any in cache we need to update those, so in this case we stall EVERYONE. { //WAIT: Since we requested the lock someone may have put credentials in the collection, so we have to check again. System.Threading.Monitor.PulseAll(g_Lock); if ((forceUpdate == false) && (g_CachedBlockedCredentials.ContainsKey(entryUri))) { return(false); } IWebAuthenticationProvider credentials; g_CachedCredentials.TryGetValue(cacheKey, out credentials); //we only want one thread to pop up the UI to request authentication at a time. lock (g_RequestLock) { var credentialEventArgs = new CredentialsRequiredEventArgs(entryUri, repositoryId, true, credentials); OnCredentialsRequired(null, credentialEventArgs); if (credentialEventArgs.Cancel == false) { if (credentialEventArgs.AuthenticationProvider == null) { throw new InvalidOperationException("No credentials are available for the specified server"); } newCredentialsProvided = true; g_CachedBlockedCredentials.Remove(entryUri); //if it was previously blocked, unblock it. g_CachedCredentials[cacheKey] = credentialEventArgs.AuthenticationProvider; //overwrite any existing value. } System.Threading.Monitor.PulseAll(g_RequestLock); } System.Threading.Monitor.PulseAll(g_Lock); } return(newCredentialsProvided); }