using System; using System.IO; namespace Unosquare.Swan.Networking.Ldap { /// /// 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(this._entry != null) { return this._entry; } LdapAttributeSet attrs = new LdapAttributeSet(); RfcSearchResultEntry entry = (RfcSearchResultEntry)this.Message.Response; foreach(Asn1Object o in entry.Attributes.ToArray()) { Asn1Sequence seq = (Asn1Sequence)o; LdapAttribute attr = new LdapAttribute(((Asn1OctetString)seq.Get(0)).StringValue()); Asn1Set set = (Asn1Set)seq.Get(1); foreach(Asn1Object t in set.ToArray()) { attr.AddValue(((Asn1OctetString)t).ByteValue()); } _ = attrs.Add(attr); } this._entry = new LdapEntry(entry.ObjectName, attrs); return this._entry; } } public override String ToString() => this._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, Int32 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 Int32 ResponseNameCode = 10; public const Int32 ResponseCode = 11; private readonly Int32 _referralIndex; private readonly Int32 _responseNameIndex; private readonly Int32 _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, Int32 len) : base(stream, len) { if(this.Size() <= 3) { return; } for(Int32 i = 3; i < this.Size(); i++) { Asn1Tagged obj = (Asn1Tagged)this.Get(i); Asn1Identifier id = obj.GetIdentifier(); switch(id.Tag) { case RfcLdapResult.Referral: SByte[] content = ((Asn1OctetString)obj.TaggedValue).ByteValue(); using(MemoryStream bais = new MemoryStream(content.ToByteArray())) { this.Set(i, new Asn1SequenceOf(bais, content.Length)); } this._referralIndex = i; break; case ResponseNameCode: this.Set(i, new Asn1OctetString(((Asn1OctetString)obj.TaggedValue).ByteValue())); this._responseNameIndex = i; break; case ResponseCode: this.Set(i, obj.TaggedValue); this._responseIndex = i; break; } } } public Asn1OctetString ResponseName => this._responseNameIndex != 0 ? (Asn1OctetString)this.Get(this._responseNameIndex) : null; public Asn1OctetString Response => this._responseIndex != 0 ? (Asn1OctetString)this.Get(this._responseIndex) : null; public Asn1Enumerated GetResultCode() => (Asn1Enumerated)this.Get(0); public Asn1OctetString GetMatchedDN() => new Asn1OctetString(((Asn1OctetString)this.Get(1)).ByteValue()); public Asn1OctetString GetErrorMessage() => new Asn1OctetString(((Asn1OctetString)this.Get(2)).ByteValue()); public Asn1SequenceOf GetReferral() => this._referralIndex != 0 ? (Asn1SequenceOf)this.Get(this._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, Int32 len) : base(stream, len) { // Decode optional referral from Asn1OctetString to Referral. if(this.Size() <= 3) { return; } Asn1Tagged obj = (Asn1Tagged)this.Get(3); if(obj.GetIdentifier().Tag != RfcLdapResult.Referral) { return; } SByte[] content = ((Asn1OctetString)obj.TaggedValue).ByteValue(); using(MemoryStream bais = new MemoryStream(content.ToByteArray())) { this.Set(3, new Asn1SequenceOf(bais, content.Length)); } } public Asn1Enumerated GetResultCode() => (Asn1Enumerated)this.Get(0); public Asn1OctetString GetMatchedDN() => new Asn1OctetString(((Asn1OctetString)this.Get(1)).ByteValue()); public Asn1OctetString GetErrorMessage() => new Asn1OctetString(((Asn1OctetString)this.Get(2)).ByteValue()); public Asn1SequenceOf GetReferral() => this.Size() > 3 && this.Get(3) is Asn1SequenceOf ? (Asn1SequenceOf)this.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 Int32 TagResponseName = 0; public const Int32 TagResponse = 1; public RfcIntermediateResponse(Stream stream, Int32 len) : base(stream, len) { Int32 i = this.Size() >= 3 ? 3 : 0; for(; i < this.Size(); i++) { Asn1Tagged obj = (Asn1Tagged)this.Get(i); switch(obj.GetIdentifier().Tag) { case TagResponseName: this.Set(i, new Asn1OctetString(((Asn1OctetString)obj.TaggedValue).ByteValue())); break; case TagResponse: this.Set(i, obj.TaggedValue); break; } } } public Asn1Enumerated GetResultCode() => this.Size() > 3 ? (Asn1Enumerated)this.Get(0) : null; public Asn1OctetString GetMatchedDN() => this.Size() > 3 ? new Asn1OctetString(((Asn1OctetString)this.Get(1)).ByteValue()) : null; public Asn1OctetString GetErrorMessage() => this.Size() > 3 ? new Asn1OctetString(((Asn1OctetString)this.Get(2)).ByteValue()) : null; public Asn1SequenceOf GetReferral() => this.Size() > 3 ? (Asn1SequenceOf)this.Get(3) : null; public override Asn1Identifier GetIdentifier() => new Asn1Identifier(LdapOperation.IntermediateResponse); } }