using System;
namespace Unosquare.Swan.Networking.Ldap {
///
/// Represents an Ldap Control.
///
/// Control ::= SEQUENCE {
/// controlType LdapOID,
/// criticality BOOLEAN DEFAULT FALSE,
/// controlValue OCTET STRING OPTIONAL }
///
///
///
internal class RfcControl : Asn1Sequence {
///
/// Initializes a new instance of the class.
/// Note: criticality is only added if true, as per RFC 2251 sec 5.1 part
/// (4): If a value of a type is its default value, it MUST be
/// absent.
///
/// Type of the control.
/// The criticality.
/// The control value.
public RfcControl(String controlType, Asn1Boolean criticality = null, Asn1Object controlValue = null)
: base(3) {
this.Add(controlType);
this.Add(criticality ?? new Asn1Boolean(false));
if(controlValue != null) {
this.Add(controlValue);
}
}
public RfcControl(Asn1Structured seqObj)
: base(3) {
for(Int32 i = 0; i < seqObj.Size(); i++) {
this.Add(seqObj.Get(i));
}
}
public Asn1OctetString ControlType => (Asn1OctetString)this.Get(0);
public Asn1Boolean Criticality => this.Size() > 1 && this.Get(1) is Asn1Boolean boolean ? boolean : new Asn1Boolean(false);
public Asn1OctetString ControlValue {
get {
if(this.Size() > 2) {
// MUST be a control value
return (Asn1OctetString)this.Get(2);
}
return this.Size() > 1 && this.Get(1) is Asn1OctetString s ? s : null;
}
set {
if(value == null) {
return;
}
if(this.Size() == 3) {
// We already have a control value, replace it
this.Set(2, value);
return;
}
if(this.Size() == 2) {
// Get the second element
Asn1Object obj = this.Get(1);
// Is this a control value
if(obj is Asn1OctetString) {
// replace this one
this.Set(1, value);
} else {
// add a new one at the end
this.Add(value);
}
}
}
}
}
///
/// Represents Ldap Sasl Credentials.
///
/// SaslCredentials ::= SEQUENCE {
/// mechanism LdapString,
/// credentials OCTET STRING OPTIONAL }
///
///
internal class RfcSaslCredentials : Asn1Sequence {
public RfcSaslCredentials(String mechanism, SByte[] credentials = null)
: base(2) {
this.Add(mechanism);
if(credentials != null) {
this.Add(new Asn1OctetString(credentials));
}
}
}
///
/// Represents an Ldap Authentication Choice.
///
/// AuthenticationChoice ::= CHOICE {
/// simple [0] OCTET STRING,
/// -- 1 and 2 reserved
/// sasl [3] SaslCredentials }
///
///
internal class RfcAuthenticationChoice : Asn1Choice {
public RfcAuthenticationChoice(SByte[] passwd)
: base(new Asn1Tagged(new Asn1Identifier(0), new Asn1OctetString(passwd), false)) {
}
public RfcAuthenticationChoice(String mechanism, SByte[] credentials)
: base(new Asn1Tagged(new Asn1Identifier(3, true), new RfcSaslCredentials(mechanism, credentials), false)) {
// implicit tagging
}
}
}