namespace Unosquare.Swan.Networking.Ldap { using System.IO; /// /// Encapsulates a single search result that is in response to an asynchronous /// search operation. /// /// internal class LdapSearchResult : LdapMessage { private LdapEntry _entry; internal LdapSearchResult(RfcLdapMessage message) : base(message) { } public LdapEntry Entry { get { if (_entry != null) return _entry; var attrs = new LdapAttributeSet(); var entry = (RfcSearchResultEntry) Message.Response; foreach (var o in entry.Attributes.ToArray()) { var seq = (Asn1Sequence) o; var attr = new LdapAttribute(((Asn1OctetString)seq.Get(0)).StringValue()); var set = (Asn1Set)seq.Get(1); foreach (var t in set.ToArray()) { attr.AddValue(((Asn1OctetString)t).ByteValue()); } attrs.Add(attr); } _entry = new LdapEntry(entry.ObjectName, attrs); return _entry; } } public override string ToString() => _entry?.ToString() ?? base.ToString(); } /// /// Represents an Ldap Search Result Reference. ///
    /// SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LdapURL
    /// 
///
/// internal class RfcSearchResultReference : Asn1SequenceOf { /// /// Initializes a new instance of the class. /// The only time a client will create a SearchResultReference is when it is /// decoding it from an Stream. /// /// The streab. /// The length. public RfcSearchResultReference(Stream stream, int len) : base(stream, len) { } public override Asn1Identifier GetIdentifier() => new Asn1Identifier(LdapOperation.SearchResultReference); } /// /// Represents an Ldap Extended Response. ///
    /// ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
    /// COMPONENTS OF LdapResult,
    /// responseName     [10] LdapOID OPTIONAL,
    /// response         [11] OCTET STRING OPTIONAL }
    /// 
///
/// /// internal class RfcExtendedResponse : Asn1Sequence, IRfcResponse { public const int ResponseNameCode = 10; public const int ResponseCode = 11; private readonly int _referralIndex; private readonly int _responseNameIndex; private readonly int _responseIndex; /// /// Initializes a new instance of the class. /// The only time a client will create a ExtendedResponse is when it is /// decoding it from an stream. /// /// The stream. /// The length. public RfcExtendedResponse(Stream stream, int len) : base(stream, len) { if (Size() <= 3) return; for (var i = 3; i < Size(); i++) { var obj = (Asn1Tagged) Get(i); var id = obj.GetIdentifier(); switch (id.Tag) { case RfcLdapResult.Referral: var content = ((Asn1OctetString) obj.TaggedValue).ByteValue(); using (var bais = new MemoryStream(content.ToByteArray())) Set(i, new Asn1SequenceOf(bais, content.Length)); _referralIndex = i; break; case ResponseNameCode: Set(i, new Asn1OctetString(((Asn1OctetString) obj.TaggedValue).ByteValue())); _responseNameIndex = i; break; case ResponseCode: Set(i, obj.TaggedValue); _responseIndex = i; break; } } } public Asn1OctetString ResponseName => _responseNameIndex != 0 ? (Asn1OctetString) Get(_responseNameIndex) : null; public Asn1OctetString Response => _responseIndex != 0 ? (Asn1OctetString) Get(_responseIndex) : null; public Asn1Enumerated GetResultCode() => (Asn1Enumerated) Get(0); public Asn1OctetString GetMatchedDN() => new Asn1OctetString(((Asn1OctetString) Get(1)).ByteValue()); public Asn1OctetString GetErrorMessage() => new Asn1OctetString(((Asn1OctetString) Get(2)).ByteValue()); public Asn1SequenceOf GetReferral() => _referralIndex != 0 ? (Asn1SequenceOf) Get(_referralIndex) : null; public override Asn1Identifier GetIdentifier() => new Asn1Identifier(LdapOperation.ExtendedResponse); } /// /// Represents and Ldap Bind Response. ///
    /// BindResponse ::= [APPLICATION 1] SEQUENCE {
    /// COMPONENTS OF LdapResult,
    /// serverSaslCreds    [7] OCTET STRING OPTIONAL }
    /// 
///
/// /// internal class RfcBindResponse : Asn1Sequence, IRfcResponse { /// /// Initializes a new instance of the class. /// The only time a client will create a BindResponse is when it is /// decoding it from an InputStream /// Note: If serverSaslCreds is included in the BindResponse, it does not /// need to be decoded since it is already an OCTET STRING. /// /// The in renamed. /// The length. public RfcBindResponse(Stream stream, int len) : base(stream, len) { // Decode optional referral from Asn1OctetString to Referral. if (Size() <= 3) return; var obj = (Asn1Tagged) Get(3); if (obj.GetIdentifier().Tag != RfcLdapResult.Referral) return; var content = ((Asn1OctetString) obj.TaggedValue).ByteValue(); using (var bais = new MemoryStream(content.ToByteArray())) Set(3, new Asn1SequenceOf(bais, content.Length)); } public Asn1Enumerated GetResultCode() => (Asn1Enumerated) Get(0); public Asn1OctetString GetMatchedDN() => new Asn1OctetString(((Asn1OctetString) Get(1)).ByteValue()); public Asn1OctetString GetErrorMessage() => new Asn1OctetString(((Asn1OctetString) Get(2)).ByteValue()); public Asn1SequenceOf GetReferral() => Size() > 3 && Get(3) is Asn1SequenceOf ? (Asn1SequenceOf) Get(3) : null; public override Asn1Identifier GetIdentifier() => new Asn1Identifier(LdapOperation.BindResponse); } /// /// Represents an LDAP Intermediate Response. /// IntermediateResponse ::= [APPLICATION 25] SEQUENCE { /// COMPONENTS OF LDAPResult, note: only present on incorrectly /// encoded response from pre Falcon-sp1 server /// responseName [10] LDAPOID OPTIONAL, /// responseValue [11] OCTET STRING OPTIONAL }. /// /// /// internal class RfcIntermediateResponse : Asn1Sequence, IRfcResponse { public const int TagResponseName = 0; public const int TagResponse = 1; public RfcIntermediateResponse(Stream stream, int len) : base(stream, len) { var i = Size() >= 3 ? 3 : 0; for (; i < Size(); i++) { var obj = (Asn1Tagged) Get(i); switch (obj.GetIdentifier().Tag) { case TagResponseName: Set(i, new Asn1OctetString(((Asn1OctetString) obj.TaggedValue).ByteValue())); break; case TagResponse: Set(i, obj.TaggedValue); break; } } } public Asn1Enumerated GetResultCode() => Size() > 3 ? (Asn1Enumerated) Get(0) : null; public Asn1OctetString GetMatchedDN() => Size() > 3 ? new Asn1OctetString(((Asn1OctetString) Get(1)).ByteValue()) : null; public Asn1OctetString GetErrorMessage() => Size() > 3 ? new Asn1OctetString(((Asn1OctetString) Get(2)).ByteValue()) : null; public Asn1SequenceOf GetReferral() => Size() > 3 ? (Asn1SequenceOf) Get(3) : null; public override Asn1Identifier GetIdentifier() => new Asn1Identifier(LdapOperation.IntermediateResponse); } }