/// <summary> /// Handles the async reception of the public key from the authentication service. /// </summary> /// <param name="ar">The async result instance.</param> private void OnGetKey(IAsyncResult ar) { AuthAsyncResult arAuth = (AuthAsyncResult)ar.AsyncState; GetPublicKeyAck ack; AuthMsg authMsg; using (TimedLock.Lock(this)) { try { if (!isOpen) { throw new AuthenticationException(NotOpenMsg); } ack = (GetPublicKeyAck)router.EndQuery(ar); publicKey = ack.PublicKey; // Now that we have the public key, we're going to broadcast // it to the authentication service instances so that they can // perform a man-in-the-middle security check. router.BroadcastTo(AbstractAuthServerEP, new AuthServerIDMsg(ack.PublicKey, ack.MachineName, ack.Address)); // Now initiate the authentication query. arAuth.OpState = AuthOpState.AuthPending; authMsg = new AuthMsg(AuthMsg.EncryptCredentials(publicKey, arAuth.Realm, arAuth.Account, arAuth.Password, out arAuth.SymmetricKey)); router.BeginQuery(AbstractAuthServerEP, authMsg, onAuth, arAuth); } catch (System.TimeoutException) { arAuth.Notify(new AuthenticationException("No authentication service instances responded.")); } catch (Exception e) { arAuth.Notify(e); } } }
/// <summary> /// Initiates an asynchronous account credential authentication. /// </summary> /// <param name="realm">The authentication realm.</param> /// <param name="account">The account.</param> /// <param name="password">The password.</param> /// <param name="callback">The delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application defined state (or <c>null</c>).</param> /// <returns>An <see cref="IAsyncResult" /> instance to be used to track the operation.</returns> /// <remarks> /// <note> /// Successful calls to this method must eventually be followed by a call /// to <see cref="EndAuthenticate" />. /// </note> /// </remarks> /// <exception cref="AuthenticationException">Thrown if the authenticator is not open.</exception> public IAsyncResult BeginAuthenticate(string realm, string account, string password, AsyncCallback callback, object state) { string cacheKey = GetCacheKey(realm, account, password); AuthAsyncResult arAuth; AuthenticationResult result; using (TimedLock.Lock(this)) { if (!isOpen) { throw new AuthenticationException(NotOpenMsg); } arAuth = new AuthAsyncResult(this, callback, state); arAuth.Realm = realm; arAuth.Account = account; arAuth.Password = password; arAuth.Started(); // First check to see if the answer is already cached if (cache != null && cache.TryGetValue(cacheKey, out result)) { arAuth.Result = result; arAuth.Notify(); if (result.Status != AuthenticationStatus.Authenticated && result.Status != AuthenticationStatus.AccountLocked) { // If the authentication failed and the account is not locked // then broadcast message to the authentication services so that // they can increment their fail counts. router.BroadcastTo(AbstractAuthServerEP, new AuthControlMsg("auth-failed", string.Format("realm={0};account={1};status={2}", realm, account, result.Status))); } return(arAuth); } // If we don't have the authentication service's public key yet then // initiate an async query to get it. if (publicKey == null) { arAuth.OpState = AuthOpState.GetPublicKey; router.BeginQuery(AbstractAuthServerEP, new GetPublicKeyMsg(), onGetKey, arAuth); return(arAuth); } // Initiate an async authentication query, encrypting the credentials // using the authentication service's public key. AuthMsg authMsg; arAuth.OpState = AuthOpState.AuthPending; authMsg = new AuthMsg(AuthMsg.EncryptCredentials(publicKey, realm, account, password, out arAuth.SymmetricKey)); router.BeginQuery(AbstractAuthServerEP, authMsg, onAuth, arAuth); return(arAuth); } }