private async Task OnRequestAsync(LdapRequestMessage message, LdapClientConnection connection) { if (!await connection.TryAddPendingAsync(message).ConfigureAwait(false)) { return; } try { if (message is LdapAbandonRequest abandon) { connection.ContinueRead(); if (CriticalControlsSupported(abandon.Controls)) { connection.AbandonRequest(abandon.MessageId); } } else if (message is LdapBindRequest bind) { connection.ContinueRead(); try { await connection.BeginBindAsync().ConfigureAwait(false); var response = await BindRequestAsync(bind, connection).ConfigureAwait(false); await WriteAsync(response, connection).ConfigureAwait(false); } catch (Exception ex) { await WriteAsync(bind.Response(ResultCode.Other, ex.Message), connection).ConfigureAwait(false); } finally { connection.FinishBind(); } } else if (message is LdapUnbindRequest) { connection.ContinueRead(); UnbindRequest(connection); } else if (message is LdapSearchRequest search) { connection.ContinueRead(); await SearchRequestAsync(search, connection).ConfigureAwait(false); } else if (message is LdapExtendedRequest extended) { await ExtendedRequestAsync(extended, connection).ConfigureAwait(false); } else { connection.ContinueRead(); throw new NotImplementedException(); } } finally { connection.RemovePending(message); } }
private async Task SearchRequestAsync(LdapSearchRequest request, LdapClientConnection connection, CancellationToken cancellationToken) { try { if (request.BaseObject.RDNs.Count == 0 && request.Scope == SearchScope.BaseObject && request.Filter is LdapPresentFilter filter && (filter.Attribute.Oid.Equals("objectClass", StringComparison.OrdinalIgnoreCase) || filter.Attribute.Oid == "2.5.4.0")) { ICollection <LdapAttribute> attributes = _rootDse.GetAttributes(request.Attributes, request.TypesOnly).ToList(); if (_sslOptions != null && request.Attributes.Where(x => x.Selector != null).Any(x => x.Selector.Oid == SupportedExtensionAttribute.OidValue || x.Selector.Oid == SupportedExtensionAttribute.ShortName)) { var attribute = attributes.OfType <SupportedExtensionAttribute>().FirstOrDefault(); if (attribute == null) { attribute = new SupportedExtensionAttribute { Entries = { LdapExtendedRequest.StartTLS } }; attributes.Add(attribute); } else { attribute.Entries.Add(LdapExtendedRequest.StartTLS); } } attributes = await OnGetRootDSEAsync(attributes, connection, cancellationToken).ConfigureAwait(false); var entry = request.Result(LdapDistinguishedName.Empty, attributes.ToArray(), Array.Empty <LdapControl>()); await WriteAsync(entry, connection).ConfigureAwait(false); await WriteAsync(request.Done(), connection).ConfigureAwait(false); } else { var results = await OnSearchAsync(request, connection, cancellationToken).ConfigureAwait(false); bool done = false; foreach (var response in results) { await WriteAsync(response, connection).ConfigureAwait(false); if (response is LdapSearchResultDone) { done = true; break; } } if (!done) { await WriteAsync(request.Done(), connection).ConfigureAwait(false); } } }
private async Task <LdapBindResponse> OnBindAsync(LdapBindRequest request, LdapClientConnection connection) { ResultCode result = ResultCode.AuthMethodNotSupported; if (request.Simple != null) { result = await OnBindAsync(request.Name, request.Simple.Value, connection).ConfigureAwait(false); } else if (request.SaslMechanism == SupportedSASLMechanismsAttribute.Anonymous) { var credentials = request.SaslCredentials.GetValueOrDefault(ReadOnlyMemory <byte> .Empty); result = await OnSaslBindAsync(request.Name, String.Empty, credentials, connection).ConfigureAwait(false); } else if (request.SaslMechanism == SupportedSASLMechanismsAttribute.Plain) { if (request.SaslCredentials == null) { result = ResultCode.InappropriateAuthentication; } else { var credentials = request.SaslCredentials.Value; var first = credentials.Span.IndexOf((byte)0); var last = credentials.Span.LastIndexOf((byte)0); if (first == last) { result = ResultCode.InappropriateAuthentication; } else { first++; var user = Encoding.UTF8.GetString(credentials.Slice(first, last - first).Span); var password = credentials.Slice(last + 1); result = await OnSaslBindAsync(request.Name, user, password, connection).ConfigureAwait(false); } } } switch (result) { case ResultCode.Other: return(request.Response(result, "Not implemented")); case ResultCode.Success: return(request.Response()); default: return(request.Response(result, String.Empty)); } }
private async Task SearchRequestAsync(LdapSearchRequest request, LdapClientConnection connection) { if (request.TimeLimit != TimeSpan.Zero) { using (var cts = new CancellationTokenSource(request.TimeLimit)) using (var combined = CancellationTokenSource.CreateLinkedTokenSource(connection.CancellationToken, cts.Token)) { await SearchRequestAsync(request, connection, combined.Token).ConfigureAwait(false); } } else { await SearchRequestAsync(request, connection, connection.CancellationToken).ConfigureAwait(false); } }
private Task <LdapBindResponse> BindRequestAsync(LdapBindRequest request, LdapClientConnection connection) { if (request.Version != 3) { return(Task.FromResult(request.Response(ResultCode.ProtocolError, "only version 3 is supported"))); } if (!CriticalControlsSupported(request.Controls)) { return(Task.FromResult(request.Response(ResultCode.UnavailableCriticalExtension, String.Empty))); } if (request.Simple.HasValue && request.Simple.Value.Length == 0 && request.Name.RDNs.Count > 0) { //https://tools.ietf.org/html/rfc4513#section-5.1.2 return(Task.FromResult(request.Response(ResultCode.UnwillingToPerform, "Unauthenticated Bind"))); } if (request.SaslMechanism != null && request.SaslMechanism.Length == 0) { return(Task.FromResult(request.Response(ResultCode.AuthMethodNotSupported, "SASL aborted"))); } return(OnBindAsync(request, connection)); }
private static void UnbindRequest(LdapClientConnection connection) { connection.CloseConnection(); }
protected virtual Task <LdapExtendedResponse> OnExtendedAsync(LdapExtendedRequest request, LdapClientConnection connection) { return(Task.FromResult(request.NotSupported())); }
protected virtual Task <ICollection <LdapAttribute> > OnGetRootDSEAsync(ICollection <LdapAttribute> attributes, LdapClientConnection connection, CancellationToken cancellationToken) { return(Task.FromResult(attributes)); }
protected virtual Task <IEnumerable <LdapRequestMessage> > OnSearchAsync(LdapSearchRequest request, LdapClientConnection connection, CancellationToken cancellationToken) { return(Task.FromResult(Enumerable.Empty <LdapRequestMessage>())); }
protected virtual Task <ResultCode> OnSaslBindAsync(LdapDistinguishedName bindDN, string username, ReadOnlyMemory <byte> password, LdapClientConnection connection) { return(Task.FromResult(ResultCode.Other)); }
protected virtual void OnError(LdapClientConnection connection, LdapException exception) { return; }